Compare commits

...

7 Commits

Author SHA1 Message Date
7b1e3ea7b4 Default textures for diffuse/specular/normal/emission mat slots 2024-05-11 05:11:54 +04:00
c884d2624d Normal mapping 2024-05-07 05:23:36 +04:00
8c6b1d5821 Adjust shadow map texture sizes 2024-05-06 23:23:52 +04:00
dfd1fe9c5e Material settings+normal matrices on CPU 2024-05-06 22:55:57 +04:00
24613823a7 Fix gitignore 2024-05-06 22:18:15 +04:00
0386f441d6 Profiling 2024-05-06 22:16:20 +04:00
57ab851534 Update gglm 2024-05-05 00:34:38 +04:00
18 changed files with 599 additions and 223 deletions

5
.gitignore vendored
View File

@ -15,4 +15,7 @@
vendor/
.vscode/
imgui.ini
*~
*~
# Custom
*.pprof

View File

@ -23,6 +23,15 @@ const (
ColorFormat_RGBA8
)
var (
DefaultBlackTexId Texture
DefaultWhiteTexId Texture
DefaultDiffuseTexId Texture
DefaultSpecularTexId Texture
DefaultNormalTexId Texture
DefaultEmissionTexId Texture
)
type Texture struct {
// Path only exists for textures loaded from disk
Path string

View File

@ -41,7 +41,7 @@ func (c *Camera) Update() {
c.ViewMat = gglm.LookAtRH(&c.Pos, c.Pos.Clone().Add(&c.Forward), &c.WorldUp).Mat4
if c.Type == Type_Perspective {
c.ProjMat = *gglm.Perspective(c.Fov, c.AspectRatio, c.NearClip, c.FarClip)
c.ProjMat = gglm.Perspective(c.Fov, c.AspectRatio, c.NearClip, c.FarClip)
} else {
c.ProjMat = gglm.Ortho(c.Left, c.Right, c.Top, c.Bottom, c.NearClip, c.FarClip).Mat4
}

View File

@ -1,10 +1,13 @@
package engine
import (
"image"
"image/color"
"runtime"
imgui "github.com/AllenDang/cimgui-go"
"github.com/bloeys/nmage/assert"
"github.com/bloeys/nmage/assets"
"github.com/bloeys/nmage/input"
"github.com/bloeys/nmage/renderer"
"github.com/bloeys/nmage/timing"
@ -202,6 +205,8 @@ func createWindow(title string, x, y, width, height int32, flags WindowFlags, re
return win, err
}
setupDefaultTextures()
// Get rid of the blinding white startup screen (unfortunately there is still one frame of white)
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
win.SDLWin.GLSwap()
@ -231,6 +236,57 @@ func initOpenGL() error {
return nil
}
func setupDefaultTextures() error {
// 1x1 black texture
defaultBlackImg := image.NewNRGBA(image.Rect(0, 0, 1, 1))
defaultBlackImg.Set(0, 0, color.NRGBA{R: 0, G: 0, B: 0, A: 1})
defaultBlackImgTex, err := assets.LoadTextureInMemPngImg(defaultBlackImg, &assets.TextureLoadOptions{NoSrgba: true})
if err != nil {
return err
}
assets.DefaultBlackTexId = defaultBlackImgTex
// 1x1 white texture
defaultWhiteImg := image.NewNRGBA(image.Rect(0, 0, 1, 1))
defaultWhiteImg.Set(0, 0, color.NRGBA{R: 255, G: 255, B: 255, A: 1})
defaultWhiteImgTex, err := assets.LoadTextureInMemPngImg(defaultWhiteImg, &assets.TextureLoadOptions{NoSrgba: true})
if err != nil {
return err
}
assets.DefaultWhiteTexId = defaultWhiteImgTex
// Default diffuse
assets.DefaultDiffuseTexId = defaultWhiteImgTex
// Default specular
assets.DefaultSpecularTexId = defaultBlackImgTex
// Default Normal map which is created to be RGB(0.5,0.5,1), which when multiplied by TBN matrix gives the vertex normal.
// 128 is better than 127 for normal maps. See 'Flat Color' section here: http://wiki.polycount.com/wiki/Normal_map
// Basically, 127 can create seams while 128 looks correct
defaultNormalMapImg := image.NewNRGBA(image.Rect(0, 0, 1, 1))
defaultNormalMapImg.Set(0, 0, color.NRGBA{R: 128, G: 128, B: 255, A: 1})
defaultNormalMapTex, err := assets.LoadTextureInMemPngImg(defaultNormalMapImg, &assets.TextureLoadOptions{NoSrgba: true})
if err != nil {
return err
}
assets.DefaultNormalTexId = defaultNormalMapTex
// Default emission
assets.DefaultEmissionTexId = defaultBlackImgTex
assert.T(assets.DefaultBlackTexId.TexID != 0, "The default black texture handle is zero. Either texture wasn't created or handle wasn't updated")
assert.T(assets.DefaultWhiteTexId.TexID != 0, "The default white texture handle is zero. Either texture wasn't created or handle wasn't updated")
assert.T(assets.DefaultDiffuseTexId.TexID != 0, "The default diffuse texture handle is zero. Either texture wasn't created or handle wasn't updated")
assert.T(assets.DefaultSpecularTexId.TexID != 0, "The default specular texture handle is zero. Either texture wasn't created or handle wasn't updated")
assert.T(assets.DefaultNormalTexId.TexID != 0, "The default normal texture handle is zero. Either texture wasn't created or handle wasn't updated")
assert.T(assets.DefaultEmissionTexId.TexID != 0, "The default emission texture handle is zero. Either texture wasn't created or handle wasn't updated")
return nil
}
func SetSrgbFramebuffer(isEnabled bool) {
if isEnabled {

2
go.mod
View File

@ -8,7 +8,7 @@ require github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6
require (
github.com/bloeys/assimp-go v0.4.4
github.com/bloeys/gglm v0.43.0
github.com/bloeys/gglm v0.49.0
)
require (

4
go.sum
View File

@ -2,8 +2,8 @@ github.com/AllenDang/cimgui-go v0.0.0-20230720025235-f2ff398a66b2 h1:3HA/5qD8Rim
github.com/AllenDang/cimgui-go v0.0.0-20230720025235-f2ff398a66b2/go.mod h1:iNfbIyOBN8k3XScMxULbrwYbPsXEAUD0Jb6UwrspQb8=
github.com/bloeys/assimp-go v0.4.4 h1:Yn5e/RpE0Oes0YMBy8O7KkwAO4R/RpgrZPJCt08dVIU=
github.com/bloeys/assimp-go v0.4.4/go.mod h1:my3yRxT7CfOztmvi+0svmwbaqw0KFrxaHxncoyaEIP0=
github.com/bloeys/gglm v0.43.0 h1:ZpOghR3PHfpkigTDh+FqxLsF0gN8CD6s/bWoei6LyxI=
github.com/bloeys/gglm v0.43.0/go.mod h1:qwJQ0WzV191wAMwlGicbfbChbKoSedMk7gFFX6GnyOk=
github.com/bloeys/gglm v0.49.0 h1:YtbyHpszYhjnxw7KVV0LaCdBktRMqfGx/i37EMomxsE=
github.com/bloeys/gglm v0.49.0/go.mod h1:qwJQ0WzV191wAMwlGicbfbChbKoSedMk7gFFX6GnyOk=
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk=
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
github.com/mandykoh/go-parallel v0.1.0 h1:7vJMNMC4dsbgZdkAb2A8tV5ENY1v7VxIO1wzQWZoT8k=

306
main.go
View File

@ -2,7 +2,9 @@ package main
import (
"fmt"
"os"
"runtime"
"runtime/pprof"
"strconv"
imgui "github.com/AllenDang/cimgui-go"
@ -34,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
@ -71,8 +74,9 @@ func (d *DirLight) GetProjViewMat() gglm.Mat4 {
nearClip := dirLightNear
farClip := dirLightFar
up := gglm.NewVec3(0, 1, 0)
projMat := gglm.Ortho(-size, size, -size, size, nearClip, farClip).Mat4
viewMat := gglm.LookAtRH(pos, pos.Clone().Add(&d.Dir), gglm.NewVec3(0, 1, 0)).Mat4
viewMat := gglm.LookAtRH(&pos, pos.Clone().Add(&d.Dir), &up).Mat4
return *projMat.Mul(&viewMat)
}
@ -109,13 +113,34 @@ func (p *PointLight) GetProjViewMats(shadowMapWidth, shadowMapHeight float32) [6
aspect := float32(shadowMapWidth) / float32(shadowMapHeight)
projMat := gglm.Perspective(90*gglm.Deg2Rad, aspect, pointLightNear, p.FarPlane)
targetPos0 := gglm.NewVec3(1+p.Pos.X(), p.Pos.Y(), p.Pos.Z())
targetPos1 := gglm.NewVec3(-1+p.Pos.X(), p.Pos.Y(), p.Pos.Z())
targetPos2 := gglm.NewVec3(p.Pos.X(), 1+p.Pos.Y(), p.Pos.Z())
targetPos3 := gglm.NewVec3(p.Pos.X(), -1+p.Pos.Y(), p.Pos.Z())
targetPos4 := gglm.NewVec3(p.Pos.X(), p.Pos.Y(), 1+p.Pos.Z())
targetPos5 := gglm.NewVec3(p.Pos.X(), p.Pos.Y(), -1+p.Pos.Z())
worldUp0 := gglm.NewVec3(0, -1, 0)
worldUp1 := gglm.NewVec3(0, -1, 0)
worldUp2 := gglm.NewVec3(0, 0, 1)
worldUp3 := gglm.NewVec3(0, 0, -1)
worldUp4 := gglm.NewVec3(0, -1, 0)
worldUp5 := gglm.NewVec3(0, -1, 0)
lookAt0 := gglm.LookAtRH(&p.Pos, &targetPos0, &worldUp0)
lookAt1 := gglm.LookAtRH(&p.Pos, &targetPos1, &worldUp1)
lookAt2 := gglm.LookAtRH(&p.Pos, &targetPos2, &worldUp2)
lookAt3 := gglm.LookAtRH(&p.Pos, &targetPos3, &worldUp3)
lookAt4 := gglm.LookAtRH(&p.Pos, &targetPos4, &worldUp4)
lookAt5 := gglm.LookAtRH(&p.Pos, &targetPos5, &worldUp5)
projViewMats := [6]gglm.Mat4{
*projMat.Clone().Mul(&gglm.LookAtRH(&p.Pos, gglm.NewVec3(1, 0, 0).Add(&p.Pos), gglm.NewVec3(0, -1, 0)).Mat4),
*projMat.Clone().Mul(&gglm.LookAtRH(&p.Pos, gglm.NewVec3(-1, 0, 0).Add(&p.Pos), gglm.NewVec3(0, -1, 0)).Mat4),
*projMat.Clone().Mul(&gglm.LookAtRH(&p.Pos, gglm.NewVec3(0, 1, 0).Add(&p.Pos), gglm.NewVec3(0, 0, 1)).Mat4),
*projMat.Clone().Mul(&gglm.LookAtRH(&p.Pos, gglm.NewVec3(0, -1, 0).Add(&p.Pos), gglm.NewVec3(0, 0, -1)).Mat4),
*projMat.Clone().Mul(&gglm.LookAtRH(&p.Pos, gglm.NewVec3(0, 0, 1).Add(&p.Pos), gglm.NewVec3(0, -1, 0)).Mat4),
*projMat.Clone().Mul(&gglm.LookAtRH(&p.Pos, gglm.NewVec3(0, 0, -1).Add(&p.Pos), gglm.NewVec3(0, -1, 0)).Mat4),
*projMat.Clone().Mul(&lookAt0.Mat4),
*projMat.Clone().Mul(&lookAt1.Mat4),
*projMat.Clone().Mul(&lookAt2.Mat4),
*projMat.Clone().Mul(&lookAt3.Mat4),
*projMat.Clone().Mul(&lookAt4.Mat4),
*projMat.Clone().Mul(&lookAt5.Mat4),
}
return projViewMats
@ -143,11 +168,11 @@ func (s *SpotLight) GetProjViewMat() gglm.Mat4 {
// Adjust up vector if lightDir is parallel or nearly parallel to upVector
// as lookat view matrix breaks if up and look at are parallel
up := gglm.NewVec3(0, 1, 0)
if gglm.Abs32(gglm.DotVec3(&s.Dir, up)) > 0.99 {
if gglm.Abs32(gglm.DotVec3(&s.Dir, &up)) > 0.99 {
up.SetXY(1, 0)
}
viewMat := gglm.LookAtRH(&s.Pos, s.Pos.Clone().Add(&s.Dir), up).Mat4
viewMat := gglm.LookAtRH(&s.Pos, s.Pos.Clone().Add(&s.Dir), &up).Mat4
return *projMat.Mul(&viewMat)
}
@ -166,6 +191,8 @@ const (
unscaledWindowWidth = 1280
unscaledWindowHeight = 720
PROFILE_CPU = true
)
var (
@ -200,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
@ -224,17 +252,18 @@ var (
// Light settings
ambientColor = gglm.NewVec3(0, 0, 0)
dirLightDir = gglm.NewVec3(0, -0.5, -0.8)
// Lights
dirLight = DirLight{
Dir: *gglm.NewVec3(0, -0.5, -0.8).Normalize(),
DiffuseColor: *gglm.NewVec3(1, 1, 1),
SpecularColor: *gglm.NewVec3(1, 1, 1),
Dir: *dirLightDir.Normalize(),
DiffuseColor: gglm.NewVec3(1, 1, 1),
SpecularColor: gglm.NewVec3(1, 1, 1),
}
pointLights = [...]PointLight{
{
Pos: *gglm.NewVec3(0, 2, -2),
DiffuseColor: *gglm.NewVec3(1, 0, 0),
SpecularColor: *gglm.NewVec3(1, 1, 1),
Pos: gglm.NewVec3(0, 2, -2),
DiffuseColor: gglm.NewVec3(1, 0, 0),
SpecularColor: gglm.NewVec3(1, 1, 1),
// These values are for 50m range
Constant: 1.0,
Linear: 0.09,
@ -243,45 +272,47 @@ var (
FarPlane: 25,
},
{
Pos: *gglm.NewVec3(0, -5, 0),
DiffuseColor: *gglm.NewVec3(0, 1, 0),
SpecularColor: *gglm.NewVec3(1, 1, 1),
Pos: gglm.NewVec3(0, -5, 0),
DiffuseColor: gglm.NewVec3(0, 1, 0),
SpecularColor: gglm.NewVec3(1, 1, 1),
Constant: 1.0,
Linear: 0.09,
Quadratic: 0.032,
FarPlane: 25,
},
{
Pos: *gglm.NewVec3(5, 0, 0),
DiffuseColor: *gglm.NewVec3(1, 1, 1),
SpecularColor: *gglm.NewVec3(1, 1, 1),
Pos: gglm.NewVec3(5, 0, 0),
DiffuseColor: gglm.NewVec3(1, 1, 1),
SpecularColor: gglm.NewVec3(1, 1, 1),
Constant: 1.0,
Linear: 0.09,
Quadratic: 0.032,
FarPlane: 25,
},
{
Pos: *gglm.NewVec3(-3, 4, 3),
DiffuseColor: *gglm.NewVec3(1, 1, 1),
SpecularColor: *gglm.NewVec3(1, 1, 1),
Pos: gglm.NewVec3(-3, 4, 3),
DiffuseColor: gglm.NewVec3(1, 1, 1),
SpecularColor: gglm.NewVec3(1, 1, 1),
Constant: 1.0,
Linear: 0.09,
Quadratic: 0.032,
FarPlane: 25,
},
}
spotLights = [...]SpotLight{
spotLightDir0 = gglm.NewVec3(1.5, -0.9, 0)
spotLights = [...]SpotLight{
{
Pos: *gglm.NewVec3(-4, 7, 5),
Dir: *gglm.NewVec3(1.5, -0.9, 0).Normalize(),
DiffuseColor: *gglm.NewVec3(1, 0, 1),
SpecularColor: *gglm.NewVec3(1, 1, 1),
Pos: gglm.NewVec3(-4, 7, 5),
Dir: *spotLightDir0.Normalize(),
DiffuseColor: gglm.NewVec3(1, 0, 1),
SpecularColor: gglm.NewVec3(1, 1, 1),
// These must be cosine values
InnerCutoffRad: 15 * gglm.Deg2Rad,
OuterCutoffRad: 20 * gglm.Deg2Rad,
NearPlane: 1,
FarPlane: 30,
NearPlane: 2,
FarPlane: 50,
},
}
)
@ -321,7 +352,36 @@ func main() {
}
window.EventCallbacks = append(window.EventCallbacks, game.handleWindowEvents)
if PROFILE_CPU {
pf, err := os.Create("cpu.pprof")
if err == nil {
defer pf.Close()
pprof.StartCPUProfile(pf)
} else {
logging.ErrLog.Printf("Creating cpu.pprof file failed. CPU profiling will not run. Err=%v\n", err)
}
}
engine.Run(game, &window, game.ImGUIInfo)
if PROFILE_CPU {
pprof.StopCPUProfile()
heapProfile, err := os.Create("heap.pprof")
if err == nil {
err = pprof.WriteHeapProfile(heapProfile)
if err != nil {
logging.ErrLog.Printf("Writing heap profile to heap.pprof failed. Err=%v\n", err)
}
heapProfile.Close()
} else {
logging.ErrLog.Printf("Creating heap.pprof file failed. Err=%v\n", err)
}
}
}
func (g *Game) handleWindowEvents(e sdl.Event) {
@ -380,10 +440,14 @@ func (g *Game) Init() {
// Camera
winWidth, winHeight := g.Win.SDLWin.GetSize()
camPos := gglm.NewVec3(0, 0, 10)
camForward := gglm.NewVec3(0, 0, -1)
camWorldUp := gglm.NewVec3(0, 1, 0)
cam = camera.NewPerspective(
gglm.NewVec3(0, 0, 10),
gglm.NewVec3(0, 0, -1),
gglm.NewVec3(0, 1, 0),
&camPos,
&camForward,
&camWorldUp,
0.1, 200,
45*gglm.Deg2Rad,
float32(winWidth)/float32(winHeight),
@ -411,16 +475,6 @@ func (g *Game) Init() {
}
//Load textures
whiteTex, err := assets.LoadTexturePNG("./res/textures/white.png", &assets.TextureLoadOptions{})
if err != nil {
logging.ErrLog.Fatalln("Failed to load texture. Err: ", err)
}
blackTex, err := assets.LoadTexturePNG("./res/textures/black.png", &assets.TextureLoadOptions{})
if err != nil {
logging.ErrLog.Fatalln("Failed to load texture. Err: ", err)
}
containerDiffuseTex, err := assets.LoadTexturePNG("./res/textures/container-diffuse.png", &assets.TextureLoadOptions{})
if err != nil {
logging.ErrLog.Fatalln("Failed to load texture. Err: ", err)
@ -436,6 +490,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{NoSrgba: true})
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",
@ -450,24 +514,22 @@ func (g *Game) Init() {
// Create materials and assign any unused texture slots to black
//
screenQuadMat = materials.NewMaterial("Screen Quad Mat", "./res/shaders/screen-quad.glsl")
screenQuadMat.SetUnifVec2("scale", demoFboScale)
screenQuadMat.SetUnifVec2("offset", demoFboOffset)
screenQuadMat.SetUnifVec2("scale", &demoFboScale)
screenQuadMat.SetUnifVec2("offset", &demoFboOffset)
screenQuadMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse))
unlitMat = materials.NewMaterial("Unlit mat", "./res/shaders/simple-unlit.glsl")
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_HasModelMtx)
whiteMat.Shininess = 64
whiteMat.DiffuseTex = whiteTex.TexID
whiteMat.SpecularTex = blackTex.TexID
whiteMat.NormalTex = blackTex.TexID
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.SetUnifVec3("ambientColor", &ambientColor)
whiteMat.SetUnifFloat32("material.shininess", whiteMat.Shininess)
whiteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
whiteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
@ -477,16 +539,15 @@ 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_HasModelMtx)
containerMat.Shininess = 64
containerMat.DiffuseTex = containerDiffuseTex.TexID
containerMat.SpecularTex = containerSpecularTex.TexID
containerMat.NormalTex = blackTex.TexID
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.SetUnifVec3("ambientColor", &ambientColor)
containerMat.SetUnifFloat32("material.shininess", containerMat.Shininess)
containerMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
containerMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
@ -495,18 +556,35 @@ 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)
groundMat.Shininess = 64
groundMat.DiffuseTex = brickwallDiffuseTex.TexID
groundMat.NormalTex = brickwallNormalTex.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_HasModelMtx)
palleteMat.Shininess = 64
palleteMat.DiffuseTex = palleteTex.TexID
palleteMat.SpecularTex = blackTex.TexID
palleteMat.NormalTex = blackTex.TexID
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.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))
@ -514,22 +592,29 @@ 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_HasModelMtx)
depthMapMat = materials.NewMaterial("Depth Map mat", "./res/shaders/depth-map.glsl")
depthMapMat.Settings.Set(materials.MaterialSettings_HasModelMtx)
arrayDepthMapMat = materials.NewMaterial("Array Depth Map mat", "./res/shaders/array-depth-map.glsl")
arrayDepthMapMat.Settings.Set(materials.MaterialSettings_HasModelMtx)
omnidirDepthMapMat = materials.NewMaterial("Omnidirectional Depth Map mat", "./res/shaders/omnidirectional-depth-map.glsl")
omnidirDepthMapMat.Settings.Set(materials.MaterialSettings_HasModelMtx)
skyboxMat = materials.NewMaterial("Skybox mat", "./res/shaders/skybox.glsl")
skyboxMat.CubemapTex = skyboxCmap.TexID
skyboxMat.SetUnifInt32("skybox", int32(materials.TextureSlot_Cubemap))
// Cube model mat
translationMat := gglm.NewTranslationMat(gglm.NewVec3(0, 0, 0))
scaleMat := gglm.NewScaleMat(gglm.NewVec3(1, 1, 1))
rotMat := gglm.NewRotMat(gglm.NewQuatEuler(gglm.NewVec3(-90, -90, 0).AsRad()))
cubeModelMat.Mul(translationMat.Mul(rotMat.Mul(scaleMat)))
translationMat := gglm.NewTranslationMat(0, 0, 0)
scaleMat := gglm.NewScaleMat(1, 1, 1)
rotMatRot := gglm.NewQuatEuler(-90*gglm.Deg2Rad, -90*gglm.Deg2Rad, 0)
rotMat := gglm.NewRotMatQuat(&rotMatRot)
cubeModelMat.Mul(translationMat.Mul(rotMat.Mul(&scaleMat)))
// Screen quad vao setup.
// We don't actually care about the values here because the quad is hardcoded in the shader,
@ -566,7 +651,7 @@ func (g *Game) initFbos() {
assert.T(demoFbo.IsComplete(), "Demo fbo is not complete after init")
// Depth map fbo
dirLightDepthMapFbo = buffers.NewFramebuffer(1024, 1024)
dirLightDepthMapFbo = buffers.NewFramebuffer(2048, 2048)
dirLightDepthMapFbo.SetNoColorBuffer()
dirLightDepthMapFbo.NewDepthAttachment(
buffers.FramebufferAttachmentType_Texture,
@ -576,7 +661,7 @@ func (g *Game) initFbos() {
assert.T(dirLightDepthMapFbo.IsComplete(), "Depth map fbo is not complete after init")
// Point light depth map fbo
pointLightDepthMapFbo = buffers.NewFramebuffer(1024, 1024)
pointLightDepthMapFbo = buffers.NewFramebuffer(512, 512)
pointLightDepthMapFbo.SetNoColorBuffer()
pointLightDepthMapFbo.NewDepthCubemapArrayAttachment(
buffers.FramebufferAttachmentDataFormat_DepthF32,
@ -586,7 +671,7 @@ func (g *Game) initFbos() {
assert.T(pointLightDepthMapFbo.IsComplete(), "Point light depth map fbo is not complete after init")
// Spot light depth map fbo
spotLightDepthMapFbo = buffers.NewFramebuffer(1024, 1024)
spotLightDepthMapFbo = buffers.NewFramebuffer(512, 512)
spotLightDepthMapFbo.SetNoColorBuffer()
spotLightDepthMapFbo.NewDepthTextureArrayAttachment(
buffers.FramebufferAttachmentDataFormat_DepthF32,
@ -601,6 +686,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
@ -611,35 +697,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
@ -653,31 +747,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
}
@ -722,9 +823,10 @@ func (g *Game) showDebugWindow() {
imgui.Text("Ambient Light")
if imgui.DragFloat3("Ambient Color", &ambientColor.Data) {
whiteMat.SetUnifVec3("ambientColor", ambientColor)
containerMat.SetUnifVec3("ambientColor", ambientColor)
palleteMat.SetUnifVec3("ambientColor", ambientColor)
whiteMat.SetUnifVec3("ambientColor", &ambientColor)
containerMat.SetUnifVec3("ambientColor", &ambientColor)
groundMat.SetUnifVec3("ambientColor", &ambientColor)
palleteMat.SetUnifVec3("ambientColor", &ambientColor)
}
imgui.Spacing()
@ -737,18 +839,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)
}
@ -765,6 +870,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)
}
@ -788,18 +894,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)
}
@ -828,24 +937,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)
}
@ -855,6 +968,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)
}
@ -864,6 +978,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)
}
@ -944,10 +1059,12 @@ func (g *Game) updateCameraPos() {
// Left and right
if input.KeyDown(sdl.K_d) {
cam.Pos.Add(gglm.Cross(&cam.Forward, &cam.WorldUp).Normalize().Scale(camSpeed * camSpeedScale * timing.DT()))
cross := gglm.Cross(&cam.Forward, &cam.WorldUp)
cam.Pos.Add(cross.Normalize().Scale(camSpeed * camSpeedScale * timing.DT()))
update = true
} else if input.KeyDown(sdl.K_a) {
cam.Pos.Add(gglm.Cross(&cam.Forward, &cam.WorldUp).Normalize().Scale(-camSpeed * camSpeedScale * timing.DT()))
cross := gglm.Cross(&cam.Forward, &cam.WorldUp)
cam.Pos.Add(cross.Normalize().Scale(-camSpeed * camSpeedScale * timing.DT()))
update = true
}
@ -958,27 +1075,28 @@ func (g *Game) updateCameraPos() {
}
var (
renderDirLightShadows = true
renderPointLightShadows = true
renderDirLightShadows = false
renderPointLightShadows = false
renderSpotLightShadows = true
rotatingCubeSpeedDeg1 float32 = 45
rotatingCubeSpeedDeg2 float32 = 120
rotatingCubeSpeedDeg3 float32 = 120
rotatingCubeTrMat1 = *gglm.NewTrMatId().Translate(gglm.NewVec3(-4, -1, 4))
rotatingCubeTrMat2 = *gglm.NewTrMatId().Translate(gglm.NewVec3(-1, 0.5, 4))
rotatingCubeTrMat3 = *gglm.NewTrMatId().Translate(gglm.NewVec3(5, 0.5, 4))
rotatingCubeTrMat1 = gglm.NewTrMatWithPos(-4, -1, 4)
rotatingCubeTrMat2 = gglm.NewTrMatWithPos(-1, 0.5, 4)
rotatingCubeTrMat3 = gglm.NewTrMatWithPos(5, 0.5, 4)
)
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(), gglm.NewVec3(0, 1, 0))
rotatingCubeTrMat2.Rotate(rotatingCubeSpeedDeg2*gglm.Deg2Rad*timing.DT(), gglm.NewVec3(1, 1, 0))
rotatingCubeTrMat3.Rotate(rotatingCubeSpeedDeg3*gglm.Deg2Rad*timing.DT(), gglm.NewVec3(1, 1, 1))
rotatingCubeTrMat1.Rotate(rotatingCubeSpeedDeg1*gglm.Deg2Rad*timing.DT(), 0, 1, 0)
rotatingCubeTrMat2.Rotate(rotatingCubeSpeedDeg2*gglm.Deg2Rad*timing.DT(), 1, 1, 0)
rotatingCubeTrMat3.Rotate(rotatingCubeSpeedDeg3*gglm.Deg2Rad*timing.DT(), 1, 1, 1)
if renderDirLightShadows {
g.renderDirectionalLightShadowmap()
@ -1017,6 +1135,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)
@ -1038,8 +1157,8 @@ func (g *Game) renderDirectionalLightShadowmap() {
if showDirLightDepthMapFbo {
screenQuadMat.DiffuseTex = dirLightDepthMapFbo.Attachments[0].Id
screenQuadMat.SetUnifVec2("offset", dirLightDepthMapFboOffset)
screenQuadMat.SetUnifVec2("scale", dirLightDepthMapFboScale)
screenQuadMat.SetUnifVec2("offset", &dirLightDepthMapFboOffset)
screenQuadMat.SetUnifVec2("scale", &dirLightDepthMapFboScale)
screenQuadMat.Bind()
window.Rend.DrawVertexArray(&screenQuadMat, &screenQuadVao, 0, 6)
}
@ -1058,6 +1177,7 @@ func (g *Game) renderSpotLightShadowmaps() {
whiteMat.SetUnifMat4(projViewMatIndexStr, &projViewMat)
containerMat.SetUnifMat4(projViewMatIndexStr, &projViewMat)
groundMat.SetUnifMat4(projViewMatIndexStr, &projViewMat)
palleteMat.SetUnifMat4(projViewMatIndexStr, &projViewMat)
// Set depth uniforms
@ -1120,8 +1240,8 @@ func (g *Game) renderDemoFob() {
demoFbo.UnBind()
screenQuadMat.DiffuseTex = demoFbo.Attachments[0].Id
screenQuadMat.SetUnifVec2("offset", demoFboOffset)
screenQuadMat.SetUnifVec2("scale", demoFboScale)
screenQuadMat.SetUnifVec2("offset", &demoFboOffset)
screenQuadMat.SetUnifVec2("scale", &demoFboScale)
window.Rend.DrawVertexArray(&screenQuadMat, &screenQuadVao, 0, 6)
}
@ -1134,34 +1254,39 @@ 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
window.Rend.DrawMesh(&sphereMesh, gglm.NewTrMatId().Translate(gglm.NewVec3(0, 10, 0)).Scale(gglm.NewVec3(0.1, 0.1, 0.1)), sunMat)
dirLightTrMat := gglm.NewTrMatId()
window.Rend.DrawMesh(&sphereMesh, dirLightTrMat.Translate(0, 10, 0).Scale(0.1, 0.1, 0.1), sunMat)
// Draw point lights
for i := 0; i < len(pointLights); i++ {
pl := &pointLights[i]
window.Rend.DrawMesh(&cubeMesh, gglm.NewTrMatId().Translate(&pl.Pos).Scale(gglm.NewVec3(0.1, 0.1, 0.1)), sunMat)
plTrMat := gglm.NewTrMatId()
window.Rend.DrawMesh(&cubeMesh, plTrMat.TranslateVec(&pl.Pos).Scale(0.1, 0.1, 0.1), sunMat)
}
// Chair
window.Rend.DrawMesh(&chairMesh, tempModelMatrix, chairMat)
// Ground
window.Rend.DrawMesh(&cubeMesh, gglm.NewTrMatId().Translate(gglm.NewVec3(0, -3, 0)).Scale(gglm.NewVec3(20, 1, 20)), cubeMat)
groundTrMat := gglm.NewTrMatId()
window.Rend.DrawMesh(&cubeMesh, groundTrMat.Translate(0, -3, 0).Scale(20, 1, 20), groundMat)
// Cubes
tempModelMatrix.Translate(gglm.NewVec3(-6, 0, 0))
tempModelMatrix.Translate(-6, 0, 0)
window.Rend.DrawMesh(&cubeMesh, tempModelMatrix, cubeMat)
tempModelMatrix.Translate(gglm.NewVec3(0, -1, -4))
tempModelMatrix.Translate(0, -1, -4)
window.Rend.DrawMesh(&cubeMesh, tempModelMatrix, cubeMat)
// Rotating cubes
@ -1205,6 +1330,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

@ -3,6 +3,7 @@ package materials
import (
"github.com/bloeys/gglm/gglm"
"github.com/bloeys/nmage/assert"
"github.com/bloeys/nmage/assets"
"github.com/bloeys/nmage/logging"
"github.com/bloeys/nmage/shaders"
"github.com/go-gl/gl/v4.1-core/gl"
@ -21,14 +22,35 @@ const (
TextureSlot_ShadowMap_Array1 TextureSlot = 13
)
type MaterialSettings uint64
const (
MaterialSettings_None MaterialSettings = iota
MaterialSettings_HasModelMtx MaterialSettings = 1 << (iota - 1)
MaterialSettings_HasNormalMtx
)
func (ms *MaterialSettings) Set(flags MaterialSettings) {
*ms |= flags
}
func (ms *MaterialSettings) Remove(flags MaterialSettings) {
*ms &= ^flags
}
func (ms *MaterialSettings) Has(flags MaterialSettings) bool {
return *ms&flags == flags
}
type Material struct {
Name string
ShaderProg shaders.ShaderProgram
Settings MaterialSettings
UnifLocs map[string]int32
AttribLocs map[string]int32
// @TODO do this in a better way. Perhaps something like how we do fbo attachments
// @TODO: Do this in a better way?. Perhaps something like how we do fbo attachments? Or keep it?
// Phong shading
DiffuseTex uint32
SpecularTex uint32
@ -51,26 +73,19 @@ func (m *Material) Bind() {
m.ShaderProg.Bind()
if m.DiffuseTex != 0 {
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Diffuse))
gl.BindTexture(gl.TEXTURE_2D, m.DiffuseTex)
}
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Diffuse))
gl.BindTexture(gl.TEXTURE_2D, m.DiffuseTex)
if m.SpecularTex != 0 {
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Specular))
gl.BindTexture(gl.TEXTURE_2D, m.SpecularTex)
}
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Specular))
gl.BindTexture(gl.TEXTURE_2D, m.SpecularTex)
if m.NormalTex != 0 {
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Normal))
gl.BindTexture(gl.TEXTURE_2D, m.NormalTex)
}
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Normal))
gl.BindTexture(gl.TEXTURE_2D, m.NormalTex)
if m.EmissionTex != 0 {
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Emission))
gl.BindTexture(gl.TEXTURE_2D, m.EmissionTex)
}
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Emission))
gl.BindTexture(gl.TEXTURE_2D, m.EmissionTex)
// @TODO: Have defaults for these
if m.CubemapTex != 0 {
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Cubemap))
gl.BindTexture(gl.TEXTURE_CUBE_MAP, m.CubemapTex)
@ -173,7 +188,17 @@ func NewMaterial(matName, shaderPath string) Material {
logging.ErrLog.Fatalf("Failed to create new material '%s'. Err: %s\n", matName, err.Error())
}
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),
DiffuseTex: assets.DefaultDiffuseTexId.TexID,
SpecularTex: assets.DefaultSpecularTexId.TexID,
NormalTex: assets.DefaultNormalTexId.TexID,
EmissionTex: assets.DefaultEmissionTexId.TexID,
}
}
func NewMaterialSrc(matName string, shaderSrc []byte) Material {
@ -183,5 +208,15 @@ func NewMaterialSrc(matName string, shaderSrc []byte) Material {
logging.ErrLog.Fatalf("Failed to create new material '%s'. Err: %s\n", matName, err.Error())
}
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),
DiffuseTex: assets.DefaultDiffuseTexId.TexID,
SpecularTex: assets.DefaultSpecularTexId.TexID,
NormalTex: assets.DefaultNormalTexId.TexID,
EmissionTex: assets.DefaultEmissionTexId.TexID,
}
}

View File

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

View File

@ -29,7 +29,14 @@ func (r *Rend3DGL) DrawMesh(mesh *meshes.Mesh, modelMat *gglm.TrMat, mat *materi
r.BoundMat = mat
}
mat.SetUnifMat4("modelMat", &modelMat.Mat4)
if mat.Settings.Has(materials.MaterialSettings_HasModelMtx) {
mat.SetUnifMat4("modelMat", &modelMat.Mat4)
}
if mat.Settings.Has(materials.MaterialSettings_HasNormalMtx) {
normalMat := modelMat.Clone().InvertAndTranspose().ToMat3()
mat.SetUnifMat3("normalMat", &normalMat)
}
for i := 0; i < len(mesh.SubMeshes); i++ {
gl.DrawElementsBaseVertexWithOffset(gl.TRIANGLES, mesh.SubMeshes[i].IndexCount, gl.UNSIGNED_INT, uintptr(mesh.SubMeshes[i].BaseIndex), mesh.SubMeshes[i].BaseVertex)

View File

@ -2,22 +2,19 @@
#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;
layout(location=2) in vec3 vertTangentIn;
layout(location=3) in vec2 vertUV0In;
layout(location=4) in vec3 vertColorIn;
out vec3 vertNormal;
out vec2 vertUV0;
out vec3 vertColor;
out vec3 fragPos;
//MVP = Model View Projection
uniform mat4 modelMat;
uniform mat4 projViewMat;
void main()
{
vertNormal = mat3(transpose(inverse(modelMat))) * vertNormalIn;
vertUV0 = vertUV0In;
vertColor = vertColorIn;
@ -31,7 +28,6 @@ void main()
#version 410
in vec3 vertColor;
in vec3 vertNormal;
in vec2 vertUV0;
in vec3 fragPos;

View File

@ -3,26 +3,19 @@
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 vertNormal;
out vec2 vertUV0;
out vec3 vertColor;
out vec3 fragPos;
//MVP = Model View Projection
uniform mat4 modelMat;
uniform mat4 projViewMat;
void main()
{
// @TODO: Calculate this on the CPU and send it as a uniform
//
// This produces the normal matrix that multiplies with the model normal to produce the
// world space normal. Based on 'One last thing' section from: https://learnopengl.com/Lighting/Basic-Lighting
vertNormal = mat3(transpose(inverse(modelMat))) * vertNormalIn;
vertUV0 = vertUV0In;
vertColor = vertColorIn;
@ -41,7 +34,6 @@ struct Material {
uniform Material material;
in vec3 vertColor;
in vec3 vertNormal;
in vec2 vertUV0;
in vec3 fragPos;

View File

@ -1,66 +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()
{
// @TODO: Calculate this on the CPU and send it as a uniform
//
// This produces the normal matrix that multiplies with the model normal to produce the
// world space normal. Based on 'One last thing' section from: https://learnopengl.com/Lighting/Basic-Lighting
vertNormal = mat3(transpose(inverse(modelMat))) * 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 {
@ -72,8 +40,133 @@ 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 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));
// 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 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;
@ -85,37 +178,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)
@ -126,7 +211,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
@ -151,14 +236,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;
@ -168,9 +253,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;
@ -180,7 +265,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;
@ -193,28 +279,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;
@ -231,7 +318,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
@ -259,12 +346,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));
@ -276,7 +364,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,15 +374,21 @@ vec3 CalcSpotLight(SpotLight light, int lightIndex)
return (finalDiffuse + finalSpecular) * intensity * (1 - shadow);
}
#define DRAW_NORMALS false
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;
// Remap normal to [-1,1]
normalizedVertNorm = normalize(normalizedVertNorm * 2.0 - 1.0);
// Light contributions
vec3 finalColor = CalcDirLight();
@ -313,4 +407,9 @@ void main()
vec3 finalAmbient = ambientColor * diffuseTexColor.rgb;
fragColor = vec4(finalColor + finalAmbient + finalEmission, 1);
if (DRAW_NORMALS)
{
fragColor = vec4(texture(material.normal, vertUV0).rgb, 1);
}
}

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;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 B

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 B