Compare commits

...

7 Commits

Author SHA1 Message Date
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
d523c0951b Get rid of unneeded pointers+update todos 2024-05-01 01:16:33 +04:00
abd7079e61 Correct modifier keys input to imgui 2024-04-24 19:56:35 +04:00
13 changed files with 257 additions and 173 deletions

5
.gitignore vendored
View File

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

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
}
@ -59,9 +59,9 @@ func (c *Camera) UpdateRotation(pitch, yaw float32) {
c.Update()
}
func NewPerspective(pos, forward, worldUp *gglm.Vec3, nearClip, farClip, fovRadians, aspectRatio float32) *Camera {
func NewPerspective(pos, forward, worldUp *gglm.Vec3, nearClip, farClip, fovRadians, aspectRatio float32) Camera {
cam := &Camera{
cam := Camera{
Type: Type_Perspective,
Pos: *pos,
Forward: *forward,
@ -78,9 +78,9 @@ func NewPerspective(pos, forward, worldUp *gglm.Vec3, nearClip, farClip, fovRadi
return cam
}
func NewOrthographic(pos, forward, worldUp *gglm.Vec3, nearClip, farClip, left, right, top, bottom float32) *Camera {
func NewOrthographic(pos, forward, worldUp *gglm.Vec3, nearClip, farClip, left, right, top, bottom float32) Camera {
cam := &Camera{
cam := Camera{
Type: Type_Orthographic,
Pos: *pos,
Forward: *forward,

View File

@ -58,25 +58,15 @@ func (w *Window) handleInputs() {
case *sdl.KeyboardEvent:
input.HandleKeyboardEvent(e)
// Send modifier key updates to imgui (based on the imgui SDL backend)
imIo.AddKeyEvent(imgui.ModCtrl, e.Keysym.Mod&sdl.KMOD_CTRL != 0)
imIo.AddKeyEvent(imgui.ModShift, e.Keysym.Mod&sdl.KMOD_SHIFT != 0)
imIo.AddKeyEvent(imgui.ModAlt, e.Keysym.Mod&sdl.KMOD_ALT != 0)
imIo.AddKeyEvent(imgui.ModSuper, e.Keysym.Mod&sdl.KMOD_GUI != 0)
imIo.AddKeyEvent(nmageimgui.SdlScancodeToImGuiKey(e.Keysym.Scancode), e.Type == sdl.KEYDOWN)
// Send modifier key updates to imgui
if e.Keysym.Sym == sdl.K_LCTRL || e.Keysym.Sym == sdl.K_RCTRL {
imIo.SetKeyCtrl(e.Type == sdl.KEYDOWN)
}
if e.Keysym.Sym == sdl.K_LSHIFT || e.Keysym.Sym == sdl.K_RSHIFT {
imIo.SetKeyShift(e.Type == sdl.KEYDOWN)
}
if e.Keysym.Sym == sdl.K_LALT || e.Keysym.Sym == sdl.K_RALT {
imIo.SetKeyAlt(e.Type == sdl.KEYDOWN)
}
if e.Keysym.Sym == sdl.K_LGUI || e.Keysym.Sym == sdl.K_RGUI {
imIo.SetKeySuper(e.Type == sdl.KEYDOWN)
}
case *sdl.TextInputEvent:
imIo.AddInputCharactersUTF8(e.GetText())
@ -177,42 +167,44 @@ func initSDL() error {
return nil
}
func CreateOpenGLWindow(title string, x, y, width, height int32, flags WindowFlags, rend renderer.Render) (*Window, error) {
func CreateOpenGLWindow(title string, x, y, width, height int32, flags WindowFlags, rend renderer.Render) (Window, error) {
return createWindow(title, x, y, width, height, WindowFlags_OPENGL|flags, rend)
}
func CreateOpenGLWindowCentered(title string, width, height int32, flags WindowFlags, rend renderer.Render) (*Window, error) {
func CreateOpenGLWindowCentered(title string, width, height int32, flags WindowFlags, rend renderer.Render) (Window, error) {
return createWindow(title, sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED, width, height, WindowFlags_OPENGL|flags, rend)
}
func createWindow(title string, x, y, width, height int32, flags WindowFlags, rend renderer.Render) (*Window, error) {
func createWindow(title string, x, y, width, height int32, flags WindowFlags, rend renderer.Render) (Window, error) {
assert.T(isInited, "engine.Init() was not called!")
sdlWin, err := sdl.CreateWindow(title, x, y, width, height, uint32(flags))
if err != nil {
return nil, err
}
win := &Window{
SDLWin: sdlWin,
win := Window{
SDLWin: nil,
EventCallbacks: make([]func(sdl.Event), 0),
Rend: rend,
}
win.GlCtx, err = sdlWin.GLCreateContext()
var err error
win.SDLWin, err = sdl.CreateWindow(title, x, y, width, height, uint32(flags))
if err != nil {
return nil, err
return win, err
}
win.GlCtx, err = win.SDLWin.GLCreateContext()
if err != nil {
return win, err
}
err = initOpenGL()
if err != nil {
return nil, err
return win, err
}
// 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)
sdlWin.GLSwap()
win.SDLWin.GLSwap()
return win, err
}

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=

284
main.go
View File

@ -2,7 +2,9 @@ package main
import (
"fmt"
"os"
"runtime"
"runtime/pprof"
"strconv"
imgui "github.com/AllenDang/cimgui-go"
@ -33,19 +35,19 @@ import (
- Directional light shadows ✅
- Point light shadows ✅
- Spotlight shadows ✅
- Create VAO struct independent from VBO to support multi-VBO use cases (e.g. instancing) ✅
- UBO support
- HDR
- Cascaded shadow mapping
- Skeletal animations
- In some cases we DO want input even when captured by UI. We need two systems within input package, one filtered and one not
- In some cases we DO want input even when captured by UI. We need two systems within input package, one filtered and one not
- Proper model loading (i.e. load model by reading all its meshes, textures, and so on together)
- Create VAO struct independent from VBO to support multi-VBO use cases (e.g. instancing) ✅
- Renderer batching
- Scene graph
- Separate engine loop from rendering loop? or leave it to the user?
- Abstract keys enum away from sdl
- Proper Asset loading
- Abstract keys enum away from sdl?
- Frustum culling
- Proper Asset loading system
- Material system editor with fields automatically extracted from the shader
*/
@ -71,8 +73,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 +112,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 +167,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,14 +190,16 @@ const (
unscaledWindowWidth = 1280
unscaledWindowHeight = 720
PROFILE_CPU = true
)
var (
window *engine.Window
window engine.Window
pitch float32 = 0
yaw float32 = -1.5
cam *camera.Camera
cam camera.Camera
// Demo fbo
renderToDemoFbo = false
@ -195,22 +221,22 @@ var (
spotLightDepthMapFbo buffers.Framebuffer
screenQuadVao buffers.VertexArray
screenQuadMat *materials.Material
screenQuadMat materials.Material
unlitMat *materials.Material
whiteMat *materials.Material
containerMat *materials.Material
palleteMat *materials.Material
skyboxMat *materials.Material
depthMapMat *materials.Material
arrayDepthMapMat *materials.Material
omnidirDepthMapMat *materials.Material
debugDepthMat *materials.Material
unlitMat materials.Material
whiteMat materials.Material
containerMat materials.Material
palleteMat materials.Material
skyboxMat materials.Material
depthMapMat materials.Material
arrayDepthMapMat materials.Material
omnidirDepthMapMat materials.Material
debugDepthMat materials.Material
cubeMesh *meshes.Mesh
sphereMesh *meshes.Mesh
chairMesh *meshes.Mesh
skyboxMesh *meshes.Mesh
cubeMesh meshes.Mesh
sphereMesh meshes.Mesh
chairMesh meshes.Mesh
skyboxMesh meshes.Mesh
cubeModelMat = gglm.NewTrMatId()
@ -224,17 +250,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,39 +270,41 @@ 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,
@ -314,14 +343,43 @@ func main() {
engine.SetSrgbFramebuffer(true)
game := &Game{
Win: window,
Win: &window,
WinWidth: int32(unscaledWindowWidth * dpiScaling),
WinHeight: int32(unscaledWindowHeight * dpiScaling),
ImGUIInfo: nmageimgui.NewImGui("./res/shaders/imgui.glsl"),
}
window.EventCallbacks = append(window.EventCallbacks, game.handleWindowEvents)
engine.Run(game, window, game.ImGUIInfo)
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 +438,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),
@ -450,14 +512,16 @@ 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_HasModelMat)
unlitMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse))
whiteMat = materials.NewMaterial("White mat", "./res/shaders/simple.glsl")
whiteMat.Settings.Set(materials.MaterialSettings_HasModelMat | materials.MaterialSettings_HasNormalMat)
whiteMat.Shininess = 64
whiteMat.DiffuseTex = whiteTex.TexID
whiteMat.SpecularTex = blackTex.TexID
@ -467,7 +531,7 @@ func (g *Game) Init() {
whiteMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular))
// 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,6 +541,7 @@ func (g *Game) Init() {
whiteMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1))
containerMat = materials.NewMaterial("Container mat", "./res/shaders/simple.glsl")
containerMat.Settings.Set(materials.MaterialSettings_HasModelMat | materials.MaterialSettings_HasNormalMat)
containerMat.Shininess = 64
containerMat.DiffuseTex = containerDiffuseTex.TexID
containerMat.SpecularTex = containerSpecularTex.TexID
@ -486,7 +551,7 @@ func (g *Game) Init() {
containerMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular))
// 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)
@ -496,6 +561,7 @@ func (g *Game) Init() {
containerMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1))
palleteMat = materials.NewMaterial("Pallete mat", "./res/shaders/simple.glsl")
palleteMat.Settings.Set(materials.MaterialSettings_HasModelMat | materials.MaterialSettings_HasNormalMat)
palleteMat.Shininess = 64
palleteMat.DiffuseTex = palleteTex.TexID
palleteMat.SpecularTex = blackTex.TexID
@ -505,7 +571,7 @@ func (g *Game) Init() {
palleteMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular))
// 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.diffuseColor", &dirLight.DiffuseColor)
palleteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
@ -514,22 +580,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_HasModelMat)
depthMapMat = materials.NewMaterial("Depth Map mat", "./res/shaders/depth-map.glsl")
depthMapMat.Settings.Set(materials.MaterialSettings_HasModelMat)
arrayDepthMapMat = materials.NewMaterial("Array Depth Map mat", "./res/shaders/array-depth-map.glsl")
arrayDepthMapMat.Settings.Set(materials.MaterialSettings_HasModelMat)
omnidirDepthMapMat = materials.NewMaterial("Omnidirectional Depth Map mat", "./res/shaders/omnidirectional-depth-map.glsl")
omnidirDepthMapMat.Settings.Set(materials.MaterialSettings_HasModelMat)
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 +639,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 +649,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 +659,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,
@ -722,9 +795,9 @@ 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)
palleteMat.SetUnifVec3("ambientColor", &ambientColor)
}
imgui.Spacing()
@ -944,10 +1017,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
}
@ -965,9 +1040,9 @@ var (
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() {
@ -976,9 +1051,9 @@ func (g *Game) Render() {
containerMat.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()
@ -995,7 +1070,7 @@ func (g *Game) Render() {
if renderToBackBuffer {
if renderDepthBuffer {
g.RenderScene(debugDepthMat)
g.RenderScene(&debugDepthMat)
} else {
g.RenderScene(nil)
}
@ -1031,17 +1106,17 @@ func (g *Game) renderDirectionalLightShadowmap() {
//
// Some note that this is too troublesome and fails in many cases. Might be better to remove.
gl.CullFace(gl.FRONT)
g.RenderScene(depthMapMat)
g.RenderScene(&depthMapMat)
gl.CullFace(gl.BACK)
dirLightDepthMapFbo.UnBindWithViewport(uint32(g.WinWidth), uint32(g.WinHeight))
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)
window.Rend.DrawVertexArray(&screenQuadMat, &screenQuadVao, 0, 6)
}
}
@ -1070,7 +1145,7 @@ func (g *Game) renderSpotLightShadowmaps() {
// Front culling created issues
// gl.CullFace(gl.FRONT)
g.RenderScene(arrayDepthMapMat)
g.RenderScene(&arrayDepthMapMat)
// gl.CullFace(gl.BACK)
spotLightDepthMapFbo.UnBindWithViewport(uint32(g.WinWidth), uint32(g.WinHeight))
@ -1096,7 +1171,7 @@ func (g *Game) renderPointLightShadowmaps() {
omnidirDepthMapMat.SetUnifMat4("cubemapProjViewMats["+strconv.Itoa(j)+"]", &projViewMats[j])
}
g.RenderScene(omnidirDepthMapMat)
g.RenderScene(&omnidirDepthMapMat)
}
pointLightDepthMapFbo.UnBindWithViewport(uint32(g.WinWidth), uint32(g.WinHeight))
@ -1108,7 +1183,7 @@ func (g *Game) renderDemoFob() {
demoFbo.Clear()
if renderDepthBuffer {
g.RenderScene(debugDepthMat)
g.RenderScene(&debugDepthMat)
} else {
g.RenderScene(nil)
}
@ -1120,10 +1195,10 @@ 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)
window.Rend.DrawVertexArray(&screenQuadMat, &screenQuadVao, 0, 6)
}
func (g *Game) RenderScene(overrideMat *materials.Material) {
@ -1131,9 +1206,9 @@ func (g *Game) RenderScene(overrideMat *materials.Material) {
tempModelMatrix := cubeModelMat.Clone()
// See if we need overrides
sunMat := palleteMat
chairMat := palleteMat
cubeMat := containerMat
sunMat := &palleteMat
chairMat := &palleteMat
cubeMat := &containerMat
if overrideMat != nil {
sunMat = overrideMat
@ -1142,32 +1217,35 @@ func (g *Game) RenderScene(overrideMat *materials.Material) {
}
// 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)
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), cubeMat)
// Cubes
tempModelMatrix.Translate(gglm.NewVec3(-6, 0, 0))
window.Rend.DrawMesh(cubeMesh, tempModelMatrix, cubeMat)
tempModelMatrix.Translate(-6, 0, 0)
window.Rend.DrawMesh(&cubeMesh, tempModelMatrix, cubeMat)
tempModelMatrix.Translate(gglm.NewVec3(0, -1, -4))
window.Rend.DrawMesh(cubeMesh, tempModelMatrix, cubeMat)
tempModelMatrix.Translate(0, -1, -4)
window.Rend.DrawMesh(&cubeMesh, tempModelMatrix, cubeMat)
// Rotating cubes
window.Rend.DrawMesh(cubeMesh, &rotatingCubeTrMat1, cubeMat)
window.Rend.DrawMesh(cubeMesh, &rotatingCubeTrMat2, cubeMat)
window.Rend.DrawMesh(cubeMesh, &rotatingCubeTrMat3, cubeMat)
window.Rend.DrawMesh(&cubeMesh, &rotatingCubeTrMat1, cubeMat)
window.Rend.DrawMesh(&cubeMesh, &rotatingCubeTrMat2, cubeMat)
window.Rend.DrawMesh(&cubeMesh, &rotatingCubeTrMat3, cubeMat)
// Cubes generator
// rowSize := 1
@ -1185,7 +1263,7 @@ func (g *Game) DrawSkybox() {
gl.Disable(gl.CULL_FACE)
gl.DepthFunc(gl.LEQUAL)
window.Rend.DrawCubemap(skyboxMesh, skyboxMat)
window.Rend.DrawCubemap(&skyboxMesh, &skyboxMat)
gl.DepthFunc(gl.LESS)
gl.Enable(gl.CULL_FACE)

View File

@ -21,9 +21,30 @@ const (
TextureSlot_ShadowMap_Array1 TextureSlot = 13
)
type MaterialSettings uint64
const (
MaterialSettings_None MaterialSettings = iota
MaterialSettings_HasModelMat MaterialSettings = 1 << (iota - 1)
MaterialSettings_HasNormalMat
)
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
@ -166,22 +187,22 @@ func (m *Material) Delete() {
gl.DeleteProgram(m.ShaderProg.Id)
}
func NewMaterial(matName, shaderPath string) *Material {
func NewMaterial(matName, shaderPath string) Material {
shdrProg, err := shaders.LoadAndCompileCombinedShader(shaderPath)
if err != nil {
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)}
}
func NewMaterialSrc(matName string, shaderSrc []byte) *Material {
func NewMaterialSrc(matName string, shaderSrc []byte) Material {
shdrProg, err := shaders.LoadAndCompileCombinedShaderSrc(shaderSrc)
if err != nil {
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)}
}

View File

@ -21,19 +21,19 @@ type Mesh struct {
SubMeshes []SubMesh
}
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)
if err != nil {
return nil, errors.New("Failed to load model. Err: " + err.Error())
return Mesh{}, errors.New("Failed to load model. Err: " + err.Error())
}
defer release()
if len(scene.Meshes) == 0 {
return nil, errors.New("No meshes found in file: " + modelPath)
return Mesh{}, errors.New("No meshes found in file: " + modelPath)
}
mesh := &Mesh{
mesh := Mesh{
Name: name,
Vao: buffers.NewVertexArray(),
SubMeshes: make([]SubMesh, 0, 1),

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_HasModelMat) {
mat.SetUnifMat4("modelMat", &modelMat.Mat4)
}
if mat.Settings.Has(materials.MaterialSettings_HasNormalMat) {
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,18 @@
#version 410
layout(location=0) in vec3 vertPosIn;
layout(location=1) in vec3 vertNormalIn;
layout(location=2) in vec2 vertUV0In;
layout(location=3) in vec3 vertColorIn;
out vec3 vertNormal;
out vec2 vertUV0;
out vec3 vertColor;
out vec3 fragPos;
//MVP = Model View Projection
uniform mat4 modelMat;
uniform mat4 projViewMat;
void main()
{
vertNormal = mat3(transpose(inverse(modelMat))) * vertNormalIn;
vertUV0 = vertUV0In;
vertColor = vertColorIn;
@ -31,7 +27,6 @@ void main()
#version 410
in vec3 vertColor;
in vec3 vertNormal;
in vec2 vertUV0;
in vec3 fragPos;

View File

@ -6,23 +6,15 @@ layout(location=1) in vec3 vertNormalIn;
layout(location=2) in vec2 vertUV0In;
layout(location=3) in vec3 vertColorIn;
out vec3 vertNormal;
out vec2 vertUV0;
out vec3 vertColor;
out vec3 fragPos;
//MVP = Model View Projection
uniform mat4 modelMat;
uniform mat4 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 +33,6 @@ struct Material {
uniform Material material;
in vec3 vertColor;
in vec3 vertNormal;
in vec2 vertUV0;
in vec3 fragPos;

View File

@ -7,6 +7,7 @@ layout(location=2) in vec2 vertUV0In;
layout(location=3) in vec3 vertColorIn;
uniform mat4 modelMat;
uniform mat3 normalMat;
uniform mat4 projViewMat;
uniform mat4 dirLightProjViewMat;
@ -22,11 +23,7 @@ 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;
vertNormal = normalMat * vertNormalIn;
vertUV0 = vertUV0In;
vertColor = vertColorIn;

View File

@ -12,7 +12,7 @@ import (
type ImguiInfo struct {
ImCtx imgui.Context
Mat *materials.Material
Mat materials.Material
VaoID uint32
VboID uint32
IndexBufID uint32
@ -204,7 +204,7 @@ void main()
// If the path is empty a default nMage shader is used
func NewImGui(shaderPath string) ImguiInfo {
var imguiMat *materials.Material
var imguiMat materials.Material
if shaderPath == "" {
imguiMat = materials.NewMaterialSrc("ImGUI Mat", []byte(DefaultImguiShader))
} else {