Support combined shaders+allow loading shaders from string

This commit is contained in:
bloeys
2022-07-02 22:49:28 +04:00
parent d4fe6d4071
commit fe2aef6b6d
9 changed files with 167 additions and 108 deletions

10
main.go
View File

@ -19,10 +19,9 @@ import (
) )
//TODO: Tasks: //TODO: Tasks:
// Build simple game
// Integrate physx
// Entities and components
// Camera class // Camera class
// Entities and components
// Integrate physx
//Low Priority: //Low Priority:
// Create VAO struct independent from VBO to support multi-VBO use cases (e.g. instancing) // Create VAO struct independent from VBO to support multi-VBO use cases (e.g. instancing)
@ -31,7 +30,6 @@ import (
// Separate engine loop from rendering loop? or leave it to the user? // Separate engine loop from rendering loop? or leave it to the user?
// Abstract keys enum away from sdl // Abstract keys enum away from sdl
// Proper Asset loading // Proper Asset loading
// Audio
// Frustum culling // Frustum culling
// Material system editor with fields automatically extracted from the shader // Material system editor with fields automatically extracted from the shader
@ -58,7 +56,7 @@ type OurGame struct {
func (g *OurGame) Init() { func (g *OurGame) Init() {
//Create materials //Create materials
simpleMat = materials.NewMaterial("Simple Mat", "./res/shaders/simple") simpleMat = materials.NewMaterial("Simple Mat", "./res/shaders/simple.glsl")
//Load meshes //Load meshes
var err error var err error
@ -98,7 +96,7 @@ func (g *OurGame) Init() {
func (g *OurGame) Update() { func (g *OurGame) Update() {
if input.IsQuitClicked() { if input.IsQuitClicked() || input.KeyClicked(sdl.K_ESCAPE) {
engine.Quit() engine.Quit()
} }

View File

@ -106,24 +106,20 @@ func (m *Material) Delete() {
func NewMaterial(matName, shaderPath string) *Material { func NewMaterial(matName, shaderPath string) *Material {
shdrProg, err := shaders.NewShaderProgram() shdrProg, err := shaders.LoadAndCompileCombinedShader(shaderPath)
if err != nil { if err != nil {
logging.ErrLog.Fatalln("Failed to create new shader program. Err: ", err) logging.ErrLog.Fatalln("Failed to create new material. Err: ", err)
}
return &Material{Name: matName, ShaderProg: shdrProg, UnifLocs: make(map[string]int32), AttribLocs: make(map[string]int32)}
}
func NewMaterialSrc(matName string, shaderSrc []byte) *Material {
shdrProg, err := shaders.LoadAndCompileCombinedShaderSrc(shaderSrc)
if err != nil {
logging.ErrLog.Fatalln("Failed to create new material. Err: ", err)
} }
vertShader, err := shaders.LoadAndCompilerShader(shaderPath+".vert.glsl", shaders.VertexShaderType)
if err != nil {
logging.ErrLog.Fatalln("Failed to load and create vertex shader. Err: ", err)
}
fragShader, err := shaders.LoadAndCompilerShader(shaderPath+".frag.glsl", shaders.FragmentShaderType)
if err != nil {
logging.ErrLog.Fatalln("Failed to load and create fragment shader. Err: ", err)
}
shdrProg.AttachShader(vertShader)
shdrProg.AttachShader(fragShader)
shdrProg.Link()
return &Material{Name: matName, ShaderProg: shdrProg, UnifLocs: make(map[string]int32), AttribLocs: make(map[string]int32)} return &Material{Name: matName, ShaderProg: shdrProg, UnifLocs: make(map[string]int32), AttribLocs: make(map[string]int32)}
} }

View File

@ -1,13 +0,0 @@
#version 410
uniform sampler2D Texture;
in vec2 Frag_UV;
in vec4 Frag_Color;
out vec4 Out_Color;
void main()
{
Out_Color = vec4(Frag_Color.rgb, Frag_Color.a * texture(Texture, Frag_UV.st).r);
}

View File

@ -1,17 +0,0 @@
#version 410
uniform mat4 ProjMtx;
in vec2 Position;
in vec2 UV;
in vec4 Color;
out vec2 Frag_UV;
out vec4 Frag_Color;
void main()
{
Frag_UV = UV;
Frag_Color = Color;
gl_Position = ProjMtx * vec4(Position.xy, 0, 1);
}

View File

@ -1,26 +0,0 @@
#version 410
uniform float ambientStrength = 0.1;
uniform vec3 ambientLightColor = vec3(1, 1, 1);
uniform vec3 lightPos1;
uniform vec3 lightColor1;
uniform sampler2D diffTex;
in vec3 vertColor;
in vec3 vertNormal;
in vec2 vertUV0;
in vec3 fragPos;
out vec4 fragColor;
void main()
{
vec3 lightDir = normalize(lightPos1 - fragPos);
float diffStrength = max(0.0, dot(normalize(vertNormal), lightDir));
vec3 finalAmbientColor = ambientLightColor * ambientStrength;
vec4 texColor = texture(diffTex, vertUV0);
fragColor = vec4(texColor.rgb * vertColor * (finalAmbientColor + diffStrength*lightColor1) , texColor.a);
}

55
res/shaders/simple.glsl Executable file
View File

@ -0,0 +1,55 @@
//shader:vertex
#version 410
layout(location=0) in vec3 vertPosIn;
layout(location=1) in vec3 vertNormalIn;
layout(location=2) in vec2 vertUV0In;
layout(location=3) in vec3 vertColorIn;
out vec3 vertNormal;
out vec2 vertUV0;
out vec3 vertColor;
out vec3 fragPos;
//MVP = Model View Projection
uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projMat;
void main()
{
vertNormal = mat3(transpose(inverse(modelMat))) * vertNormalIn;
vertUV0 = vertUV0In;
vertColor = vertColorIn;
fragPos = vec3(modelMat * vec4(vertPosIn, 1.0));
gl_Position = projMat * viewMat * modelMat * vec4(vertPosIn, 1.0);
}
//shader:fragment
#version 410
uniform float ambientStrength = 0.1;
uniform vec3 ambientLightColor = vec3(1, 1, 1);
uniform vec3 lightPos1;
uniform vec3 lightColor1;
uniform sampler2D diffTex;
in vec3 vertColor;
in vec3 vertNormal;
in vec2 vertUV0;
in vec3 fragPos;
out vec4 fragColor;
void main()
{
vec3 lightDir = normalize(lightPos1 - fragPos);
float diffStrength = max(0.0, dot(normalize(vertNormal), lightDir));
vec3 finalAmbientColor = ambientLightColor * ambientStrength;
vec4 texColor = texture(diffTex, vertUV0);
fragColor = vec4(texColor.rgb * vertColor * (finalAmbientColor + diffStrength*lightColor1) , texColor.a);
}

View File

@ -1,26 +0,0 @@
#version 410
layout(location=0) in vec3 vertPosIn;
layout(location=1) in vec3 vertNormalIn;
layout(location=2) in vec2 vertUV0In;
layout(location=3) in vec3 vertColorIn;
out vec3 vertNormal;
out vec2 vertUV0;
out vec3 vertColor;
out vec3 fragPos;
//MVP = Model View Projection
uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projMat;
void main()
{
vertNormal = mat3(transpose(inverse(modelMat))) * vertNormalIn;
vertUV0 = vertUV0In;
vertColor = vertColorIn;
fragPos = vec3(modelMat * vec4(vertPosIn, 1.0));
gl_Position = projMat * viewMat * modelMat * vec4(vertPosIn, 1.0);
}

View File

@ -1,6 +1,7 @@
package shaders package shaders
import ( import (
"bytes"
"errors" "errors"
"os" "os"
"strings" "strings"
@ -28,14 +29,69 @@ func NewShaderProgram() (ShaderProgram, error) {
return ShaderProgram{ID: id}, nil return ShaderProgram{ID: id}, nil
} }
func LoadAndCompilerShader(shaderPath string, shaderType ShaderType) (Shader, error) { func LoadAndCompileCombinedShader(shaderPath string) (ShaderProgram, error) {
shaderSource, err := os.ReadFile(shaderPath) combinedSource, err := os.ReadFile(shaderPath)
if err != nil { if err != nil {
logging.ErrLog.Println("Failed to read shader. Err: ", err) logging.ErrLog.Println("Failed to read shader. Err: ", err)
return Shader{}, err return ShaderProgram{}, err
} }
return LoadAndCompileCombinedShaderSrc(combinedSource)
}
func LoadAndCompileCombinedShaderSrc(shaderSrc []byte) (ShaderProgram, error) {
shaderSources := bytes.Split(shaderSrc, []byte("//shader:"))
if len(shaderSources) == 1 {
return ShaderProgram{}, errors.New("failed to read combined shader. Did not find '//shader:vertex' or '//shader:fragment'")
}
shdrProg, err := NewShaderProgram()
if err != nil {
return ShaderProgram{}, errors.New("failed to create new shader program. Err: " + err.Error())
}
loadedShdrCount := 0
for i := 0; i < len(shaderSources); i++ {
src := shaderSources[i]
//This can happen when the shader type is at the start of the file
if len(bytes.TrimSpace(src)) == 0 {
continue
}
var shdrType ShaderType
if bytes.HasPrefix(src, []byte("vertex")) {
src = src[6:]
shdrType = VertexShaderType
} else if bytes.HasPrefix(src, []byte("fragment")) {
src = src[8:]
shdrType = FragmentShaderType
} else {
return ShaderProgram{}, errors.New("unknown shader type. Must be '//shader:vertex' or '//shader:fragment'")
}
shdr, err := CompileShaderOfType(src, shdrType)
if err != nil {
return ShaderProgram{}, err
}
loadedShdrCount++
shdrProg.AttachShader(shdr)
}
if loadedShdrCount == 0 {
return ShaderProgram{}, errors.New("no valid shaders found. Please put '//shader:vertex' or '//shader:fragment' before your shaders")
}
shdrProg.Link()
return shdrProg, nil
}
func CompileShaderOfType(shaderSource []byte, shaderType ShaderType) (Shader, error) {
shaderID := gl.CreateShader(uint32(shaderType)) shaderID := gl.CreateShader(uint32(shaderType))
if shaderID == 0 { if shaderID == 0 {
logging.ErrLog.Println("Failed to create shader.") logging.ErrLog.Println("Failed to create shader.")

View File

@ -149,11 +149,47 @@ func (i *ImguiInfo) AddFontTTF(fontPath string, fontSize float32, fontConfig *im
return f return f
} }
const imguiShdrSrc = `
//shader:vertex
#version 410
uniform mat4 ProjMtx;
in vec2 Position;
in vec2 UV;
in vec4 Color;
out vec2 Frag_UV;
out vec4 Frag_Color;
void main()
{
Frag_UV = UV;
Frag_Color = Color;
gl_Position = ProjMtx * vec4(Position.xy, 0, 1);
}
//shader:fragment
#version 410
uniform sampler2D Texture;
in vec2 Frag_UV;
in vec4 Frag_Color;
out vec4 Out_Color;
void main()
{
Out_Color = vec4(Frag_Color.rgb, Frag_Color.a * texture(Texture, Frag_UV.st).r);
}
`
func NewImGUI() ImguiInfo { func NewImGUI() ImguiInfo {
imguiInfo := ImguiInfo{ imguiInfo := ImguiInfo{
ImCtx: imgui.CreateContext(nil), ImCtx: imgui.CreateContext(nil),
Mat: materials.NewMaterial("ImGUI Mat", "./res/shaders/imgui"), Mat: materials.NewMaterialSrc("ImGUI Mat", []byte(imguiShdrSrc)),
} }
imIO := imgui.CurrentIO() imIO := imgui.CurrentIO()