mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 13:28:20 +00:00
Spot lights
This commit is contained in:
145
main.go
145
main.go
@ -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()
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user