Created
September 23, 2019 12:16
-
-
Save s4y/28ccf14a7eb3629f238ffad27d6ac38d to your computer and use it in GitHub Desktop.
A ray marched cube (runs in Pythonista)
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
# coding: utf-8 | |
import scene | |
import motion | |
preamble = """ | |
precision highp float; | |
varying vec2 v_tex_coord; | |
uniform vec2 u_sprite_size; | |
uniform sampler2D u_texture; | |
uniform float u_time; | |
uniform vec3 u_tilt; | |
float aspect = | |
u_sprite_size.x / u_sprite_size.y; | |
""" | |
shader = scene.Shader(preamble + """ | |
float sdBox(vec3 p, vec3 b) { | |
vec3 d = abs(p) - b; | |
return length(max(d,0.0)) + min(max(d.x,max(d.y,d.z)),0.0); | |
} | |
mat4 rotX(float angle) { | |
return mat4( | |
1, 0, 0, 0, | |
0, cos(angle), -sin(angle), 0, | |
0, sin(angle), cos(angle), 0, | |
0, 0, 0, 1 | |
); | |
} | |
mat4 rotY(float angle) { | |
return mat4( | |
cos(angle), 0, sin(angle), 0, | |
0, 1, 0, 0, | |
-sin(angle), 0, cos(angle), 0, | |
0, 0, 0, 1 | |
); | |
} | |
mat4 rotZ(float angle) { | |
return mat4( | |
cos(angle), -sin(angle), 0, 0, | |
sin(angle), cos(angle), 0, 0, | |
0, 0, 1, 0, | |
0, 0, 0, 1 | |
); | |
} | |
vec3 transform(vec3 p, mat4 t) { | |
vec4 p4 = t * vec4(p, 1.0); | |
return p4.xyz / p4.w; | |
} | |
float ease(float t) { | |
return t*t/(2.*(t*t-t)+1.); | |
} | |
vec2 sceneDistance(vec3 p, vec3 tilt) { | |
vec3 boxP = (rotX(-u_tilt.y) * rotY(u_tilt.x) * vec4(p, 1.0)).xyz; | |
float dist = 1e10; | |
float color = 0.; | |
const int imax = 3; | |
for (int i=0; i<imax;i++) { | |
float slc = float(i)/float(imax)-1./float(imax); | |
float ezR = ease(clamp(mod(u_time+slc*0.5, 1.0)*2.0,0.,1.)); | |
bool which = mod(u_time+1./3., 2.0)>1.0; | |
float ezTot = ease(clamp(mod(u_time+(1./float(imax)), 1.0)*1.0,0.,1.)); | |
float rotAmt = ezR*(atan(-1.)*2.0); | |
vec3 sliceP = (rotX(rotAmt) * rotZ(which?atan(-1.)*2.:0.) * vec4(boxP, 1.0)).xyz; | |
sliceP.x += slc*(0.5+(0.5-abs(0.5-ezTot))*0.25); | |
float ndist = sdBox( | |
sliceP, vec3(0.25/float(imax),0.25,0.25)); | |
if (ndist < dist) { | |
dist = ndist; | |
color = 0.25+pow(abs(sliceP.x)*8.0, 4.)*(0.5-abs(0.5-ezTot))*1.0; | |
} | |
} | |
return vec2(dist, color); | |
} | |
const int kMarchSteps = 40; | |
const float kEpsilon = 0.0001; | |
void main() { | |
vec3 p = vec3(v_tex_coord, 0.5) * 2.0 - 1.0; | |
vec3 tilt = u_tilt; | |
p.x *= aspect; | |
p.z += 1.0; | |
float dist = 0.0; | |
float ldist = 1.0/0.0; | |
float color = 0.0; | |
for (int i = 0; i < kMarchSteps; i++) { | |
vec2 ret = sceneDistance(p + vec3(0.0, 0.0, -dist) , tilt); | |
ldist = ret[0]; | |
color = ret[1]; | |
dist += ldist; | |
if (dist > 10.) | |
discard; | |
if (ldist < kEpsilon) | |
break; | |
} | |
float bri = max(dist, 0.0); | |
bri=max(0.0,1.8-dist); | |
bri=pow(bri,0.5); | |
bri = pow(bri, 2.0); | |
gl_FragColor = vec4(color, 1.0-color, 1.0, 1.0) * bri; | |
} | |
""") | |
class Scene (scene.Scene): | |
def setup(self): | |
motion.start_updates() | |
self.sprite = scene.SpriteNode(parent=self) | |
self.sprite.shader = shader | |
self.did_change_size() | |
self.background_color = 'black'; | |
def update(self): | |
self.sprite.shader.set_uniform( | |
'u_tilt', motion.get_attitude()) | |
def did_change_size(self): | |
self.sprite.position = self.size/2 | |
self.sprite.size = self.size | |
s = Scene() | |
scene.run(s) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment