I have a custom-made object, an obelisk, next to a cube. The obelisk is made with THREE.Geometry (each vertex and face added manually), while the cube is made with THREE.BoxGeometry. They both use THREE.MeshNormalMaterial.
So why does the cube get colors that change with rotation, while the obelisk is just gray? I've managed to get other meshes to add color to the obelisk, but can't figure out how to get the sides to change colors during rotation.
<!DOCTYPE html>
<html>
<head>
<title>Washington Monument</title>
<style>
html, body {
margin: 0; padding:0;
overflow: hidden;
}
canvas {
width: 100%; height: 100%;
}
</style>
</head>
<body>
<script src="../../lib/three.min.js"></script>
<script>
var scene = new THREE.Scene();
var fieldOfView = 45;
var aspect = window.innerWidth/window.innerHeight;
var nearClippingPlane = 0.01;
var farClippingPlane = 1000;
var camera = new THREE.PerspectiveCamera(fieldOfView, aspect, nearClippingPlane, farClippingPlane);
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var obeliskMaterial = new THREE.MeshNormalMaterial();
var obeliskGeometry = new THREE.Geometry();
obeliskGeometry.vertices.push(new THREE.Vector3( 8.40, -80, 8.40));
obeliskGeometry.vertices.push(new THREE.Vector3( 8.40, -80, -8.40));
obeliskGeometry.vertices.push(new THREE.Vector3(-8.40, -80, -8.40));
obeliskGeometry.vertices.push(new THREE.Vector3(-8.40, -80, 8.40));
obeliskGeometry.vertices.push(new THREE.Vector3( 5.25, 72.36, 5.25));
obeliskGeometry.vertices.push(new THREE.Vector3( 5.25, 72.36, -5.25));
obeliskGeometry.vertices.push(new THREE.Vector3(-5.25, 72.36, -5.25));
obeliskGeometry.vertices.push(new THREE.Vector3(-5.25, 72.36, 5.25));
obeliskGeometry.vertices.push(new THREE.Vector3( 0, 89.29, 0));
obeliskGeometry.faces.push(new THREE.Face3(0, 1, 5), new THREE.Face3(0, 5, 4));
obeliskGeometry.faces.push(new THREE.Face3(1, 2, 6), new THREE.Face3(1, 6, 5));
obeliskGeometry.faces.push(new THREE.Face3(2, 3, 7), new THREE.Face3(2, 7, 6));
obeliskGeometry.faces.push(new THREE.Face3(3, 0, 4), new THREE.Face3(3, 4, 7));
obeliskGeometry.faces.push(new THREE.Face3(4, 5, 8));
obeliskGeometry.faces.push(new THREE.Face3(5, 6, 8));
obeliskGeometry.faces.push(new THREE.Face3(6, 7, 8));
obeliskGeometry.faces.push(new THREE.Face3(7, 4, 8));
var obeliskMesh = new THREE.Mesh(obeliskGeometry, obeliskMaterial);
scene.add(obeliskMesh);
var material = new THREE.MeshNormalMaterial();
var geom = new THREE.BoxGeometry(16, 16, 8);
var cube = new THREE.Mesh(geom, material);
cube.position.x = 40;
scene.add(cube);
camera.position.z = 320;
var render = function () {
requestAnimationFrame(render);
obeliskMesh.rotation.y += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
If you want to use MeshNormalMaterial in a custom geometry, you have to compute the normals of the geometry before creating the mesh:
obeliskGeometry.computeFaceNormals();
In your example:
[...]
obeliskGeometry.faces.push(new THREE.Face3(7, 4, 8));
obeliskGeometry.computeFaceNormals();
var obeliskMesh = new THREE.Mesh(obeliskGeometry, obeliskMaterial);
[...]
Related
I have a BufferGeometry triangular prism; where I have specified the 6 vertices and then added indexes to create the 8 faces (2 triangle faces per square plane).
I have then setup 5 groups, so that each side of the prism is a group.
And it works here when I have a single material assigned to the whole object: https://jsfiddle.net/30ez17dw/1/
However I want to be able to assign an array of materials, so that each side (group) has it's own materials. But when I do this the object disappears:
https://jsfiddle.net/30ez17dw/2/
How can I fix my code to make the array of materials work?
You have not specified your groups correctly. Try it like so:
var camera, scene, renderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 5;
camera.position.y = 2;
camera.lookAt(0, 0, 0);
scene = new THREE.Scene();
var geometry = new THREE.BufferGeometry();
const y = 0.866025404;
const y2 = 0.5;
const h = 1;
const vertices = new Float32Array([
-y2, 0, 0,
y2, 0, 0,
0, 0, y,
-y2, h, 0,
y2, h, 0,
0, h, y,
]);
const indices = [
0, 1, 2, // Top
5, 4, 3, // Bottom
3, 1, 0, // Back
1, 3, 4, // Back
0, 2, 3, // Left
5, 3, 2, // Left
4, 2, 1, // Right
2, 4, 5, // Right
];
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setIndex(indices);
geometry.computeVertexNormals();
geometry.clearGroups();
geometry.addGroup(0, 3, 0);
geometry.addGroup(3, 6, 1);
geometry.addGroup(6, 12, 2);
geometry.addGroup(12, 18, 3);
geometry.addGroup(18, 24, 4);
var material = [
new THREE.MeshBasicMaterial({
color: 0x00ff00
}),
new THREE.MeshBasicMaterial({
color: 0xff0000
}),
new THREE.MeshBasicMaterial({
color: 0x0000ff,
}),
new THREE.MeshBasicMaterial({
color: 0xffff00
}),
new THREE.MeshBasicMaterial({
color: 0x00ffff
})
];
var mesh = new THREE.Mesh(geometry, material); // , side: THREE.DoubleSide
scene.add(mesh);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.132.0/build/three.min.js"></script>
The indices you pass to addGroup() are meant to be consecutive.
Trying to create a tetrahedron with three triangles. I could'nt orient faces. Here is the code :
HTML
<div id="myid"></div>
JAVASCRIPT
const divid = document.getElementById("myid");
let facesVectors = [ // triangles vertices
[0, 0, 0],
[-1, 0, 0],
[0, 1, 0],
]
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
1,
1000
);
let renderer = new THREE.WebGLRenderer({ alpha: true });
divid.appendChild(renderer.domElement);
camera.position.z = 2.5;
// equilateral triangle template
const geometry = new THREE.Geometry()
geometry.vertices.push(new THREE.Vector3(-0.48, 0, 0))
geometry.vertices.push(new THREE.Vector3(0.48, 0, 0))
geometry.vertices.push(new THREE.Vector3(0, 0.72, 0))
geometry.faces.push(new THREE.Face3(0, 1, 2))
let material, face, i
let faces = []
for (i = 0; i < facesVectors.length; i++) {
material = new THREE.MeshBasicMaterial({ color: 0x00FF00, side: THREE.DoubleSide })
face = new THREE.Mesh(geometry, material)
face.position.set(facesVectors[i][0], facesVectors[i][1], facesVectors[i][2])
if (i === 1) {
face.rotation.x = -(Math.PI / 2)
} else if (i === 2) {
face.rotation.x = -(Math.PI / 2)
}
faces.push(face)
scene.add(face)
}
let animate = function() {
requestAnimationFrame(animate);
faces.forEach((face)=>{
face.rotation.x += 0.005;
face.rotation.y += 0.01;
})
renderer.render(scene, camera);
};
animate();
demo : https://codepen.io/jeffprod/pen/GRJGYoQ
How to rotate triangles 1 and 2 so that i get a tetrahedron ? Is there a simplest way to do ?
Of course i don't want to use the TetrahedronBufferGeomety because i will need to manage faces colors and a lot of other triangles oriented differently.
Based on this forum topic. Just commented out two lines for faces and uvs:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.set(0, -1, 2);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
// tetrahedron
// ---------------------------------------------------------------------------------------
var pts = [ // https://en.wikipedia.org/wiki/Tetrahedron#Coordinates_for_a_regular_tetrahedron
new THREE.Vector3(Math.sqrt(8 / 9), 0, -(1 / 3)),
new THREE.Vector3(-Math.sqrt(2 / 9), Math.sqrt(2 / 3), -(1 / 3)),
new THREE.Vector3(-Math.sqrt(2 / 9), -Math.sqrt(2 / 3), -(1 / 3)),
new THREE.Vector3(0, 0, 1)
];
var faces = [ // triangle soup
//pts[0].clone(), pts[2].clone(), pts[1].clone(),
pts[0].clone(), pts[1].clone(), pts[3].clone(),
pts[1].clone(), pts[2].clone(), pts[3].clone(),
pts[2].clone(), pts[0].clone(), pts[3].clone()
];
var geom = new THREE.BufferGeometry().setFromPoints(faces);
geom.rotateX(-Math.PI * 0.5);
geom.computeVertexNormals();
geom.setAttribute("uv", new THREE.Float32BufferAttribute([ // UVs
//0.5, 1, 0.06698729810778059, 0.2500000000000001, 0.9330127018922194, 0.2500000000000001,
0.06698729810778059, 0.2500000000000001, 0.9330127018922194, 0.2500000000000001, 0.5, 1,
0.06698729810778059, 0.2500000000000001, 0.9330127018922194, 0.2500000000000001, 0.5, 1,
0.06698729810778059, 0.2500000000000001, 0.9330127018922194, 0.2500000000000001, 0.5, 1
], 2));
// ---------------------------------------------------------------------------------------
var tetrahedron = new THREE.Mesh(geom, new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load("https://threejs.org/examples/textures/uv_grid_opengl.jpg"),
side: THREE.DoubleSide
}));
scene.add(tetrahedron);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
In the code below, cubes sometimes move with animation and sometimes without. How can I fix it ?
Also, how should I set rotation speed ?
new Vue({
el: '#app',
data () {
return {
camera: null,
scene: null,
renderer: null,
cube: null,
angle: null
}
},
methods: {
init: function () {
this.camera = new THREE.PerspectiveCamera(1, 1);
this.camera.position.z = 200;
// Make a scene
this.scene = new THREE.Scene();
this.clock = new THREE.Clock();
//
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
let container = document.getElementById('container')
this.renderer.setSize(container.offsetWidth, container.offsetHeight);
container.appendChild(this.renderer.domElement);
let cube2 = this.createCube()
cube2.name = "cube2"
// cube2.position = new THREE.Vector3(1, 0)
this.scene.add(cube2);
},
createCube: function () {
// GEOMETRY
// 1. Start with empty geometry
let geometry = new THREE.Geometry();
// 2. Add vertices to geometry
geometry.vertices.push(
// verts [0-3] are in in +z
new THREE.Vector3(-1, 1, 1),
new THREE.Vector3(-1, -1, 1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(1, 1, 1),
// verts [4-7] in -z
new THREE.Vector3(-1, 1, -1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(1, 1, -1),
);
// 3. Connect vertices in desired order to make faces
let b = 0x1db0ec
let y = 0xffef3a
let r = 0xea353d
let w = 0xffffff
// Set half faces
geometry.faces.push(new THREE.Face3(0, 1, 2)); // blue
geometry.faces.push(new THREE.Face3(0, 2, 3)); // yellow
geometry.faces.push(new THREE.Face3(5, 4, 6)); // white
geometry.faces.push(new THREE.Face3(6, 4, 7)); // red
// Set whole faces
geometry.faces.push(new THREE.Face3(1, 0, 5)); // blue
geometry.faces.push(new THREE.Face3(5, 0, 4));
geometry.faces.push(new THREE.Face3(1, 5, 2)); // white
geometry.faces.push(new THREE.Face3(5, 6, 2));
geometry.faces.push(new THREE.Face3(2, 6, 3)); // red
geometry.faces.push(new THREE.Face3(3, 6, 7));
geometry.faces.push(new THREE.Face3(0, 3, 4)); // yellow
geometry.faces.push(new THREE.Face3(3, 7, 4));
// Set faces colors
geometry.faces[0].color.setHex(b); // Half face
geometry.faces[1].color.setHex(y);
geometry.faces[2].color.setHex(w);
geometry.faces[3].color.setHex(r);
geometry.faces[4].color.setHex(b); // Whole face
geometry.faces[5].color.setHex(b);
geometry.faces[6].color.setHex(w);
geometry.faces[7].color.setHex(w);
geometry.faces[8].color.setHex(r);
geometry.faces[9].color.setHex(r);
geometry.faces[10].color.setHex(y);
geometry.faces[11].color.setHex(y);
// MATERIAL
// Make a material
let material = new THREE.MeshBasicMaterial({
// color: 0x00FF00,
vertexColors: THREE.FaceColors,
wireframe: false,
});
// MESH
let cube = new THREE.Mesh(geometry, material);
return cube
},
rotateTo: function (face) {
if (face == 'yellow')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, Math.PI / 2));
else if (face == 'red')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, Math.PI / 2));
else if (face == 'blue')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, - Math.PI / 2));
else if (face == 'white')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(- Math.PI / 2, Math.PI / 2, 0));
else if (face == 'yb')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
else if (face == 'rw')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI, 0, 0));
this.animate()
},
animate: function () {
let id = requestAnimationFrame(this.animate);
let delta = this.clock.getDelta();
this.scene.children[0].quaternion.rotateTowards(this.angle, Math.PI * delta);
this.renderer.render(this.scene, this.camera);
if (this.scene.children[0].quaternion.equals(this.angle)) {
cancelAnimationFrame(id)
}
}
},
mounted () {
this.init();
this.renderer.render(this.scene, this.camera);
}
})
#container {
background-color: #aaa;
width: 20em;
height: 20em;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://threejs.org/build/three.min.js"></script>
<div id="app">
<div>
<button v-on:click="rotateTo('yellow')">yellow</button>
<button v-on:click="rotateTo('red')">red</button>
<button v-on:click="rotateTo('blue')">blue</button>
<button v-on:click="rotateTo('white')">white</button>
<button v-on:click="rotateTo('yb')">yellow/blue</button>
<button v-on:click="rotateTo('rw')">red/white</button>
</div>
<div id="container"></div>
</div>
UPDATE
Code isolated to only the threejs portion.
var camera = null;
var scene = null;
var renderer = null;
var cube = null;
var angle = null;
init();
renderer.render(scene, camera);
function init() {
camera = new THREE.PerspectiveCamera(1, 1);
camera.position.z = 200;
// Make a scene
scene = new THREE.Scene();
clock = new THREE.Clock();
//
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
let container = document.getElementById('container');
renderer.setSize(container.offsetWidth, container.offsetHeight);
container.appendChild(renderer.domElement);
let cube2 = createCube();
cube2.name = "cube2";
// cube2.position = new THREE.Vector3(1, 0)
scene.add(cube2);
}
function createCube() {
// GEOMETRY
// 1. Start with empty geometry
let geometry = new THREE.Geometry();
// 2. Add vertices to geometry
geometry.vertices.push(
// verts [0-3] are in in +z
new THREE.Vector3(-1, 1, 1),
new THREE.Vector3(-1, -1, 1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(1, 1, 1),
// verts [4-7] in -z
new THREE.Vector3(-1, 1, -1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(1, 1, -1),
);
// 3. Connect vertices in desired order to make faces
let b = 0x1db0ec;
let y = 0xffef3a;
let r = 0xea353d;
let w = 0xffffff;
// Set half faces
geometry.faces.push(new THREE.Face3(0, 1, 2)); // blue
geometry.faces.push(new THREE.Face3(0, 2, 3)); // yellow
geometry.faces.push(new THREE.Face3(5, 4, 6)); // white
geometry.faces.push(new THREE.Face3(6, 4, 7)); // red
// Set whole faces
geometry.faces.push(new THREE.Face3(1, 0, 5)); // blue
geometry.faces.push(new THREE.Face3(5, 0, 4));
geometry.faces.push(new THREE.Face3(1, 5, 2)); // white
geometry.faces.push(new THREE.Face3(5, 6, 2));
geometry.faces.push(new THREE.Face3(2, 6, 3)); // red
geometry.faces.push(new THREE.Face3(3, 6, 7));
geometry.faces.push(new THREE.Face3(0, 3, 4)); // yellow
geometry.faces.push(new THREE.Face3(3, 7, 4));
// Set faces colors
geometry.faces[0].color.setHex(b); // Half face
geometry.faces[1].color.setHex(y);
geometry.faces[2].color.setHex(w);
geometry.faces[3].color.setHex(r);
geometry.faces[4].color.setHex(b); // Whole face
geometry.faces[5].color.setHex(b);
geometry.faces[6].color.setHex(w);
geometry.faces[7].color.setHex(w);
geometry.faces[8].color.setHex(r);
geometry.faces[9].color.setHex(r);
geometry.faces[10].color.setHex(y);
geometry.faces[11].color.setHex(y);
// MATERIAL
// Make a material
let material = new THREE.MeshBasicMaterial({
// color: 0x00FF00,
vertexColors: THREE.FaceColors,
wireframe: false,
});
// MESH
let cube = new THREE.Mesh(geometry, material);
return cube;
}
function rotateTo(face) {
if (face == 'yellow')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, Math.PI / 2));
else if (face == 'red')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, Math.PI / 2));
else if (face == 'blue')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, -Math.PI / 2));
else if (face == 'white')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI / 2, Math.PI / 2, 0));
else if (face == 'yb')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
else if (face == 'rw')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI, 0, 0));
animate();
}
function animate() {
let id = requestAnimationFrame(animate);
let delta = clock.getDelta();
scene.children[0].quaternion.rotateTowards(angle, Math.PI * delta);
renderer.render(scene, camera);
if (scene.children[0].quaternion.equals(angle)) {
cancelAnimationFrame(id);
}
}
#container {
background-color: #aaa;
width: 20em;
height: 20em;
}
<script src="https://threejs.org/build/three.min.js"></script>
<div>
<button onclick="rotateTo('yellow')">yellow</button>
<button onclick="rotateTo('red')">red</button>
<button onclick="rotateTo('blue')">blue</button>
<button onclick="rotateTo('white')">white</button>
<button onclick="rotateTo('yb')">yellow/blue</button>
<button onclick="rotateTo('rw')">red/white</button>
</div>
<div id="container"></div>
The reason for the animation not playing is because when you cancelAnimationFrame the clock is still running, so the next time you call rotateTo the delta is so high that the animation ends immediately.
you can avoid this by stopping the clock with cancelAnimationFrame, and start it again when calling rotateTo as follows:
function rotateTo(face) {
clock.start()
...
}
function animate() {
...
if (scene.children[0].quaternion.equals(angle)) {
cancelAnimationFrame(id);
clock.stop()
}
}
as for rotation speed, the 2nd arg of rotateTowards is step, which determines how fast will it get there. So if you add a modifier var to it, you can control the speed.
let rotSpeedMotifier = 0.2 // the higher the faster
scene.children[0].quaternion.rotateTowards(angle, Math.PI * delta * rotSpeedMotifier );
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 10, 300);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.TrackballControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(100);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
var closedSpline = new THREE.CatmullRomCurve3([
new THREE.Vector3(-60, -100, -10),
new THREE.Vector3(-60, 20, 0),
new THREE.Vector3(-60, 120, -20),
new THREE.Vector3(60, 120, 0),
new THREE.Vector3(60, -100, 10)
]);
closedSpline.curveType = 'catmullrom';
closedSpline.closed = true;
var closedSpline1 = new THREE.CatmullRomCurve3([
new THREE.Vector3(-50, -90, -10),
new THREE.Vector3(-50, 10, 0),
new THREE.Vector3(-50, 110, -20),
new THREE.Vector3(50, 110, 0),
new THREE.Vector3(50, -90, 10)
]);
closedSpline1.curveType = 'catmullrom';
closedSpline1.closed = true;
var tubeGeometry = new THREE.TubeBufferGeometry(closedSpline, 100, 1, 5, true);
var material = new THREE.MeshLambertMaterial({
color: 0xb00000,
wireframe: false
});
var mesh = new THREE.Mesh(tubeGeometry, material);
scene.add(mesh);
var tubeGeometry1 = new THREE.TubeBufferGeometry(closedSpline1, 100, 1, 5,true);
var material1 = new THREE.MeshLambertMaterial({
color: 0xb00000,
wireframe: false
});
var mesh1 = new THREE.Mesh(tubeGeometry1, material1);
scene.add(mesh1);
// magic starts here
var shape = new THREE.Shape(closedSpline1.getPoints(100)); // make a shape
shape.holes.push(new THREE.Path(closedSpline1.getPoints(100))); // add a hole
var shapeGeometry = new THREE.ShapeGeometry(shape); // create a geometry
var track = new THREE.Mesh(shapeGeometry, new THREE.MeshLambertMaterial({
color: "yellow",
side:THREE.DoubleSide,
})); // create a track from the geometry
scene.add(track);
render();
function render() {
requestAnimationFrame(render);
controls.update();
renderer.render(scene, camera);
}
Above is my code which draw two tube geometry using THREE.CatmullRomCurve3 points and surface between those two tubes. Issue i am facing is surface between those two tubes(Track in above code) is always flat(2d) instead of 3d. I think THREE.Shape() are not using z axis values to draw surface. Can anybody guide me to right direction or some related samples. Thanks
You can do the trick, using concatenated sets of points from curves and THREE.PlaneGeometry():
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 10, 300);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(100);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
var closedSpline = new THREE.CatmullRomCurve3([
new THREE.Vector3(-60, -100, -10),
new THREE.Vector3(-60, 20, 0),
new THREE.Vector3(-60, 120, -20),
new THREE.Vector3(60, 120, 0),
new THREE.Vector3(60, -100, 10)
]);
closedSpline.curveType = 'catmullrom';
closedSpline.closed = true;
var closedSpline1 = new THREE.CatmullRomCurve3([
new THREE.Vector3(-50, -90, -10),
new THREE.Vector3(-50, 10, 0),
new THREE.Vector3(-50, 110, -20),
new THREE.Vector3(50, 110, 0),
new THREE.Vector3(50, -90, 10)
]);
closedSpline1.curveType = 'catmullrom';
closedSpline1.closed = true;
var tubeGeometry = new THREE.TubeBufferGeometry(closedSpline, 100, 1, 5, true);
var material = new THREE.MeshLambertMaterial({
color: 0xb00000,
wireframe: false
});
var mesh = new THREE.Mesh(tubeGeometry, material);
scene.add(mesh);
var tubeGeometry1 = new THREE.TubeBufferGeometry(closedSpline1, 100, 1, 5,
true);
var material1 = new THREE.MeshLambertMaterial({
color: 0xb00000,
wireframe: false
});
var mesh1 = new THREE.Mesh(tubeGeometry1, material1);
scene.add(mesh1);
// magic starts here
var points1 = closedSpline.getPoints(100); // get the first set of points
var points2 = closedSpline1.getPoints(100); // get the second set of points
var allPoints = points1.concat(points2); // concatenate them
var planeGeom = new THREE.PlaneGeometry(1, 1, 100, 1); // create a plane geometry
planeGeom.vertices = allPoints; // replace its vertices with the previously concatenated array of points
planeGeom.computeFaceNormals();
planeGeom.computeVertexNormals();
var track = new THREE.Mesh(planeGeom, new THREE.MeshLambertMaterial({
color: "yellow",
wireframe: false
}));
scene.add(track);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
Currently I want to render the axis over the cube (rather than through it). But I can't figure out a way to do that. Does any one know how to render the axis lines over the cube module? Thanks.
Have provided the JS code below.
The cube will be rendered in scene and axis lines will be rendered in fscene. (The axis lines rendered in fscene is supposed to cover the cube which rendered in scene)
var container, stats;
var camera, scene, fscene, renderer;
var cube, plane;
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.01, 999999 );
camera.position.y = 5;
camera.position.z = 5;
camera.position.x = 4;
camera.lookAt(new THREE.Vector3());
scene = new THREE.Scene();
fscene = new THREE.Scene();
// Cube
var geometry = new THREE.CubeGeometry( 1, 1, 1 );
for ( var i = 0; i < geometry.faces.length; i ++ ) {
geometry.faces[ i ].color.setHex( 0xcccccc * i );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors } );
cube = new THREE.Mesh( geometry, material );
scene.add(cube);
addAxis();
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.autoClear = false;
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
animate();
}
function animate() {
requestAnimationFrame(animate);
renderer.clear();
renderer.render(scene, camera);
renderer.render(fscene, camera);
}
function addAxis() {
var sceneSize = 9000;
line({ begin: [0, 0, 0], end: [sceneSize, 0, 0], color: 0xff0000, scene: scene });
line({ begin: [0, 0, 0], end: [-sceneSize, 0, 0], color: 0xff0000, dashed: true, scene: scene });
line({ begin: [0, 0, 0], end: [0, sceneSize, 0], color: 0x00ff00, scene: scene });
line({ begin: [0, 0, 0], end: [0, -sceneSize, 0], color: 0x00ff00, dashed: true, scene: scene });
line({ begin: [0, 0, 0], end: [0, 0, sceneSize], color: 0x0000ff, scene: scene });
line({ begin: [0, 0, 0], end: [0, 0, -sceneSize], color: 0x0000ff, dashed: true, scene: scene });
}
function line(cfg){
var p = cfg.begin;
var q = cfg.end;
if (cfg.color) {
cfg.colorb = cfg.colorb || cfg.color;
cfg.colore = cfg.colore || cfg.color;
}
var geometry = new THREE.Geometry();
var material = cfg.dashed ? new THREE.LineDashedMaterial({ linewidth: 1, color: cfg.color, dashSize: 1, gapSize: 1, depthWrite:false }) : new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors, depthWrite:false });
var cp = new THREE.Color(cfg.colorb);
var cq = new THREE.Color(cfg.colore);
geometry.vertices.push(new THREE.Vector3(p[0], p[1], p[2]));
geometry.vertices.push(new THREE.Vector3(q[0], q[1], q[2]));
geometry.colors.push(cp,cq);
geometry.computeLineDistances();
var line = new THREE.Line(geometry, material, THREE.LinePieces);
fscene.add(line);
}
TransformControls.js contains the code that might help you.
depthTest should be set to false and transparent should be set to true.