I made a TubeGeometry by passing in a SplineCurve3 / CatmullRomCurve3 path as a parameter.
I am trying to update the position of each of the path's points with geometry.parameters.path.points[1].y += 0.01; under requestAnimationFrame.
The values itself updates on console.log but the points dont move. How can i do this?
By the way, i'm not looking to move 'vertices' but rather the points of the path that shape how the tube is rendered.
var camera, scene, light, renderer, geometry, material, mesh;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// default bg canvas color //
renderer.setClearColor(0x00ff00);
// use device aspect ratio //
// renderer.setPixelRatio(window.devicePixelRatio);
// set size of canvas within window //
renderer.setSize(window.innerWidth, window.innerHeight);
// create camera //
// params = field of view, aspect ratio, clipping of near objects, clipping of far objs
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 3000);
camera.position.z = 100;
// create scene
scene = new THREE.Scene();
// create ambient lighting, params -> color, intensity
light = new THREE.AmbientLight(0xffffff, 0.5)
// add light to scene
scene.add(light)
// create line, with params as x,y,z
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3( -60, 0, 0 ),
new THREE.Vector3( -50, 10, 0 ),
new THREE.Vector3( -40, 0, 0 ),
new THREE.Vector3( -30, -10, 0 ),
new THREE.Vector3( -20, 0, 0 ),
new THREE.Vector3( -10, 10, 0 ),
new THREE.Vector3( 0, 0, 0 ),
new THREE.Vector3( 10, -10, 0 ),
new THREE.Vector3( 20, 0, 0 ),
new THREE.Vector3( 30, 10, 0 ),
new THREE.Vector3( 40, 0, 0 ),
new THREE.Vector3( 50, -10, 0 ),
new THREE.Vector3( 60, 0, 0 )
]);
curve.verticesNeedUpdate = true;
for (i = 0; i < curve.points.length; i++) {
// this will get a number between 1 and 10;
var num = Math.floor(Math.random()*10) + 1;
num *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
curve.points[i].y = num;
// console.log(curve.points[i].y);
}
geometry = new THREE.TubeGeometry(curve, 1000, 0.2, 8, false);
geometry.dynamic = true;
/* standard material */
material = new THREE.MeshBasicMaterial({
color: 0xff0000
});
// create mesh
mesh = new THREE.Mesh(geometry, material);
// set positon of line
mesh.position.set(0,0,-10);
// add to scene
scene.add(mesh);
document.body.appendChild(renderer.domElement);
} /* end init */
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//console.log(geometry.parameters.path.points);
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
// mesh.rotation.x += 0.01;
// mesh.rotation.y += 0.01;
geometry.parameters.path.points[1].y += 0.01;
geometry.verticesNeedUpdate = true;
//console.log(geometry.parameters.path.points[1].y)
/* render scene and camera */
renderer.render(scene,camera);
}
body {
margin:0;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
I wasn't able to get it working using TubeGeometry, but I did with TubeBufferGeometry. Luckily, there isn't much to change, because both use the curve path to define the mesh vertices. You're free to try to replicate this with TubeGeometry instead.
The main problem you're seeing though is that Tube(Buffer)Geometry BUILDS geometry, rather than IS geometry, and that's where the convenience ends. Updating the path does not trigger the geometry to rebuild. Instead, if you update your path, you must recreate the Tube(Buffer)Geometry.
In the code below, all I did was swap TubeBufferGeometry in place of TubeGeometry, changed geometry.verticesNeedUpdated to geometry.needsUpdate (this is how BufferGeometry handles updates), and added the line which re-builds the tube:
geometry.copy(new THREE.TubeBufferGeometry(geometry.parameters.path, 1000, 0.2, 8, false));
var camera, scene, light, renderer, geometry, material, mesh;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// default bg canvas color //
renderer.setClearColor(0x00ff00);
// use device aspect ratio //
// renderer.setPixelRatio(window.devicePixelRatio);
// set size of canvas within window //
renderer.setSize(window.innerWidth, window.innerHeight);
// create camera //
// params = field of view, aspect ratio, clipping of near objects, clipping of far objs
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 3000);
camera.position.z = 100;
// create scene
scene = new THREE.Scene();
// create ambient lighting, params -> color, intensity
light = new THREE.AmbientLight(0xffffff, 0.5)
// add light to scene
scene.add(light)
// create line, with params as x,y,z
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3( -60, 0, 0 ),
new THREE.Vector3( -50, 10, 0 ),
new THREE.Vector3( -40, 0, 0 ),
new THREE.Vector3( -30, -10, 0 ),
new THREE.Vector3( -20, 0, 0 ),
new THREE.Vector3( -10, 10, 0 ),
new THREE.Vector3( 0, 0, 0 ),
new THREE.Vector3( 10, -10, 0 ),
new THREE.Vector3( 20, 0, 0 ),
new THREE.Vector3( 30, 10, 0 ),
new THREE.Vector3( 40, 0, 0 ),
new THREE.Vector3( 50, -10, 0 ),
new THREE.Vector3( 60, 0, 0 )
]);
curve.verticesNeedUpdate = true;
for (i = 0; i < curve.points.length; i++) {
// this will get a number between 1 and 10;
var num = Math.floor(Math.random()*10) + 1;
num *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
curve.points[i].y = num;
// console.log(curve.points[i].y);
}
geometry = new THREE.TubeBufferGeometry(curve, 1000, 0.2, 8, false);
geometry.dynamic = true;
/* standard material */
material = new THREE.MeshBasicMaterial({
color: 0xff0000
});
// create mesh
mesh = new THREE.Mesh(geometry, material);
// set positon of line
mesh.position.set(0,0,-10);
// add to scene
scene.add(mesh);
document.body.appendChild(renderer.domElement);
} /* end init */
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//console.log(geometry.parameters.path.points);
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
// mesh.rotation.x += 0.01;
// mesh.rotation.y += 0.01;
geometry.parameters.path.points[3].y += 0.01;
geometry.copy(new THREE.TubeBufferGeometry(geometry.parameters.path, 1000, 0.2, 8, false));
geometry.needsUpdate = true;
//console.log(geometry.parameters.path.points[1].y)
/* render scene and camera */
renderer.render(scene,camera);
}
body {
margin:0;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
Related
I want to rotate this cube around the light blue axis. I works If I change the rotation around THREE.Vector3(0,0,0) instead of THREE.Vector3(0.4,0,0.9)
I don't know why the cubes shape changes and why it gets smaller with more iterations
An fiddle showing this problem (please ignore the crappy implementation. I just changed a old one)
So this is how I do the rotation:
function rotate(deg) {
_initTranslation = new THREE.Vector3();
_initRotation = new THREE.Quaternion();
_initScale = new THREE.Vector3();
rotateMatrix = new THREE.Matrix4();
cube.matrix.decompose(_initTranslation, _initRotation, _initScale);
cube.matrix = rotateMatrix.compose(_initTranslation, new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0.4,1,0.9), THREE.Math.degToRad(deg)), _initScale);
cube.matrixAutoUpdate = false;
cube.matrixWorldNeedsUpdate = true;
}
Maybe someone knows what I did wrong.
var renderer, scene, camera, controls;
var geometry, material, line, vertices, last, _initTranslation, _initRotation, initScale, rotateMatrix;
var deg = 0;
init();
animate();
function init() {
document.body.style.cssText = 'margin: 0; overflow: hidden;' ;
renderer = new THREE.WebGLRenderer( { alpha: 1, antialias: true, clearColor: 0xffffff } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 5, 5, 5 );
controls = new THREE.OrbitControls( camera, renderer.domElement );
geometry2 = new THREE.BoxGeometry( .5, .5, .5 );
material2 = new THREE.MeshNormalMaterial();
cube = new THREE.Mesh( geometry2, material2 );
scene.add( cube );
material = new THREE.LineBasicMaterial({ color: 0x0077ff });
geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3( 0, 0, 0) );
line = new THREE.Line( geometry, material )
scene.add( line );
var sphereAxis = new THREE.AxesHelper(20);
scene.add(sphereAxis);
addStep();
cube.lookAt(new THREE.Vector3(0.4,0,0.9));
}
function addStep() {
vertices = geometry.vertices;
last = vertices[ vertices.length - 1 ];
vertices.push(
new THREE.Vector3(0.4,0,0.9)
);
geometry = new THREE.Geometry();
geometry.vertices = vertices;
scene.remove( line );
line = new THREE.Line( geometry, material )
scene.add( line );
}
function animate() {
rotate(deg)
deg += 5
requestAnimationFrame( animate );
renderer.render(scene, camera);
controls.update();
}
function rotate(deg) {
_initTranslation = new THREE.Vector3();
_initRotation = new THREE.Quaternion();
_initScale = new THREE.Vector3();
rotateMatrix = new THREE.Matrix4();
cube.matrix.decompose(_initTranslation, _initRotation, _initScale);
cube.matrix = rotateMatrix.compose(_initTranslation, new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0.4,0,0.9), THREE.Math.degToRad(deg)), _initScale);
cube.matrixAutoUpdate = false;
cube.matrixWorldNeedsUpdate = true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
The vector component of the Quaternion has to be (normalize.). The length of a normalized vector (Unit vector) is 1.0.
In your case the length of the vector component (THREE.Vector3(0.4, 0, 0.9)) is less than 1.0:
sqrt(0.9*0.9 + 0.0*0.0 + 0.4*0.4) = sqrt(0.81 + 0.16) = sqrt(0.97) = 0.9409
This causes that the cube scales sown by time. This can be verified by logging the scaling component (console.log(_initScale)).
If you would use a vector component with a length greater than 1.0 (e.g. THREE.Vector3(0.5, 0, 0.9), then the cube will scale up.
Normalize the axis of the Quaternion, to solve the issue:
let axis = new THREE.Vector3(0.4, 0, 0.9);
let q = new THREE.Quaternion().setFromAxisAngle(axis.normalize(), THREE.Math.degToRad(deg));
cube.matrix = rotateMatrix.compose(_initTranslation, q, _initScale);
If you want that one side of the cube is aligned to the axis, in that way, that the axis is normal to the side, then this is something completely different.
You've to do 2 rotations. First rotate the cube (e.g.) continuously around the x-axis, then turn the x-axis to the target axis (0.4, 0, 0.9). Use .setFromAxisAngle` to initialize a quaternion which rotates the x-axis to the target axis:
let x_axis = new THREE.Vector3(1, 0, 0);
let axis = new THREE.Vector3(0.4, 0, 0.9);
let q_align = new THREE.Quaternion().setFromUnitVectors(x_axis, axis.normalize());
let q_rotate = new THREE.Quaternion().setFromAxisAngle(x_axis, THREE.Math.degToRad(deg));
let q_final = q_align.clone().multiply(q_rotate);
cube.matrix = rotateMatrix.compose(_initTranslation, q, _initScale);
See the example, which compares the 2 different behavior:
var renderer, scene, camera, controls;
var geometry, material, line, vertices, last, _initTranslation, _initRotation, initScale, rotateMatrix;
var deg = 0;
init();
animate();
function init() {
document.body.style.cssText = 'margin: 0; overflow: hidden;' ;
renderer = new THREE.WebGLRenderer( { alpha: 1, antialias: true, clearColor: 0xffffff } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 1, 3, 3 );
controls = new THREE.OrbitControls( camera, renderer.domElement );
geometry2 = new THREE.BoxGeometry( .5, .5, .5 );
material2 = new THREE.MeshNormalMaterial();
let shift = 0.5
cube = new THREE.Mesh( geometry2, material2 );
cube.matrix.makeTranslation(shift, 0, 0);
scene.add( cube );
cube2 = new THREE.Mesh( geometry2, material2 );
cube2.matrix.makeTranslation(-shift, 0, 0);
scene.add( cube2 );
material = new THREE.LineBasicMaterial({ color: 0x0077ff });
geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3(-0.4, 0, -0.9), new THREE.Vector3(0.4, 0, 0.9) );
line = new THREE.Line( geometry, material )
line.position.set(shift, 0, 0);
scene.add( line );
line2 = new THREE.Line( geometry, material )
line2.position.set(-shift, 0, 0);
scene.add( line2 );
var sphereAxis = new THREE.AxesHelper(20);
scene.add(sphereAxis);
window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
}
function animate() {
rotate(deg)
deg += 5
requestAnimationFrame( animate );
renderer.render(scene, camera);
controls.update();
}
function rotate(deg) {
_initTranslation = new THREE.Vector3();
_initRotation = new THREE.Quaternion();
_initScale = new THREE.Vector3();
let x_axis = new THREE.Vector3(1, 0, 0);
let axis = new THREE.Vector3(0.4, 0, 0.9);
// cube
cube.matrix.decompose(_initTranslation, _initRotation, _initScale);
let q_align = new THREE.Quaternion().setFromUnitVectors(x_axis, axis.normalize());
let q_rotate = new THREE.Quaternion().setFromAxisAngle(x_axis, THREE.Math.degToRad(deg));
let q_final = q_align.clone().multiply(q_rotate);
cube.matrix.compose(_initTranslation, q_final, _initScale);
cube.matrixAutoUpdate = false;
cube.matrixWorldNeedsUpdate = true;
// cube2
cube2.matrix.decompose(_initTranslation, _initRotation, _initScale);
q = new THREE.Quaternion().setFromAxisAngle(axis.normalize(), THREE.Math.degToRad(deg));
cube2.matrix.compose(_initTranslation, q, _initScale);
cube2.matrixAutoUpdate = false;
cube2.matrixWorldNeedsUpdate = true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
I try to animate a 2D curve in Three.js over time.
I'll need more than 4 control points, so I'm not using Bezier curves.
I created a Three.Line based on a SplineCurve.
If I log the geometry.vertices position of my line they'll change over time, but geometry.attributes.position remains the same. Is it possible to animate the line based on the curve animation ? I managed to do this with Bezier Curves, but can't find a way with SplineCurve.
Thank you for your help, here's my code :
First I create the line :
var curve = new THREE.SplineCurve( [
new THREE.Vector3( -10, 0, 10 ),
new THREE.Vector3( -5, 5, 5 ),
new THREE.Vector3( 0, 0, 0 ),
new THREE.Vector3( 5, -5, 5 ),
new THREE.Vector3( 10, 0, 10 )
] );
var points = curve.getPoints( 50 );
var geometry = new THREE.BufferGeometry().setFromPoints( points );
var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
// Create the final object to add to the scene
curveObject = new THREE.Line( geometry, material );
scene.add( curveObject );
curveObject.curve = curve;
Then I try to update it :
curveObject.curve.points[0].x += 1;
curveObject.geometry.vertices = curveObject.curve.getPoints( 50 );
curveObject.geometry.verticesNeedUpdate = true;
curveObject.geometry.attributes.needsUpdate = true;
You can do it like that:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);
camera.position.set(8, 13, 25);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
var canvas = renderer.domElement;
document.body.appendChild(canvas);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper(20, 40));
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(-10, 0, 10),
new THREE.Vector3(-5, 5, 5),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(5, -5, 5),
new THREE.Vector3(10, 0, 10)
]);
var points = curve.getPoints(50);
var geometry = new THREE.BufferGeometry().setFromPoints(points);
var material = new THREE.LineBasicMaterial({
color: 0x00ffff
});
var curveObject = new THREE.Line(geometry, material);
scene.add(curveObject);
var clock = new THREE.Clock();
var time = 0;
render();
function resize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resize(renderer)) {
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
time += clock.getDelta();
curve.points[1].y = Math.sin(time) * 2.5;
geometry = new THREE.BufferGeometry().setFromPoints(curve.getPoints(50));
curveObject.geometry.dispose();
curveObject.geometry = geometry;
requestAnimationFrame(render);
}
html,
body {
height: 100%;
margin: 0;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
display;
block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
The following code is a working example using custom geometry to draw a tetrahedron with three.js (relevant is mesh2):
<!DOCTYPE html>
<html>
<header>
<script src="three.min.js"></script>
<style>
body {
overflow: hidden;
}
</style>
</header>
<body>
<script>
var camera, scene, renderer;
var geometry, material, mesh1, mesh2;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, 0.01, 300 );
camera.position.z = 50;
scene = new THREE.Scene();
material = new THREE.MeshNormalMaterial();
// 1
geometry = new THREE.BoxGeometry( 10, 10, 10 );
mesh1 = new THREE.Mesh( geometry, material );
scene.add( mesh1 );
// 2 begin
geometry = new THREE.Geometry( );
geometry.vertices.push( new THREE.Vector3( 6,6, 6), new THREE.Vector3( 10,6, 6), new THREE.Vector3( 6,10, 6), new THREE.Vector3( 6,6, 10) );
geometry.faces.push( new THREE.Face3( 0,2,1),new THREE.Face3( 1,2,3),new THREE.Face3( 1,3,0),new THREE.Face3( 0,3,2));
geometry.computeFaceNormals();
geometry.computeVertexNormals();
mesh2 = new THREE.Mesh( geometry, material );
scene.add( mesh2 );
// 2 end
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
mesh1.rotation.x += 0.01;
mesh1.rotation.y += 0.02;
mesh2.rotation.x += 0.01;
mesh2.rotation.y += 0.02;
renderer.render( scene, camera );
}
</script>
</body>
</html>
The following code tries to draw a component of a furniture:
<!DOCTYPE html>
<html>
<header>
<script src="three.min.js"></script>
<style>
body {
overflow: hidden;
}
</style>
</header>
<body>
<script>
var camera, scene, renderer;
var geometry, material, mesh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, 0, 550 );
camera.position.z = 4000;
scene = new THREE.Scene();
scene.add(camera);
function cos(x) {
return Math.cos(Math.PI*x/180);
}
function sin(x) {
return Math.sin(Math.PI*x/180);
}
var geometry = new THREE.Geometry();
var step_deg = 10;
var count = -1;
for(deg=0 ;deg<=360;deg+=step_deg) {
var x1,y1,z1,x2,y2,z2;
if (deg>=0 && deg<=90) {
x1 = 400+100*cos(deg); y1 = 900+100*sin(deg); z1=0;
x2 = x1; y2 = y1; z2 = 27;
geometry.vertices.push( new THREE.Vector3( x1,y1, z1), new THREE.Vector3( x2,y2,z2) );
count++; console.log(""+count+": ["+x1+","+y1+","+z1+"]");
count++; console.log(""+count+": ["+x2+","+y2+","+z2+"]");
}
if (deg>=90 && deg<=180) {
x1 = 50+50*cos(deg); y1 = 950+50*sin(deg); z1 = 0;
x2 = x1; y2 = y1; z2 = 27;
geometry.vertices.push( new THREE.Vector3( x1,y1, z1), new THREE.Vector3( x2,y2,z2) );
count++; console.log(""+count+": ["+x1+","+y1+","+z1+"]");
count++; console.log(""+count+": ["+x2+","+y2+","+z2+"]");
}
if (deg>=180 && deg<=270) {
x1 = 50+50*cos(deg); y1 = -950+50*sin(deg); z1 = 0;
x2 = x1; y2 = y1; z2 = 27;
geometry.vertices.push( new THREE.Vector3( x1,y1, z1), new THREE.Vector3( x2,y2,z2) );
count++; console.log(""+count+": ["+x1+","+y1+","+z1+"]");
count++; console.log(""+count+": ["+x2+","+y2+","+z2+"]");
}
if (deg>=270 && deg<=360) {
x1 = 400+100*cos(deg); y1 = -900+100*sin(deg); z1 = 0;
x2 = x1; y2 = y1; z2 = 27;
geometry.vertices.push( new THREE.Vector3( x1,y1, z1), new THREE.Vector3( x2,y2,z2) );
count++; console.log(""+count+": ["+x1+","+y1+","+z1+"]");
count++; console.log(""+count+": ["+x2+","+y2+","+z2+"]");
}
}
geometry.vertices.push( new THREE.Vector3( 400,900, 0), new THREE.Vector3( 400,900, 27) ); // 80, 81
geometry.vertices.push( new THREE.Vector3( 50,950, 0), new THREE.Vector3( 50,950, 27) );
geometry.vertices.push( new THREE.Vector3( 50,-950, 0), new THREE.Vector3( 50,-950, 27) );
geometry.vertices.push( new THREE.Vector3( 400,-900, 0), new THREE.Vector3( 400,-900, 27) ); // 86, 87
for(i=0;i<40;i++) {
geometry.faces.push( new THREE.Face3( i*2, (i*2+2) % 80, i*2+1) );
console.log("["+i*2+","+ ((i*2+2) % 80)+","+ (i*2+1)+"]");
geometry.faces.push( new THREE.Face3( i*2+1, (i*2+2) % 80, (i*2+3) % 80) );
console.log("["+(i*2+1)+","+ ((i*2+2)%80)+","+ ((i*2+3) % 80)+"]");
}
geometry.faces.push( new THREE.Face3( 82,20,80), new THREE.Face3( 18,80,20),
new THREE.Face3( 84,38,82), new THREE.Face3( 84,40,38),
new THREE.Face3( 80,86,82), new THREE.Face3( 82,86,84),
new THREE.Face3( 0,78,80), new THREE.Face3( 80,78,86),
new THREE.Face3( 60,84,86), new THREE.Face3( 60,58,84)
);
geometry.faces.push( new THREE.Face3( 83,81,21), new THREE.Face3( 19,21,81),
new THREE.Face3( 85,83,39), new THREE.Face3( 85,39,41),
new THREE.Face3( 81,83,87), new THREE.Face3( 83,85,87),
new THREE.Face3( 1,81,79), new THREE.Face3( 81,87,79),
new THREE.Face3( 61,87,85), new THREE.Face3( 61,85,59)
);
for(i=0;i<10;i++) {
geometry.faces.push( new THREE.Face3( 80, 2*(i+1), 2*i),new THREE.Face3( 81, 2*i+1, 2*(i+1)+1),
new THREE.Face3( 82, 2*(i+1)+20,2*i+20),new THREE.Face3( 83, 2*i+21, 2*(i+1)+21),
new THREE.Face3( 84, 2*(i+1)+40,2*i+40),new THREE.Face3( 85, 2*i+41, 2*(i+1)+41),
new THREE.Face3( 86, (2*(i+1)+60)%80,2*i+60),new THREE.Face3( 87, 2*i+61, (2*(i+1)+61)%80)
);
}
geometry.computeFaceNormals();
geometry.computeVertexNormals();
var box = new THREE.Box3().setFromPoints( geometry.vertices );
console.log( box.min, box.max, box.getSize() );
material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
renderer.render( scene, camera );
}
</script>
</body>
</html>
Basically it is the same technology but more complex. This second example does not show up.
My questions:
Is there a rule of dumb, given that the mesh is in x=0..500,y=-1000..1000,z=0..27 (mm), how do I set PerspectiveCamera and camera.position.z (or to generalize: given x=-X..X,y=-Y..Y,z=-Z..Z)?
How sensible is the library from stopping rendering the object (in the console there is no error!)?
Can the orientation of a some faces be inverted?
Can the surface be incomplete?
What else could be wrong?
EDIT
Now it works! I made following change
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 500, 0 );
camera.position.z = 3000;
If I understand it correctly, we are in the point (0,0,3000) observing in the direction of (0,0,0) with an angle of 60°, and the "near" is the xy-plane with z=500 resp. the "far" is the xy-plane with z=0. The mesh is 100% correct (at the first try! ;-) ).
EDIT 2 Fiddle with the complete furniture: link
Updated, now the animation make a lot more meaningful. But the main point is: I need the center of the furniture in the center of the picture. I need some sort of function "lookAt" for the camera and set it to the difference between camera position and furniture center (pos_center.add(pos_camera.negate()).normalize()).
The granite texture for the floor does not work, but this is another question.
I need to create perfect ring geometry in three.js. I am looking for something like this:
I spend more than a day to find how to do this, and I am stuck with code like this:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
var controls = new THREE.OrbitControls( camera, renderer.domElement );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
ring = '';
var loader = new THREE.TextureLoader();
loader.load('img/water.jpg', function ( texture ) {
var geometry = new THREE.TorusGeometry( 5, 1, 8, 1900 );
ring = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({map: texture, wireframe: true}));
scene.add(ring);
});
camera.position.z = 20;
var render = function () {
requestAnimationFrame( render );
ring.rotation.y = 0.4;
renderer.render(scene,camera);
};
render();
EDIT:
My code has changed, and now it looks like this:
var container, stats;
var camera, scene, renderer;
var group;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 100, 350, 00 );
scene.add( camera );
var light = new THREE.PointLight( 0xffffff, 0.9 );
camera.add( light );
group = new THREE.Group();
group.position.y = 0;
scene.add( group );
var loader = new THREE.TextureLoader();
var texture = loader.load( "img/metal.png" );
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 0.008, 0.008 );
function addShape( shape, extrudeSettings, color, x, y, z, rx, ry, rz, s ) {
// flat shape with texture
// note: default UVs generated by ShapeGemoetry are simply the x- and y-coordinates of the vertices
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { color: color } ) );
mesh.position.set( x, y, z );
mesh.rotation.set( rx, ry, rz );
mesh.scale.set( s, s, s );
group.add( mesh );
}
// Arc circle 1
var x = 0, y = 0;
var arcShape1 = new THREE.Shape();
arcShape1.moveTo( 0, 0 );
arcShape1.absarc( 10, 10, 11, 0, Math.PI*2, false );
var holePath1 = new THREE.Path();
holePath1.moveTo( 20, 10 );
holePath1.absarc( 10, 10, 10, 0, Math.PI*2, true );
arcShape1.holes.push( holePath1 );
//
// Arc circle 2
var x = 0, y = 0;
var arcShape2 = new THREE.Shape();
arcShape2.moveTo( 0, 0 );
arcShape2.absarc( 10, 10, 13, 0, Math.PI*2, false );
var holePath2 = new THREE.Path();
holePath2.moveTo( 25, 10 );
holePath2.absarc( 10, 10, 12, 0, Math.PI*2, true );
arcShape2.holes.push( holePath2 );
//
var extrudeSettings = { amount: 1.6, bevelEnabled: true, bevelSegments: 30, steps: 30, bevelSize: 0.3, bevelThickness: 1.5, curveSegments: 100 };
// addShape( shape, color, x, y, z, rx, ry,rz, s );
//addShape( heartShape, extrudeSettings, 0xf00000, 60, 100, 0, 0, 0, Math.PI, 1 );
addShape( arcShape1, extrudeSettings, 0xffc107, -35, -30, -20, 0, 0, 0, 4 );
addShape( arcShape2, extrudeSettings, 0xffc107, -40, -22, -50, 0, 0.6, 0, 4 );
//
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setClearColor( 0xf0f0f0 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMapEnabled = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
group.castShadow = true;
group.receiveShadow = false;
container.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
renderer.render( scene, camera );
}
The result looks like this:
And now the questions: how to make this line on the ring dissapear, how to make my ring more shiny, how to make my ring more 'circular' on the left and right side?
Should works fine. It was the bevel at junction at PI*2 causing the 'line' thing. You can solve the problem by overlapping the two edges of the curve.
arcShape1.absarc( 10, 10, 11, 0, Math.PI*1.99, false );
holePath1.absarc( 10, 10, 10, 0, Math.PI*2.01, true );
arcShape2.absarc( 10, 10, 13, 0, Math.PI*1.99, false );
holePath2.absarc( 10, 10, 12, 0, Math.PI*2.01, true );
! Please click to see the screenshot. I do not have enough reputation to post the picture here.
I found that by adding more light sources in various locations and color, I could increase perceived reflectivity and shine, but this is assuming it is the only object in the scene.
I have a strange problem, which can be a three.js bug, but it also can be my curve hands.
I have a scene with some meshes (in example below I used several transparent cubes and small spheres) and one line object (can be Line or LineSegments - doesn't matter) based on buffer geometry. While I rotating the camera line object sometimes disappears form view like it's covered by another object. It seems it also disappears if I cannot see the start point (if rotate camera to a degree where start point is offscreen, even without additional meshes) of the line while 90% of the line object should be in view.
The question is: Why does the line disappear and how should I prevent such its behavior?
This is how it looks on screencast:
http://screencast.com/t/HLC99OMmDdK
And this is an example of the problem:
http://jsfiddle.net/exiara/sa4bxhc3/
You should be able to see how line disappears when camera rotates.
The code of jsfiddle example:
var camera, controls, scene, renderer, dummy, projector,
stats, fps = 30, fpsTimeout = 1000 / fps,
linesGeometry,globalLine;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setClearColor(0xFFFFeF, 1);
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xFFFFeF, 100, 2500 );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 50000 );
camera.position.set(-450, 300, 650);
camera.target = new THREE.Vector3(0,0,0);
controls = new THREE.OrbitControls( camera );
controls.addEventListener('change', render );
// ------------ MAIN PART START ------------ //
var lines = 1000;
linesGeometry = new THREE.BufferGeometry();
var positions = new Float32Array( lines * 6 );
for ( var i = 0, j, ll = lines; i < ll; i++ ) {
j=i*6;
positions[j] = Math.random()*100;
positions[j+1] = Math.random()*100;
positions[j+2] = Math.random()*100;
positions[j+3] = Math.random()*100;
positions[j+4] = Math.random()*100;
positions[j+5] = Math.random()*100;
}
linesGeometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
globalLine = new THREE.Line( linesGeometry, new THREE.LineBasicMaterial({
color: 0x000000,
transparent: true,
opacity: 0.8
} ));
scene.add( globalLine );
// ------------ MAIN PART END ------------ //
// add cubes
var step = 400;
var gridSize = 4;
var offset = step*gridSize/2;
var cubeGeometry = new THREE.BoxGeometry(step, step, step);
var cubeMaterial = new THREE.MeshBasicMaterial({ color:0xFF0000, ambient: 0xCCCCCC, transparent: true, opacity: 0 });
var testCube, edge;
for (var x = -offset; x <= offset; x+=step) {
for (var y = -offset; y <= offset; y+=step) {
for (var z = -offset; z <= offset; z+=step) {
testCube = new THREE.Mesh(cubeGeometry,cubeMaterial);
testCube.position.set(x, y, z);
edge = new THREE.EdgesHelper( testCube, 0x000000 );
scene.add(testCube);
scene.add(edge);
}
}
}
// spheres
var sphereGeometry = new THREE.SphereGeometry( 10,32,16),
sphere;
var spheres = [
[0xff0000, 0, 0, 0 ], // red
[0x0000ff, 200, 0, 0 ], // blue
[0x00FF00, -200, 0, 0 ], // green
[0xFF00ff, 0, 200, 0 ], // magenta
[0x00ffff, 0, -200, 0 ], // aqua
[0xFFff00, 0, 0, 200 ], // lime
[0x000000, 0, 0, -200] // black
];
for (var i = 0, sl = spheres.length; i <sl; i++) {
sphere = new THREE.Mesh(sphereGeometry, new THREE.MeshBasicMaterial({color: spheres[i][0]}));
sphere.position.set(spheres[i][1], spheres[i][2], spheres[i][3]);
scene.add(sphere);
}
/* Stats */
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
document.body.appendChild( stats.domElement );
/* window observers */
window.addEventListener( 'resize', onWindowResize, false );
window.addEventListener( 'load', render, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function degInRad(deg) {
return deg * Math.PI / 180;
}
function animate()
{
setTimeout(function() {
requestAnimationFrame(animate);
}, fpsTimeout );
render();
}
function render() {
camera.lookAt(camera.target);
renderer.render( scene, camera );
stats.update();
}
The problem is that you are drawing multiple levels of opacity on top of each other and webgl needs to sort them. So the short answer is to add depthTest: false to your cube material.
var cubeMaterial = new THREE.MeshBasicMaterial({ color:0xFF0000, ambient: 0xCCCCCC, transparent: true, opacity: 0, depthTest: false });
But I would like to mention that what you are doing is inefficient. You should not be drawing a grid that way. Use lines instead.