Normal mapping

This commit is contained in:
bloeys
2024-05-07 05:23:36 +04:00
parent 8c6b1d5821
commit c884d2624d
10 changed files with 337 additions and 110 deletions

101
main.go
View File

@ -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)

View File

@ -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) {

View File

@ -17,13 +17,37 @@ type SubMesh struct {
type Mesh struct {
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]})
}

View File

@ -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)
}

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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;

BIN
res/textures/brickwall-normal.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
res/textures/brickwall.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB