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/ vendor/
.vscode/ .vscode/
imgui.ini imgui.ini
*~ *~
# Custom
*.pprof

View File

@ -23,6 +23,15 @@ const (
ColorFormat_RGBA8 ColorFormat_RGBA8
) )
var (
DefaultBlackTexId Texture
DefaultWhiteTexId Texture
DefaultDiffuseTexId Texture
DefaultSpecularTexId Texture
DefaultNormalTexId Texture
DefaultEmissionTexId Texture
)
type Texture struct { type Texture struct {
// Path only exists for textures loaded from disk // Path only exists for textures loaded from disk
Path string 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 c.ViewMat = gglm.LookAtRH(&c.Pos, c.Pos.Clone().Add(&c.Forward), &c.WorldUp).Mat4
if c.Type == Type_Perspective { 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 { } else {
c.ProjMat = gglm.Ortho(c.Left, c.Right, c.Top, c.Bottom, c.NearClip, c.FarClip).Mat4 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 package engine
import ( import (
"image"
"image/color"
"runtime" "runtime"
imgui "github.com/AllenDang/cimgui-go" imgui "github.com/AllenDang/cimgui-go"
"github.com/bloeys/nmage/assert" "github.com/bloeys/nmage/assert"
"github.com/bloeys/nmage/assets"
"github.com/bloeys/nmage/input" "github.com/bloeys/nmage/input"
"github.com/bloeys/nmage/renderer" "github.com/bloeys/nmage/renderer"
"github.com/bloeys/nmage/timing" "github.com/bloeys/nmage/timing"
@ -202,6 +205,8 @@ func createWindow(title string, x, y, width, height int32, flags WindowFlags, re
return win, err return win, err
} }
setupDefaultTextures()
// Get rid of the blinding white startup screen (unfortunately there is still one frame of white) // 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) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
win.SDLWin.GLSwap() win.SDLWin.GLSwap()
@ -231,6 +236,57 @@ func initOpenGL() error {
return nil 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) { func SetSrgbFramebuffer(isEnabled bool) {
if isEnabled { if isEnabled {

2
go.mod
View File

@ -8,7 +8,7 @@ require github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6
require ( require (
github.com/bloeys/assimp-go v0.4.4 github.com/bloeys/assimp-go v0.4.4
github.com/bloeys/gglm v0.43.0 github.com/bloeys/gglm v0.49.0
) )
require ( 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/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 h1:Yn5e/RpE0Oes0YMBy8O7KkwAO4R/RpgrZPJCt08dVIU=
github.com/bloeys/assimp-go v0.4.4/go.mod h1:my3yRxT7CfOztmvi+0svmwbaqw0KFrxaHxncoyaEIP0= 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.49.0 h1:YtbyHpszYhjnxw7KVV0LaCdBktRMqfGx/i37EMomxsE=
github.com/bloeys/gglm v0.43.0/go.mod h1:qwJQ0WzV191wAMwlGicbfbChbKoSedMk7gFFX6GnyOk= 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 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk=
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw= github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
github.com/mandykoh/go-parallel v0.1.0 h1:7vJMNMC4dsbgZdkAb2A8tV5ENY1v7VxIO1wzQWZoT8k= github.com/mandykoh/go-parallel v0.1.0 h1:7vJMNMC4dsbgZdkAb2A8tV5ENY1v7VxIO1wzQWZoT8k=

306
main.go
View File

@ -2,7 +2,9 @@ package main
import ( import (
"fmt" "fmt"
"os"
"runtime" "runtime"
"runtime/pprof"
"strconv" "strconv"
imgui "github.com/AllenDang/cimgui-go" imgui "github.com/AllenDang/cimgui-go"
@ -34,6 +36,7 @@ import (
- Point light shadows ✅ - Point light shadows ✅
- Spotlight shadows ✅ - Spotlight shadows ✅
- Create VAO struct independent from VBO to support multi-VBO use cases (e.g. instancing) ✅ - Create VAO struct independent from VBO to support multi-VBO use cases (e.g. instancing) ✅
- Normals maps
- UBO support - UBO support
- HDR - HDR
- Cascaded shadow mapping - Cascaded shadow mapping
@ -71,8 +74,9 @@ func (d *DirLight) GetProjViewMat() gglm.Mat4 {
nearClip := dirLightNear nearClip := dirLightNear
farClip := dirLightFar farClip := dirLightFar
up := gglm.NewVec3(0, 1, 0)
projMat := gglm.Ortho(-size, size, -size, size, nearClip, farClip).Mat4 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) return *projMat.Mul(&viewMat)
} }
@ -109,13 +113,34 @@ func (p *PointLight) GetProjViewMats(shadowMapWidth, shadowMapHeight float32) [6
aspect := float32(shadowMapWidth) / float32(shadowMapHeight) aspect := float32(shadowMapWidth) / float32(shadowMapHeight)
projMat := gglm.Perspective(90*gglm.Deg2Rad, aspect, pointLightNear, p.FarPlane) 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{ 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(&lookAt0.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(&lookAt1.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(&lookAt2.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(&lookAt3.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(&lookAt4.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(&lookAt5.Mat4),
} }
return projViewMats return projViewMats
@ -143,11 +168,11 @@ func (s *SpotLight) GetProjViewMat() gglm.Mat4 {
// Adjust up vector if lightDir is parallel or nearly parallel to upVector // Adjust up vector if lightDir is parallel or nearly parallel to upVector
// as lookat view matrix breaks if up and look at are parallel // as lookat view matrix breaks if up and look at are parallel
up := gglm.NewVec3(0, 1, 0) 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) 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) return *projMat.Mul(&viewMat)
} }
@ -166,6 +191,8 @@ const (
unscaledWindowWidth = 1280 unscaledWindowWidth = 1280
unscaledWindowHeight = 720 unscaledWindowHeight = 720
PROFILE_CPU = true
) )
var ( var (
@ -200,6 +227,7 @@ var (
unlitMat materials.Material unlitMat materials.Material
whiteMat materials.Material whiteMat materials.Material
containerMat materials.Material containerMat materials.Material
groundMat materials.Material
palleteMat materials.Material palleteMat materials.Material
skyboxMat materials.Material skyboxMat materials.Material
depthMapMat materials.Material depthMapMat materials.Material
@ -224,17 +252,18 @@ var (
// Light settings // Light settings
ambientColor = gglm.NewVec3(0, 0, 0) ambientColor = gglm.NewVec3(0, 0, 0)
dirLightDir = gglm.NewVec3(0, -0.5, -0.8)
// Lights // Lights
dirLight = DirLight{ dirLight = DirLight{
Dir: *gglm.NewVec3(0, -0.5, -0.8).Normalize(), Dir: *dirLightDir.Normalize(),
DiffuseColor: *gglm.NewVec3(1, 1, 1), DiffuseColor: gglm.NewVec3(1, 1, 1),
SpecularColor: *gglm.NewVec3(1, 1, 1), SpecularColor: gglm.NewVec3(1, 1, 1),
} }
pointLights = [...]PointLight{ pointLights = [...]PointLight{
{ {
Pos: *gglm.NewVec3(0, 2, -2), Pos: gglm.NewVec3(0, 2, -2),
DiffuseColor: *gglm.NewVec3(1, 0, 0), DiffuseColor: gglm.NewVec3(1, 0, 0),
SpecularColor: *gglm.NewVec3(1, 1, 1), SpecularColor: gglm.NewVec3(1, 1, 1),
// These values are for 50m range // These values are for 50m range
Constant: 1.0, Constant: 1.0,
Linear: 0.09, Linear: 0.09,
@ -243,45 +272,47 @@ var (
FarPlane: 25, FarPlane: 25,
}, },
{ {
Pos: *gglm.NewVec3(0, -5, 0), Pos: gglm.NewVec3(0, -5, 0),
DiffuseColor: *gglm.NewVec3(0, 1, 0), DiffuseColor: gglm.NewVec3(0, 1, 0),
SpecularColor: *gglm.NewVec3(1, 1, 1), SpecularColor: gglm.NewVec3(1, 1, 1),
Constant: 1.0, Constant: 1.0,
Linear: 0.09, Linear: 0.09,
Quadratic: 0.032, Quadratic: 0.032,
FarPlane: 25, FarPlane: 25,
}, },
{ {
Pos: *gglm.NewVec3(5, 0, 0), Pos: gglm.NewVec3(5, 0, 0),
DiffuseColor: *gglm.NewVec3(1, 1, 1), DiffuseColor: gglm.NewVec3(1, 1, 1),
SpecularColor: *gglm.NewVec3(1, 1, 1), SpecularColor: gglm.NewVec3(1, 1, 1),
Constant: 1.0, Constant: 1.0,
Linear: 0.09, Linear: 0.09,
Quadratic: 0.032, Quadratic: 0.032,
FarPlane: 25, FarPlane: 25,
}, },
{ {
Pos: *gglm.NewVec3(-3, 4, 3), Pos: gglm.NewVec3(-3, 4, 3),
DiffuseColor: *gglm.NewVec3(1, 1, 1), DiffuseColor: gglm.NewVec3(1, 1, 1),
SpecularColor: *gglm.NewVec3(1, 1, 1), SpecularColor: gglm.NewVec3(1, 1, 1),
Constant: 1.0, Constant: 1.0,
Linear: 0.09, Linear: 0.09,
Quadratic: 0.032, Quadratic: 0.032,
FarPlane: 25, FarPlane: 25,
}, },
} }
spotLights = [...]SpotLight{
spotLightDir0 = gglm.NewVec3(1.5, -0.9, 0)
spotLights = [...]SpotLight{
{ {
Pos: *gglm.NewVec3(-4, 7, 5), Pos: gglm.NewVec3(-4, 7, 5),
Dir: *gglm.NewVec3(1.5, -0.9, 0).Normalize(), Dir: *spotLightDir0.Normalize(),
DiffuseColor: *gglm.NewVec3(1, 0, 1), DiffuseColor: gglm.NewVec3(1, 0, 1),
SpecularColor: *gglm.NewVec3(1, 1, 1), SpecularColor: gglm.NewVec3(1, 1, 1),
// These must be cosine values // These must be cosine values
InnerCutoffRad: 15 * gglm.Deg2Rad, InnerCutoffRad: 15 * gglm.Deg2Rad,
OuterCutoffRad: 20 * gglm.Deg2Rad, OuterCutoffRad: 20 * gglm.Deg2Rad,
NearPlane: 1, NearPlane: 2,
FarPlane: 30, FarPlane: 50,
}, },
} }
) )
@ -321,7 +352,36 @@ func main() {
} }
window.EventCallbacks = append(window.EventCallbacks, game.handleWindowEvents) 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) 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) { func (g *Game) handleWindowEvents(e sdl.Event) {
@ -380,10 +440,14 @@ func (g *Game) Init() {
// Camera // Camera
winWidth, winHeight := g.Win.SDLWin.GetSize() 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( cam = camera.NewPerspective(
gglm.NewVec3(0, 0, 10), &camPos,
gglm.NewVec3(0, 0, -1), &camForward,
gglm.NewVec3(0, 1, 0), &camWorldUp,
0.1, 200, 0.1, 200,
45*gglm.Deg2Rad, 45*gglm.Deg2Rad,
float32(winWidth)/float32(winHeight), float32(winWidth)/float32(winHeight),
@ -411,16 +475,6 @@ func (g *Game) Init() {
} }
//Load textures //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{}) containerDiffuseTex, err := assets.LoadTexturePNG("./res/textures/container-diffuse.png", &assets.TextureLoadOptions{})
if err != nil { if err != nil {
logging.ErrLog.Fatalln("Failed to load texture. Err: ", err) 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) 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( skyboxCmap, err = assets.LoadCubemapTextures(
"./res/textures/sb-right.jpg", "./res/textures/sb-left.jpg", "./res/textures/sb-right.jpg", "./res/textures/sb-left.jpg",
"./res/textures/sb-top.jpg", "./res/textures/sb-bottom.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 // Create materials and assign any unused texture slots to black
// //
screenQuadMat = materials.NewMaterial("Screen Quad Mat", "./res/shaders/screen-quad.glsl") screenQuadMat = materials.NewMaterial("Screen Quad Mat", "./res/shaders/screen-quad.glsl")
screenQuadMat.SetUnifVec2("scale", demoFboScale) screenQuadMat.SetUnifVec2("scale", &demoFboScale)
screenQuadMat.SetUnifVec2("offset", demoFboOffset) screenQuadMat.SetUnifVec2("offset", &demoFboOffset)
screenQuadMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse)) screenQuadMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse))
unlitMat = materials.NewMaterial("Unlit mat", "./res/shaders/simple-unlit.glsl") unlitMat = materials.NewMaterial("Unlit mat", "./res/shaders/simple-unlit.glsl")
unlitMat.Settings.Set(materials.MaterialSettings_HasModelMtx)
unlitMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse)) unlitMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse))
whiteMat = materials.NewMaterial("White mat", "./res/shaders/simple.glsl") whiteMat = materials.NewMaterial("White mat", "./res/shaders/simple.glsl")
whiteMat.Settings.Set(materials.MaterialSettings_HasModelMtx)
whiteMat.Shininess = 64 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.diffuse", int32(materials.TextureSlot_Diffuse))
whiteMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular)) 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.SetUnifInt32("material.emission", int32(materials.TextureSlot_Emission))
whiteMat.SetUnifVec3("ambientColor", ambientColor) whiteMat.SetUnifVec3("ambientColor", &ambientColor)
whiteMat.SetUnifFloat32("material.shininess", whiteMat.Shininess) whiteMat.SetUnifFloat32("material.shininess", whiteMat.Shininess)
whiteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir) whiteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
whiteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) whiteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
@ -477,16 +539,15 @@ func (g *Game) Init() {
whiteMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1)) whiteMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1))
containerMat = materials.NewMaterial("Container mat", "./res/shaders/simple.glsl") containerMat = materials.NewMaterial("Container mat", "./res/shaders/simple.glsl")
containerMat.Settings.Set(materials.MaterialSettings_HasModelMtx)
containerMat.Shininess = 64 containerMat.Shininess = 64
containerMat.DiffuseTex = containerDiffuseTex.TexID containerMat.DiffuseTex = containerDiffuseTex.TexID
containerMat.SpecularTex = containerSpecularTex.TexID containerMat.SpecularTex = containerSpecularTex.TexID
containerMat.NormalTex = blackTex.TexID
containerMat.EmissionTex = blackTex.TexID
containerMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse)) containerMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse))
containerMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular)) 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.SetUnifInt32("material.emission", int32(materials.TextureSlot_Emission))
containerMat.SetUnifVec3("ambientColor", ambientColor) containerMat.SetUnifVec3("ambientColor", &ambientColor)
containerMat.SetUnifFloat32("material.shininess", containerMat.Shininess) containerMat.SetUnifFloat32("material.shininess", containerMat.Shininess)
containerMat.SetUnifVec3("dirLight.dir", &dirLight.Dir) containerMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
containerMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) containerMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
@ -495,18 +556,35 @@ func (g *Game) Init() {
containerMat.SetUnifInt32("pointLightCubeShadowMaps", int32(materials.TextureSlot_Cubemap_Array)) containerMat.SetUnifInt32("pointLightCubeShadowMaps", int32(materials.TextureSlot_Cubemap_Array))
containerMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1)) 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 = materials.NewMaterial("Pallete mat", "./res/shaders/simple.glsl")
palleteMat.Settings.Set(materials.MaterialSettings_HasModelMtx)
palleteMat.Shininess = 64 palleteMat.Shininess = 64
palleteMat.DiffuseTex = palleteTex.TexID 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.diffuse", int32(materials.TextureSlot_Diffuse))
palleteMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular)) 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.SetUnifInt32("material.emission", int32(materials.TextureSlot_Emission))
palleteMat.SetUnifVec3("ambientColor", ambientColor) palleteMat.SetUnifVec3("ambientColor", &ambientColor)
palleteMat.SetUnifFloat32("material.shininess", palleteMat.Shininess) palleteMat.SetUnifFloat32("material.shininess", palleteMat.Shininess)
palleteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
palleteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) palleteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
palleteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor) palleteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
palleteMat.SetUnifInt32("dirLight.shadowMap", int32(materials.TextureSlot_ShadowMap1)) palleteMat.SetUnifInt32("dirLight.shadowMap", int32(materials.TextureSlot_ShadowMap1))
@ -514,22 +592,29 @@ func (g *Game) Init() {
palleteMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1)) palleteMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1))
debugDepthMat = materials.NewMaterial("Debug depth mat", "./res/shaders/debug-depth.glsl") 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 = 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 = 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 = 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 = materials.NewMaterial("Skybox mat", "./res/shaders/skybox.glsl")
skyboxMat.CubemapTex = skyboxCmap.TexID skyboxMat.CubemapTex = skyboxCmap.TexID
skyboxMat.SetUnifInt32("skybox", int32(materials.TextureSlot_Cubemap)) skyboxMat.SetUnifInt32("skybox", int32(materials.TextureSlot_Cubemap))
// Cube model mat // Cube model mat
translationMat := gglm.NewTranslationMat(gglm.NewVec3(0, 0, 0)) translationMat := gglm.NewTranslationMat(0, 0, 0)
scaleMat := gglm.NewScaleMat(gglm.NewVec3(1, 1, 1))
rotMat := gglm.NewRotMat(gglm.NewQuatEuler(gglm.NewVec3(-90, -90, 0).AsRad())) scaleMat := gglm.NewScaleMat(1, 1, 1)
cubeModelMat.Mul(translationMat.Mul(rotMat.Mul(scaleMat)))
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. // Screen quad vao setup.
// We don't actually care about the values here because the quad is hardcoded in the shader, // 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") assert.T(demoFbo.IsComplete(), "Demo fbo is not complete after init")
// Depth map fbo // Depth map fbo
dirLightDepthMapFbo = buffers.NewFramebuffer(1024, 1024) dirLightDepthMapFbo = buffers.NewFramebuffer(2048, 2048)
dirLightDepthMapFbo.SetNoColorBuffer() dirLightDepthMapFbo.SetNoColorBuffer()
dirLightDepthMapFbo.NewDepthAttachment( dirLightDepthMapFbo.NewDepthAttachment(
buffers.FramebufferAttachmentType_Texture, buffers.FramebufferAttachmentType_Texture,
@ -576,7 +661,7 @@ func (g *Game) initFbos() {
assert.T(dirLightDepthMapFbo.IsComplete(), "Depth map fbo is not complete after init") assert.T(dirLightDepthMapFbo.IsComplete(), "Depth map fbo is not complete after init")
// Point light depth map fbo // Point light depth map fbo
pointLightDepthMapFbo = buffers.NewFramebuffer(1024, 1024) pointLightDepthMapFbo = buffers.NewFramebuffer(512, 512)
pointLightDepthMapFbo.SetNoColorBuffer() pointLightDepthMapFbo.SetNoColorBuffer()
pointLightDepthMapFbo.NewDepthCubemapArrayAttachment( pointLightDepthMapFbo.NewDepthCubemapArrayAttachment(
buffers.FramebufferAttachmentDataFormat_DepthF32, 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") assert.T(pointLightDepthMapFbo.IsComplete(), "Point light depth map fbo is not complete after init")
// Spot light depth map fbo // Spot light depth map fbo
spotLightDepthMapFbo = buffers.NewFramebuffer(1024, 1024) spotLightDepthMapFbo = buffers.NewFramebuffer(512, 512)
spotLightDepthMapFbo.SetNoColorBuffer() spotLightDepthMapFbo.SetNoColorBuffer()
spotLightDepthMapFbo.NewDepthTextureArrayAttachment( spotLightDepthMapFbo.NewDepthTextureArrayAttachment(
buffers.FramebufferAttachmentDataFormat_DepthF32, buffers.FramebufferAttachmentDataFormat_DepthF32,
@ -601,6 +686,7 @@ func (g *Game) updateLights() {
// Directional light // Directional light
whiteMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id whiteMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id
containerMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id containerMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id
groundMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id
palleteMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id palleteMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id
// Point lights // Point lights
@ -611,35 +697,43 @@ func (g *Game) updateLights() {
whiteMat.SetUnifVec3(indexString+".pos", &p.Pos) whiteMat.SetUnifVec3(indexString+".pos", &p.Pos)
containerMat.SetUnifVec3(indexString+".pos", &p.Pos) containerMat.SetUnifVec3(indexString+".pos", &p.Pos)
groundMat.SetUnifVec3(indexString+".pos", &p.Pos)
palleteMat.SetUnifVec3(indexString+".pos", &p.Pos) palleteMat.SetUnifVec3(indexString+".pos", &p.Pos)
whiteMat.SetUnifVec3(indexString+".diffuseColor", &p.DiffuseColor) whiteMat.SetUnifVec3(indexString+".diffuseColor", &p.DiffuseColor)
containerMat.SetUnifVec3(indexString+".diffuseColor", &p.DiffuseColor) containerMat.SetUnifVec3(indexString+".diffuseColor", &p.DiffuseColor)
groundMat.SetUnifVec3(indexString+".diffuseColor", &p.DiffuseColor)
palleteMat.SetUnifVec3(indexString+".diffuseColor", &p.DiffuseColor) palleteMat.SetUnifVec3(indexString+".diffuseColor", &p.DiffuseColor)
whiteMat.SetUnifVec3(indexString+".specularColor", &p.SpecularColor) whiteMat.SetUnifVec3(indexString+".specularColor", &p.SpecularColor)
containerMat.SetUnifVec3(indexString+".specularColor", &p.SpecularColor) containerMat.SetUnifVec3(indexString+".specularColor", &p.SpecularColor)
groundMat.SetUnifVec3(indexString+".specularColor", &p.SpecularColor)
palleteMat.SetUnifVec3(indexString+".specularColor", &p.SpecularColor) palleteMat.SetUnifVec3(indexString+".specularColor", &p.SpecularColor)
whiteMat.SetUnifFloat32(indexString+".constant", p.Constant) whiteMat.SetUnifFloat32(indexString+".constant", p.Constant)
containerMat.SetUnifFloat32(indexString+".constant", p.Constant) containerMat.SetUnifFloat32(indexString+".constant", p.Constant)
groundMat.SetUnifFloat32(indexString+".constant", p.Constant)
palleteMat.SetUnifFloat32(indexString+".constant", p.Constant) palleteMat.SetUnifFloat32(indexString+".constant", p.Constant)
whiteMat.SetUnifFloat32(indexString+".linear", p.Linear) whiteMat.SetUnifFloat32(indexString+".linear", p.Linear)
containerMat.SetUnifFloat32(indexString+".linear", p.Linear) containerMat.SetUnifFloat32(indexString+".linear", p.Linear)
groundMat.SetUnifFloat32(indexString+".linear", p.Linear)
palleteMat.SetUnifFloat32(indexString+".linear", p.Linear) palleteMat.SetUnifFloat32(indexString+".linear", p.Linear)
whiteMat.SetUnifFloat32(indexString+".quadratic", p.Quadratic) whiteMat.SetUnifFloat32(indexString+".quadratic", p.Quadratic)
containerMat.SetUnifFloat32(indexString+".quadratic", p.Quadratic) containerMat.SetUnifFloat32(indexString+".quadratic", p.Quadratic)
groundMat.SetUnifFloat32(indexString+".quadratic", p.Quadratic)
palleteMat.SetUnifFloat32(indexString+".quadratic", p.Quadratic) palleteMat.SetUnifFloat32(indexString+".quadratic", p.Quadratic)
whiteMat.SetUnifFloat32(indexString+".farPlane", p.FarPlane) whiteMat.SetUnifFloat32(indexString+".farPlane", p.FarPlane)
containerMat.SetUnifFloat32(indexString+".farPlane", p.FarPlane) containerMat.SetUnifFloat32(indexString+".farPlane", p.FarPlane)
groundMat.SetUnifFloat32(indexString+".farPlane", p.FarPlane)
palleteMat.SetUnifFloat32(indexString+".farPlane", p.FarPlane) palleteMat.SetUnifFloat32(indexString+".farPlane", p.FarPlane)
} }
whiteMat.CubemapArrayTex = pointLightDepthMapFbo.Attachments[0].Id whiteMat.CubemapArrayTex = pointLightDepthMapFbo.Attachments[0].Id
containerMat.CubemapArrayTex = pointLightDepthMapFbo.Attachments[0].Id containerMat.CubemapArrayTex = pointLightDepthMapFbo.Attachments[0].Id
groundMat.CubemapArrayTex = pointLightDepthMapFbo.Attachments[0].Id
palleteMat.CubemapArrayTex = pointLightDepthMapFbo.Attachments[0].Id palleteMat.CubemapArrayTex = pointLightDepthMapFbo.Attachments[0].Id
// Spotlights // Spotlights
@ -653,31 +747,38 @@ func (g *Game) updateLights() {
whiteMat.SetUnifVec3(indexString+".pos", &l.Pos) whiteMat.SetUnifVec3(indexString+".pos", &l.Pos)
containerMat.SetUnifVec3(indexString+".pos", &l.Pos) containerMat.SetUnifVec3(indexString+".pos", &l.Pos)
groundMat.SetUnifVec3(indexString+".pos", &l.Pos)
palleteMat.SetUnifVec3(indexString+".pos", &l.Pos) palleteMat.SetUnifVec3(indexString+".pos", &l.Pos)
whiteMat.SetUnifVec3(indexString+".dir", &l.Dir) whiteMat.SetUnifVec3(indexString+".dir", &l.Dir)
containerMat.SetUnifVec3(indexString+".dir", &l.Dir) containerMat.SetUnifVec3(indexString+".dir", &l.Dir)
groundMat.SetUnifVec3(indexString+".dir", &l.Dir)
palleteMat.SetUnifVec3(indexString+".dir", &l.Dir) palleteMat.SetUnifVec3(indexString+".dir", &l.Dir)
whiteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) whiteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
containerMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) containerMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
groundMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
palleteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) palleteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
whiteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) whiteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
containerMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) containerMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
groundMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
palleteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) palleteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
whiteMat.SetUnifFloat32(indexString+".innerCutoff", innerCutoffCos) whiteMat.SetUnifFloat32(indexString+".innerCutoff", innerCutoffCos)
containerMat.SetUnifFloat32(indexString+".innerCutoff", innerCutoffCos) containerMat.SetUnifFloat32(indexString+".innerCutoff", innerCutoffCos)
groundMat.SetUnifFloat32(indexString+".innerCutoff", innerCutoffCos)
palleteMat.SetUnifFloat32(indexString+".innerCutoff", innerCutoffCos) palleteMat.SetUnifFloat32(indexString+".innerCutoff", innerCutoffCos)
whiteMat.SetUnifFloat32(indexString+".outerCutoff", outerCutoffCos) whiteMat.SetUnifFloat32(indexString+".outerCutoff", outerCutoffCos)
containerMat.SetUnifFloat32(indexString+".outerCutoff", outerCutoffCos) containerMat.SetUnifFloat32(indexString+".outerCutoff", outerCutoffCos)
groundMat.SetUnifFloat32(indexString+".outerCutoff", outerCutoffCos)
palleteMat.SetUnifFloat32(indexString+".outerCutoff", outerCutoffCos) palleteMat.SetUnifFloat32(indexString+".outerCutoff", outerCutoffCos)
} }
whiteMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id whiteMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id
containerMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id containerMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id
groundMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id
palleteMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id palleteMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id
} }
@ -722,9 +823,10 @@ func (g *Game) showDebugWindow() {
imgui.Text("Ambient Light") imgui.Text("Ambient Light")
if imgui.DragFloat3("Ambient Color", &ambientColor.Data) { if imgui.DragFloat3("Ambient Color", &ambientColor.Data) {
whiteMat.SetUnifVec3("ambientColor", ambientColor) whiteMat.SetUnifVec3("ambientColor", &ambientColor)
containerMat.SetUnifVec3("ambientColor", ambientColor) containerMat.SetUnifVec3("ambientColor", &ambientColor)
palleteMat.SetUnifVec3("ambientColor", ambientColor) groundMat.SetUnifVec3("ambientColor", &ambientColor)
palleteMat.SetUnifVec3("ambientColor", &ambientColor)
} }
imgui.Spacing() imgui.Spacing()
@ -737,18 +839,21 @@ func (g *Game) showDebugWindow() {
if imgui.DragFloat3("Direction", &dirLight.Dir.Data) { if imgui.DragFloat3("Direction", &dirLight.Dir.Data) {
whiteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir) whiteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
containerMat.SetUnifVec3("dirLight.dir", &dirLight.Dir) containerMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
groundMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
palleteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir) palleteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
} }
if imgui.DragFloat3("Diffuse Color", &dirLight.DiffuseColor.Data) { if imgui.DragFloat3("Diffuse Color", &dirLight.DiffuseColor.Data) {
whiteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) whiteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
containerMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) containerMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
groundMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
palleteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor) palleteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
} }
if imgui.DragFloat3("Specular Color", &dirLight.SpecularColor.Data) { if imgui.DragFloat3("Specular Color", &dirLight.SpecularColor.Data) {
whiteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor) whiteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
containerMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor) containerMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
groundMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
palleteMat.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) { if imgui.DragFloat("Specular Shininess", &whiteMat.Shininess) {
whiteMat.SetUnifFloat32("material.shininess", whiteMat.Shininess) whiteMat.SetUnifFloat32("material.shininess", whiteMat.Shininess)
containerMat.SetUnifFloat32("material.shininess", whiteMat.Shininess) containerMat.SetUnifFloat32("material.shininess", whiteMat.Shininess)
groundMat.SetUnifFloat32("material.shininess", whiteMat.Shininess)
palleteMat.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) { if imgui.DragFloat3("Pos", &pl.Pos.Data) {
whiteMat.SetUnifVec3(indexString+".pos", &pl.Pos) whiteMat.SetUnifVec3(indexString+".pos", &pl.Pos)
containerMat.SetUnifVec3(indexString+".pos", &pl.Pos) containerMat.SetUnifVec3(indexString+".pos", &pl.Pos)
groundMat.SetUnifVec3(indexString+".pos", &pl.Pos)
palleteMat.SetUnifVec3(indexString+".pos", &pl.Pos) palleteMat.SetUnifVec3(indexString+".pos", &pl.Pos)
} }
if imgui.DragFloat3("Diffuse Color", &pl.DiffuseColor.Data) { if imgui.DragFloat3("Diffuse Color", &pl.DiffuseColor.Data) {
whiteMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor) whiteMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor)
containerMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor) containerMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor)
groundMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor)
palleteMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor) palleteMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor)
} }
if imgui.DragFloat3("Specular Color", &pl.SpecularColor.Data) { if imgui.DragFloat3("Specular Color", &pl.SpecularColor.Data) {
whiteMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor) whiteMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor)
containerMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor) containerMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor)
groundMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor)
palleteMat.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) { if imgui.DragFloat3("Pos", &l.Pos.Data) {
whiteMat.SetUnifVec3(indexString+".pos", &l.Pos) whiteMat.SetUnifVec3(indexString+".pos", &l.Pos)
containerMat.SetUnifVec3(indexString+".pos", &l.Pos) containerMat.SetUnifVec3(indexString+".pos", &l.Pos)
groundMat.SetUnifVec3(indexString+".pos", &l.Pos)
palleteMat.SetUnifVec3(indexString+".pos", &l.Pos) palleteMat.SetUnifVec3(indexString+".pos", &l.Pos)
} }
if imgui.DragFloat3("Dir", &l.Dir.Data) { if imgui.DragFloat3("Dir", &l.Dir.Data) {
whiteMat.SetUnifVec3(indexString+".dir", &l.Dir) whiteMat.SetUnifVec3(indexString+".dir", &l.Dir)
containerMat.SetUnifVec3(indexString+".dir", &l.Dir) containerMat.SetUnifVec3(indexString+".dir", &l.Dir)
groundMat.SetUnifVec3(indexString+".dir", &l.Dir)
palleteMat.SetUnifVec3(indexString+".dir", &l.Dir) palleteMat.SetUnifVec3(indexString+".dir", &l.Dir)
} }
if imgui.DragFloat3("Diffuse Color", &l.DiffuseColor.Data) { if imgui.DragFloat3("Diffuse Color", &l.DiffuseColor.Data) {
whiteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) whiteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
containerMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) containerMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
groundMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
palleteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor) palleteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
} }
if imgui.DragFloat3("Specular Color", &l.SpecularColor.Data) { if imgui.DragFloat3("Specular Color", &l.SpecularColor.Data) {
whiteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) whiteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
containerMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) containerMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
groundMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
palleteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor) palleteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
} }
@ -855,6 +968,7 @@ func (g *Game) showDebugWindow() {
whiteMat.SetUnifFloat32(indexString+".innerCutoff", cos) whiteMat.SetUnifFloat32(indexString+".innerCutoff", cos)
containerMat.SetUnifFloat32(indexString+".innerCutoff", cos) containerMat.SetUnifFloat32(indexString+".innerCutoff", cos)
groundMat.SetUnifFloat32(indexString+".innerCutoff", cos)
palleteMat.SetUnifFloat32(indexString+".innerCutoff", cos) palleteMat.SetUnifFloat32(indexString+".innerCutoff", cos)
} }
@ -864,6 +978,7 @@ func (g *Game) showDebugWindow() {
whiteMat.SetUnifFloat32(indexString+".outerCutoff", cos) whiteMat.SetUnifFloat32(indexString+".outerCutoff", cos)
containerMat.SetUnifFloat32(indexString+".outerCutoff", cos) containerMat.SetUnifFloat32(indexString+".outerCutoff", cos)
groundMat.SetUnifFloat32(indexString+".outerCutoff", cos)
palleteMat.SetUnifFloat32(indexString+".outerCutoff", cos) palleteMat.SetUnifFloat32(indexString+".outerCutoff", cos)
} }
@ -944,10 +1059,12 @@ func (g *Game) updateCameraPos() {
// Left and right // Left and right
if input.KeyDown(sdl.K_d) { 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 update = true
} else if input.KeyDown(sdl.K_a) { } 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 update = true
} }
@ -958,27 +1075,28 @@ func (g *Game) updateCameraPos() {
} }
var ( var (
renderDirLightShadows = true renderDirLightShadows = false
renderPointLightShadows = true renderPointLightShadows = false
renderSpotLightShadows = true renderSpotLightShadows = true
rotatingCubeSpeedDeg1 float32 = 45 rotatingCubeSpeedDeg1 float32 = 45
rotatingCubeSpeedDeg2 float32 = 120 rotatingCubeSpeedDeg2 float32 = 120
rotatingCubeSpeedDeg3 float32 = 120 rotatingCubeSpeedDeg3 float32 = 120
rotatingCubeTrMat1 = *gglm.NewTrMatId().Translate(gglm.NewVec3(-4, -1, 4)) rotatingCubeTrMat1 = gglm.NewTrMatWithPos(-4, -1, 4)
rotatingCubeTrMat2 = *gglm.NewTrMatId().Translate(gglm.NewVec3(-1, 0.5, 4)) rotatingCubeTrMat2 = gglm.NewTrMatWithPos(-1, 0.5, 4)
rotatingCubeTrMat3 = *gglm.NewTrMatId().Translate(gglm.NewVec3(5, 0.5, 4)) rotatingCubeTrMat3 = gglm.NewTrMatWithPos(5, 0.5, 4)
) )
func (g *Game) Render() { func (g *Game) Render() {
whiteMat.SetUnifVec3("camPos", &cam.Pos) whiteMat.SetUnifVec3("camPos", &cam.Pos)
containerMat.SetUnifVec3("camPos", &cam.Pos) containerMat.SetUnifVec3("camPos", &cam.Pos)
groundMat.SetUnifVec3("camPos", &cam.Pos)
palleteMat.SetUnifVec3("camPos", &cam.Pos) palleteMat.SetUnifVec3("camPos", &cam.Pos)
rotatingCubeTrMat1.Rotate(rotatingCubeSpeedDeg1*gglm.Deg2Rad*timing.DT(), gglm.NewVec3(0, 1, 0)) rotatingCubeTrMat1.Rotate(rotatingCubeSpeedDeg1*gglm.Deg2Rad*timing.DT(), 0, 1, 0)
rotatingCubeTrMat2.Rotate(rotatingCubeSpeedDeg2*gglm.Deg2Rad*timing.DT(), gglm.NewVec3(1, 1, 0)) rotatingCubeTrMat2.Rotate(rotatingCubeSpeedDeg2*gglm.Deg2Rad*timing.DT(), 1, 1, 0)
rotatingCubeTrMat3.Rotate(rotatingCubeSpeedDeg3*gglm.Deg2Rad*timing.DT(), gglm.NewVec3(1, 1, 1)) rotatingCubeTrMat3.Rotate(rotatingCubeSpeedDeg3*gglm.Deg2Rad*timing.DT(), 1, 1, 1)
if renderDirLightShadows { if renderDirLightShadows {
g.renderDirectionalLightShadowmap() g.renderDirectionalLightShadowmap()
@ -1017,6 +1135,7 @@ func (g *Game) renderDirectionalLightShadowmap() {
whiteMat.SetUnifMat4("dirLightProjViewMat", &dirLightProjViewMat) whiteMat.SetUnifMat4("dirLightProjViewMat", &dirLightProjViewMat)
containerMat.SetUnifMat4("dirLightProjViewMat", &dirLightProjViewMat) containerMat.SetUnifMat4("dirLightProjViewMat", &dirLightProjViewMat)
groundMat.SetUnifMat4("dirLightProjViewMat", &dirLightProjViewMat)
palleteMat.SetUnifMat4("dirLightProjViewMat", &dirLightProjViewMat) palleteMat.SetUnifMat4("dirLightProjViewMat", &dirLightProjViewMat)
depthMapMat.SetUnifMat4("projViewMat", &dirLightProjViewMat) depthMapMat.SetUnifMat4("projViewMat", &dirLightProjViewMat)
@ -1038,8 +1157,8 @@ func (g *Game) renderDirectionalLightShadowmap() {
if showDirLightDepthMapFbo { if showDirLightDepthMapFbo {
screenQuadMat.DiffuseTex = dirLightDepthMapFbo.Attachments[0].Id screenQuadMat.DiffuseTex = dirLightDepthMapFbo.Attachments[0].Id
screenQuadMat.SetUnifVec2("offset", dirLightDepthMapFboOffset) screenQuadMat.SetUnifVec2("offset", &dirLightDepthMapFboOffset)
screenQuadMat.SetUnifVec2("scale", dirLightDepthMapFboScale) screenQuadMat.SetUnifVec2("scale", &dirLightDepthMapFboScale)
screenQuadMat.Bind() screenQuadMat.Bind()
window.Rend.DrawVertexArray(&screenQuadMat, &screenQuadVao, 0, 6) window.Rend.DrawVertexArray(&screenQuadMat, &screenQuadVao, 0, 6)
} }
@ -1058,6 +1177,7 @@ func (g *Game) renderSpotLightShadowmaps() {
whiteMat.SetUnifMat4(projViewMatIndexStr, &projViewMat) whiteMat.SetUnifMat4(projViewMatIndexStr, &projViewMat)
containerMat.SetUnifMat4(projViewMatIndexStr, &projViewMat) containerMat.SetUnifMat4(projViewMatIndexStr, &projViewMat)
groundMat.SetUnifMat4(projViewMatIndexStr, &projViewMat)
palleteMat.SetUnifMat4(projViewMatIndexStr, &projViewMat) palleteMat.SetUnifMat4(projViewMatIndexStr, &projViewMat)
// Set depth uniforms // Set depth uniforms
@ -1120,8 +1240,8 @@ func (g *Game) renderDemoFob() {
demoFbo.UnBind() demoFbo.UnBind()
screenQuadMat.DiffuseTex = demoFbo.Attachments[0].Id screenQuadMat.DiffuseTex = demoFbo.Attachments[0].Id
screenQuadMat.SetUnifVec2("offset", demoFboOffset) screenQuadMat.SetUnifVec2("offset", &demoFboOffset)
screenQuadMat.SetUnifVec2("scale", demoFboScale) screenQuadMat.SetUnifVec2("scale", &demoFboScale)
window.Rend.DrawVertexArray(&screenQuadMat, &screenQuadVao, 0, 6) window.Rend.DrawVertexArray(&screenQuadMat, &screenQuadVao, 0, 6)
} }
@ -1134,34 +1254,39 @@ func (g *Game) RenderScene(overrideMat *materials.Material) {
sunMat := &palleteMat sunMat := &palleteMat
chairMat := &palleteMat chairMat := &palleteMat
cubeMat := &containerMat cubeMat := &containerMat
groundMat := &groundMat
if overrideMat != nil { if overrideMat != nil {
sunMat = overrideMat sunMat = overrideMat
chairMat = overrideMat chairMat = overrideMat
cubeMat = overrideMat cubeMat = overrideMat
groundMat = overrideMat
} }
// Draw dir light // 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 // Draw point lights
for i := 0; i < len(pointLights); i++ { for i := 0; i < len(pointLights); i++ {
pl := &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 // Chair
window.Rend.DrawMesh(&chairMesh, tempModelMatrix, chairMat) window.Rend.DrawMesh(&chairMesh, tempModelMatrix, chairMat)
// Ground // 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 // Cubes
tempModelMatrix.Translate(gglm.NewVec3(-6, 0, 0)) tempModelMatrix.Translate(-6, 0, 0)
window.Rend.DrawMesh(&cubeMesh, tempModelMatrix, cubeMat) window.Rend.DrawMesh(&cubeMesh, tempModelMatrix, cubeMat)
tempModelMatrix.Translate(gglm.NewVec3(0, -1, -4)) tempModelMatrix.Translate(0, -1, -4)
window.Rend.DrawMesh(&cubeMesh, tempModelMatrix, cubeMat) window.Rend.DrawMesh(&cubeMesh, tempModelMatrix, cubeMat)
// Rotating cubes // Rotating cubes
@ -1205,6 +1330,7 @@ func updateAllProjViewMats(projMat, viewMat gglm.Mat4) {
unlitMat.SetUnifMat4("projViewMat", projViewMat) unlitMat.SetUnifMat4("projViewMat", projViewMat)
whiteMat.SetUnifMat4("projViewMat", projViewMat) whiteMat.SetUnifMat4("projViewMat", projViewMat)
containerMat.SetUnifMat4("projViewMat", projViewMat) containerMat.SetUnifMat4("projViewMat", projViewMat)
groundMat.SetUnifMat4("projViewMat", projViewMat)
palleteMat.SetUnifMat4("projViewMat", projViewMat) palleteMat.SetUnifMat4("projViewMat", projViewMat)
debugDepthMat.SetUnifMat4("projViewMat", projViewMat) debugDepthMat.SetUnifMat4("projViewMat", projViewMat)

View File

@ -3,6 +3,7 @@ package materials
import ( import (
"github.com/bloeys/gglm/gglm" "github.com/bloeys/gglm/gglm"
"github.com/bloeys/nmage/assert" "github.com/bloeys/nmage/assert"
"github.com/bloeys/nmage/assets"
"github.com/bloeys/nmage/logging" "github.com/bloeys/nmage/logging"
"github.com/bloeys/nmage/shaders" "github.com/bloeys/nmage/shaders"
"github.com/go-gl/gl/v4.1-core/gl" "github.com/go-gl/gl/v4.1-core/gl"
@ -21,14 +22,35 @@ const (
TextureSlot_ShadowMap_Array1 TextureSlot = 13 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 { type Material struct {
Name string Name string
ShaderProg shaders.ShaderProgram ShaderProg shaders.ShaderProgram
Settings MaterialSettings
UnifLocs map[string]int32 UnifLocs map[string]int32
AttribLocs 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 // Phong shading
DiffuseTex uint32 DiffuseTex uint32
SpecularTex uint32 SpecularTex uint32
@ -51,26 +73,19 @@ func (m *Material) Bind() {
m.ShaderProg.Bind() m.ShaderProg.Bind()
if m.DiffuseTex != 0 { gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Diffuse))
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Diffuse)) gl.BindTexture(gl.TEXTURE_2D, m.DiffuseTex)
gl.BindTexture(gl.TEXTURE_2D, m.DiffuseTex)
}
if m.SpecularTex != 0 { gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Specular))
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Specular)) gl.BindTexture(gl.TEXTURE_2D, m.SpecularTex)
gl.BindTexture(gl.TEXTURE_2D, m.SpecularTex)
}
if m.NormalTex != 0 { gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Normal))
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Normal)) gl.BindTexture(gl.TEXTURE_2D, m.NormalTex)
gl.BindTexture(gl.TEXTURE_2D, m.NormalTex)
}
if m.EmissionTex != 0 { gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Emission))
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Emission)) gl.BindTexture(gl.TEXTURE_2D, m.EmissionTex)
gl.BindTexture(gl.TEXTURE_2D, m.EmissionTex)
}
// @TODO: Have defaults for these
if m.CubemapTex != 0 { if m.CubemapTex != 0 {
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Cubemap)) gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Cubemap))
gl.BindTexture(gl.TEXTURE_CUBE_MAP, m.CubemapTex) 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()) 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 { 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()) 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 { 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 Vao buffers.VertexArray
SubMeshes []SubMesh 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) { 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 { if err != nil {
return Mesh{}, errors.New("Failed to load model. Err: " + err.Error()) 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() vbo := buffers.NewVertexBuffer()
ibo := buffers.NewIndexBuffer() ibo := buffers.NewIndexBuffer()
// Initial sizes assuming one submesh that has vertex pos+normals+texCoords, and 3 indices per face // Estimate a useful prealloc capacity based on the first submesh that has vertex pos+normals+tangents+texCoords
var vertexBufData []float32 = make([]float32, 0, len(scene.Meshes[0].Vertices)*3*3*2) 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) 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)) // 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] 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 { if len(sceneMesh.TexCoords[0]) == 0 {
sceneMesh.TexCoords[0] = make([]gglm.Vec3, len(sceneMesh.Vertices)) sceneMesh.TexCoords[0] = make([]gglm.Vec3, len(sceneMesh.Vertices))
} }
layoutToUse := []buffers.Element{{ElementType: buffers.DataTypeVec3}, {ElementType: buffers.DataTypeVec3}, {ElementType: buffers.DataTypeVec2}} hasColorSet0 := len(sceneMesh.ColorSets) > 0 && len(sceneMesh.ColorSets[0]) > 0
if 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}) 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])}} arrs := []arrToInterleave{
if len(sceneMesh.ColorSets) > 0 && len(sceneMesh.ColorSets[0]) > 0 { {V3s: sceneMesh.Vertices},
{V3s: sceneMesh.Normals},
{V3s: sceneMesh.Tangents},
{V2s: v3sToV2s(sceneMesh.TexCoords[0])},
}
if hasColorSet0 {
arrs = append(arrs, arrToInterleave{V4s: sceneMesh.ColorSets[0]}) 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 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++ { 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) 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 #version 410
layout(location=0) in vec3 vertPosIn; layout(location=0) in vec3 vertPosIn;
layout(location=1) in vec3 vertNormalIn; layout(location=2) in vec3 vertTangentIn;
layout(location=2) in vec2 vertUV0In; layout(location=3) in vec2 vertUV0In;
layout(location=3) in vec3 vertColorIn; layout(location=4) in vec3 vertColorIn;
out vec3 vertNormal;
out vec2 vertUV0; out vec2 vertUV0;
out vec3 vertColor; out vec3 vertColor;
out vec3 fragPos; out vec3 fragPos;
//MVP = Model View Projection
uniform mat4 modelMat; uniform mat4 modelMat;
uniform mat4 projViewMat; uniform mat4 projViewMat;
void main() void main()
{ {
vertNormal = mat3(transpose(inverse(modelMat))) * vertNormalIn;
vertUV0 = vertUV0In; vertUV0 = vertUV0In;
vertColor = vertColorIn; vertColor = vertColorIn;
@ -31,7 +28,6 @@ void main()
#version 410 #version 410
in vec3 vertColor; in vec3 vertColor;
in vec3 vertNormal;
in vec2 vertUV0; in vec2 vertUV0;
in vec3 fragPos; in vec3 fragPos;

View File

@ -3,26 +3,19 @@
layout(location=0) in vec3 vertPosIn; layout(location=0) in vec3 vertPosIn;
layout(location=1) in vec3 vertNormalIn; layout(location=1) in vec3 vertNormalIn;
layout(location=2) in vec2 vertUV0In; layout(location=2) in vec3 vertTangentIn;
layout(location=3) in vec3 vertColorIn; layout(location=3) in vec2 vertUV0In;
layout(location=4) in vec3 vertColorIn;
out vec3 vertNormal;
out vec2 vertUV0; out vec2 vertUV0;
out vec3 vertColor; out vec3 vertColor;
out vec3 fragPos; out vec3 fragPos;
//MVP = Model View Projection
uniform mat4 modelMat; uniform mat4 modelMat;
uniform mat4 projViewMat; uniform mat4 projViewMat;
void main() 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; vertUV0 = vertUV0In;
vertColor = vertColorIn; vertColor = vertColorIn;
@ -41,7 +34,6 @@ struct Material {
uniform Material material; uniform Material material;
in vec3 vertColor; in vec3 vertColor;
in vec3 vertNormal;
in vec2 vertUV0; in vec2 vertUV0;
in vec3 fragPos; in vec3 fragPos;

View File

@ -1,66 +1,34 @@
//shader:vertex //shader:vertex
#version 410 #version 410
#define NUM_SPOT_LIGHTS 4
#define NUM_POINT_LIGHTS 8
//
// Inputs
//
layout(location=0) in vec3 vertPosIn; layout(location=0) in vec3 vertPosIn;
layout(location=1) in vec3 vertNormalIn; layout(location=1) in vec3 vertNormalIn;
layout(location=2) in vec2 vertUV0In; layout(location=2) in vec3 vertTangentIn;
layout(location=3) in vec3 vertColorIn; layout(location=3) in vec2 vertUV0In;
layout(location=4) in vec3 vertColorIn;
//
// Uniforms
//
uniform vec3 camPos;
uniform mat4 modelMat; uniform mat4 modelMat;
uniform mat3 normalMat;
uniform mat4 projViewMat; uniform mat4 projViewMat;
uniform mat4 dirLightProjViewMat; uniform mat4 dirLightProjViewMat;
#define NUM_SPOT_LIGHTS 4
uniform mat4 spotLightProjViewMats[NUM_SPOT_LIGHTS]; 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 { struct DirLight {
vec3 dir; vec3 dir;
vec3 diffuseColor; vec3 diffuseColor;
vec3 specularColor; vec3 specularColor;
sampler2D shadowMap; sampler2D shadowMap;
}; };
uniform DirLight dirLight; uniform DirLight dirLight;
struct PointLight { struct PointLight {
@ -72,8 +40,133 @@ struct PointLight {
float quadratic; float quadratic;
float farPlane; 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 #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 PointLight pointLights[NUM_POINT_LIGHTS];
uniform samplerCubeArray pointLightCubeShadowMaps; uniform samplerCubeArray pointLightCubeShadowMaps;
@ -85,37 +178,29 @@ struct SpotLight {
float innerCutoff; float innerCutoff;
float outerCutoff; float outerCutoff;
}; };
#define NUM_SPOT_LIGHTS 4
uniform SpotLight spotLights[NUM_SPOT_LIGHTS]; uniform SpotLight spotLights[NUM_SPOT_LIGHTS];
uniform sampler2DArray spotLightShadowMaps; uniform sampler2DArray spotLightShadowMaps;
uniform vec3 camPos;
uniform vec3 ambientColor = vec3(0.2, 0.2, 0.2); uniform vec3 ambientColor = vec3(0.2, 0.2, 0.2);
in vec3 vertColor; //
in vec3 vertNormal; // Outputs
in vec2 vertUV0; //
in vec3 fragPos;
in vec4 fragPosDirLight;
in vec4 fragPosSpotLight[NUM_SPOT_LIGHTS];
out vec4 fragColor; out vec4 fragColor;
//
// Global variables used as cache for lighting calculations // Global variables used as cache for lighting calculations
//
vec3 tangentViewDir;
vec4 diffuseTexColor; vec4 diffuseTexColor;
vec4 specularTexColor; vec4 specularTexColor;
vec4 emissionTexColor; vec4 emissionTexColor;
vec3 normalizedVertNorm; 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] // 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 sampling outside the depth texture then force 'no shadow'
if(projCoords.z > 1) 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 // 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 // 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'. // 'Percentage Close Filtering'.
// Basically get soft shadows by averaging this texel and surrounding ones // Basically get soft shadows by averaging this texel and surrounding ones
@ -151,14 +236,14 @@ float CalcDirShadow(sampler2D shadowMap, vec3 lightDir)
vec3 CalcDirLight() vec3 CalcDirLight()
{ {
vec3 lightDir = normalize(-dirLight.dir); vec3 lightDir = normalize(-tangentDirLightDir);
// Diffuse // Diffuse
float diffuseAmount = max(0.0, dot(normalizedVertNorm, lightDir)); float diffuseAmount = max(0.0, dot(normalizedVertNorm, lightDir));
vec3 finalDiffuse = diffuseAmount * dirLight.diffuseColor * diffuseTexColor.rgb; vec3 finalDiffuse = diffuseAmount * dirLight.diffuseColor * diffuseTexColor.rgb;
// Specular // Specular
vec3 halfwayDir = normalize(lightDir + viewDir); vec3 halfwayDir = normalize(lightDir + tangentViewDir);
float specularAmount = pow(max(dot(normalizedVertNorm, halfwayDir), 0.0), material.shininess); float specularAmount = pow(max(dot(normalizedVertNorm, halfwayDir), 0.0), material.shininess);
vec3 finalSpecular = specularAmount * dirLight.specularColor * specularTexColor.rgb; vec3 finalSpecular = specularAmount * dirLight.specularColor * specularTexColor.rgb;
@ -168,9 +253,9 @@ vec3 CalcDirLight()
return (finalDiffuse + finalSpecular) * (1 - shadow); 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; 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 // Get depth of current fragment
float currentDepth = length(lightToFrag); 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; float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
return shadow; return shadow;
@ -193,28 +279,29 @@ vec3 CalcPointLight(PointLight pointLight, int lightIndex)
return vec3(0); return vec3(0);
} }
vec3 lightDir = normalize(pointLight.pos - fragPos); vec3 tangentLightPos = tangentPointLightPositions[lightIndex];
vec3 tangentLightDir = normalize(tangentLightPos - tangentFragPos);
// Diffuse // Diffuse
float diffuseAmount = max(0.0, dot(normalizedVertNorm, lightDir)); float diffuseAmount = max(0.0, dot(normalizedVertNorm, tangentLightDir));
vec3 finalDiffuse = diffuseAmount * pointLight.diffuseColor * diffuseTexColor.rgb; vec3 finalDiffuse = diffuseAmount * pointLight.diffuseColor * diffuseTexColor.rgb;
// Specular // Specular
vec3 halfwayDir = normalize(lightDir + viewDir); vec3 halfwayDir = normalize(tangentLightDir + tangentViewDir);
float specularAmount = pow(max(dot(normalizedVertNorm, halfwayDir), 0.0), material.shininess); float specularAmount = pow(max(dot(normalizedVertNorm, halfwayDir), 0.0), material.shininess);
vec3 finalSpecular = specularAmount * pointLight.specularColor * specularTexColor.rgb; vec3 finalSpecular = specularAmount * pointLight.specularColor * specularTexColor.rgb;
// Attenuation // Attenuation
float distToLight = length(pointLight.pos - fragPos); float distToLight = length(tangentLightPos - tangentFragPos);
float attenuation = 1 / (pointLight.constant + pointLight.linear * distToLight + pointLight.quadratic * (distToLight * distToLight)); float attenuation = 1 / (pointLight.constant + pointLight.linear * distToLight + pointLight.quadratic * (distToLight * distToLight));
// Shadow // 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); return (finalDiffuse + finalSpecular) * attenuation * (1 - shadow);
} }
float CalcSpotShadow(vec3 lightDir, int lightIndex) float CalcSpotShadow(vec3 tangentLightDir, int lightIndex)
{ {
// Move from clip space to NDC // Move from clip space to NDC
vec3 projCoords = fragPosSpotLight[lightIndex].xyz / fragPosSpotLight[lightIndex].w; 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 // 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 // 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'. // 'Percentage Close Filtering'.
// Basically get soft shadows by averaging this texel and surrounding ones // 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) if (light.innerCutoff == 0)
return vec3(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, // Spot light cone with full intensity within inner cutoff,
// and falloff between inner-outer cutoffs, and zero // and falloff between inner-outer cutoffs, and zero
// light after outer cutoff // light after outer cutoff
float theta = dot(fragToLightDir, normalize(-light.dir)); float theta = dot(fragToLightDir, normalize(-tangentLightDir));
float epsilon = (light.innerCutoff - light.outerCutoff); float epsilon = (light.innerCutoff - light.outerCutoff);
float intensity = clamp((theta - light.outerCutoff) / epsilon, float(0), float(1)); 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; vec3 finalDiffuse = diffuseAmount * light.diffuseColor * diffuseTexColor.rgb;
// Specular // Specular
vec3 halfwayDir = normalize(fragToLightDir + viewDir); vec3 halfwayDir = normalize(fragToLightDir + tangentViewDir);
float specularAmount = pow(max(dot(normalizedVertNorm, halfwayDir), 0.0), material.shininess); float specularAmount = pow(max(dot(normalizedVertNorm, halfwayDir), 0.0), material.shininess);
vec3 finalSpecular = specularAmount * light.specularColor * specularTexColor.rgb; vec3 finalSpecular = specularAmount * light.specularColor * specularTexColor.rgb;
@ -286,15 +374,21 @@ vec3 CalcSpotLight(SpotLight light, int lightIndex)
return (finalDiffuse + finalSpecular) * intensity * (1 - shadow); return (finalDiffuse + finalSpecular) * intensity * (1 - shadow);
} }
#define DRAW_NORMALS false
void main() void main()
{ {
// Shared values // Shared values
tangentViewDir = normalize(tangentCamPos - tangentFragPos);
diffuseTexColor = texture(material.diffuse, vertUV0); diffuseTexColor = texture(material.diffuse, vertUV0);
specularTexColor = texture(material.specular, vertUV0); specularTexColor = texture(material.specular, vertUV0);
emissionTexColor = texture(material.emission, vertUV0); emissionTexColor = texture(material.emission, vertUV0);
normalizedVertNorm = normalize(vertNormal); // Read normal data encoded [0,1]
viewDir = normalize(camPos - fragPos); normalizedVertNorm = texture(material.normal, vertUV0).rgb;
// Remap normal to [-1,1]
normalizedVertNorm = normalize(normalizedVertNorm * 2.0 - 1.0);
// Light contributions // Light contributions
vec3 finalColor = CalcDirLight(); vec3 finalColor = CalcDirLight();
@ -313,4 +407,9 @@ void main()
vec3 finalAmbient = ambientColor * diffuseTexColor.rgb; vec3 finalAmbient = ambientColor * diffuseTexColor.rgb;
fragColor = vec4(finalColor + finalAmbient + finalEmission, 1); 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=0) in vec3 vertPosIn;
layout(location=1) in vec3 vertNormalIn; layout(location=1) in vec3 vertNormalIn;
layout(location=2) in vec2 vertUV0In; layout(location=2) in vec3 vertTangentIn;
layout(location=3) in vec3 vertColorIn; layout(location=3) in vec2 vertUV0In;
layout(location=4) in vec3 vertColorIn;
out vec3 vertUV0; 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