Reputation: 1207
I'm trying to render a torus using webgl. I'm using a third party library which makes this process easier: I only have to declare the various vertices, their normals and their indexes. Each tuple of 3 indexes draws a triangle and the vertices must follow the right hand rule.
So far this is what I have:
this.vertices = [];
this.indices = [];
this.normals = [];
this.texCoords = [];
let slices_angle = 0;
let loops_angle = 0;
let slices_delta = (2 * Math.PI) / this.slices;
let loops_delta = (2 * Math.PI) / this.loops;
let abc = 0;
while (slices_angle < 2 * Math.PI + slices_delta) {
let cos_slices = Math.cos(slices_angle);
let sin_slices = Math.sin(slices_angle);
let cos_loops = Math.cos(loops_angle);
let sin_loops = Math.sin(loops_angle);
while (loops_angle < 2 * Math.PI + loops_delta) {
// x=(R+r·cos(v))cos(w)
// y=(R+r·cos(v))sin(w)
// z=r.sin(v)
let x = (this.outerRad + this.inner_rad * cos_slices) * cos_loops;
let y = (this.outerRad + this.inner_rad * cos_slices) * sin_loops;
let z = this.inner_rad * sin_slices;
this.vertices.push(x, y, z);
this.normals.push(x, y, z);
// this.texCoords.push(j / this.slices);
// this.texCoords.push(i / this.stacks);
loops_angle += loops_delta;
}
slices_angle += slices_delta;
}
for (var i = 0; i < this.loops; i++) {
let v1 = i * (this.slices + 1);
let v2 = v1 + this.slices + 1;
for (var j = 0; j < this.slices; j++) {
this.indices.push(v1);
this.indices.push(v2);
this.indices.push(v1 + 1);
this.indices.push(v1 + 1);
this.indices.push(v2);
this.indices.push(v2 + 1);
v1++;
v2++;
}
}
I had the help of this website in order to declare the coordinates of the vertices but I'm having problems with the indexes.
Upvotes: 2
Views: 1756
Reputation:
The code doesn't make a lot of sense at a glance. You've got an inner and outer loop
In the inner loop this code computes a vertex
let x = (this.outerRad + this.inner_rad * cos_slices) * cos_loops;
let y = (this.outerRad + this.inner_rad * cos_slices) * sin_loops;
let z = this.inner_rad * sin_slices;
this.vertices.push(x, y, z);
this.normals.push(x, y, z);
But nothing about those calculations change inside the inner loop
The normals can't be x, y, z (the same as the positions).
Also you need to make loops + 1 and slices + 1 vertices. The vertices start vertex of each loop, slice will have the same position but it will not have the same texture coordinate.
Then as far as your indices go each slice as (loops + 1) vertices so I think the loops in the code are backward.
If it was me, rather than loop based on the angles I'd loop based on the loops and slices
for (slice = 0; slice < this.slices; ++slice) {
for (loop = 0; loop < this.loops; ++loop) {
...
So here's another version
const o = {
slices: 8,
loops: 20,
inner_rad: 0.5,
outerRad: 2,
makeVerts() {
this.vertices = [];
this.indices = [];
this.normals = [];
this.texCoords = [];
for (let slice = 0; slice <= this.slices; ++slice) {
const v = slice / this.slices;
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.inner_rad * cos_slices;
for (let loop = 0; loop <= this.loops; ++loop) {
// x=(R+r·cos(v))cos(w)
// y=(R+r·cos(v))sin(w)
// z=r.sin(v)
const u = loop / this.loops;
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.inner_rad * sin_slices;
this.vertices.push(x, y, z);
this.normals.push(
cos_loops * sin_slices,
sin_loops * sin_slices,
cos_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.loops + 1;
for (let i = 0; i < this.slices; ++i) {
let v1 = i * vertsPerSlice;
let v2 = v1 + vertsPerSlice;
for (let j = 0; j < this.loops; ++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;
}
}
//this.indices = undefined;
},
};
o.makeVerts();
// -------------- ignore below this line -------------
const gl = document.querySelector('canvas').getContext('webgl');
const m4 = twgl.m4;
const vs = `
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texcoord;
uniform mat4 u_matrix;
varying vec3 v_normal;
void main() {
gl_Position = u_matrix * position;
v_normal = normal; // just for testing
//v_normal = vec3(texcoord, 0); // comment in to see texcoords
gl_PointSize = 3.0;
}
`;
const fs = `
precision highp float;
varying vec3 v_normal;
void main() {
gl_FragColor = vec4(v_normal * 0.5 + 0.5, 1);
}
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
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, -7]);
mat = m4.rotateY(mat, time * 0.001);
mat = m4.rotateX(mat, time * 0.0005);
twgl.setUniforms(programInfo, { u_matrix: mat });
twgl.drawBufferInfo(gl, bufferInfo);
//twgl.drawBufferInfo(gl, bufferInfo, gl.POINTS);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
Upvotes: 5