summaryrefslogtreecommitdiff
path: root/data
diff options
context:
space:
mode:
authorDavid Thompson <dthompson2@worcester.edu>2021-05-12 20:49:48 -0400
committerDavid Thompson <dthompson2@worcester.edu>2021-05-12 20:49:48 -0400
commitf88da6fb6d50568d8d1889cca3f9ed32c4451a06 (patch)
treebccf5fb2b2bd947a0c2a173d8f9ca7657907d8e3 /data
parent21ab482f62b6f12469b56e7533a1b41d0ff7a0cd (diff)
graphics: model: Add support for dynamic lights in PBR models.
Diffstat (limited to 'data')
-rw-r--r--data/shaders/pbr-frag.glsl138
-rw-r--r--data/shaders/pbr-vert.glsl9
2 files changed, 85 insertions, 62 deletions
diff --git a/data/shaders/pbr-frag.glsl b/data/shaders/pbr-frag.glsl
index 73a6840..b025bb7 100644
--- a/data/shaders/pbr-frag.glsl
+++ b/data/shaders/pbr-frag.glsl
@@ -13,7 +13,6 @@ struct Material {
vec3 normalFactor;
bool normalTextureEnabled;
int normalTexcoord;
- vec3 occlusionFactor;
bool occlusionTextureEnabled;
int occlusionTexcoord;
vec3 emissiveFactor;
@@ -23,16 +22,23 @@ struct Material {
float alphaCutoff;
};
+struct Light {
+ bool enabled;
+ int type;
+ vec3 position;
+ vec3 direction;
+ vec4 color;
+ float cutOff;
+};
+
#ifdef GLSL120
attribute vec3 fragWorldPos;
-attribute vec3 fragCamPos;
attribute vec3 fragNormal;
attribute vec2 fragTexcoord0;
attribute vec2 fragTexcoord1
attribute vec4 fragColor0;
#else
in vec3 fragWorldPos;
-in vec3 fragCamPos;
in vec3 fragNormal;
in vec2 fragTexcoord0;
in vec2 fragTexcoord1;
@@ -44,7 +50,10 @@ out vec4 fragColor;
#endif
uniform Material material;
+uniform Light lights[4];
+uniform vec4 ambientLightColor;
uniform bool vertexColored;
+uniform vec3 cameraPosition;
uniform sampler2D baseColorTexture;
uniform sampler2D metallicRoughnessTexture;
uniform sampler2D normalTexture;
@@ -53,16 +62,6 @@ uniform sampler2D emissiveTexture;
const float PI = 3.14159265359;
-vec4 sampleTexture(sampler2D tex, bool enabled, int texcoord, vec3 factor, vec4 defaultColor) {
- if(enabled && texcoord == 0) {
- return texture(tex, fragTexcoord0) * vec4(factor, 1.0);
- } else if(enabled && texcoord == 1) {
- return texture(tex, fragTexcoord1) * vec4(factor, 1.0);
- } else {
- return defaultColor;
- }
-}
-
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0);
@@ -130,12 +129,19 @@ vec2 texcoord(int i) {
}
}
+vec4 sRGBtoLinear(vec4 srgb) {
+ return vec4(pow(srgb.r, 2.2),
+ pow(srgb.g, 2.2),
+ pow(srgb.b, 2.2),
+ srgb.a);
+}
+
float materialMetallic() {
float m = material.metallicFactor;
if(material.metallicRoughnessTextureEnabled) {
- m *= texture2D(metallicRoughnessTexture,
- texcoord(material.metallicRoughnessTexcoord)).b;
+ m *= texture(metallicRoughnessTexture,
+ texcoord(material.metallicRoughnessTexcoord)).b;
}
return m;
@@ -145,8 +151,8 @@ float materialRoughness() {
float r = material.roughnessFactor;
if(material.metallicRoughnessTextureEnabled) {
- r *= texture2D(metallicRoughnessTexture,
- texcoord(material.metallicRoughnessTexcoord)).g;
+ r *= texture(metallicRoughnessTexture,
+ texcoord(material.metallicRoughnessTexcoord)).g;
}
return r;
@@ -156,8 +162,9 @@ vec4 materialAlbedo() {
vec4 color = vec4(0.0, 0.0, 1.0, 1.0);
if(material.baseColorTextureEnabled) {
- color = texture2D(baseColorTexture,
- texcoord(material.baseColorTexcoord));
+ vec4 texColor = texture(baseColorTexture,
+ texcoord(material.baseColorTexcoord));
+ color = sRGBtoLinear(texColor);
}
color *= vec4(material.baseColorFactor, 1.0);
@@ -169,23 +176,33 @@ vec4 materialAlbedo() {
return color;
}
-vec3 materialOcclusion() {
- vec3 color = vec3(0.0);
+vec4 materialEmissive() {
+ vec4 color = vec4(0.0);
- if(material.occlusionTextureEnabled) {
- color = texture2D(occlusionTexture,
- texcoord(material.occlusionTexcoord)).rgb;
+ if(material.emissiveTextureEnabled) {
+ vec4 texColor = texture(emissiveTexture,
+ texcoord(material.emissiveTexcoord));
+ color = sRGBtoLinear(texColor);
}
- return color * material.occlusionFactor;
+ return color * vec4(material.emissiveFactor, 1.0);
+}
+
+vec3 materialOcclusion() {
+ if(material.occlusionTextureEnabled) {
+ return vec3(texture(occlusionTexture,
+ texcoord(material.occlusionTexcoord)).r);
+ } else {
+ return vec3(1.0);
+ }
}
vec3 materialNormal() {
vec3 normal;
if(material.normalTextureEnabled) {
- normal = texture2D(normalTexture,
- texcoord(material.normalTexcoord)).rgb * 2.0 - 1.0;
+ normal = texture(normalTexture,
+ texcoord(material.normalTexcoord)).rgb * 2.0 - 1.0;
} else {
normal = fragNormal;
}
@@ -193,38 +210,52 @@ vec3 materialNormal() {
return normalize(normal);
}
-struct PointLight {
- vec3 position;
- vec3 color;
-};
-
-PointLight lights[1];
-vec3 ambientLightColor = vec3(0.05);
-
void main(void) {
- // TODO: Support user supplied lights.
- lights[0].position = vec3(0.0, 0.2, 2.0);
- lights[0].color = vec3(1.0, 1.0, 1.0);
-
float metallic = materialMetallic();
float roughness = materialRoughness();
vec3 N = materialNormal();
- vec3 V = normalize(-fragCamPos - fragWorldPos);
- vec3 albedo = materialAlbedo().rgb;
+ vec3 V = normalize(cameraPosition - fragWorldPos);
+ vec4 rawAlbedo = materialAlbedo();
+ vec3 albedo = rawAlbedo.rgb;
vec3 ao = materialOcclusion();
vec3 F0 = mix(vec3(0.4), albedo, metallic);
// reflectance equation
vec3 Lo = vec3(0.0);
- for(int i = 0; i < 1; ++i)
+ for(int i = 0; i < 4; ++i)
{
- PointLight light = lights[i];
+ Light light = lights[i];
+
+ if(!light.enabled) {
+ continue;
+ }
+
+ vec3 L;
+ vec3 radiance;
+
// calculate per-light radiance
- vec3 L = normalize(light.position - fragWorldPos);
+ if(light.type == 0) { // point light
+ L = normalize(light.position - fragWorldPos);
+ float distance = length(light.position - fragWorldPos);
+ float attenuation = 1.0 / (distance * distance);
+ radiance = light.color.rgb * attenuation;
+ } else if(light.type == 1) { // directional light
+ L = normalize(-light.direction);
+ radiance = light.color.rgb;
+ } else if(light.type == 2) { // spotlight
+ L = normalize(light.position - fragWorldPos);
+ float theta = dot(L, normalize(-light.direction));
+
+ if(theta > light.cutOff) {
+ float distance = length(light.position - fragWorldPos);
+ float attenuation = 1.0 / (distance * distance);
+ radiance = light.color.rgb * attenuation;
+ } else {
+ continue;
+ }
+ }
+
vec3 H = normalize(V + L);
- float distance = length(light.position - fragWorldPos);
- float attenuation = 1.0 / (distance * distance);
- vec3 radiance = light.color * attenuation;
// cook-torrance brdf
float NDF = DistributionGGX(N, H, roughness);
@@ -244,23 +275,18 @@ void main(void) {
Lo += (kD * albedo / PI + specular) * radiance * NdotL;
}
- // TODO: Process emissive color properly.
- Lo += sampleTexture(emissiveTexture,
- material.emissiveTextureEnabled,
- material.emissiveTexcoord,
- material.emissiveFactor,
- vec4(0.0, 0.0, 0.0, 0.0)).xyz;
+ // Add emissive color.
+ Lo += materialEmissive().rgb;
// Apply ambient lighting.
- vec3 ambient = ambientLightColor * albedo * ao;
+ vec3 ambient = ambientLightColor.xyz * albedo * ao;
vec3 color = ambient + Lo;
// Apply HDR.
color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0 / 2.2));
- // TODO: Preserve alpha channel throughout lighting.
- vec4 finalColor = applyAlpha(vec4(color, 1.0));
+ vec4 finalColor = applyAlpha(vec4(color, rawAlbedo.a));
#ifdef GLSL330
fragColor = finalColor;
diff --git a/data/shaders/pbr-vert.glsl b/data/shaders/pbr-vert.glsl
index 530c564..bf43e81 100644
--- a/data/shaders/pbr-vert.glsl
+++ b/data/shaders/pbr-vert.glsl
@@ -21,14 +21,12 @@ attribute vec4 color0;
#ifdef GLSL120
varying vec3 fragWorldPos;
-varying vec3 fragCamPos;
varying vec3 fragNormal;
varying vec2 fragTexcoord0;
varying vec2 fragTexcoord1;
varying vec4 fragColor0;
#else
out vec3 fragWorldPos;
-out vec3 fragCamPos;
out vec3 fragNormal;
out vec2 fragTexcoord0;
out vec2 fragTexcoord1;
@@ -40,11 +38,10 @@ uniform mat4 view;
uniform mat4 projection;
void main(void) {
- fragWorldPos = (model * vec4(position.xyz, 1.0)).xyz;
- fragCamPos = (view * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
- fragNormal = normal;
+ fragWorldPos = vec3(model * vec4(position, 1.0));
+ fragNormal = mat3(model) * normal;
fragTexcoord0 = texcoord0;
fragTexcoord1 = texcoord1;
fragColor0 = color0;
- gl_Position = projection * view * model * vec4(position.xyz, 1.0);
+ gl_Position = projection * view * vec4(fragWorldPos, 1.0);
}