WebGL rotating F: Difference between revisions

J
m (syntax highlighting fixup automation)
(J)
Line 12:
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}}==
6,951

edits