Reputation: 84519
This code should produce a mesh of a torus in three js. I'm pretty sure the maths are correct. However it renders only a piece of torus, or stranger things if I change some parameters. Is there something bad with my practice of THREE.Mesh ?
// the vertices of the mesh and the vertex normals ----------------
var nx = 64;
var ny = 32;
var R = 10; var r = 3;
var Vertices = new Array(nx);
var Normals = new Array(nx);
for (var i = 0; i < nx; i++) {
Vertices[i] = new Array(ny);
Normals[i] = new Array(ny);
var u = i / nx * 2 * Math.PI;
var cos_u = Math.cos(u);
var sin_u = Math.sin(u);
var cx = R * cos_u;
var cy = R * sin_u;
for (var j = 0; j < ny; j++) {
var v = j / ny * 2 * Math.PI;
var rcos_v = r * Math.cos(v);
var rsin_v = r * Math.sin(v);
Vertices[i][j] = new THREE.Vector3(
cx + rcos_v * cos_u,
cy + rcos_v * sin_u,
rsin_v
);
Normals[i][j] = new THREE.Vector3(
rcos_v * cos_u,
rcos_v * sin_u,
rsin_v
);
}
}
// vertices as a dot cloud ----------------------------------------
var dotGeometry = new THREE.Geometry();
for (var i = 0; i < nx; i++) {
for (var j = 0; j < ny; j++) {
dotGeometry.vertices.push(Vertices[i][j]);
}
}
var dotMaterial =
new THREE.PointsMaterial({ size: 1, sizeAttenuation: false });
var cloud = new THREE.Points(dotGeometry, dotMaterial);
// mesh -----------------------------------------------------------
var geom = new THREE.Geometry();
for (var i = 0; i < nx; i++) {
var ip1 = (i == nx - 1 ? 0 : i + 1);
for (var j = 0; j < ny; j++) {
var jp1 = (j == ny - 1 ? 0 : j + 1);
geom.vertices.push(Vertices[i][j]);
geom.vertices.push(Vertices[i][jp1]);
geom.vertices.push(Vertices[ip1][j]);
var vnormals1 =
[Normals[i][j], Normals[i][jp1], Normals[ip1][j]];
geom.faces.push(new THREE.Face3(
i * ny + j,
i * ny + jp1,
ip1 * ny + j,
vnormals1
));
geom.vertices.push(Vertices[i][jp1]);
geom.vertices.push(Vertices[ip1][jp1]);
geom.vertices.push(Vertices[ip1][j]);
var vnormals2 =
[Normals[i][jp1], Normals[ip1][jp1], Normals[ip1][j]];
geom.faces.push(new THREE.Face3(
i * ny + jp1,
ip1 * ny + jp1,
ip1 * ny + j,
vnormals2
));
}
}
var torusMesh = new THREE.Mesh(
geom,
new THREE.MeshNormalMaterial({ wireframe: false }));
// three js scene -------------------------------------------------
var scene = new THREE.Scene();
var aspect = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(50, aspect, 1, 10000);
camera.position.z = 30;
scene.add(camera);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var object = new THREE.Object3D();
object.add(torusMesh);
object.add(cloud);
scene.add(object);
renderer.render(scene, camera);
// animation ---------------------------------------------------------
var isDragging = false;
var previousMousePosition = {
x: 0,
y: 0
};
$(renderer.domElement).on('mousedown', function (e) {
isDragging = true;
}).on('mousemove', function (e) {
var deltaMove = {
x: e.offsetX - previousMousePosition.x,
y: e.offsetY - previousMousePosition.y
};
if (isDragging) {
var deltaRotationQuaternion = new THREE.Quaternion()
.setFromEuler(new THREE.Euler(
Math.PI / 180 * (deltaMove.y * 1),
Math.PI / 180 * (deltaMove.x * 1),
0,
'XYZ'
));
object.quaternion.multiplyQuaternions(deltaRotationQuaternion,
object.quaternion);
}
previousMousePosition = {
x: e.offsetX,
y: e.offsetY
};
});
$(document).on('mouseup', function (e) {
isDragging = false;
});
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function render() {
renderer.render(scene, camera);
requestAnimFrame(render);
}
render();
canvas {
width: 100%;
height: 100%
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.js"></script>
Upvotes: 0
Views: 315
Reputation: 31026
I think there were two problems with your code:
When using Geometry
, you define faces just by adding objects of type Face3
to the faces
array. The vertices of the geometry are defined just once. In your case, you can just do this:
geom.vertices = dotGeometry.vertices;
Besides, the winding order of your faces was not correct. You have to switch the first and third index.
// the vertices of the mesh and the vertex normals ----------------
var nx = 64;
var ny = 32;
var R = 10; var r = 3;
var Vertices = new Array(nx);
var Normals = new Array(nx);
for (var i = 0; i < nx; i++) {
Vertices[i] = new Array(ny);
Normals[i] = new Array(ny);
var u = i / nx * 2 * Math.PI;
var cos_u = Math.cos(u);
var sin_u = Math.sin(u);
var cx = R * cos_u;
var cy = R * sin_u;
for (var j = 0; j < ny; j++) {
var v = j / ny * 2 * Math.PI;
var rcos_v = r * Math.cos(v);
var rsin_v = r * Math.sin(v);
Vertices[i][j] = new THREE.Vector3(
cx + rcos_v * cos_u,
cy + rcos_v * sin_u,
rsin_v
);
Normals[i][j] = new THREE.Vector3(
rcos_v * cos_u,
rcos_v * sin_u,
rsin_v
);
}
}
// vertices as a dot cloud ----------------------------------------
var dotGeometry = new THREE.Geometry();
for (var i = 0; i < nx; i++) {
for (var j = 0; j < ny; j++) {
dotGeometry.vertices.push(Vertices[i][j]);
}
}
var dotMaterial =
new THREE.PointsMaterial({ size: 1, sizeAttenuation: false });
var cloud = new THREE.Points(dotGeometry, dotMaterial);
// mesh -----------------------------------------------------------
var geom = new THREE.Geometry();
geom.vertices = dotGeometry.vertices;
for (var i = 0; i < nx; i++) {
var ip1 = (i == nx - 1 ? 0 : i + 1);
for (var j = 0; j < ny; j++) {
var jp1 = (j == ny - 1 ? 0 : j + 1);
var vnormals1 =
[Normals[i][j], Normals[i][jp1], Normals[ip1][j]];
geom.faces.push(new THREE.Face3(
ip1 * ny + j,
i * ny + jp1,
i * ny + j,
vnormals1
));
var vnormals2 =
[Normals[i][jp1], Normals[ip1][jp1], Normals[ip1][j]];
geom.faces.push(new THREE.Face3(
ip1 * ny + j,
ip1 * ny + jp1,
i * ny + jp1,
vnormals2
));
}
}
var torusMesh = new THREE.Mesh(
geom,
new THREE.MeshNormalMaterial({ wireframe: false }));
// three js scene -------------------------------------------------
var scene = new THREE.Scene();
var aspect = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(50, aspect, 1, 10000);
camera.position.z = 30;
scene.add(camera);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var object = new THREE.Object3D();
object.add(torusMesh);
object.add(cloud);
scene.add(object);
renderer.render(scene, camera);
// animation ---------------------------------------------------------
var isDragging = false;
var previousMousePosition = {
x: 0,
y: 0
};
$(renderer.domElement).on('mousedown', function (e) {
isDragging = true;
}).on('mousemove', function (e) {
var deltaMove = {
x: e.offsetX - previousMousePosition.x,
y: e.offsetY - previousMousePosition.y
};
if (isDragging) {
var deltaRotationQuaternion = new THREE.Quaternion()
.setFromEuler(new THREE.Euler(
Math.PI / 180 * (deltaMove.y * 1),
Math.PI / 180 * (deltaMove.x * 1),
0,
'XYZ'
));
object.quaternion.multiplyQuaternions(deltaRotationQuaternion,
object.quaternion);
}
previousMousePosition = {
x: e.offsetX,
y: e.offsetY
};
});
$(document).on('mouseup', function (e) {
isDragging = false;
});
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function render() {
renderer.render(scene, camera);
requestAnimFrame(render);
}
render();
canvas {
width: 100%;
height: 100%
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.js"></script>
<script
src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E="
crossorigin="anonymous"></script>
Besides, consider to use the approach of TorusBufferGeometry
. Moreover, it's much faster to generate a geometry with BufferGeometry
than with Geometry
.
Upvotes: 2