Default textures for diffuse/specular/normal/emission mat slots

This commit is contained in:
bloeys
2024-05-11 05:11:54 +04:00
parent c884d2624d
commit 7b1e3ea7b4
7 changed files with 112 additions and 55 deletions

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

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

31
main.go
View File

@ -475,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)
@ -505,7 +495,7 @@ func (g *Game) Init() {
logging.ErrLog.Fatalln("Failed to load texture. Err: ", err) logging.ErrLog.Fatalln("Failed to load texture. Err: ", err)
} }
brickwallNormalTex, err := assets.LoadTexturePNG("./res/textures/brickwall-normal.png", &assets.TextureLoadOptions{}) brickwallNormalTex, err := assets.LoadTexturePNG("./res/textures/brickwall-normal.png", &assets.TextureLoadOptions{NoSrgba: true})
if err != nil { if err != nil {
logging.ErrLog.Fatalln("Failed to load texture. Err: ", err) logging.ErrLog.Fatalln("Failed to load texture. Err: ", err)
} }
@ -533,12 +523,8 @@ func (g *Game) Init() {
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 | materials.MaterialSettings_HasNormalMtx) 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))
@ -553,12 +539,10 @@ 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 | materials.MaterialSettings_HasNormalMtx) 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))
@ -573,12 +557,10 @@ func (g *Game) Init() {
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 = materials.NewMaterial("Ground mat", "./res/shaders/simple.glsl")
groundMat.Settings.Set(materials.MaterialSettings_HasModelMtx | materials.MaterialSettings_HasNormalMtx) groundMat.Settings.Set(materials.MaterialSettings_HasModelMtx)
groundMat.Shininess = 64 groundMat.Shininess = 64
groundMat.DiffuseTex = brickwallDiffuseTex.TexID groundMat.DiffuseTex = brickwallDiffuseTex.TexID
groundMat.SpecularTex = blackTex.TexID
groundMat.NormalTex = brickwallNormalTex.TexID groundMat.NormalTex = brickwallNormalTex.TexID
groundMat.EmissionTex = blackTex.TexID
groundMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse)) groundMat.SetUnifInt32("material.diffuse", int32(materials.TextureSlot_Diffuse))
groundMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular)) groundMat.SetUnifInt32("material.specular", int32(materials.TextureSlot_Specular))
groundMat.SetUnifInt32("material.normal", int32(materials.TextureSlot_Normal)) groundMat.SetUnifInt32("material.normal", int32(materials.TextureSlot_Normal))
@ -593,12 +575,9 @@ func (g *Game) Init() {
groundMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1)) 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 | materials.MaterialSettings_HasNormalMtx) 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))

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"
@ -49,7 +50,7 @@ type Material struct {
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
@ -72,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)
@ -194,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 {
@ -204,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

@ -64,7 +64,6 @@ out vec4 fragPosSpotLight[NUM_SPOT_LIGHTS];
out vec3 tangentCamPos; out vec3 tangentCamPos;
out vec3 tangentFragPos; out vec3 tangentFragPos;
out vec3 tangentVertNormal;
out vec3 tangentDirLightDir; out vec3 tangentDirLightDir;
out vec3 tangentSpotLightPositions[NUM_SPOT_LIGHTS]; out vec3 tangentSpotLightPositions[NUM_SPOT_LIGHTS];
out vec3 tangentSpotLightDirections[NUM_SPOT_LIGHTS]; out vec3 tangentSpotLightDirections[NUM_SPOT_LIGHTS];
@ -86,8 +85,6 @@ void main()
vec3 B = cross(N, T); vec3 B = cross(N, T);
mat3 tbnMtx = transpose(mat3(T, B, N)); mat3 tbnMtx = transpose(mat3(T, B, N));
tangentVertNormal = tbnMtx * normalMat * vertNormalIn;
// Lighting related // Lighting related
fragPos = modelVert.xyz; fragPos = modelVert.xyz;
fragPosDirLight = vec3(dirLightProjViewMat * vec4(fragPos, 1)); fragPosDirLight = vec3(dirLightProjViewMat * vec4(fragPos, 1));
@ -136,7 +133,6 @@ in vec4 fragPosSpotLight[NUM_SPOT_LIGHTS];
in vec3 tangentCamPos; in vec3 tangentCamPos;
in vec3 tangentFragPos; in vec3 tangentFragPos;
in vec3 tangentVertNormal;
in vec3 tangentDirLightDir; in vec3 tangentDirLightDir;
in vec3 tangentSpotLightPositions[NUM_SPOT_LIGHTS]; in vec3 tangentSpotLightPositions[NUM_SPOT_LIGHTS];
in vec3 tangentSpotLightDirections[NUM_SPOT_LIGHTS]; in vec3 tangentSpotLightDirections[NUM_SPOT_LIGHTS];
@ -378,6 +374,8 @@ 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
@ -389,12 +387,8 @@ void main()
// Read normal data encoded [0,1] // Read normal data encoded [0,1]
normalizedVertNorm = texture(material.normal, vertUV0).rgb; normalizedVertNorm = texture(material.normal, vertUV0).rgb;
// Handle no normal map // Remap normal to [-1,1]
if (normalizedVertNorm == vec3(0)) normalizedVertNorm = normalize(normalizedVertNorm * 2.0 - 1.0);
normalizedVertNorm = normalize(tangentVertNormal);
else
// Remap normal to [-1,1]
normalizedVertNorm = normalize(normalizedVertNorm * 2.0 - 1.0);
// Light contributions // Light contributions
vec3 finalColor = CalcDirLight(); vec3 finalColor = CalcDirLight();
@ -413,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);
}
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 B