diff --git a/main.go b/main.go index 6345519..98e90e3 100755 --- a/main.go +++ b/main.go @@ -36,6 +36,7 @@ import ( - Point light shadows ✅ - Spotlight shadows ✅ - Create VAO struct independent from VBO to support multi-VBO use cases (e.g. instancing) ✅ + - Normals maps - UBO support - HDR - Cascaded shadow mapping @@ -226,6 +227,7 @@ var ( unlitMat materials.Material whiteMat materials.Material containerMat materials.Material + groundMat materials.Material palleteMat materials.Material skyboxMat materials.Material depthMapMat materials.Material @@ -309,8 +311,8 @@ var ( InnerCutoffRad: 15 * gglm.Deg2Rad, OuterCutoffRad: 20 * gglm.Deg2Rad, - NearPlane: 1, - FarPlane: 30, + NearPlane: 2, + FarPlane: 50, }, } ) @@ -498,6 +500,16 @@ func (g *Game) Init() { logging.ErrLog.Fatalln("Failed to load texture. Err: ", err) } + brickwallDiffuseTex, err := assets.LoadTexturePNG("./res/textures/brickwall.png", &assets.TextureLoadOptions{}) + if err != nil { + logging.ErrLog.Fatalln("Failed to load texture. Err: ", err) + } + + brickwallNormalTex, err := assets.LoadTexturePNG("./res/textures/brickwall-normal.png", &assets.TextureLoadOptions{}) + if err != nil { + logging.ErrLog.Fatalln("Failed to load texture. Err: ", err) + } + skyboxCmap, err = assets.LoadCubemapTextures( "./res/textures/sb-right.jpg", "./res/textures/sb-left.jpg", "./res/textures/sb-top.jpg", "./res/textures/sb-bottom.jpg", @@ -517,11 +529,11 @@ func (g *Game) Init() { screenQuadMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse)) unlitMat = materials.NewMaterial("Unlit mat", "./res/shaders/simple-unlit.glsl") - unlitMat.Settings.Set(materials.MaterialSettings_HasModelMat) + unlitMat.Settings.Set(materials.MaterialSettings_HasModelMtx) unlitMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse)) whiteMat = materials.NewMaterial("White mat", "./res/shaders/simple.glsl") - whiteMat.Settings.Set(materials.MaterialSettings_HasModelMat | materials.MaterialSettings_HasNormalMat) + whiteMat.Settings.Set(materials.MaterialSettings_HasModelMtx | materials.MaterialSettings_HasNormalMtx) whiteMat.Shininess = 64 whiteMat.DiffuseTex = whiteTex.TexID whiteMat.SpecularTex = blackTex.TexID @@ -529,7 +541,7 @@ func (g *Game) Init() { whiteMat.EmissionTex = blackTex.TexID whiteMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse)) whiteMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular)) - // whiteMat.SetUnifInt32("material.normal", int32(materials.TextureSlot_Normal)) + whiteMat.SetUnifInt32("material.normal", int32(materials.TextureSlot_Normal)) whiteMat.SetUnifInt32("material.emission", int32(materials.TextureSlot_Emission)) whiteMat.SetUnifVec3("ambientColor", &ambientColor) whiteMat.SetUnifFloat32("material.shininess", whiteMat.Shininess) @@ -541,7 +553,7 @@ func (g *Game) Init() { whiteMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1)) containerMat = materials.NewMaterial("Container mat", "./res/shaders/simple.glsl") - containerMat.Settings.Set(materials.MaterialSettings_HasModelMat | materials.MaterialSettings_HasNormalMat) + containerMat.Settings.Set(materials.MaterialSettings_HasModelMtx | materials.MaterialSettings_HasNormalMtx) containerMat.Shininess = 64 containerMat.DiffuseTex = containerDiffuseTex.TexID containerMat.SpecularTex = containerSpecularTex.TexID @@ -549,7 +561,7 @@ func (g *Game) Init() { containerMat.EmissionTex = blackTex.TexID containerMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse)) containerMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular)) - // containerMat.SetUnifInt32("material.normal", int32(materials.TextureSlot_Normal)) + containerMat.SetUnifInt32("material.normal", int32(materials.TextureSlot_Normal)) containerMat.SetUnifInt32("material.emission", int32(materials.TextureSlot_Emission)) containerMat.SetUnifVec3("ambientColor", &ambientColor) containerMat.SetUnifFloat32("material.shininess", containerMat.Shininess) @@ -560,8 +572,28 @@ func (g *Game) Init() { containerMat.SetUnifInt32("pointLightCubeShadowMaps", int32(materials.TextureSlot_Cubemap_Array)) containerMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1)) + groundMat = materials.NewMaterial("Ground mat", "./res/shaders/simple.glsl") + groundMat.Settings.Set(materials.MaterialSettings_HasModelMtx | materials.MaterialSettings_HasNormalMtx) + groundMat.Shininess = 64 + groundMat.DiffuseTex = brickwallDiffuseTex.TexID + groundMat.SpecularTex = blackTex.TexID + groundMat.NormalTex = brickwallNormalTex.TexID + groundMat.EmissionTex = blackTex.TexID + groundMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse)) + groundMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular)) + groundMat.SetUnifInt32("material.normal", int32(materials.TextureSlot_Normal)) + groundMat.SetUnifInt32("material.emission", int32(materials.TextureSlot_Emission)) + groundMat.SetUnifVec3("ambientColor", &ambientColor) + groundMat.SetUnifFloat32("material.shininess", groundMat.Shininess) + groundMat.SetUnifVec3("dirLight.dir", &dirLight.Dir) + groundMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) + groundMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor) + groundMat.SetUnifInt32("dirLight.shadowMap", int32(materials.TextureSlot_ShadowMap1)) + groundMat.SetUnifInt32("pointLightCubeShadowMaps", int32(materials.TextureSlot_Cubemap_Array)) + groundMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1)) + palleteMat = materials.NewMaterial("Pallete mat", "./res/shaders/simple.glsl") - palleteMat.Settings.Set(materials.MaterialSettings_HasModelMat | materials.MaterialSettings_HasNormalMat) + palleteMat.Settings.Set(materials.MaterialSettings_HasModelMtx | materials.MaterialSettings_HasNormalMtx) palleteMat.Shininess = 64 palleteMat.DiffuseTex = palleteTex.TexID palleteMat.SpecularTex = blackTex.TexID @@ -569,10 +601,11 @@ func (g *Game) Init() { palleteMat.EmissionTex = blackTex.TexID palleteMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse)) palleteMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular)) - // palleteMat.SetUnifInt32("material.normal", int32(materials.TextureSlot_Normal)) + palleteMat.SetUnifInt32("material.normal", int32(materials.TextureSlot_Normal)) palleteMat.SetUnifInt32("material.emission", int32(materials.TextureSlot_Emission)) palleteMat.SetUnifVec3("ambientColor", &ambientColor) palleteMat.SetUnifFloat32("material.shininess", palleteMat.Shininess) + palleteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir) palleteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) palleteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor) palleteMat.SetUnifInt32("dirLight.shadowMap", int32(materials.TextureSlot_ShadowMap1)) @@ -580,16 +613,16 @@ func (g *Game) Init() { palleteMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1)) debugDepthMat = materials.NewMaterial("Debug depth mat", "./res/shaders/debug-depth.glsl") - debugDepthMat.Settings.Set(materials.MaterialSettings_HasModelMat) + debugDepthMat.Settings.Set(materials.MaterialSettings_HasModelMtx) depthMapMat = materials.NewMaterial("Depth Map mat", "./res/shaders/depth-map.glsl") - depthMapMat.Settings.Set(materials.MaterialSettings_HasModelMat) + depthMapMat.Settings.Set(materials.MaterialSettings_HasModelMtx) arrayDepthMapMat = materials.NewMaterial("Array Depth Map mat", "./res/shaders/array-depth-map.glsl") - arrayDepthMapMat.Settings.Set(materials.MaterialSettings_HasModelMat) + arrayDepthMapMat.Settings.Set(materials.MaterialSettings_HasModelMtx) omnidirDepthMapMat = materials.NewMaterial("Omnidirectional Depth Map mat", "./res/shaders/omnidirectional-depth-map.glsl") - omnidirDepthMapMat.Settings.Set(materials.MaterialSettings_HasModelMat) + omnidirDepthMapMat.Settings.Set(materials.MaterialSettings_HasModelMtx) skyboxMat = materials.NewMaterial("Skybox mat", "./res/shaders/skybox.glsl") skyboxMat.CubemapTex = skyboxCmap.TexID @@ -674,6 +707,7 @@ func (g *Game) updateLights() { // Directional light whiteMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id containerMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id + groundMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id palleteMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id // Point lights @@ -684,35 +718,43 @@ func (g *Game) updateLights() { whiteMat.SetUnifVec3(indexString+".pos", &p.Pos) containerMat.SetUnifVec3(indexString+".pos", &p.Pos) + groundMat.SetUnifVec3(indexString+".pos", &p.Pos) palleteMat.SetUnifVec3(indexString+".pos", &p.Pos) whiteMat.SetUnifVec3(indexString+".diffuseColor", &p.DiffuseColor) containerMat.SetUnifVec3(indexString+".diffuseColor", &p.DiffuseColor) + groundMat.SetUnifVec3(indexString+".diffuseColor", &p.DiffuseColor) palleteMat.SetUnifVec3(indexString+".diffuseColor", &p.DiffuseColor) whiteMat.SetUnifVec3(indexString+".specularColor", &p.SpecularColor) containerMat.SetUnifVec3(indexString+".specularColor", &p.SpecularColor) + groundMat.SetUnifVec3(indexString+".specularColor", &p.SpecularColor) palleteMat.SetUnifVec3(indexString+".specularColor", &p.SpecularColor) whiteMat.SetUnifFloat32(indexString+".constant", p.Constant) containerMat.SetUnifFloat32(indexString+".constant", p.Constant) + groundMat.SetUnifFloat32(indexString+".constant", p.Constant) palleteMat.SetUnifFloat32(indexString+".constant", p.Constant) whiteMat.SetUnifFloat32(indexString+".linear", p.Linear) containerMat.SetUnifFloat32(indexString+".linear", p.Linear) + groundMat.SetUnifFloat32(indexString+".linear", p.Linear) palleteMat.SetUnifFloat32(indexString+".linear", p.Linear) whiteMat.SetUnifFloat32(indexString+".quadratic", p.Quadratic) containerMat.SetUnifFloat32(indexString+".quadratic", p.Quadratic) + groundMat.SetUnifFloat32(indexString+".quadratic", p.Quadratic) palleteMat.SetUnifFloat32(indexString+".quadratic", p.Quadratic) whiteMat.SetUnifFloat32(indexString+".farPlane", p.FarPlane) containerMat.SetUnifFloat32(indexString+".farPlane", p.FarPlane) + groundMat.SetUnifFloat32(indexString+".farPlane", p.FarPlane) palleteMat.SetUnifFloat32(indexString+".farPlane", p.FarPlane) } whiteMat.CubemapArrayTex = pointLightDepthMapFbo.Attachments[0].Id containerMat.CubemapArrayTex = pointLightDepthMapFbo.Attachments[0].Id + groundMat.CubemapArrayTex = pointLightDepthMapFbo.Attachments[0].Id palleteMat.CubemapArrayTex = pointLightDepthMapFbo.Attachments[0].Id // Spotlights @@ -726,31 +768,38 @@ func (g *Game) updateLights() { whiteMat.SetUnifVec3(indexString+".pos", &l.Pos) containerMat.SetUnifVec3(indexString+".pos", &l.Pos) + groundMat.SetUnifVec3(indexString+".pos", &l.Pos) palleteMat.SetUnifVec3(indexString+".pos", &l.Pos) whiteMat.SetUnifVec3(indexString+".dir", &l.Dir) containerMat.SetUnifVec3(indexString+".dir", &l.Dir) + groundMat.SetUnifVec3(indexString+".dir", &l.Dir) palleteMat.SetUnifVec3(indexString+".dir", &l.Dir) whiteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) containerMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) + groundMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) palleteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) whiteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) containerMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) + groundMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) palleteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) whiteMat.SetUnifFloat32(indexString+".innerCutoff", innerCutoffCos) containerMat.SetUnifFloat32(indexString+".innerCutoff", innerCutoffCos) + groundMat.SetUnifFloat32(indexString+".innerCutoff", innerCutoffCos) palleteMat.SetUnifFloat32(indexString+".innerCutoff", innerCutoffCos) whiteMat.SetUnifFloat32(indexString+".outerCutoff", outerCutoffCos) containerMat.SetUnifFloat32(indexString+".outerCutoff", outerCutoffCos) + groundMat.SetUnifFloat32(indexString+".outerCutoff", outerCutoffCos) palleteMat.SetUnifFloat32(indexString+".outerCutoff", outerCutoffCos) } whiteMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id containerMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id + groundMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id palleteMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id } @@ -797,6 +846,7 @@ func (g *Game) showDebugWindow() { if imgui.DragFloat3("Ambient Color", &ambientColor.Data) { whiteMat.SetUnifVec3("ambientColor", &ambientColor) containerMat.SetUnifVec3("ambientColor", &ambientColor) + groundMat.SetUnifVec3("ambientColor", &ambientColor) palleteMat.SetUnifVec3("ambientColor", &ambientColor) } @@ -810,18 +860,21 @@ func (g *Game) showDebugWindow() { if imgui.DragFloat3("Direction", &dirLight.Dir.Data) { whiteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir) containerMat.SetUnifVec3("dirLight.dir", &dirLight.Dir) + groundMat.SetUnifVec3("dirLight.dir", &dirLight.Dir) palleteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir) } if imgui.DragFloat3("Diffuse Color", &dirLight.DiffuseColor.Data) { whiteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) containerMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) + groundMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) palleteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) } if imgui.DragFloat3("Specular Color", &dirLight.SpecularColor.Data) { whiteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor) containerMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor) + groundMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor) palleteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor) } @@ -838,6 +891,7 @@ func (g *Game) showDebugWindow() { if imgui.DragFloat("Specular Shininess", &whiteMat.Shininess) { whiteMat.SetUnifFloat32("material.shininess", whiteMat.Shininess) containerMat.SetUnifFloat32("material.shininess", whiteMat.Shininess) + groundMat.SetUnifFloat32("material.shininess", whiteMat.Shininess) palleteMat.SetUnifFloat32("material.shininess", whiteMat.Shininess) } @@ -861,18 +915,21 @@ func (g *Game) showDebugWindow() { if imgui.DragFloat3("Pos", &pl.Pos.Data) { whiteMat.SetUnifVec3(indexString+".pos", &pl.Pos) containerMat.SetUnifVec3(indexString+".pos", &pl.Pos) + groundMat.SetUnifVec3(indexString+".pos", &pl.Pos) palleteMat.SetUnifVec3(indexString+".pos", &pl.Pos) } if imgui.DragFloat3("Diffuse Color", &pl.DiffuseColor.Data) { whiteMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor) containerMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor) + groundMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor) palleteMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor) } if imgui.DragFloat3("Specular Color", &pl.SpecularColor.Data) { whiteMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor) containerMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor) + groundMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor) palleteMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor) } @@ -901,24 +958,28 @@ func (g *Game) showDebugWindow() { if imgui.DragFloat3("Pos", &l.Pos.Data) { whiteMat.SetUnifVec3(indexString+".pos", &l.Pos) containerMat.SetUnifVec3(indexString+".pos", &l.Pos) + groundMat.SetUnifVec3(indexString+".pos", &l.Pos) palleteMat.SetUnifVec3(indexString+".pos", &l.Pos) } if imgui.DragFloat3("Dir", &l.Dir.Data) { whiteMat.SetUnifVec3(indexString+".dir", &l.Dir) containerMat.SetUnifVec3(indexString+".dir", &l.Dir) + groundMat.SetUnifVec3(indexString+".dir", &l.Dir) palleteMat.SetUnifVec3(indexString+".dir", &l.Dir) } if imgui.DragFloat3("Diffuse Color", &l.DiffuseColor.Data) { whiteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) containerMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) + groundMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) palleteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) } if imgui.DragFloat3("Specular Color", &l.SpecularColor.Data) { whiteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) containerMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) + groundMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) palleteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) } @@ -928,6 +989,7 @@ func (g *Game) showDebugWindow() { whiteMat.SetUnifFloat32(indexString+".innerCutoff", cos) containerMat.SetUnifFloat32(indexString+".innerCutoff", cos) + groundMat.SetUnifFloat32(indexString+".innerCutoff", cos) palleteMat.SetUnifFloat32(indexString+".innerCutoff", cos) } @@ -937,6 +999,7 @@ func (g *Game) showDebugWindow() { whiteMat.SetUnifFloat32(indexString+".outerCutoff", cos) containerMat.SetUnifFloat32(indexString+".outerCutoff", cos) + groundMat.SetUnifFloat32(indexString+".outerCutoff", cos) palleteMat.SetUnifFloat32(indexString+".outerCutoff", cos) } @@ -1033,8 +1096,8 @@ func (g *Game) updateCameraPos() { } var ( - renderDirLightShadows = true - renderPointLightShadows = true + renderDirLightShadows = false + renderPointLightShadows = false renderSpotLightShadows = true rotatingCubeSpeedDeg1 float32 = 45 @@ -1049,6 +1112,7 @@ func (g *Game) Render() { whiteMat.SetUnifVec3("camPos", &cam.Pos) containerMat.SetUnifVec3("camPos", &cam.Pos) + groundMat.SetUnifVec3("camPos", &cam.Pos) palleteMat.SetUnifVec3("camPos", &cam.Pos) rotatingCubeTrMat1.Rotate(rotatingCubeSpeedDeg1*gglm.Deg2Rad*timing.DT(), 0, 1, 0) @@ -1092,6 +1156,7 @@ func (g *Game) renderDirectionalLightShadowmap() { whiteMat.SetUnifMat4("dirLightProjViewMat", &dirLightProjViewMat) containerMat.SetUnifMat4("dirLightProjViewMat", &dirLightProjViewMat) + groundMat.SetUnifMat4("dirLightProjViewMat", &dirLightProjViewMat) palleteMat.SetUnifMat4("dirLightProjViewMat", &dirLightProjViewMat) depthMapMat.SetUnifMat4("projViewMat", &dirLightProjViewMat) @@ -1133,6 +1198,7 @@ func (g *Game) renderSpotLightShadowmaps() { whiteMat.SetUnifMat4(projViewMatIndexStr, &projViewMat) containerMat.SetUnifMat4(projViewMatIndexStr, &projViewMat) + groundMat.SetUnifMat4(projViewMatIndexStr, &projViewMat) palleteMat.SetUnifMat4(projViewMatIndexStr, &projViewMat) // Set depth uniforms @@ -1209,11 +1275,13 @@ func (g *Game) RenderScene(overrideMat *materials.Material) { sunMat := &palleteMat chairMat := &palleteMat cubeMat := &containerMat + groundMat := &groundMat if overrideMat != nil { sunMat = overrideMat chairMat = overrideMat cubeMat = overrideMat + groundMat = overrideMat } // Draw dir light @@ -1233,7 +1301,7 @@ func (g *Game) RenderScene(overrideMat *materials.Material) { // Ground groundTrMat := gglm.NewTrMatId() - window.Rend.DrawMesh(&cubeMesh, groundTrMat.Translate(0, -3, 0).Scale(20, 1, 20), cubeMat) + window.Rend.DrawMesh(&cubeMesh, groundTrMat.Translate(0, -3, 0).Scale(20, 1, 20), groundMat) // Cubes tempModelMatrix.Translate(-6, 0, 0) @@ -1283,6 +1351,7 @@ func updateAllProjViewMats(projMat, viewMat gglm.Mat4) { unlitMat.SetUnifMat4("projViewMat", projViewMat) whiteMat.SetUnifMat4("projViewMat", projViewMat) containerMat.SetUnifMat4("projViewMat", projViewMat) + groundMat.SetUnifMat4("projViewMat", projViewMat) palleteMat.SetUnifMat4("projViewMat", projViewMat) debugDepthMat.SetUnifMat4("projViewMat", projViewMat) diff --git a/materials/material.go b/materials/material.go index 1d8efdf..e1040ed 100755 --- a/materials/material.go +++ b/materials/material.go @@ -25,8 +25,8 @@ type MaterialSettings uint64 const ( MaterialSettings_None MaterialSettings = iota - MaterialSettings_HasModelMat MaterialSettings = 1 << (iota - 1) - MaterialSettings_HasNormalMat + MaterialSettings_HasModelMtx MaterialSettings = 1 << (iota - 1) + MaterialSettings_HasNormalMtx ) func (ms *MaterialSettings) Set(flags MaterialSettings) { diff --git a/meshes/mesh.go b/meshes/mesh.go index ec13b19..051eaf6 100755 --- a/meshes/mesh.go +++ b/meshes/mesh.go @@ -16,14 +16,38 @@ type SubMesh struct { } type Mesh struct { - Name string + Name string + /* + Vao has the following shader attribute layout: + - Loc0: Pos + - Loc1: Normal + - Loc2: UV0 + - Loc3: Tangent + - (Optional) Color + + Optional stuff appear in the order in this list, depending on what other optional stuff exists. + + For example: + - If color exists it will be in Loc3, otherwise it is unset + */ Vao buffers.VertexArray SubMeshes []SubMesh } +var ( + // DefaultMeshLoadFlags are the flags always applied when loading a new mesh regardless + // of what post process flags are used when loading a mesh. + // + // Defaults to: asig.PostProcessTriangulate | asig.PostProcessCalcTangentSpace; + // Note: changing this will break the normal lit shaders, which expect tangents to be there + DefaultMeshLoadFlags asig.PostProcess = asig.PostProcessTriangulate | asig.PostProcessCalcTangentSpace +) + func NewMesh(name, modelPath string, postProcessFlags asig.PostProcess) (Mesh, error) { - scene, release, err := asig.ImportFile(modelPath, asig.PostProcessTriangulate|postProcessFlags) + finalPostProcessFlags := DefaultMeshLoadFlags | postProcessFlags + + scene, release, err := asig.ImportFile(modelPath, finalPostProcessFlags) if err != nil { return Mesh{}, errors.New("Failed to load model. Err: " + err.Error()) } @@ -42,8 +66,17 @@ func NewMesh(name, modelPath string, postProcessFlags asig.PostProcess) (Mesh, e vbo := buffers.NewVertexBuffer() ibo := buffers.NewIndexBuffer() - // Initial sizes assuming one submesh that has vertex pos+normals+texCoords, and 3 indices per face - var vertexBufData []float32 = make([]float32, 0, len(scene.Meshes[0].Vertices)*3*3*2) + // Estimate a useful prealloc capacity based on the first submesh that has vertex pos+normals+tangents+texCoords + vertexBufDataCapacity := len(scene.Meshes[0].Vertices) * 3 * 3 * 3 * 2 + + // Increase capacity depending on what the mesh has + if len(scene.Meshes[0].ColorSets) > 0 && len(scene.Meshes[0].ColorSets[0]) > 0 { + vertexBufDataCapacity *= 4 + } + + var vertexBufData []float32 = make([]float32, 0, vertexBufDataCapacity) + + // Initial size assumes 3 indices per face var indexBufData []uint32 = make([]uint32, 0, len(scene.Meshes[0].Faces)*3) // fmt.Printf("\nMesh %s has %d meshe(s) with first mesh having %d vertices\n", name, len(scene.Meshes), len(scene.Meshes[0].Vertices)) @@ -52,12 +85,25 @@ func NewMesh(name, modelPath string, postProcessFlags asig.PostProcess) (Mesh, e sceneMesh := scene.Meshes[i] + // We always want tangents and UV0 + if len(sceneMesh.Tangents) == 0 { + sceneMesh.Tangents = make([]gglm.Vec3, len(sceneMesh.Vertices)) + } + if len(sceneMesh.TexCoords[0]) == 0 { sceneMesh.TexCoords[0] = make([]gglm.Vec3, len(sceneMesh.Vertices)) } - layoutToUse := []buffers.Element{{ElementType: buffers.DataTypeVec3}, {ElementType: buffers.DataTypeVec3}, {ElementType: buffers.DataTypeVec2}} - if len(sceneMesh.ColorSets) > 0 && len(sceneMesh.ColorSets[0]) > 0 { + hasColorSet0 := len(sceneMesh.ColorSets) > 0 && len(sceneMesh.ColorSets[0]) > 0 + + layoutToUse := []buffers.Element{ + {ElementType: buffers.DataTypeVec3}, // Position + {ElementType: buffers.DataTypeVec3}, // Normals + {ElementType: buffers.DataTypeVec3}, // Tangents + {ElementType: buffers.DataTypeVec2}, // UV0 + } + + if hasColorSet0 { layoutToUse = append(layoutToUse, buffers.Element{ElementType: buffers.DataTypeVec4}) } @@ -79,8 +125,14 @@ func NewMesh(name, modelPath string, postProcessFlags asig.PostProcess) (Mesh, e } } - arrs := []arrToInterleave{{V3s: sceneMesh.Vertices}, {V3s: sceneMesh.Normals}, {V2s: v3sToV2s(sceneMesh.TexCoords[0])}} - if len(sceneMesh.ColorSets) > 0 && len(sceneMesh.ColorSets[0]) > 0 { + arrs := []arrToInterleave{ + {V3s: sceneMesh.Vertices}, + {V3s: sceneMesh.Normals}, + {V3s: sceneMesh.Tangents}, + {V2s: v3sToV2s(sceneMesh.TexCoords[0])}, + } + + if hasColorSet0 { arrs = append(arrs, arrToInterleave{V4s: sceneMesh.ColorSets[0]}) } diff --git a/renderer/rend3dgl/rend3dgl.go b/renderer/rend3dgl/rend3dgl.go index cc7a46b..6e5d596 100755 --- a/renderer/rend3dgl/rend3dgl.go +++ b/renderer/rend3dgl/rend3dgl.go @@ -29,11 +29,11 @@ func (r *Rend3DGL) DrawMesh(mesh *meshes.Mesh, modelMat *gglm.TrMat, mat *materi r.BoundMat = mat } - if mat.Settings.Has(materials.MaterialSettings_HasModelMat) { + if mat.Settings.Has(materials.MaterialSettings_HasModelMtx) { mat.SetUnifMat4("modelMat", &modelMat.Mat4) } - if mat.Settings.Has(materials.MaterialSettings_HasNormalMat) { + if mat.Settings.Has(materials.MaterialSettings_HasNormalMtx) { normalMat := modelMat.Clone().InvertAndTranspose().ToMat3() mat.SetUnifMat3("normalMat", &normalMat) } diff --git a/res/shaders/debug-depth.glsl b/res/shaders/debug-depth.glsl index dbcd3ad..f53638c 100755 --- a/res/shaders/debug-depth.glsl +++ b/res/shaders/debug-depth.glsl @@ -2,8 +2,9 @@ #version 410 layout(location=0) in vec3 vertPosIn; -layout(location=2) in vec2 vertUV0In; -layout(location=3) in vec3 vertColorIn; +layout(location=2) in vec3 vertTangentIn; +layout(location=3) in vec2 vertUV0In; +layout(location=4) in vec3 vertColorIn; out vec2 vertUV0; out vec3 vertColor; diff --git a/res/shaders/simple-unlit.glsl b/res/shaders/simple-unlit.glsl index 0ac27d4..be9392c 100755 --- a/res/shaders/simple-unlit.glsl +++ b/res/shaders/simple-unlit.glsl @@ -3,8 +3,9 @@ layout(location=0) in vec3 vertPosIn; layout(location=1) in vec3 vertNormalIn; -layout(location=2) in vec2 vertUV0In; -layout(location=3) in vec3 vertColorIn; +layout(location=2) in vec3 vertTangentIn; +layout(location=3) in vec2 vertUV0In; +layout(location=4) in vec3 vertColorIn; out vec2 vertUV0; out vec3 vertColor; diff --git a/res/shaders/simple.glsl b/res/shaders/simple.glsl index 742a7e8..52ad6fc 100755 --- a/res/shaders/simple.glsl +++ b/res/shaders/simple.glsl @@ -1,63 +1,34 @@ //shader:vertex #version 410 +#define NUM_SPOT_LIGHTS 4 +#define NUM_POINT_LIGHTS 8 + +// +// Inputs +// layout(location=0) in vec3 vertPosIn; layout(location=1) in vec3 vertNormalIn; -layout(location=2) in vec2 vertUV0In; -layout(location=3) in vec3 vertColorIn; +layout(location=2) in vec3 vertTangentIn; +layout(location=3) in vec2 vertUV0In; +layout(location=4) in vec3 vertColorIn; +// +// Uniforms +// +uniform vec3 camPos; uniform mat4 modelMat; uniform mat3 normalMat; uniform mat4 projViewMat; uniform mat4 dirLightProjViewMat; - -#define NUM_SPOT_LIGHTS 4 uniform mat4 spotLightProjViewMats[NUM_SPOT_LIGHTS]; -out vec3 vertNormal; -out vec2 vertUV0; -out vec3 vertColor; -out vec3 fragPos; -out vec4 fragPosDirLight; -out vec4 fragPosSpotLight[NUM_SPOT_LIGHTS]; - -void main() -{ - vertNormal = normalMat * vertNormalIn; - - vertUV0 = vertUV0In; - vertColor = vertColorIn; - - vec4 modelVert = modelMat * vec4(vertPosIn, 1); - fragPos = modelVert.xyz; - fragPosDirLight = dirLightProjViewMat * vec4(fragPos, 1); - - for (int i = 0; i < NUM_SPOT_LIGHTS; i++) - fragPosSpotLight[i] = spotLightProjViewMats[i] * vec4(fragPos, 1); - - gl_Position = projViewMat * modelVert; -} - -//shader:fragment -#version 410 - -struct Material { - sampler2D diffuse; - sampler2D specular; - // sampler2D normal; - sampler2D emission; - float shininess; -}; - -uniform Material material; - struct DirLight { vec3 dir; vec3 diffuseColor; vec3 specularColor; sampler2D shadowMap; }; - uniform DirLight dirLight; struct PointLight { @@ -69,8 +40,137 @@ struct PointLight { float quadratic; float farPlane; }; +uniform PointLight pointLights[NUM_POINT_LIGHTS]; +struct SpotLight { + vec3 pos; + vec3 dir; + vec3 diffuseColor; + vec3 specularColor; + float innerCutoff; + float outerCutoff; +}; +uniform SpotLight spotLights[NUM_SPOT_LIGHTS]; + +// +// Outputs +// +out vec2 vertUV0; +out vec3 vertColor; + +out vec3 fragPos; +out vec3 fragPosDirLight; +out vec4 fragPosSpotLight[NUM_SPOT_LIGHTS]; + +out vec3 tangentCamPos; +out vec3 tangentFragPos; +out vec3 tangentVertNormal; +out vec3 tangentDirLightDir; +out vec3 tangentSpotLightPositions[NUM_SPOT_LIGHTS]; +out vec3 tangentSpotLightDirections[NUM_SPOT_LIGHTS]; +out vec3 tangentPointLightPositions[NUM_POINT_LIGHTS]; + +void main() +{ + vertUV0 = vertUV0In; + vertColor = vertColorIn; + vec4 modelVert = modelMat * vec4(vertPosIn, 1); + + // Tangent-BiTangent-Normal matrix for normal mapping + vec3 T = normalize(vec3(modelMat * vec4(vertTangentIn, 0.0))); + vec3 N = normalize(vec3(modelMat * vec4(vertNormalIn, 0.0))); + + // Ensure T is orthogonal with respect to N + T = normalize(T - dot(T, N) * N); + + vec3 B = cross(N, T); + mat3 tbnMtx = transpose(mat3(T, B, N)); + + tangentVertNormal = tbnMtx * normalMat * vertNormalIn; + + // Lighting related + fragPos = modelVert.xyz; + fragPosDirLight = vec3(dirLightProjViewMat * vec4(fragPos, 1)); + + tangentCamPos = tbnMtx * camPos; + tangentFragPos = tbnMtx * fragPos; + tangentDirLightDir = tbnMtx * dirLight.dir; + + for (int i = 0; i < NUM_POINT_LIGHTS; i++) + tangentPointLightPositions[i] = tbnMtx * pointLights[i].pos; + + for (int i = 0; i < NUM_SPOT_LIGHTS; i++) + { + fragPosSpotLight[i] = spotLightProjViewMats[i] * vec4(fragPos, 1); + + tangentSpotLightPositions[i] = tbnMtx * spotLights[i].pos; + tangentSpotLightDirections[i] = tbnMtx * spotLights[i].dir; + } + + gl_Position = projViewMat * modelVert; +} + +//shader:fragment +#version 410 + +/* + Note that while all lighting calculations are done in tangent space, + shadow mapping is done in world space. + + The exception is the bias calculation. Since the bias relies on the normal + and the normal is in tangent space, we use a tangent space fragment position + with it, but the rest of shadow processing is in world space. +*/ + +#define NUM_SPOT_LIGHTS 4 #define NUM_POINT_LIGHTS 8 + +// +// Inputs +// +in vec3 fragPos; +in vec2 vertUV0; +in vec3 vertColor; +in vec3 fragPosDirLight; +in vec4 fragPosSpotLight[NUM_SPOT_LIGHTS]; + +in vec3 tangentCamPos; +in vec3 tangentFragPos; +in vec3 tangentVertNormal; +in vec3 tangentDirLightDir; +in vec3 tangentSpotLightPositions[NUM_SPOT_LIGHTS]; +in vec3 tangentSpotLightDirections[NUM_SPOT_LIGHTS]; +in vec3 tangentPointLightPositions[NUM_POINT_LIGHTS]; + +// +// Uniforms +// +struct Material { + sampler2D diffuse; + sampler2D specular; + sampler2D normal; + sampler2D emission; + float shininess; +}; +uniform Material material; + +struct DirLight { + vec3 dir; + vec3 diffuseColor; + vec3 specularColor; + sampler2D shadowMap; +}; +uniform DirLight dirLight; + +struct PointLight { + vec3 pos; + vec3 diffuseColor; + vec3 specularColor; + float constant; + float linear; + float quadratic; + float farPlane; +}; uniform PointLight pointLights[NUM_POINT_LIGHTS]; uniform samplerCubeArray pointLightCubeShadowMaps; @@ -82,37 +182,29 @@ struct SpotLight { float innerCutoff; float outerCutoff; }; - -#define NUM_SPOT_LIGHTS 4 uniform SpotLight spotLights[NUM_SPOT_LIGHTS]; uniform sampler2DArray spotLightShadowMaps; -uniform vec3 camPos; uniform vec3 ambientColor = vec3(0.2, 0.2, 0.2); -in vec3 vertColor; -in vec3 vertNormal; -in vec2 vertUV0; -in vec3 fragPos; -in vec4 fragPosDirLight; -in vec4 fragPosSpotLight[NUM_SPOT_LIGHTS]; - +// +// Outputs +// out vec4 fragColor; +// // Global variables used as cache for lighting calculations +// +vec3 tangentViewDir; vec4 diffuseTexColor; vec4 specularTexColor; vec4 emissionTexColor; vec3 normalizedVertNorm; -vec3 viewDir; -float CalcDirShadow(sampler2D shadowMap, vec3 lightDir) +float CalcDirShadow(sampler2D shadowMap, vec3 tangentLightDir) { - // Move from clip space to NDC - vec3 projCoords = fragPosDirLight.xyz / fragPosDirLight.w; - // Move from [-1,1] to [0, 1] - projCoords = projCoords * 0.5 + 0.5; + vec3 projCoords = fragPosDirLight * 0.5 + 0.5; // If sampling outside the depth texture then force 'no shadow' if(projCoords.z > 1) @@ -123,7 +215,7 @@ float CalcDirShadow(sampler2D shadowMap, vec3 lightDir) // Bias in the range [0.005, 0.05] depending on the angle, where a higher // angle gives a higher bias, as shadow acne gets worse with angle - float bias = max(0.05 * (1 - dot(normalizedVertNorm, lightDir)), 0.005); + float bias = max(0.05 * (1 - dot(normalizedVertNorm, tangentLightDir)), 0.005); // 'Percentage Close Filtering'. // Basically get soft shadows by averaging this texel and surrounding ones @@ -148,14 +240,14 @@ float CalcDirShadow(sampler2D shadowMap, vec3 lightDir) vec3 CalcDirLight() { - vec3 lightDir = normalize(-dirLight.dir); + vec3 lightDir = normalize(-tangentDirLightDir); // Diffuse float diffuseAmount = max(0.0, dot(normalizedVertNorm, lightDir)); vec3 finalDiffuse = diffuseAmount * dirLight.diffuseColor * diffuseTexColor.rgb; // Specular - vec3 halfwayDir = normalize(lightDir + viewDir); + vec3 halfwayDir = normalize(lightDir + tangentViewDir); float specularAmount = pow(max(dot(normalizedVertNorm, halfwayDir), 0.0), material.shininess); vec3 finalSpecular = specularAmount * dirLight.specularColor * specularTexColor.rgb; @@ -165,9 +257,9 @@ vec3 CalcDirLight() return (finalDiffuse + finalSpecular) * (1 - shadow); } -float CalcPointShadow(int lightIndex, vec3 lightPos, vec3 lightDir, float farPlane) { +float CalcPointShadow(int lightIndex, vec3 worldLightPos, vec3 tangentLightDir, float farPlane) { - vec3 lightToFrag = fragPos - lightPos; + vec3 lightToFrag = fragPos - worldLightPos; float closestDepth = texture(pointLightCubeShadowMaps, vec4(lightToFrag, lightIndex)).r; @@ -177,7 +269,8 @@ float CalcPointShadow(int lightIndex, vec3 lightPos, vec3 lightDir, float farPla // Get depth of current fragment float currentDepth = length(lightToFrag); - float bias = max(0.05 * (1 - dot(normalizedVertNorm, lightDir)), 0.005); + float bias = max(0.05 * (1 - dot(normalizedVertNorm, tangentLightDir)), 0.005); + float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; return shadow; @@ -190,28 +283,29 @@ vec3 CalcPointLight(PointLight pointLight, int lightIndex) return vec3(0); } - vec3 lightDir = normalize(pointLight.pos - fragPos); + vec3 tangentLightPos = tangentPointLightPositions[lightIndex]; + vec3 tangentLightDir = normalize(tangentLightPos - tangentFragPos); // Diffuse - float diffuseAmount = max(0.0, dot(normalizedVertNorm, lightDir)); + float diffuseAmount = max(0.0, dot(normalizedVertNorm, tangentLightDir)); vec3 finalDiffuse = diffuseAmount * pointLight.diffuseColor * diffuseTexColor.rgb; // Specular - vec3 halfwayDir = normalize(lightDir + viewDir); + vec3 halfwayDir = normalize(tangentLightDir + tangentViewDir); float specularAmount = pow(max(dot(normalizedVertNorm, halfwayDir), 0.0), material.shininess); vec3 finalSpecular = specularAmount * pointLight.specularColor * specularTexColor.rgb; // Attenuation - float distToLight = length(pointLight.pos - fragPos); + float distToLight = length(tangentLightPos - tangentFragPos); float attenuation = 1 / (pointLight.constant + pointLight.linear * distToLight + pointLight.quadratic * (distToLight * distToLight)); // Shadow - float shadow = CalcPointShadow(lightIndex, pointLight.pos, lightDir, pointLight.farPlane); + float shadow = CalcPointShadow(lightIndex, pointLight.pos, tangentLightDir, pointLight.farPlane); return (finalDiffuse + finalSpecular) * attenuation * (1 - shadow); } -float CalcSpotShadow(vec3 lightDir, int lightIndex) +float CalcSpotShadow(vec3 tangentLightDir, int lightIndex) { // Move from clip space to NDC vec3 projCoords = fragPosSpotLight[lightIndex].xyz / fragPosSpotLight[lightIndex].w; @@ -228,7 +322,7 @@ float CalcSpotShadow(vec3 lightDir, int lightIndex) // Bias in the range [0.005, 0.05] depending on the angle, where a higher // angle gives a higher bias, as shadow acne gets worse with angle - float bias = max(0.05 * (1 - dot(normalizedVertNorm, lightDir)), 0.005); + float bias = max(0.05 * (1 - dot(normalizedVertNorm, tangentLightDir)), 0.005); // 'Percentage Close Filtering'. // Basically get soft shadows by averaging this texel and surrounding ones @@ -256,12 +350,13 @@ vec3 CalcSpotLight(SpotLight light, int lightIndex) if (light.innerCutoff == 0) return vec3(0); - vec3 fragToLightDir = normalize(light.pos - fragPos); + vec3 tangentLightDir = tangentSpotLightDirections[lightIndex]; + vec3 fragToLightDir = normalize(tangentSpotLightPositions[lightIndex] - tangentFragPos); // Spot light cone with full intensity within inner cutoff, // and falloff between inner-outer cutoffs, and zero // light after outer cutoff - float theta = dot(fragToLightDir, normalize(-light.dir)); + float theta = dot(fragToLightDir, normalize(-tangentLightDir)); float epsilon = (light.innerCutoff - light.outerCutoff); float intensity = clamp((theta - light.outerCutoff) / epsilon, float(0), float(1)); @@ -273,7 +368,7 @@ vec3 CalcSpotLight(SpotLight light, int lightIndex) vec3 finalDiffuse = diffuseAmount * light.diffuseColor * diffuseTexColor.rgb; // Specular - vec3 halfwayDir = normalize(fragToLightDir + viewDir); + vec3 halfwayDir = normalize(fragToLightDir + tangentViewDir); float specularAmount = pow(max(dot(normalizedVertNorm, halfwayDir), 0.0), material.shininess); vec3 finalSpecular = specularAmount * light.specularColor * specularTexColor.rgb; @@ -286,12 +381,20 @@ vec3 CalcSpotLight(SpotLight light, int lightIndex) void main() { // Shared values + tangentViewDir = normalize(tangentCamPos - tangentFragPos); diffuseTexColor = texture(material.diffuse, vertUV0); specularTexColor = texture(material.specular, vertUV0); emissionTexColor = texture(material.emission, vertUV0); - normalizedVertNorm = normalize(vertNormal); - viewDir = normalize(camPos - fragPos); + // Read normal data encoded [0,1] + normalizedVertNorm = texture(material.normal, vertUV0).rgb; + + // Handle no normal map + if (normalizedVertNorm == vec3(0)) + normalizedVertNorm = normalize(tangentVertNormal); + else + // Remap normal to [-1,1] + normalizedVertNorm = normalize(normalizedVertNorm * 2.0 - 1.0); // Light contributions vec3 finalColor = CalcDirLight(); diff --git a/res/shaders/skybox.glsl b/res/shaders/skybox.glsl index fb45fab..e63ec9e 100755 --- a/res/shaders/skybox.glsl +++ b/res/shaders/skybox.glsl @@ -3,8 +3,9 @@ layout(location=0) in vec3 vertPosIn; layout(location=1) in vec3 vertNormalIn; -layout(location=2) in vec2 vertUV0In; -layout(location=3) in vec3 vertColorIn; +layout(location=2) in vec3 vertTangentIn; +layout(location=3) in vec2 vertUV0In; +layout(location=4) in vec3 vertColorIn; out vec3 vertUV0; diff --git a/res/textures/brickwall-normal.png b/res/textures/brickwall-normal.png new file mode 100755 index 0000000..7ba1703 Binary files /dev/null and b/res/textures/brickwall-normal.png differ diff --git a/res/textures/brickwall.png b/res/textures/brickwall.png new file mode 100755 index 0000000..f9eb789 Binary files /dev/null and b/res/textures/brickwall.png differ