// surfman/resources/examples/check.fs.glsl precision highp float; uniform vec2 uViewportOrigin; uniform vec2 uSpherePosition; uniform vec3 uRotation; uniform vec4 uColorA; uniform vec4 uColorB; uniform vec3 uCameraPosition; uniform vec3 uLightPosition; uniform float uRadius; in vec2 vTexCoord; out vec4 oFragColor; const float PI = 3.14159; const float LIGHT_AMBIENT = 1.0; const float LIGHT_DIFFUSE = 1.0; const float LIGHT_SPECULAR = 1.0; const float MATERIAL_AMBIENT = 0.2; const float MATERIAL_DIFFUSE = 0.7; const float MATERIAL_SPECULAR = 0.1; const vec2 CHECKER_COUNTS = vec2(16.0, 8.0); // Hardcoded albedo of 16.0. Works around precision issues. float pow16(float n) { float n2 = n * n; float n4 = n2 * n2; float n8 = n4 * n4; return n8 * n8; } mat3 rotateZXY(vec3 theta) { vec3 tCos = cos(theta), tSin = sin(theta); vec4 zx = vec4(tSin.zz, tCos.zz) * vec4(tCos.x, tSin.xx, tCos.x); return mat3( tCos.y * tCos.z, -tCos.y * tSin.z, tSin.y, tSin.y * zx.z, -tSin.y * zx.y, -tCos.y * tSin.x, -tSin.y * zx.w, tSin.y * zx.x, tCos.y * tCos.x) + mat3(0.0, 0.0, 0.0, zx.x, zx.w, 0.0, zx.y, zx.z, 0.0); } bool raytraceSphere(vec3 rayOrigin, vec3 rayDirection, vec3 center, float radius, out vec3 outHitPosition, out vec3 outHitNormal) { vec3 originToCenter = center - rayOrigin; float tCA = dot(originToCenter, rayDirection); if (tCA < 0.0) return false; float d2 = dot(originToCenter, originToCenter) - tCA * tCA; float radiusSq = radius * radius; if (d2 > radiusSq) return false; float tHC = sqrt(radiusSq - d2); vec2 ts = vec2(tCA) + vec2(-tHC, tHC); ts = vec2(min(ts.x, ts.y), max(ts.x, ts.y)); float t = ts.x >= 0.0 ? ts.x : ts.y; if (t < 0.0) return false; vec3 hitPosition = rayOrigin + rayDirection * vec3(t); outHitPosition = hitPosition; outHitNormal = normalize(hitPosition - center); return true; } void main() { vec3 rayOrigin = uCameraPosition; vec3 rayDirection = normalize(vec3(gl_FragCoord.xy + uViewportOrigin, 0.0) - rayOrigin); vec3 center = vec3(uSpherePosition, 0.0); vec3 hitPosition, normal; bool hit = raytraceSphere(rayOrigin, rayDirection, center, uRadius, hitPosition, normal); if (!hit) { oFragColor = vec4(0.0); return; } // Hack: Just rotate the texture instead of rotating the sphere. vec3 texNormal = rotateZXY(uRotation) * normal; vec2 uv = vec2((1.0 + atan(texNormal.z, texNormal.x) / PI) * 0.5, acos(texNormal.y) / PI) * CHECKER_COUNTS; ivec2 on = ivec2(greaterThanEqual(mod(uv, vec2(2.0)), vec2(1.0))); vec4 diffuse = ((on.x ^ on.y) > 0) ? uColorA : uColorB; vec3 lightDirection = normalize(uLightPosition - hitPosition); vec3 reflection = -reflect(lightDirection, normal); vec3 viewer = normalize(uCameraPosition - hitPosition); float intensity = LIGHT_AMBIENT * MATERIAL_AMBIENT + MATERIAL_DIFFUSE * dot(lightDirection, normal) * LIGHT_DIFFUSE + MATERIAL_SPECULAR * pow16(dot(reflection, viewer)) * LIGHT_SPECULAR; oFragColor = vec4(intensity * diffuse.rgb, diffuse.a); }