|
@@ -0,0 +1,107 @@
|
|
|
+local glsl = {}
|
|
|
+local lightPosition = {}
|
|
|
+local headsetPosition = {}
|
|
|
+local controller = nil
|
|
|
+
|
|
|
+function lovr.load()
|
|
|
+ model = lovr.graphics.newModel('helmet/DamagedHelmet.gltf')
|
|
|
+ shader = lovr.graphics.newShader(unpack(glsl.pbr))
|
|
|
+ lovr.graphics.setBackgroundColor(.18, .18, .20)
|
|
|
+ lightPosition = { 75, 60, 20 }
|
|
|
+end
|
|
|
+
|
|
|
+function lovr.update(dt)
|
|
|
+ controller = lovr.headset.getControllers()[1]
|
|
|
+ if controller then lightPosition = { controller:getPosition() } end
|
|
|
+ headsetPosition = { lovr.headset.getPosition() }
|
|
|
+
|
|
|
+ shader:send('lightPosition', lightPosition)
|
|
|
+ shader:send('headsetPosition', headsetPosition)
|
|
|
+end
|
|
|
+
|
|
|
+function lovr.draw()
|
|
|
+ lovr.graphics.setShader(shader)
|
|
|
+ model:draw(0, 1.6, -1.5, .4, lovr.timer.getTime() * .12 + .1)
|
|
|
+ lovr.graphics.setShader()
|
|
|
+
|
|
|
+ if controller then
|
|
|
+ local x, y, z = unpack(lightPosition)
|
|
|
+ lovr.graphics.setColor(1, 1, 1)
|
|
|
+ lovr.graphics.sphere(x, y, z, .01)
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+glsl.pbr = {
|
|
|
+[[
|
|
|
+out vec3 vNormal;
|
|
|
+out vec3 vVertex;
|
|
|
+
|
|
|
+vec4 position(mat4 projection, mat4 transform, vec4 vertex) {
|
|
|
+ vNormal = mat3(lovrModel) * lovrNormal;
|
|
|
+ vVertex = vec3(lovrModel * vertex);
|
|
|
+ return projection * lovrView * vec4(vVertex, 1.0);
|
|
|
+}
|
|
|
+]],
|
|
|
+
|
|
|
+[[
|
|
|
+#define PI 3.141592653
|
|
|
+
|
|
|
+in vec3 vNormal;
|
|
|
+in vec3 vVertex;
|
|
|
+
|
|
|
+uniform vec3 headsetPosition;
|
|
|
+uniform vec3 lightPosition;
|
|
|
+
|
|
|
+float D_GGX(float NoH, float roughness) {
|
|
|
+ float alpha = roughness * roughness;
|
|
|
+ float alpha2 = alpha * alpha;
|
|
|
+ float denom = (NoH * NoH) * (alpha2 - 1.) + 1.;
|
|
|
+ return alpha2 / (PI * denom * denom);
|
|
|
+}
|
|
|
+
|
|
|
+float G_SmithGGXCorrelated(float NoV, float NoL, float roughness) {
|
|
|
+ float alpha = roughness * roughness;
|
|
|
+ float alpha2 = alpha * alpha;
|
|
|
+ float GGXV = NoL * sqrt(alpha2 + (1. - alpha2) * (NoV * NoV));
|
|
|
+ float GGXL = NoV * sqrt(alpha2 + (1. - alpha2) * (NoL * NoL));
|
|
|
+ return .5 / max(GGXV + GGXL, 1e-5);
|
|
|
+}
|
|
|
+
|
|
|
+vec3 F_Schlick(vec3 F0, float LoH) {
|
|
|
+ return F0 + (vec3(1.) - F0) * pow(1. - LoH, 5.);
|
|
|
+}
|
|
|
+
|
|
|
+vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) {
|
|
|
+ vec3 baseColor = texture(lovrDiffuseTexture, uv).rgb;
|
|
|
+ vec3 emissive = texture(lovrEmissiveTexture, uv).rgb;
|
|
|
+ float metalness = texture(lovrMetalnessTexture, uv).b * lovrMetalness;
|
|
|
+ float roughness = max(texture(lovrRoughnessTexture, uv).g * lovrRoughness, .05);
|
|
|
+ float occlusion = texture(lovrOcclusionTexture, uv).r;
|
|
|
+ vec3 F0 = mix(vec3(.04), baseColor, metalness);
|
|
|
+
|
|
|
+ vec3 N = normalize(vNormal);
|
|
|
+ vec3 V = normalize(headsetPosition - vVertex);
|
|
|
+ vec3 L = normalize(lightPosition - vVertex);
|
|
|
+ vec3 H = normalize(V + L);
|
|
|
+
|
|
|
+ float NoV = abs(dot(N, V)) + 1e-5;
|
|
|
+ float NoL = clamp(dot(N, L), 0., 1.);
|
|
|
+ float NoH = clamp(dot(N, H), 0., 1.);
|
|
|
+ float LoH = clamp(dot(L, H), 0., 1.);
|
|
|
+
|
|
|
+ float D = D_GGX(NoH, roughness);
|
|
|
+ float G = G_SmithGGXCorrelated(NoV, NoL, roughness);
|
|
|
+ vec3 F = F_Schlick(F0, LoH);
|
|
|
+
|
|
|
+ vec3 specular = vec3(D * G * F);
|
|
|
+ vec3 diffuse = (vec3(1.) - F) * (1. - metalness) * baseColor;
|
|
|
+ vec3 color = (diffuse + specular) * NoL * occlusion + emissive;
|
|
|
+
|
|
|
+]] ..
|
|
|
+(lovr.getOS() == 'Web' and ' color = pow(color, vec3(.4545));\n' or '') ..
|
|
|
+[[
|
|
|
+
|
|
|
+ return vec4(vec3(color), 1.);
|
|
|
+}
|
|
|
+]]
|
|
|
+}
|