Created
May 22, 2016 00:34
-
-
Save sudonhim/9e43c255edcb45519fe6ddc612ab1ac5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifdef GL_ES | |
precision mediump float; | |
#endif | |
#extension GL_OES_standard_derivatives : enable | |
uniform float time; | |
uniform vec2 mouse; | |
uniform vec2 resolution; | |
const float speed = 0.5; | |
const float planetRadius = 60.0; | |
const float cameraHeightAboveSurface = 5.0; | |
// Forward declaration of simplex noise function, see bottom of file | |
float snoise(vec3 v); | |
bool notEmpty(ivec3 p) | |
{ | |
vec3 fp = vec3(p); | |
float x = fp.x; | |
float theta = atan(fp.y, fp.z); | |
float r = length(vec3(p)); | |
r -= abs(x); | |
r += sin(theta*10.0); | |
return r < planetRadius; | |
} | |
// Intersect the scene with a DDA (discrete digital analyzer) | |
bool intersect(vec3 ro, vec3 rd, out ivec3 hitCube, out float hitDist, out vec3 normal) | |
{ | |
bool success = false; | |
ivec3 mapPos = ivec3(floor(ro)); | |
vec3 deltaDist = abs(vec3(length(rd)) / rd); | |
ivec3 rayStep = ivec3(sign(rd)); | |
vec3 sideDist = (sign(rd) * (vec3(mapPos) - ro) + (sign(rd) * 0.5) + 0.5) * deltaDist; | |
bvec3 mask; | |
for (int i = 0; i < 64; i++) { | |
if (notEmpty(mapPos)) {success = true; break;} | |
if (sideDist.x < sideDist.y) { | |
if (sideDist.x < sideDist.z) { | |
sideDist.x += deltaDist.x; | |
mapPos.x += rayStep.x; | |
mask = bvec3(true, false, false); | |
} | |
else { | |
sideDist.z += deltaDist.z; | |
mapPos.z += rayStep.z; | |
mask = bvec3(false, false, true); | |
} | |
} | |
else { | |
if (sideDist.y < sideDist.z) { | |
sideDist.y += deltaDist.y; | |
mapPos.y += rayStep.y; | |
mask = bvec3(false, true, false); | |
} | |
else { | |
sideDist.z += deltaDist.z; | |
mapPos.z += rayStep.z; | |
mask = bvec3(false, false, true); | |
} | |
} | |
} | |
hitCube = mapPos; | |
hitDist = length((sideDist - deltaDist)*vec3(mask)); | |
normal = -sign(rd)*vec3(mask); | |
return success; | |
} | |
void cameraTransform(inout vec3 ro, inout vec3 rd) | |
{ | |
// Move over the planet with time | |
float theta = time*speed/5.0; | |
float c = cos(theta); | |
float s = sin(theta); | |
mat3 rot = mat3( | |
1.0, 0.0, 0.0, | |
0.0, c, -s, | |
0.0, s, c | |
); | |
rd *= rot; | |
ro *= rot; | |
// Look down a little bit | |
theta = 0.4; | |
c = cos(theta); | |
s = sin(theta); | |
rot = mat3( | |
1.0, 0.0, 0.0, | |
0.0, c, -s, | |
0.0, s, c | |
); | |
rd *= rot; | |
// Rotate ray direction horizontally a little | |
theta = snoise(ro/planetRadius+time/16.0); | |
c = cos(theta); | |
s = sin(theta); | |
rot = mat3( | |
c, 0.0, s, | |
0.0, 1.0, 0.0, | |
-s, 0.0, c | |
); | |
rd *= rot; | |
} | |
// Return how close this point is to a block edge | |
float edgeDetect(vec3 pos) | |
{ | |
vec3 dists = min(fract(abs(pos)), 1.0-fract(abs(pos))); | |
float sum = dists.x + dists.y + dists.z; | |
return sum - max(dists.x, max(dists.y, dists.z)); | |
} | |
vec3 hashPosition(ivec3 p) | |
{ | |
return | |
sin( | |
vec3(p.xyz)*294.234 | |
+ vec3(p.yzx)*43.24 | |
+ vec3(p.zxy)*234.22 | |
)*0.5+0.5; | |
} | |
// Return the position of a point light source a bit ahead of the camera | |
vec3 lightPosition(vec3 ro) | |
{ | |
// Rotate a little futher over the planet | |
float theta = 0.3; | |
float c = cos(theta); | |
float s = sin(theta); | |
mat3 rot = mat3( | |
1.0, 0.0, 0.0, | |
0.0, c, -s, | |
0.0, s, c | |
); | |
return ro * rot; | |
} | |
vec3 snoise3(vec3 x) | |
{ | |
return vec3( | |
snoise(x), | |
snoise(x+2323.245), | |
snoise(x+3984.2423) | |
); | |
} | |
vec3 lightColorFromDirection(vec3 lightDir) | |
{ | |
lightDir.x += time/6.0; | |
float i1 = snoise(lightDir*3.0); | |
float i2 = snoise((lightDir+32.421)*3.0); | |
float t = mix(i1, i2, 0.5+0.5*sin(time)); | |
t = 0.2 + 0.6*t; | |
vec3 c1 = vec3(1.0, 1.0, 0.0); | |
vec3 c2 = vec3(0.3, 0.1, 0.0); | |
return mix(c1, c2, t); | |
} | |
vec3 perturbNormal(vec3 normal, vec3 incident, vec3 props) | |
{ | |
float freq = 20.0; | |
float strength = 0.2; | |
vec3 noise = snoise3(incident*freq); | |
return normalize(mix(normal, noise, strength)); | |
} | |
vec3 doLighting(vec3 ro, vec3 rd, float hitDist, ivec3 hitCube, vec3 normal) | |
{ | |
vec3 incident = ro + hitDist*rd; | |
float edgeDist = edgeDetect(incident); | |
float edgeAdj = smoothstep(0.1, 0.0, edgeDist); | |
vec3 props = hashPosition(hitCube); | |
normal = perturbNormal(normal, incident, props); | |
vec3 lightPos = lightPosition(ro); | |
vec3 lightDisp = incident - lightPos; | |
vec3 lightDir = normalize(lightDisp); | |
float brightness = 1.0/(1.0+length(lightDisp)); | |
float diffuse = max(dot(normal, -lightDir), 0.0)*brightness; | |
float ambient = brightness; | |
vec3 reflDir = reflect(rd, normal); | |
float specular = pow(max(dot(reflDir, -lightDir), 0.0), 8.0); | |
vec3 lightColor = lightColorFromDirection(lightDir); | |
vec3 color = vec3(0.0); | |
color += diffuse*lightColor; | |
color += 0.2*ambient*vec3(1.0); | |
color += 0.2*specular*lightColor; | |
color += props*edgeAdj*0.2; | |
return log(1.0+color)*log(2.0)/log(4.0); | |
} | |
bool intersectLightSource(vec3 ro, vec3 rd, out float hitDist) | |
{ | |
bool success = false; | |
float radius = 2.0; | |
vec3 lightPos = lightPosition(ro); | |
float a = dot(rd, rd); | |
float b = 2.0 * dot(rd, ro - lightPos); | |
float c = dot(lightPos, lightPos) + dot(ro, ro) - 2.0 * dot(lightPos, ro) - radius*radius; | |
float det = b*b-4.0*a*c; | |
if (det < 0.0) return false; | |
else | |
{ | |
hitDist = (-b - sqrt(det))/(2.0*a); | |
return true; | |
} | |
} | |
vec3 doLightingLightSource(vec3 ro, vec3 hitPos) | |
{ | |
vec3 lightDir = normalize(hitPos - lightPosition(ro)); | |
return lightColorFromDirection(lightDir); | |
} | |
void main( void ) { | |
vec2 uv = ( gl_FragCoord.xy / resolution.xy ); | |
vec2 p = uv - 0.5; | |
p.y *= resolution.y/resolution.x; | |
vec3 ro = vec3(0.0, planetRadius + cameraHeightAboveSurface, 0.0); | |
vec3 rd = normalize(vec3(p*1.5, 1.0)); | |
cameraTransform(ro, rd); | |
// Intersect the scene | |
ivec3 hitCube; | |
float hitDist; | |
vec3 normal; | |
bool hitCubes = intersect(ro, rd, hitCube, hitDist, normal); | |
// Intersect the light source | |
float hitDist2; | |
bool hitLight = intersectLightSource(ro, rd, hitDist2); | |
// If hit both, show the closest | |
if (hitCubes && hitLight && (hitDist < hitDist2)) hitLight = false; | |
vec3 color = vec3(0.0); | |
if (hitLight) { | |
color = doLightingLightSource(ro, hitDist2*rd + ro); | |
} else if (hitCubes) { | |
color = doLighting(ro, rd, hitDist, hitCube, normal); | |
} else { | |
} | |
gl_FragColor = vec4( color, 1.0 ); | |
} | |
// | |
// Description : Array and textureless GLSL 2D/3D/4D simplex | |
// noise functions. | |
// Author : Ian McEwan, Ashima Arts. | |
// Maintainer : ijm | |
// Lastmod : 20110822 (ijm) | |
// License : Copyright (C) 2011 Ashima Arts. All rights reserved. | |
// Distributed under the MIT License. See LICENSE file. | |
// https://github.com/ashima/webgl-noise | |
// | |
vec3 mod289(vec3 x) { | |
return x - floor(x * (1.0 / 289.0)) * 289.0; | |
} | |
vec4 mod289(vec4 x) { | |
return x - floor(x * (1.0 / 289.0)) * 289.0; | |
} | |
vec4 permute(vec4 x) { | |
return mod289(((x*34.0)+1.0)*x); | |
} | |
vec4 taylorInvSqrt(vec4 r) | |
{ | |
return 1.79284291400159 - 0.85373472095314 * r; | |
} | |
float snoise(vec3 v) | |
{ | |
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; | |
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); | |
// First corner | |
vec3 i = floor(v + dot(v, C.yyy) ); | |
vec3 x0 = v - i + dot(i, C.xxx) ; | |
// Other corners | |
vec3 g = step(x0.yzx, x0.xyz); | |
vec3 l = 1.0 - g; | |
vec3 i1 = min( g.xyz, l.zxy ); | |
vec3 i2 = max( g.xyz, l.zxy ); | |
// x0 = x0 - 0.0 + 0.0 * C.xxx; | |
// x1 = x0 - i1 + 1.0 * C.xxx; | |
// x2 = x0 - i2 + 2.0 * C.xxx; | |
// x3 = x0 - 1.0 + 3.0 * C.xxx; | |
vec3 x1 = x0 - i1 + C.xxx; | |
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y | |
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y | |
// Permutations | |
i = mod289(i); | |
vec4 p = permute( permute( permute( | |
i.z + vec4(0.0, i1.z, i2.z, 1.0 )) | |
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 )) | |
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 )); | |
// Gradients: 7x7 points over a square, mapped onto an octahedron. | |
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) | |
float n_ = 0.142857142857; // 1.0/7.0 | |
vec3 ns = n_ * D.wyz - D.xzx; | |
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) | |
vec4 x_ = floor(j * ns.z); | |
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) | |
vec4 x = x_ *ns.x + ns.yyyy; | |
vec4 y = y_ *ns.x + ns.yyyy; | |
vec4 h = 1.0 - abs(x) - abs(y); | |
vec4 b0 = vec4( x.xy, y.xy ); | |
vec4 b1 = vec4( x.zw, y.zw ); | |
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; | |
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; | |
vec4 s0 = floor(b0)*2.0 + 1.0; | |
vec4 s1 = floor(b1)*2.0 + 1.0; | |
vec4 sh = -step(h, vec4(0.0)); | |
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; | |
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; | |
vec3 p0 = vec3(a0.xy,h.x); | |
vec3 p1 = vec3(a0.zw,h.y); | |
vec3 p2 = vec3(a1.xy,h.z); | |
vec3 p3 = vec3(a1.zw,h.w); | |
//Normalise gradients | |
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); | |
p0 *= norm.x; | |
p1 *= norm.y; | |
p2 *= norm.z; | |
p3 *= norm.w; | |
// Mix final noise value | |
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); | |
m = m * m; | |
return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), | |
dot(p2,x2), dot(p3,x3) ) ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment