Spot lights

This commit is contained in:
bloeys
2024-04-12 21:09:14 +04:00
parent c00f6d97dd
commit 83922f1908
2 changed files with 170 additions and 20 deletions

145
main.go
View File

@ -26,9 +26,10 @@ import (
/* /*
@TODO: @TODO:
- Rendering: - Rendering:
- Phong lighting model - Phong lighting model
- Point lights - Directional lights
- Spotlights - Point lights
- Spotlights ✅
- HDR - HDR
- Cascaded shadow mapping - Cascaded shadow mapping
- Skeletal animations - Skeletal animations
@ -62,6 +63,7 @@ type PointLight struct {
} }
type SpotLight struct { type SpotLight struct {
Pos gglm.Vec3
Dir gglm.Vec3 Dir gglm.Vec3
DiffuseColor gglm.Vec3 DiffuseColor gglm.Vec3
SpecularColor gglm.Vec3 SpecularColor gglm.Vec3
@ -69,6 +71,18 @@ type SpotLight struct {
OuterCutoff float32 OuterCutoff float32
} }
// SetCutoffs properly sets the cosine values of the cutoffs using the passed
// degrees.
//
// The light has full intensity within the inner cutoff, falloff between
// inner-outer cutoff, and zero light beyond the outer cutoff.
//
// The inner cuttoff degree must be *smaller* than the outer cutoff
func (s *SpotLight) SetCutoffs(innerCutoffAngleDeg, outerCutoffAngleDeg float32) {
s.InnerCutoff = gglm.Cos32(innerCutoffAngleDeg * gglm.Deg2Rad)
s.OuterCutoff = gglm.Cos32(outerCutoffAngleDeg * gglm.Deg2Rad)
}
const ( const (
camSpeed = 15 camSpeed = 15
mouseSensitivity = 0.5 mouseSensitivity = 0.5
@ -148,6 +162,17 @@ var (
Quadratic: 0.032, Quadratic: 0.032,
}, },
} }
spotLights = [...]SpotLight{
{
Pos: *gglm.NewVec3(0, 5, 0),
Dir: *gglm.NewVec3(0, -1, 0),
DiffuseColor: *gglm.NewVec3(0, 1, 1),
SpecularColor: *gglm.NewVec3(1, 1, 1),
// These must be cosine values
InnerCutoff: gglm.Cos32(15 * gglm.Deg2Rad),
OuterCutoff: gglm.Cos32(20 * gglm.Deg2Rad),
},
}
) )
type Game struct { type Game struct {
@ -456,6 +481,36 @@ func (g *Game) updateLights() {
containerMat.SetUnifFloat32(indexString+".quadratic", pl.Quadratic) containerMat.SetUnifFloat32(indexString+".quadratic", pl.Quadratic)
palleteMat.SetUnifFloat32(indexString+".quadratic", pl.Quadratic) palleteMat.SetUnifFloat32(indexString+".quadratic", pl.Quadratic)
} }
for i := 0; i < len(spotLights); i++ {
l := &spotLights[i]
indexString := "spotLights[" + strconv.Itoa(i) + "]"
whiteMat.SetUnifVec3(indexString+".pos", &l.Pos)
containerMat.SetUnifVec3(indexString+".pos", &l.Pos)
palleteMat.SetUnifVec3(indexString+".pos", &l.Pos)
whiteMat.SetUnifVec3(indexString+".dir", &l.Dir)
containerMat.SetUnifVec3(indexString+".dir", &l.Dir)
palleteMat.SetUnifVec3(indexString+".dir", &l.Dir)
whiteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
containerMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
palleteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
whiteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
containerMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
palleteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
whiteMat.SetUnifFloat32(indexString+".innerCutoff", l.InnerCutoff)
containerMat.SetUnifFloat32(indexString+".innerCutoff", l.InnerCutoff)
palleteMat.SetUnifFloat32(indexString+".innerCutoff", l.InnerCutoff)
whiteMat.SetUnifFloat32(indexString+".outerCutoff", l.OuterCutoff)
containerMat.SetUnifFloat32(indexString+".outerCutoff", l.OuterCutoff)
palleteMat.SetUnifFloat32(indexString+".outerCutoff", l.OuterCutoff)
}
} }
func (g *Game) Update() { func (g *Game) Update() {
@ -544,35 +599,91 @@ func (g *Game) showDebugWindow() {
imgui.Spacing() imgui.Spacing()
// Point lights // Point lights
imgui.Text("Point Lights") if imgui.BeginListBoxV("Point Lights", imgui.Vec2{Y: 200}) {
if imgui.BeginListBoxV("", imgui.Vec2{Y: 200}) {
for i := 0; i < len(pointLights); i++ { for i := 0; i < len(pointLights); i++ {
pl := &pointLights[i] pl := &pointLights[i]
indexString := strconv.Itoa(i) indexNumString := strconv.Itoa(i)
if !imgui.TreeNodeExStrV("Light "+indexString, imgui.TreeNodeFlagsSpanAvailWidth) { if !imgui.TreeNodeExStrV("Point Light "+indexNumString, imgui.TreeNodeFlagsSpanAvailWidth) {
continue continue
} }
indexString := "pointLights[" + indexNumString + "]"
if imgui.DragFloat3("Pos", &pl.Pos.Data) { if imgui.DragFloat3("Pos", &pl.Pos.Data) {
whiteMat.SetUnifVec3("pointLights["+indexString+"].pos", &pl.Pos) whiteMat.SetUnifVec3(indexString+".pos", &pl.Pos)
containerMat.SetUnifVec3("pointLights["+indexString+"].pos", &pl.Pos) containerMat.SetUnifVec3(indexString+".pos", &pl.Pos)
palleteMat.SetUnifVec3("pointLights["+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("pointLights["+indexString+"].diffuseColor", &pl.DiffuseColor) whiteMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor)
containerMat.SetUnifVec3("pointLights["+indexString+"].diffuseColor", &pl.DiffuseColor) containerMat.SetUnifVec3(indexString+".diffuseColor", &pl.DiffuseColor)
palleteMat.SetUnifVec3("pointLights["+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("pointLights["+indexString+"].specularColor", &pl.SpecularColor) whiteMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor)
containerMat.SetUnifVec3("pointLights["+indexString+"].specularColor", &pl.SpecularColor) containerMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor)
palleteMat.SetUnifVec3("pointLights["+indexString+"].specularColor", &pl.SpecularColor) palleteMat.SetUnifVec3(indexString+".specularColor", &pl.SpecularColor)
}
imgui.TreePop()
}
imgui.EndListBox()
}
// Spot lights
if imgui.BeginListBoxV("Spot Lights", imgui.Vec2{Y: 200}) {
for i := 0; i < len(spotLights); i++ {
l := &spotLights[i]
indexNumString := strconv.Itoa(i)
if !imgui.TreeNodeExStrV("Spot Light "+indexNumString, imgui.TreeNodeFlagsSpanAvailWidth) {
continue
}
indexString := "spotLights[" + indexNumString + "]"
if imgui.DragFloat3("Pos", &l.Pos.Data) {
whiteMat.SetUnifVec3(indexString+".pos", &l.Pos)
containerMat.SetUnifVec3(indexString+".pos", &l.Pos)
palleteMat.SetUnifVec3(indexString+".pos", &l.Pos)
}
if imgui.DragFloat3("Dir", &l.Dir.Data) {
whiteMat.SetUnifVec3(indexString+".dir", &l.Dir)
containerMat.SetUnifVec3(indexString+".dir", &l.Dir)
palleteMat.SetUnifVec3(indexString+".dir", &l.Dir)
}
if imgui.DragFloat3("Diffuse Color", &l.DiffuseColor.Data) {
whiteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
containerMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
palleteMat.SetUnifVec3(indexString+".diffuseColor", &l.DiffuseColor)
}
if imgui.DragFloat3("Specular Color", &l.SpecularColor.Data) {
whiteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
containerMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
palleteMat.SetUnifVec3(indexString+".specularColor", &l.SpecularColor)
}
if imgui.DragFloat("Inner Cutoff", &l.InnerCutoff) {
whiteMat.SetUnifFloat32(indexString+".innerCutoff", l.InnerCutoff)
containerMat.SetUnifFloat32(indexString+".innerCutoff", l.InnerCutoff)
palleteMat.SetUnifFloat32(indexString+".innerCutoff", l.InnerCutoff)
}
if imgui.DragFloat("Outer Cutoff", &l.OuterCutoff) {
whiteMat.SetUnifFloat32(indexString+".outerCutoff", l.OuterCutoff)
containerMat.SetUnifFloat32(indexString+".outerCutoff", l.OuterCutoff)
palleteMat.SetUnifFloat32(indexString+".outerCutoff", l.OuterCutoff)
} }
imgui.TreePop() imgui.TreePop()

View File

@ -64,6 +64,18 @@ struct PointLight {
#define NUM_POINT_LIGHTS 16 #define NUM_POINT_LIGHTS 16
uniform PointLight pointLights[NUM_POINT_LIGHTS]; uniform PointLight pointLights[NUM_POINT_LIGHTS];
struct SpotLight {
vec3 pos;
vec3 dir;
vec3 diffuseColor;
vec3 specularColor;
float innerCutoff;
float outerCutoff;
};
#define NUM_SPOT_LIGHTS 4
uniform SpotLight spotLights[NUM_SPOT_LIGHTS];
uniform vec3 camPos; uniform vec3 camPos;
uniform vec3 ambientColor = vec3(0.2, 0.2, 0.2); uniform vec3 ambientColor = vec3(0.2, 0.2, 0.2);
@ -122,9 +134,33 @@ vec3 CalcPointLight(PointLight pointLight)
return (finalDiffuse + finalSpecular) * attenuation; return (finalDiffuse + finalSpecular) * attenuation;
} }
vec3 CalcSpotLight() vec3 CalcSpotLight(SpotLight light)
{ {
if (light.innerCutoff == 0)
return vec3(0); return vec3(0);
vec3 fragToLightDir = normalize(light.pos - fragPos);
// Spot light cone with full intensity within inner cutoff,
// and falloff between inner-outer cutoffs, and zero
// light after outer cutoff
float theta = dot(fragToLightDir, normalize(-light.dir));
float epsilon = (light.innerCutoff - light.outerCutoff);
float intensity = clamp((theta - light.outerCutoff) / epsilon, 0.0, 1.0);
if (intensity == 0)
return vec3(0);
// Diffuse
float diffuseAmount = max(0.0, dot(normalizedVertNorm, fragToLightDir));
vec3 finalDiffuse = diffuseAmount * light.diffuseColor * diffuseTexColor.rgb;
// Specular
vec3 reflectDir = reflect(-fragToLightDir, normalizedVertNorm);
float specularAmount = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 finalSpecular = specularAmount * light.specularColor * specularTexColor.rgb;
return (finalDiffuse + finalSpecular) * intensity;
} }
void main() void main()
@ -145,7 +181,10 @@ void main()
finalColor += CalcPointLight(pointLights[i]); finalColor += CalcPointLight(pointLights[i]);
} }
finalColor += CalcSpotLight(); for (int i = 0; i < NUM_SPOT_LIGHTS; i++)
{
finalColor += CalcSpotLight(spotLights[i]);
}
vec3 finalEmission = emissionTexColor.rgb; vec3 finalEmission = emissionTexColor.rgb;
vec3 finalAmbient = ambientColor * diffuseTexColor.rgb; vec3 finalAmbient = ambientColor * diffuseTexColor.rgb;