mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 05:18:21 +00:00
Geometry shader support+omnidirectional depth map shader+improvements
This commit is contained in:
@ -19,7 +19,8 @@ import (
|
||||
type ColorFormat int
|
||||
|
||||
const (
|
||||
ColorFormat_RGBA8 ColorFormat = iota
|
||||
ColorFormat_Unknown ColorFormat = iota
|
||||
ColorFormat_RGBA8
|
||||
)
|
||||
|
||||
type Texture struct {
|
||||
|
||||
@ -10,8 +10,10 @@ import (
|
||||
type BufUsage int
|
||||
|
||||
const (
|
||||
BufUsage_Unknown BufUsage = iota
|
||||
|
||||
//Buffer is set only once and used many times
|
||||
BufUsage_Static BufUsage = iota
|
||||
BufUsage_Static
|
||||
//Buffer is changed a lot and used many times
|
||||
BufUsage_Dynamic
|
||||
//Buffer is set only once and used by the GPU at most a few times
|
||||
|
||||
30
main.go
30
main.go
@ -30,6 +30,9 @@ import (
|
||||
- Directional lights ✅
|
||||
- Point lights ✅
|
||||
- Spotlights ✅
|
||||
- Directional light shadows ✅
|
||||
- Point light shadows
|
||||
- Spotlight shadows
|
||||
- HDR
|
||||
- Cascaded shadow mapping
|
||||
- Skeletal animations
|
||||
@ -85,6 +88,28 @@ type PointLight struct {
|
||||
Quadratic float32
|
||||
}
|
||||
|
||||
var (
|
||||
pointLightNear float32 = 1
|
||||
pointLightFar float32 = 25
|
||||
)
|
||||
|
||||
func (p *PointLight) GetProjViewMats(shadowMapWidth, shadowMapHeight float32) [6]gglm.Mat4 {
|
||||
|
||||
aspect := float32(shadowMapWidth) / float32(shadowMapHeight)
|
||||
projMat := gglm.Perspective(90*gglm.Deg2Rad, aspect, pointLightNear, pointLightFar)
|
||||
|
||||
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),
|
||||
}
|
||||
|
||||
return projViewMats
|
||||
}
|
||||
|
||||
type SpotLight struct {
|
||||
Pos gglm.Vec3
|
||||
Dir gglm.Vec3
|
||||
@ -141,6 +166,7 @@ var (
|
||||
palleteMat *materials.Material
|
||||
skyboxMat *materials.Material
|
||||
dirLightDepthMapMat *materials.Material
|
||||
omnidirDepthMapMat *materials.Material
|
||||
debugDepthMat *materials.Material
|
||||
|
||||
cubeMesh *meshes.Mesh
|
||||
@ -437,7 +463,9 @@ func (g *Game) Init() {
|
||||
|
||||
debugDepthMat = materials.NewMaterial("Debug depth mat", "./res/shaders/debug-depth.glsl")
|
||||
|
||||
dirLightDepthMapMat = materials.NewMaterial("Depth Map mat", "./res/shaders/depth-map.glsl")
|
||||
dirLightDepthMapMat = materials.NewMaterial("Directional Depth Map mat", "./res/shaders/directional-depth-map.glsl")
|
||||
|
||||
omnidirDepthMapMat = materials.NewMaterial("Omnidirectional Depth Map mat", "./res/shaders/omnidirectional-depth-map.glsl")
|
||||
|
||||
skyboxMat = materials.NewMaterial("Skybox mat", "./res/shaders/skybox.glsl")
|
||||
skyboxMat.CubemapTex = skyboxCmap.TexID
|
||||
|
||||
@ -44,7 +44,7 @@ type Material struct {
|
||||
|
||||
func (m *Material) Bind() {
|
||||
|
||||
gl.UseProgram(m.ShaderProg.ID)
|
||||
m.ShaderProg.Bind()
|
||||
|
||||
if m.DiffuseTex != 0 {
|
||||
gl.ActiveTexture(uint32(gl.TEXTURE0 + TextureSlot_Diffuse))
|
||||
@ -88,7 +88,7 @@ func (m *Material) GetAttribLoc(attribName string) int32 {
|
||||
return loc
|
||||
}
|
||||
|
||||
loc = gl.GetAttribLocation(m.ShaderProg.ID, gl.Str(attribName+"\x00"))
|
||||
loc = gl.GetAttribLocation(m.ShaderProg.Id, gl.Str(attribName+"\x00"))
|
||||
assert.T(loc != -1, "Attribute '"+attribName+"' doesn't exist on material "+m.Name)
|
||||
m.AttribLocs[attribName] = loc
|
||||
return loc
|
||||
@ -101,7 +101,7 @@ func (m *Material) GetUnifLoc(uniformName string) int32 {
|
||||
return loc
|
||||
}
|
||||
|
||||
loc = gl.GetUniformLocation(m.ShaderProg.ID, gl.Str(uniformName+"\x00"))
|
||||
loc = gl.GetUniformLocation(m.ShaderProg.Id, gl.Str(uniformName+"\x00"))
|
||||
assert.T(loc != -1, "Uniform '"+uniformName+"' doesn't exist on material "+m.Name)
|
||||
m.UnifLocs[uniformName] = loc
|
||||
return loc
|
||||
@ -116,39 +116,39 @@ func (m *Material) DisableAttribute(attribName string) {
|
||||
}
|
||||
|
||||
func (m *Material) SetUnifInt32(uniformName string, val int32) {
|
||||
gl.ProgramUniform1i(m.ShaderProg.ID, m.GetUnifLoc(uniformName), val)
|
||||
gl.ProgramUniform1i(m.ShaderProg.Id, m.GetUnifLoc(uniformName), val)
|
||||
}
|
||||
|
||||
func (m *Material) SetUnifFloat32(uniformName string, val float32) {
|
||||
gl.ProgramUniform1f(m.ShaderProg.ID, m.GetUnifLoc(uniformName), val)
|
||||
gl.ProgramUniform1f(m.ShaderProg.Id, m.GetUnifLoc(uniformName), val)
|
||||
}
|
||||
|
||||
func (m *Material) SetUnifVec2(uniformName string, vec2 *gglm.Vec2) {
|
||||
gl.ProgramUniform2fv(m.ShaderProg.ID, m.GetUnifLoc(uniformName), 1, &vec2.Data[0])
|
||||
gl.ProgramUniform2fv(m.ShaderProg.Id, m.GetUnifLoc(uniformName), 1, &vec2.Data[0])
|
||||
}
|
||||
|
||||
func (m *Material) SetUnifVec3(uniformName string, vec3 *gglm.Vec3) {
|
||||
gl.ProgramUniform3fv(m.ShaderProg.ID, m.GetUnifLoc(uniformName), 1, &vec3.Data[0])
|
||||
gl.ProgramUniform3fv(m.ShaderProg.Id, m.GetUnifLoc(uniformName), 1, &vec3.Data[0])
|
||||
}
|
||||
|
||||
func (m *Material) SetUnifVec4(uniformName string, vec4 *gglm.Vec4) {
|
||||
gl.ProgramUniform4fv(m.ShaderProg.ID, m.GetUnifLoc(uniformName), 1, &vec4.Data[0])
|
||||
gl.ProgramUniform4fv(m.ShaderProg.Id, m.GetUnifLoc(uniformName), 1, &vec4.Data[0])
|
||||
}
|
||||
|
||||
func (m *Material) SetUnifMat2(uniformName string, mat2 *gglm.Mat2) {
|
||||
gl.ProgramUniformMatrix2fv(m.ShaderProg.ID, m.GetUnifLoc(uniformName), 1, false, &mat2.Data[0][0])
|
||||
gl.ProgramUniformMatrix2fv(m.ShaderProg.Id, m.GetUnifLoc(uniformName), 1, false, &mat2.Data[0][0])
|
||||
}
|
||||
|
||||
func (m *Material) SetUnifMat3(uniformName string, mat3 *gglm.Mat3) {
|
||||
gl.ProgramUniformMatrix3fv(m.ShaderProg.ID, m.GetUnifLoc(uniformName), 1, false, &mat3.Data[0][0])
|
||||
gl.ProgramUniformMatrix3fv(m.ShaderProg.Id, m.GetUnifLoc(uniformName), 1, false, &mat3.Data[0][0])
|
||||
}
|
||||
|
||||
func (m *Material) SetUnifMat4(uniformName string, mat4 *gglm.Mat4) {
|
||||
gl.ProgramUniformMatrix4fv(m.ShaderProg.ID, m.GetUnifLoc(uniformName), 1, false, &mat4.Data[0][0])
|
||||
gl.ProgramUniformMatrix4fv(m.ShaderProg.Id, m.GetUnifLoc(uniformName), 1, false, &mat4.Data[0][0])
|
||||
}
|
||||
|
||||
func (m *Material) Delete() {
|
||||
gl.DeleteProgram(m.ShaderProg.ID)
|
||||
gl.DeleteProgram(m.ShaderProg.Id)
|
||||
}
|
||||
|
||||
func NewMaterial(matName, shaderPath string) *Material {
|
||||
|
||||
62
res/shaders/omnidirectional-depth-map.glsl
Executable file
62
res/shaders/omnidirectional-depth-map.glsl
Executable file
@ -0,0 +1,62 @@
|
||||
//shader:vertex
|
||||
#version 410
|
||||
|
||||
layout(location=0) in vec3 vertPosIn;
|
||||
|
||||
uniform mat4 modelMat;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = modelMat * vec4(vertPosIn, 1);
|
||||
}
|
||||
|
||||
//shader:geometry
|
||||
#version 410
|
||||
|
||||
layout (triangles) in;
|
||||
|
||||
// Cubemap means 6 faces, and the
|
||||
// input 3 triangle vertices are drawn once per face, so 6*3=18
|
||||
layout (triangle_strip, max_vertices=18) out;
|
||||
|
||||
uniform mat4 cubemapProjViewMats[6];
|
||||
|
||||
out vec4 FragPos;
|
||||
|
||||
void main()
|
||||
{
|
||||
for(int face = 0; face < 6; ++face)
|
||||
{
|
||||
// Built in variable that specifies which cubemap face we are rendering to
|
||||
// and only works when a cubemap is attached to the active fbo
|
||||
gl_Layer = face;
|
||||
|
||||
// Transform each triangle vertex
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
FragPos = gl_in[i].gl_Position;
|
||||
gl_Position = cubemapProjViewMats[face] * FragPos;
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
||||
|
||||
//shader:fragment
|
||||
#version 410
|
||||
|
||||
in vec4 FragPos;
|
||||
|
||||
uniform vec3 lightPos;
|
||||
uniform float farPlane;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Get distance between fragment and light source
|
||||
float lightDistance = length(FragPos.xyz - lightPos);
|
||||
|
||||
// Map to [0, 1] by dividing by far plane and use it as our depth
|
||||
lightDistance = lightDistance / farPlane;
|
||||
|
||||
gl_FragDepth = lightDistance;
|
||||
}
|
||||
@ -6,32 +6,48 @@ import (
|
||||
)
|
||||
|
||||
type ShaderProgram struct {
|
||||
ID uint32
|
||||
VertShaderID uint32
|
||||
FragShaderID uint32
|
||||
Id uint32
|
||||
VertShaderId uint32
|
||||
FragShaderId uint32
|
||||
GeomShaderId uint32
|
||||
}
|
||||
|
||||
func (sp *ShaderProgram) AttachShader(shader Shader) {
|
||||
|
||||
gl.AttachShader(sp.ID, shader.ID)
|
||||
switch shader.ShaderType {
|
||||
case VertexShaderType:
|
||||
sp.VertShaderID = shader.ID
|
||||
case FragmentShaderType:
|
||||
sp.FragShaderID = shader.ID
|
||||
gl.AttachShader(sp.Id, shader.Id)
|
||||
switch shader.Type {
|
||||
case ShaderType_Vertex:
|
||||
sp.VertShaderId = shader.Id
|
||||
case ShaderType_Fragment:
|
||||
sp.FragShaderId = shader.Id
|
||||
case ShaderType_Geometry:
|
||||
sp.GeomShaderId = shader.Id
|
||||
default:
|
||||
logging.ErrLog.Println("Unknown shader type ", shader.ShaderType, " for ID ", shader.ID)
|
||||
logging.ErrLog.Fatalf("Unknown shader type '%d' for shader id '%d'\n", shader.Type, shader.Id)
|
||||
}
|
||||
}
|
||||
|
||||
func (sp *ShaderProgram) Link() {
|
||||
|
||||
gl.LinkProgram(sp.ID)
|
||||
gl.LinkProgram(sp.Id)
|
||||
|
||||
if sp.VertShaderID != 0 {
|
||||
gl.DeleteShader(sp.VertShaderID)
|
||||
if sp.VertShaderId != 0 {
|
||||
gl.DeleteShader(sp.VertShaderId)
|
||||
}
|
||||
if sp.FragShaderID != 0 {
|
||||
gl.DeleteShader(sp.FragShaderID)
|
||||
|
||||
if sp.FragShaderId != 0 {
|
||||
gl.DeleteShader(sp.FragShaderId)
|
||||
}
|
||||
|
||||
if sp.GeomShaderId != 0 {
|
||||
gl.DeleteShader(sp.GeomShaderId)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ShaderProgram) Bind() {
|
||||
gl.UseProgram(s.Id)
|
||||
}
|
||||
|
||||
func (s *ShaderProgram) UnBind() {
|
||||
gl.UseProgram(0)
|
||||
}
|
||||
|
||||
@ -1,10 +1,31 @@
|
||||
package shaders
|
||||
|
||||
import "github.com/go-gl/gl/v4.1-core/gl"
|
||||
import (
|
||||
"github.com/bloeys/nmage/logging"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
)
|
||||
|
||||
type ShaderType int
|
||||
type ShaderType int32
|
||||
|
||||
func (s ShaderType) ToGl() uint32 {
|
||||
|
||||
switch s {
|
||||
case ShaderType_Vertex:
|
||||
return gl.VERTEX_SHADER
|
||||
case ShaderType_Fragment:
|
||||
return gl.FRAGMENT_SHADER
|
||||
case ShaderType_Geometry:
|
||||
return gl.GEOMETRY_SHADER
|
||||
|
||||
default:
|
||||
logging.ErrLog.Fatalf("Unknown shader type '%d'\n", s)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
VertexShaderType ShaderType = gl.VERTEX_SHADER
|
||||
FragmentShaderType ShaderType = gl.FRAGMENT_SHADER
|
||||
ShaderType_Unknown ShaderType = iota
|
||||
ShaderType_Vertex
|
||||
ShaderType_Fragment
|
||||
ShaderType_Geometry
|
||||
)
|
||||
|
||||
@ -3,6 +3,7 @@ package shaders
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@ -11,12 +12,13 @@ import (
|
||||
)
|
||||
|
||||
type Shader struct {
|
||||
ID uint32
|
||||
ShaderType ShaderType
|
||||
Id uint32
|
||||
Type ShaderType
|
||||
}
|
||||
|
||||
func (s Shader) Delete() {
|
||||
gl.DeleteShader(s.ID)
|
||||
func (s *Shader) Delete() {
|
||||
gl.DeleteShader(s.Id)
|
||||
s.Id = 0
|
||||
}
|
||||
|
||||
func NewShaderProgram() (ShaderProgram, error) {
|
||||
@ -26,7 +28,7 @@ func NewShaderProgram() (ShaderProgram, error) {
|
||||
return ShaderProgram{}, errors.New("failed to create shader program")
|
||||
}
|
||||
|
||||
return ShaderProgram{ID: id}, nil
|
||||
return ShaderProgram{Id: id}, nil
|
||||
}
|
||||
|
||||
func LoadAndCompileCombinedShader(shaderPath string) (ShaderProgram, error) {
|
||||
@ -43,8 +45,8 @@ func LoadAndCompileCombinedShader(shaderPath string) (ShaderProgram, error) {
|
||||
func LoadAndCompileCombinedShaderSrc(shaderSrc []byte) (ShaderProgram, error) {
|
||||
|
||||
shaderSources := bytes.Split(shaderSrc, []byte("//shader:"))
|
||||
if len(shaderSources) == 1 {
|
||||
return ShaderProgram{}, errors.New("failed to read combined shader. Did not find '//shader:vertex' or '//shader:fragment'")
|
||||
if len(shaderSources) < 2 {
|
||||
return ShaderProgram{}, errors.New("failed to read combined shader. The minimum shader types to have are '//shader:vertex' and '//shader:fragment'")
|
||||
}
|
||||
|
||||
shdrProg, err := NewShaderProgram()
|
||||
@ -65,12 +67,15 @@ func LoadAndCompileCombinedShaderSrc(shaderSrc []byte) (ShaderProgram, error) {
|
||||
var shdrType ShaderType
|
||||
if bytes.HasPrefix(src, []byte("vertex")) {
|
||||
src = src[6:]
|
||||
shdrType = VertexShaderType
|
||||
shdrType = ShaderType_Vertex
|
||||
} else if bytes.HasPrefix(src, []byte("fragment")) {
|
||||
src = src[8:]
|
||||
shdrType = FragmentShaderType
|
||||
shdrType = ShaderType_Fragment
|
||||
} else if bytes.HasPrefix(src, []byte("geometry")) {
|
||||
src = src[8:]
|
||||
shdrType = ShaderType_Geometry
|
||||
} else {
|
||||
return ShaderProgram{}, errors.New("unknown shader type. Must be '//shader:vertex' or '//shader:fragment'")
|
||||
return ShaderProgram{}, errors.New("unknown shader type. Must be '//shader:vertex' or '//shader:fragment' or '//shader:geometry'")
|
||||
}
|
||||
|
||||
shdr, err := CompileShaderOfType(src, shdrType)
|
||||
@ -83,7 +88,15 @@ func LoadAndCompileCombinedShaderSrc(shaderSrc []byte) (ShaderProgram, error) {
|
||||
}
|
||||
|
||||
if loadedShdrCount == 0 {
|
||||
return ShaderProgram{}, errors.New("no valid shaders found. Please put '//shader:vertex' or '//shader:fragment' before your shaders")
|
||||
return ShaderProgram{}, errors.New("no valid shaders found. Please put '//shader:vertex' or '//shader:fragment' or '//shader:geometry' before your shaders")
|
||||
}
|
||||
|
||||
if shdrProg.VertShaderId == 0 {
|
||||
return ShaderProgram{}, errors.New("no valid vertex shader found. Please put '//shader:vertex' before your vertex shader")
|
||||
}
|
||||
|
||||
if shdrProg.FragShaderId == 0 {
|
||||
return ShaderProgram{}, errors.New("no valid fragment shader found. Please put '//shader:fragment' before your vertex shader")
|
||||
}
|
||||
|
||||
shdrProg.Link()
|
||||
@ -92,41 +105,40 @@ func LoadAndCompileCombinedShaderSrc(shaderSrc []byte) (ShaderProgram, error) {
|
||||
|
||||
func CompileShaderOfType(shaderSource []byte, shaderType ShaderType) (Shader, error) {
|
||||
|
||||
shaderID := gl.CreateShader(uint32(shaderType))
|
||||
if shaderID == 0 {
|
||||
logging.ErrLog.Println("Failed to create shader.")
|
||||
return Shader{}, errors.New("failed to create shader")
|
||||
shaderId := gl.CreateShader(shaderType.ToGl())
|
||||
if shaderId == 0 {
|
||||
return Shader{}, fmt.Errorf("failed to create OpenGl shader. OpenGl Error=%d", gl.GetError())
|
||||
}
|
||||
|
||||
//Load shader source and compile
|
||||
shaderCStr, shaderFree := gl.Strs(string(shaderSource) + "\x00")
|
||||
defer shaderFree()
|
||||
gl.ShaderSource(shaderID, 1, shaderCStr, nil)
|
||||
gl.ShaderSource(shaderId, 1, shaderCStr, nil)
|
||||
|
||||
gl.CompileShader(shaderID)
|
||||
if err := getShaderCompileErrors(shaderID); err != nil {
|
||||
gl.DeleteShader(shaderID)
|
||||
gl.CompileShader(shaderId)
|
||||
if err := getShaderCompileErrors(shaderId); err != nil {
|
||||
gl.DeleteShader(shaderId)
|
||||
return Shader{}, err
|
||||
}
|
||||
|
||||
return Shader{ID: shaderID, ShaderType: shaderType}, nil
|
||||
return Shader{Id: shaderId, Type: shaderType}, nil
|
||||
}
|
||||
|
||||
func getShaderCompileErrors(shaderID uint32) error {
|
||||
func getShaderCompileErrors(shaderId uint32) error {
|
||||
|
||||
var compiledSuccessfully int32
|
||||
gl.GetShaderiv(shaderID, gl.COMPILE_STATUS, &compiledSuccessfully)
|
||||
gl.GetShaderiv(shaderId, gl.COMPILE_STATUS, &compiledSuccessfully)
|
||||
if compiledSuccessfully == gl.TRUE {
|
||||
return nil
|
||||
}
|
||||
|
||||
var logLength int32
|
||||
gl.GetShaderiv(shaderID, gl.INFO_LOG_LENGTH, &logLength)
|
||||
gl.GetShaderiv(shaderId, gl.INFO_LOG_LENGTH, &logLength)
|
||||
|
||||
log := gl.Str(strings.Repeat("\x00", int(logLength)))
|
||||
gl.GetShaderInfoLog(shaderID, logLength, nil, log)
|
||||
gl.GetShaderInfoLog(shaderId, logLength, nil, log)
|
||||
|
||||
errMsg := gl.GoStr(log)
|
||||
logging.ErrLog.Println("Compilation of shader with id ", shaderID, " failed. Err: ", errMsg)
|
||||
logging.ErrLog.Println("Compilation of shader with id ", shaderId, " failed. Err: ", errMsg)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user