mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 13:28:20 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf6b2655e7 |
@ -42,6 +42,7 @@ const (
|
||||
FramebufferAttachmentDataFormat_Unknown FramebufferAttachmentDataFormat = iota
|
||||
FramebufferAttachmentDataFormat_R32Int
|
||||
FramebufferAttachmentDataFormat_RGBA8
|
||||
FramebufferAttachmentDataFormat_RGBAF16
|
||||
FramebufferAttachmentDataFormat_SRGBA
|
||||
FramebufferAttachmentDataFormat_DepthF32
|
||||
FramebufferAttachmentDataFormat_Depth24Stencil8
|
||||
@ -50,7 +51,8 @@ const (
|
||||
func (f FramebufferAttachmentDataFormat) IsColorFormat() bool {
|
||||
return f == FramebufferAttachmentDataFormat_R32Int ||
|
||||
f == FramebufferAttachmentDataFormat_RGBA8 ||
|
||||
f == FramebufferAttachmentDataFormat_SRGBA
|
||||
f == FramebufferAttachmentDataFormat_SRGBA ||
|
||||
f == FramebufferAttachmentDataFormat_RGBAF16
|
||||
}
|
||||
|
||||
func (f FramebufferAttachmentDataFormat) IsDepthFormat() bool {
|
||||
@ -65,6 +67,8 @@ func (f FramebufferAttachmentDataFormat) GlInternalFormat() int32 {
|
||||
return gl.R32I
|
||||
case FramebufferAttachmentDataFormat_RGBA8:
|
||||
return gl.RGB8
|
||||
case FramebufferAttachmentDataFormat_RGBAF16:
|
||||
return gl.RGBA16F
|
||||
case FramebufferAttachmentDataFormat_SRGBA:
|
||||
return gl.SRGB_ALPHA
|
||||
case FramebufferAttachmentDataFormat_DepthF32:
|
||||
@ -85,6 +89,8 @@ func (f FramebufferAttachmentDataFormat) GlFormat() uint32 {
|
||||
|
||||
case FramebufferAttachmentDataFormat_RGBA8:
|
||||
fallthrough
|
||||
case FramebufferAttachmentDataFormat_RGBAF16:
|
||||
fallthrough
|
||||
case FramebufferAttachmentDataFormat_SRGBA:
|
||||
return gl.RGBA
|
||||
|
||||
@ -100,6 +106,33 @@ func (f FramebufferAttachmentDataFormat) GlFormat() uint32 {
|
||||
}
|
||||
}
|
||||
|
||||
func (f FramebufferAttachmentDataFormat) GlComponentType() uint32 {
|
||||
|
||||
switch f {
|
||||
|
||||
case FramebufferAttachmentDataFormat_R32Int:
|
||||
return gl.INT
|
||||
|
||||
case FramebufferAttachmentDataFormat_RGBA8:
|
||||
fallthrough
|
||||
case FramebufferAttachmentDataFormat_SRGBA:
|
||||
return gl.UNSIGNED_BYTE
|
||||
|
||||
case FramebufferAttachmentDataFormat_RGBAF16:
|
||||
// Seems this is fine to be float instead of half float
|
||||
fallthrough
|
||||
case FramebufferAttachmentDataFormat_DepthF32:
|
||||
return gl.FLOAT
|
||||
|
||||
case FramebufferAttachmentDataFormat_Depth24Stencil8:
|
||||
return gl.UNSIGNED_INT_24_8
|
||||
|
||||
default:
|
||||
logging.ErrLog.Fatalf("unknown framebuffer attachment data format. Format=%d\n", f)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
type FramebufferAttachment struct {
|
||||
Id uint32
|
||||
Type FramebufferAttachmentType
|
||||
@ -124,7 +157,7 @@ func (fbo *Framebuffer) BindWithViewport() {
|
||||
gl.Viewport(0, 0, int32(fbo.Width), int32(fbo.Height))
|
||||
}
|
||||
|
||||
// Clear calls gl.Clear with the fob's clear flags.
|
||||
// Clear calls gl.Clear with the fbo's clear flags.
|
||||
// Note that the fbo must be complete and bound.
|
||||
// Calling this without a bound fbo will clear something else, like your screen.
|
||||
func (fbo *Framebuffer) Clear() {
|
||||
@ -207,7 +240,17 @@ func (fbo *Framebuffer) NewColorAttachment(
|
||||
}
|
||||
|
||||
gl.BindTexture(gl.TEXTURE_2D, a.Id)
|
||||
gl.TexImage2D(gl.TEXTURE_2D, 0, attachFormat.GlInternalFormat(), int32(fbo.Width), int32(fbo.Height), 0, attachFormat.GlFormat(), gl.UNSIGNED_BYTE, nil)
|
||||
gl.TexImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
0,
|
||||
attachFormat.GlInternalFormat(),
|
||||
int32(fbo.Width),
|
||||
int32(fbo.Height),
|
||||
0,
|
||||
attachFormat.GlFormat(),
|
||||
attachFormat.GlComponentType(),
|
||||
nil,
|
||||
)
|
||||
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
||||
@ -298,7 +341,17 @@ func (fbo *Framebuffer) NewDepthAttachment(
|
||||
}
|
||||
|
||||
gl.BindTexture(gl.TEXTURE_2D, a.Id)
|
||||
gl.TexImage2D(gl.TEXTURE_2D, 0, attachFormat.GlInternalFormat(), int32(fbo.Width), int32(fbo.Height), 0, attachFormat.GlFormat(), gl.FLOAT, nil)
|
||||
gl.TexImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
0,
|
||||
attachFormat.GlInternalFormat(),
|
||||
int32(fbo.Width),
|
||||
int32(fbo.Height),
|
||||
0,
|
||||
attachFormat.GlFormat(),
|
||||
attachFormat.GlComponentType(),
|
||||
nil,
|
||||
)
|
||||
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
||||
@ -341,7 +394,17 @@ func (fbo *Framebuffer) NewDepthAttachment(
|
||||
|
||||
gl.BindTexture(gl.TEXTURE_CUBE_MAP, a.Id)
|
||||
for i := 0; i < 6; i++ {
|
||||
gl.TexImage2D(uint32(gl.TEXTURE_CUBE_MAP_POSITIVE_X+i), 0, attachFormat.GlInternalFormat(), int32(fbo.Width), int32(fbo.Height), 0, attachFormat.GlFormat(), gl.FLOAT, nil)
|
||||
gl.TexImage2D(
|
||||
uint32(gl.TEXTURE_CUBE_MAP_POSITIVE_X+i),
|
||||
0,
|
||||
attachFormat.GlInternalFormat(),
|
||||
int32(fbo.Width),
|
||||
int32(fbo.Height),
|
||||
0,
|
||||
attachFormat.GlFormat(),
|
||||
attachFormat.GlComponentType(),
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
||||
@ -398,7 +461,7 @@ func (fbo *Framebuffer) NewDepthCubemapArrayAttachment(
|
||||
6*numCubemaps,
|
||||
0,
|
||||
attachFormat.GlFormat(),
|
||||
gl.FLOAT,
|
||||
attachFormat.GlComponentType(),
|
||||
nil,
|
||||
)
|
||||
|
||||
@ -455,7 +518,7 @@ func (fbo *Framebuffer) NewDepthTextureArrayAttachment(
|
||||
numTextures,
|
||||
0,
|
||||
attachFormat.GlFormat(),
|
||||
gl.FLOAT,
|
||||
attachFormat.GlComponentType(),
|
||||
nil,
|
||||
)
|
||||
|
||||
@ -513,7 +576,17 @@ func (fbo *Framebuffer) NewDepthStencilAttachment(
|
||||
}
|
||||
|
||||
gl.BindTexture(gl.TEXTURE_2D, a.Id)
|
||||
gl.TexImage2D(gl.TEXTURE_2D, 0, attachFormat.GlInternalFormat(), int32(fbo.Width), int32(fbo.Height), 0, attachFormat.GlFormat(), gl.UNSIGNED_INT_24_8, nil)
|
||||
gl.TexImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
0,
|
||||
attachFormat.GlInternalFormat(),
|
||||
int32(fbo.Width),
|
||||
int32(fbo.Height),
|
||||
0,
|
||||
attachFormat.GlFormat(),
|
||||
attachFormat.GlComponentType(),
|
||||
nil,
|
||||
)
|
||||
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
||||
|
||||
86
main.go
86
main.go
@ -36,9 +36,10 @@ import (
|
||||
- Point light shadows ✅
|
||||
- Spotlight shadows ✅
|
||||
- Create VAO struct independent from VBO to support multi-VBO use cases (e.g. instancing) ✅
|
||||
- Normals maps
|
||||
- Normals maps ✅
|
||||
- HDR ✅
|
||||
- Fix bad point light acne
|
||||
- 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✅
|
||||
@ -202,12 +203,13 @@ var (
|
||||
yaw float32 = -1.5
|
||||
cam camera.Camera
|
||||
|
||||
// Demo fbo
|
||||
renderToDemoFbo = false
|
||||
renderToBackBuffer = true
|
||||
demoFboScale = gglm.NewVec2(0.25, 0.25)
|
||||
demoFboOffset = gglm.NewVec2(0.75, -0.75)
|
||||
demoFbo buffers.Framebuffer
|
||||
|
||||
// Demo fbo
|
||||
renderToDemoFbo = false
|
||||
demoFboScale = gglm.NewVec2(0.25, 0.25)
|
||||
demoFboOffset = gglm.NewVec2(0.75, -0.75)
|
||||
demoFbo buffers.Framebuffer
|
||||
|
||||
// Dir light fbo
|
||||
showDirLightDepthMapFbo = false
|
||||
@ -221,6 +223,12 @@ var (
|
||||
// Spot light fbo
|
||||
spotLightDepthMapFbo buffers.Framebuffer
|
||||
|
||||
// Hdr Fbo
|
||||
hdrRendering = true
|
||||
hdrExposure float32 = 1
|
||||
tonemappedScreenQuadMat materials.Material
|
||||
hdrFbo buffers.Framebuffer
|
||||
|
||||
screenQuadVao buffers.VertexArray
|
||||
screenQuadMat materials.Material
|
||||
|
||||
@ -243,7 +251,7 @@ var (
|
||||
cubeModelMat = gglm.NewTrMatId()
|
||||
|
||||
renderSkybox = true
|
||||
renderDepthBuffer bool
|
||||
renderDepthBuffer = false
|
||||
|
||||
skyboxCmap assets.Cubemap
|
||||
|
||||
@ -518,6 +526,9 @@ func (g *Game) Init() {
|
||||
screenQuadMat.SetUnifVec2("offset", &demoFboOffset)
|
||||
screenQuadMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse))
|
||||
|
||||
tonemappedScreenQuadMat = materials.NewMaterial("Tonemapped Screen Quad Mat", "./res/shaders/tonemapped-screen-quad.glsl")
|
||||
tonemappedScreenQuadMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse))
|
||||
|
||||
unlitMat = materials.NewMaterial("Unlit mat", "./res/shaders/simple-unlit.glsl")
|
||||
unlitMat.Settings.Set(materials.MaterialSettings_HasModelMtx)
|
||||
unlitMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse))
|
||||
@ -635,6 +646,8 @@ func (g *Game) Init() {
|
||||
|
||||
func (g *Game) initFbos() {
|
||||
|
||||
// @TODO: Resize window sized fbos on window resize
|
||||
|
||||
// Demo fbo
|
||||
demoFbo = buffers.NewFramebuffer(uint32(g.WinWidth), uint32(g.WinHeight))
|
||||
|
||||
@ -679,6 +692,20 @@ func (g *Game) initFbos() {
|
||||
)
|
||||
|
||||
assert.T(spotLightDepthMapFbo.IsComplete(), "Spot light depth map fbo is not complete after init")
|
||||
|
||||
// Hdr fbo
|
||||
hdrFbo = buffers.NewFramebuffer(uint32(g.WinWidth), uint32(g.WinHeight))
|
||||
hdrFbo.NewColorAttachment(
|
||||
buffers.FramebufferAttachmentType_Texture,
|
||||
buffers.FramebufferAttachmentDataFormat_RGBAF16,
|
||||
)
|
||||
|
||||
hdrFbo.NewDepthStencilAttachment(
|
||||
buffers.FramebufferAttachmentType_Renderbuffer,
|
||||
buffers.FramebufferAttachmentDataFormat_Depth24Stencil8,
|
||||
)
|
||||
|
||||
assert.T(hdrFbo.IsComplete(), "Hdr fbo is not complete after init")
|
||||
}
|
||||
|
||||
func (g *Game) updateLights() {
|
||||
@ -819,6 +846,14 @@ func (g *Game) showDebugWindow() {
|
||||
|
||||
imgui.Spacing()
|
||||
|
||||
imgui.Text("HDR")
|
||||
imgui.Checkbox("Enable HDR", &hdrRendering)
|
||||
if imgui.DragFloat("Exposure", &hdrExposure) {
|
||||
tonemappedScreenQuadMat.SetUnifFloat32("exposure", hdrExposure)
|
||||
}
|
||||
|
||||
imgui.Spacing()
|
||||
|
||||
// Ambient light
|
||||
imgui.Text("Ambient Light")
|
||||
|
||||
@ -1075,8 +1110,8 @@ func (g *Game) updateCameraPos() {
|
||||
}
|
||||
|
||||
var (
|
||||
renderDirLightShadows = false
|
||||
renderPointLightShadows = false
|
||||
renderDirLightShadows = true
|
||||
renderPointLightShadows = true
|
||||
renderSpotLightShadows = true
|
||||
|
||||
rotatingCubeSpeedDeg1 float32 = 45
|
||||
@ -1114,17 +1149,19 @@ func (g *Game) Render() {
|
||||
|
||||
if renderDepthBuffer {
|
||||
g.RenderScene(&debugDepthMat)
|
||||
} else if hdrRendering {
|
||||
g.renderHdrFbo()
|
||||
} else {
|
||||
|
||||
g.RenderScene(nil)
|
||||
if renderSkybox {
|
||||
g.DrawSkybox()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if renderSkybox {
|
||||
g.DrawSkybox()
|
||||
}
|
||||
|
||||
if renderToDemoFbo {
|
||||
g.renderDemoFob()
|
||||
g.renderDemoFbo()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1222,7 +1259,7 @@ func (g *Game) renderPointLightShadowmaps() {
|
||||
pointLightDepthMapFbo.UnBindWithViewport(uint32(g.WinWidth), uint32(g.WinHeight))
|
||||
}
|
||||
|
||||
func (g *Game) renderDemoFob() {
|
||||
func (g *Game) renderDemoFbo() {
|
||||
|
||||
demoFbo.Bind()
|
||||
demoFbo.Clear()
|
||||
@ -1246,6 +1283,23 @@ func (g *Game) renderDemoFob() {
|
||||
window.Rend.DrawVertexArray(&screenQuadMat, &screenQuadVao, 0, 6)
|
||||
}
|
||||
|
||||
func (g *Game) renderHdrFbo() {
|
||||
|
||||
hdrFbo.Bind()
|
||||
hdrFbo.Clear()
|
||||
|
||||
g.RenderScene(nil)
|
||||
|
||||
if renderSkybox {
|
||||
g.DrawSkybox()
|
||||
}
|
||||
|
||||
hdrFbo.UnBind()
|
||||
|
||||
tonemappedScreenQuadMat.DiffuseTex = hdrFbo.Attachments[0].Id
|
||||
window.Rend.DrawVertexArray(&tonemappedScreenQuadMat, &screenQuadVao, 0, 6)
|
||||
}
|
||||
|
||||
func (g *Game) RenderScene(overrideMat *materials.Material) {
|
||||
|
||||
tempModelMatrix := cubeModelMat.Clone()
|
||||
|
||||
50
res/shaders/tonemapped-screen-quad.glsl
Executable file
50
res/shaders/tonemapped-screen-quad.glsl
Executable file
@ -0,0 +1,50 @@
|
||||
//shader:vertex
|
||||
#version 410
|
||||
|
||||
out vec2 vertUV0;
|
||||
|
||||
// Hardcoded vertex positions for a fullscreen quad.
|
||||
// Format: vec4(pos.x, pos.y, uv0.x, uv0.y)
|
||||
vec4 quadData[6] = vec4[](
|
||||
vec4(-1.0, 1.0, 0.0, 1.0),
|
||||
vec4(-1.0, -1.0, 0.0, 0.0),
|
||||
vec4(1.0, -1.0, 1.0, 0.0),
|
||||
vec4(-1.0, 1.0, 0.0, 1.0),
|
||||
vec4(1.0, -1.0, 1.0, 0.0),
|
||||
vec4(1.0, 1.0, 1.0, 1.0)
|
||||
);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 vertData = quadData[gl_VertexID];
|
||||
|
||||
vertUV0 = vertData.zw;
|
||||
gl_Position = vec4(vertData.xy, 0.0, 1.0);
|
||||
}
|
||||
|
||||
//shader:fragment
|
||||
#version 410
|
||||
|
||||
struct Material {
|
||||
sampler2D diffuse;
|
||||
};
|
||||
|
||||
uniform float exposure = 1;
|
||||
uniform Material material;
|
||||
|
||||
in vec2 vertUV0;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 diffuseTexColor = texture(material.diffuse, vertUV0);
|
||||
|
||||
// Reinhard tone mapping
|
||||
// vec3 mappedColor = diffuseTexColor.rgb / (diffuseTexColor.rgb + vec3(1.0));
|
||||
|
||||
// Exposure tone mapping
|
||||
vec3 mappedColor = vec3(1.0) - exp(-diffuseTexColor.rgb * exposure);
|
||||
|
||||
fragColor = vec4(mappedColor, 1);
|
||||
}
|
||||
Reference in New Issue
Block a user