Skip to content

Instantly share code, notes, and snippets.

@highfestiva
Last active July 14, 2022 17:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save highfestiva/3cbd9ab9eedea3aa51270a8e5a93f27b to your computer and use it in GitHub Desktop.
Save highfestiva/3cbd9ab9eedea3aa51270a8e5a93f27b to your computer and use it in GitHub Desktop.
Rotating WebGL Donut
<html>
<head>
</head>
<body>
<canvas style="width:100%; height:100%;"></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script type="text/javascript">
const o = {
sectionVerts: 30,
sections: 60,
innerRad: 0.8,
outerRad: 2,
makeVerts() {
this.vertices = [];
this.indices = [];
this.normals = [];
this.texCoords = [];
for (let sectionVert = 0; sectionVert <= this.sectionVerts; ++sectionVert) {
const v = sectionVert / this.sectionVerts;
const slice_angle = v * 2 * Math.PI;
const cos_slices = Math.cos(slice_angle);
const sin_slices = Math.sin(slice_angle);
const slice_rad = this.outerRad + this.innerRad * cos_slices;
for (let section = 0; section <= this.sections; ++section) {
// x=(R+r·cos(v))cos(w)
// y=(R+r·cos(v))sin(w)
// z=r.sin(v)
const u = section / this.sections;
const loop_angle = u * 2 * Math.PI;
const cos_loops = Math.cos(loop_angle);
const sin_loops = Math.sin(loop_angle);
const x = slice_rad * cos_loops;
const y = slice_rad * sin_loops;
const z = this.innerRad * sin_slices;
this.vertices.push(x, y, z);
this.normals.push(
cos_loops * cos_slices,
sin_loops * cos_slices,
sin_slices);
this.texCoords.push(u);
this.texCoords.push(v);
}
}
// 0 1 2 3 4 5
// 6 7 8 9 10 11
// 12 13 14 15 16 17
const vertsPerSlice = this.sections + 1;
for (let i = 0; i < this.sectionVerts; ++i) {
let v1 = i * vertsPerSlice;
let v2 = v1 + vertsPerSlice;
for (let j = 0; j < this.sections; ++j) {
this.indices.push(v1);
this.indices.push(v1 + 1);
this.indices.push(v2);
this.indices.push(v2);
this.indices.push(v1 + 1);
this.indices.push(v2 + 1);
v1 += 1;
v2 += 1;
}
}
},
};
o.makeVerts();
const c = document.querySelector('canvas');
c.width = c.clientWidth;
c.height = c.clientHeight;
const gl = c.getContext('webgl');
const m4 = twgl.m4;
const vertexShader = `
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texcoord;
uniform mat4 u_matrix;
varying vec3 v_normal;
void main() {
gl_Position = u_matrix * (position + vec4(normal, 0));
v_normal = normal; // just for testing
//v_normal = vec3(texcoord, 0); // comment in to see texcoords
gl_PointSize = 3.0;
}
`;
const fragmentShader = `
precision highp float;
varying vec3 v_normal;
void main() {
gl_FragColor = vec4(v_normal * 0.5 + 0.5, 1);
}
`;
const programInfo = twgl.createProgramInfo(gl, [vertexShader, fragmentShader]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: o.vertices,
normal: o.normals,
texcoord: o.texCoords,
indices: o.indices,
});
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
gl.useProgram(programInfo.program);
function render(time) {
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
let mat = m4.perspective(
45 * Math.PI / 180, // fov
2, // aspect
0.1, // near
100, // far
);
mat = m4.translate(mat, [0, 0, -10]);
mat = m4.rotateY(mat, Math.sin(time * 0.00083) * 0.9);
mat = m4.rotateX(mat, Math.cos(time * 0.00053) * 0.5);
mat = m4.rotateZ(mat, time * 0.00227);
twgl.setUniforms(programInfo, { u_matrix: mat });
twgl.drawBufferInfo(gl, bufferInfo);
//twgl.drawBufferInfo(gl, bufferInfo, gl.POINTS);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment