WebGL rotating F: Difference between revisions
Content added Content deleted
Thundergnat (talk | contribs) m (syntax highlighting fixup automation) |
(J) |
||
Line 12: | Line 12: | ||
Allow toggling between the F shape and a classic Utah teapot. |
Allow toggling between the F shape and a classic Utah teapot. |
||
=={{header|J}}== |
|||
Near as I can tell, the webgl requirement means that the task is asking for a wrapper for javascript (possibly encapsulated in a library). |
|||
Here, we'll use ray marching as that "feels sort of like J": |
|||
<syntaxhighlight lang=J>webgl_close=: {{ wd'pclose'}} |
|||
wd {{)n |
|||
pc webgl; cc w webview; |
|||
pmove 0 0 300 300; |
|||
pshow; |
|||
set w html * |
|||
<html><head><title>test</title></head> |
|||
<script> |
|||
function paint(t) { |
|||
gl.uniform1f(timeNdx, t/1e3); |
|||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); |
|||
requestAnimationFrame(paint); |
|||
} |
|||
function run(){ |
|||
c= document.querySelector("#c"); |
|||
gl= c.getContext("webgl"); |
|||
P= gl.createProgram(); |
|||
function setShader(typ, src) { |
|||
shader= gl.createShader(typ); |
|||
gl.shaderSource(shader, src); |
|||
gl.compileShader(shader); |
|||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) console.log(gl.getShaderInfoLog(shader)); |
|||
gl.attachShader(P, shader); |
|||
} |
|||
setShader(gl.VERTEX_SHADER, "attribute vec4 pos;void main(){gl_Position=pos;}") |
|||
setShader(gl.FRAGMENT_SHADER, ` |
|||
precision mediump float; |
|||
uniform vec2 res; |
|||
uniform float time; |
|||
mat3 rotateY(float theta) { |
|||
float c= cos(theta); |
|||
float s= sin(theta); |
|||
return mat3( |
|||
vec3(c, 0, s), |
|||
vec3(0, 1, 0), |
|||
vec3(-s, 0, c) |
|||
); |
|||
} |
|||
const int MAX_MARCHING_STEPS= 100; |
|||
const float MIN_DIST= 0.0; |
|||
const float MAX_DIST= 100.0; |
|||
float sdBox(vec3 position, vec3 box, vec3 offset) { |
|||
vec3 q= abs(position - offset) - box/2.0; |
|||
return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0); |
|||
} |
|||
float sdScene(vec3 p) { // distance to closest object |
|||
float dist= sdBox(p, vec3(1,4,1), vec3(0, 0.3, 0)); |
|||
dist= min(dist, sdBox(p, vec3(1,1,1), vec3(1, 0.3, 0))); |
|||
return min(dist, sdBox(p, vec3(2.5,1,1), vec3(0.75, 2.3, 0))); |
|||
} |
|||
float rayMarch(vec3 ro, vec3 rd, float start, float end) { |
|||
float depth= start; |
|||
for (int i= 0; i< MAX_MARCHING_STEPS; i++) { |
|||
if (depth < end) { |
|||
vec3 p= ro + depth * rd; |
|||
depth+= sdScene(p); |
|||
} |
|||
} |
|||
return depth; |
|||
} |
|||
vec3 calcNormal(in vec3 p) { |
|||
vec2 e= vec2(1.0, -1.0) * 0.0005; // epsilon |
|||
return normalize( |
|||
e.xyy * sdScene(p + e.xyy) + |
|||
e.yyx * sdScene(p + e.yyx) + |
|||
e.yxy * sdScene(p + e.yxy) + |
|||
e.xxx * sdScene(p + e.xxx)); |
|||
} |
|||
void main(){ |
|||
vec2 uv= (gl_FragCoord.xy-.5*res)/res.x; |
|||
mat3 rot= rotateY(time); |
|||
vec3 backgroundColor= vec3(0.835, 1, 1); |
|||
vec3 color; |
|||
vec3 ro= vec3(0, 0, 7)*rot; // ray origin that represents camera position |
|||
vec3 rd= normalize(vec3(uv, -1)*rot); // ray direction |
|||
float sd= rayMarch(ro, rd, MIN_DIST, MAX_DIST); // closest object |
|||
if (sd > MAX_DIST) { |
|||
color= backgroundColor; // ray didn't hit anything |
|||
} else { |
|||
vec3 p= ro + rd * sd; // point on cube we discovered from ray marching |
|||
vec3 normal= calcNormal(p); |
|||
vec3 lightPosition= vec3(2, 2, 7)*rot; |
|||
vec3 lightDirection= normalize(lightPosition - p); |
|||
float dif= clamp(dot(normal, lightDirection), 0.3, 1.); // diffuse reflection |
|||
color= dif * vec3(1,0,0) + backgroundColor * .2; // Add a bit of background color to the diffuse color |
|||
} |
|||
gl_FragColor= vec4(color, 1.0); |
|||
}`); |
|||
gl.linkProgram(P); |
|||
posNdx= gl.getAttribLocation(P, "pos"); |
|||
resNdx= gl.getUniformLocation(P, "res"); |
|||
timeNdx= gl.getUniformLocation(P, "time"); |
|||
posBuffer= gl.createBuffer(); |
|||
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer); |
|||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, -1,1, 1,-1, 1,1]), gl.STATIC_DRAW); |
|||
gl.viewport(0,0,c.width,c.height); |
|||
gl.clearColor(0,0,0,0); |
|||
gl.clear(gl.COLOR_BUFFER_BIT); |
|||
gl.useProgram(P); |
|||
gl.enableVertexAttribArray(posNdx); |
|||
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer); |
|||
gl.vertexAttribPointer(posNdx, 2, gl.FLOAT, false, 0, 0); |
|||
gl.uniform2fv(resNdx, [c.width, c.height]); |
|||
requestAnimationFrame(paint); |
|||
} |
|||
</script> |
|||
</head><body onload="run()"> |
|||
<canvas id="c" width=300 height=300></canvas> |
|||
</body></html> |
|||
}} |
|||
</syntaxhighlight> |
|||
Tested in J9.03 and the J9.04 beta. |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |