three.js: Manually created geometry - javascript

I'm trying to create a THREE.Geometry from scratch.
When I try to use it (in a THREE.Mesh), I get
TypeError: faces3 is undefined # three.js:20426
The geometry is created and becomes visible on screen, but execution stops.
Here is the code I'm using:
makePlane = function(width, height)
{
var geom = new THREE.Geometry();
var v0 = new THREE.Vector3(0, 0, 0);
var v1 = new THREE.Vector3(width, 0, 0);
var v2 = new THREE.Vector3(width, height, 0);
geom.vertices.push(v0);
geom.vertices.push(v1);
geom.vertices.push(v2);
var face = new THREE.Face3(0, 1, 2);
geom.faces.push(face);
return geom;
};
What else do I need to do to make it work?
Update:
Still happens in R62. It happens with geometry generated by three.js' built in PlaneGeometry class too, so maybe it's a three.js bug. I'll file a report.
I should also mention that execution does in fact not stop, that was a mistake on my part. I'm just getting the error, and it doesn't feel like I should have any errors if nothing is wrong.
Update 2:
There's an issue logged here, but it's been closed.

Depending on what you do in further computation steps you may need to add these lines before you return the geom-Object:
geom.computeCentroids();
geom.computeFaceNormals();
geom.computeVertexNormals();

First off, make sure you are using the latest version of the three.js library.
In order for geometry to work, you need to make sure you have a few things set up.
You need to have a renderer, camera, scene, and your geometry.
Based on the documentation for Geometry, you need to provide a method to do something with the geometry afterwards such as computeCentroids() and computeBoundingBox().
Returning the value is not necessary here. It will actually prevent your object from showing up. Here is fully functional code for you based on your code. Just make sure your three.js reference is correct:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Custom Geometry</title>
</head>
<body>
<script src="three.min.js"></script>
<script>
var container,
camera,
scene,
renderer,
geom;
init();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
//renderer
renderer = new THREE.CanvasRenderer(); //Use CanvasRenderer with simple geometry
renderer.setSize(window.innerWidth, window.innerHeight);
//scene
scene = new THREE.Scene();
//camera
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.z = 500;
//Your custom geometry here
makePlane(200, 300);
container.appendChild(renderer.domElement);
renderer.render(scene, camera);
}
function makePlane(width, height) {
var material = new THREE.MeshBasicMaterial({ color: 0x297bbb });
geom = new THREE.Geometry()
geom.vertices.push(new THREE.Vector3(0, 0, 0));
geom.vertices.push(new THREE.Vector3(width, 0, 0));
geom.vertices.push(new THREE.Vector3(width, height, 0));
geom.faces.push(new THREE.Face3(0, 1, 2));
//return geom; //you don't need this
geom.computeBoundingSphere(); //<--add what you need here
geoMesh = new THREE.Mesh(geom, material); //added custom geometry to a mesh with a material
geoMesh.position.y = -50;
scene.add(geoMesh);
};
</script>
</body>
</html>

Related

Selecting and caluclating area of 'planes' in three.js

I am trying to calulate the area of a 'plane' of 3d object (.stl mesh object) n in three.js. By selecting it with a mouse click.
For example this area:
We know that all 'triangles' that make up the surface of the 'plane' (since it is an .stl) are attached at the same angle, if the angle changes in comparison to the last triangle, we know that this triangle is not part of the 'plane' anymore.
So knowing this is a property of the surface we are trying to calulate, we can use this in combination with some form of three.js Raycaster to select and calculate an area (by adding all the area's of the triangles with the correct properties together).
For now, we don't need to worry about the size of the selected surface (for example trying to find a 'plane' on a curved surface wouldn't be valid, but we do not need to worry about that now)
How would I go about trying to find the area and 'plane' in three.js. Or more specifically, how do I start reading the .stl format's 'triangles'.
Minimal working example of my current code (with working .stl file included), it can be run using a simple live server, for example in VS Code using Ritwick Dey's plugin, no extra plugins/libraries needed, since it's 'normal' HTML/JS.
The only requirement is that we select the point we are trying to calculate in three.js and give the area (selected triangles) a different colour, in three.js, when they are selected. Any other calculations needed could be done in some kind of backend (Python, Node.js or anything else really), but I see no obvious way of transporting such complicated data between programs.
My minimal reproduction code, see my abovementioned github link for the .stl file used in my picture:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stackoverflow Example</title>
<link rel="stylesheet" type="text/css" href="../style/render.css">
</head>
<body>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r117/build/three.min.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r117/examples/js/loaders/STLLoader.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r117/examples/js/controls/OrbitControls.js"></script>
<script>
function init() {
// Setup some basic stuff
scene = new THREE.Scene();
scene.background = new THREE.Color(0xdddddd);
// Setup Camera
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 5000);
// Setup renerer and add to page
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// Setup Camera Position
camera.rotation.y = 45 / 180 * Math.PI;
camera.position.x = 800;
camera.position.y = 100;
camera.position.z = 1000;
// Add Camera Control through orbit.js
let controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.addEventListener('change', renderer);
// Add some basic ambient lighting (Does light all parts equally and does not cast shadows)
hlight = new THREE.AmbientLight(0x404040, 20);
scene.add(hlight);
//Add some point lights to simulate real lights
light = new THREE.PointLight(0xc4c4c4, 1, 10000);
light.position.set(0, 300, 500);
scene.add(light);
light2 = new THREE.PointLight(0xc4c4c4, 1, 10000);
light2.position.set(500, 100, 0);
scene.add(light2);
light3 = new THREE.PointLight(0xc4c4c4, 1, 10000);
light3.position.set(0, 100, -500);
scene.add(light3);
light4 = new THREE.PointLight(0xc4c4c4, 1, 10000);
light4.position.set(-500, 300, 0);
scene.add(light4);
controls.update();
// Animation Script
function animate() {
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
// Setup GLTF Loader and load in obj
let loader = new THREE.STLLoader();
loader.load('example.stl', function (geometry) {
// console.log(gltf);
var material = new THREE.MeshPhongMaterial({
color: 0x171717,
shininess: 200
});
var mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
mesh.position.set(0, 0, 0);
scene.add(mesh);
renderer.render(scene, camera)
animate();
});
}
// Call method for starting init
init();
</script>
</body>
</html>
EDIT:
Example of my intended output, but in Fusion 360 instead of three.js (Note, the original file is a .stl but since three.js doesn't allow for part viewing, it is converted to .stl in the backend)
Example of the 'triangles' in a .stl file

Rendering Complicated Models in Three.js

if some rockstar could look through my code real quick and tell me why I cant render/see my three.js model I'd be forever in your debt!
I'll post the whole script, but I think some preliminary info is important. Basically, I have thousands of points that look like this:
472232.14363148 2943288.56768013 200.129142"
472237.03086105 2943289.62356560 200.119496"
472241.91809061 2943290.67945108 200.109851"
472246.80532018 2943291.73533656 200.100205"
...and so on...
and a bunch of faces that look like this:
["1021 1020 1061", "640 754 641", "1534 1633 1535", "4701 27 26", "654 753 655", ...and so on...
When I extracted all the data and configured it correctly I then push it to the geometry and try to add it to the scene but with no success. Here's the whole script:
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 0, 50, 50 );
camera.lookAt( 0, 0, 0 );
var scene = new THREE.Scene();
var material = new THREE.MeshStandardMaterial( { color : 0x00cc00 } );
var geometry = new THREE.Geometry();
var points = bigData['LandXML']['Surfaces']['Surface']['Definition']['Pnts']['P']
var faces = bigData['LandXML']['Surfaces']['Surface']['Definition']['Faces']['F']
for(i=0;i<points.length;i++){
var [point1,point2,point3] = points[i]['__text'].split(' ').map(Number)
//point1 *= .00001
//point2 *= .00001
//point3 *= .00001
geometry.vertices.push(new THREE.Vector3(point1,point2,point3))
}
for(i=0;i<faces.length;i++){
console.log(faces[i]);
var [face1,face2,face3] = faces[i].split(' ').map(Number)
var face = new THREE.Face3(face1 - 1,face2 - 1, face3 - 1)
geometry.faces.push(face)
}
scene.add( new THREE.Mesh( geometry, material ) );
You can see that in the for loop for the points, I have multiplied them by .00001 to scale the model because otherwise the numbers are so huge, if that makes sense. And I subtract 1 from each face because the data was not zero indexed. Anyways, if any coding superhero took the time to read this and has some insight, please help me out! Thanks!
So, I found your model on scene, the code missed those parts:
Your model has big coordinates, but small dimension. After dividing
all coordinates by 100.000 it has boundingSphere center at (4.72;
29,432; 0,00192) and boundingSphere radius 0,00480, So you need
to either translate model so it has center at (0;0;0) or move camera
target to it's center;
geometry.computeFaceNormals() must be called after building faces
in order to make faces resposive to lighting and shading;
Scene needs some light in it. In curent state it will not show
anything
Render loop or at least single call after adding mesh is required.
Here is fixed code, additionally I played with camera distance and added simple rotation animation. Also I used geometry translation approach to have an adequate rotation:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>DXF Test</title>
</head>
<body>
<script src="three.min.js"></script>
<script type="text/javascript" src="JFM.js"></script>
<script>
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.set(0, 650, 650);
camera.lookAt(0, 0, 0);
var scene = new THREE.Scene();
var material = new THREE.MeshStandardMaterial({color: 0x00cc00});
var geometry = new THREE.Geometry();
//geometry.vertices.push(new THREE.Vector3(4.72227256402, 29.4328751179, 0.00200138787));
//geometry.vertices.push(new THREE.Vector3(3, 3, 0));
//geometry.vertices.push(new THREE.Vector3(5, 6, 0));
//var line = new THREE.Line( geometry, material );
//scene.add( line );
//renderer.render( scene, camera );
var points = bigData['LandXML']['Surfaces']['Surface']['Definition']['Pnts']['P'];
var faces = bigData['LandXML']['Surfaces']['Surface']['Definition']['Faces']['F'];
console.log('Complete XML file');
console.log(bigData);
console.log('POINTS');
console.log(points);
console.log('FACES');
console.log(faces);
for (i = 0; i < points.length; i++) {
var [point1, point2, point3] = points[i]['__text'].split(' ').map(Number);
geometry.vertices.push(new THREE.Vector3(point1, point2, point3));
}
for (i = 0; i < faces.length; i++) {
var [face1, face2, face3] = faces[i].split(' ').map(Number);
var face = new THREE.Face3(face1 - 1, face3 - 1, face2 - 1);
geometry.faces.push(face)
}
geometry.computeFaceNormals();
geometry.computeBoundingSphere();
// translate model so it's real center will be the same as mesh pivot
geometry.translate(
-geometry.boundingSphere.center.x,
-geometry.boundingSphere.center.y,
-geometry.boundingSphere.center.z
);
// compute bounding sphere again, because it was broken during translation
geometry.computeBoundingSphere();
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
var sunLight = new THREE.DirectionalLight(0xffffff);
sunLight.position.set(200, 600, 1000);
scene.add(sunLight);
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
mesh.rotation.y += 0.01;
mesh.rotation.x += 0.01;
}
animate();
</script>
</body>
</html>
If you don't like translation, you can remove it, remove rotation and after computeBoundingSphere do like this:
camera.position.set(
geometry.boundingSphere.center.x + geometry.boundingSphere.radius,
geometry.boundingSphere.center.y + geometry.boundingSphere.radius,
geometry.boundingSphere.center.z + geometry.boundingSphere.radius,
);
camera.lookAt(
geometry.boundingSphere.center.x,
geometry.boundingSphere.center.y,
geometry.boundingSphere.center.z,
);
Hope it will help.

Why is my canvas element showing only a black screen?

I'm setting up a 3d asset viewer in Three.js. I'm running the code on a Plesk server provided by the university and have it linked via Dreamweaver. I'm a total newbie to JS and it was suggested in many threads and posts that I wrap my code within an 'init();' function. Up doing so, and clearing any errors that the code had, it is now showing a black screen, rather than the 3d model it would show before.
I've spent the whole day error checking removing problems that I was having which included the 'canvas' not being created inside the 'container' div, and the 'onWindowResize' function. All these problems have been resolved, and there are no errors in the code apparently. I've got ambient lights in the code and there was a working skybox, so I'm sure its not a problem with position of camera or lack of lighting.
I know that you need as little code as possible, but I have no idea where the problem is coming from, so a majority of the code on the page is here :
<div id="container" ></div>
<script>
let container;
let camera;
let controls;
let scene;
let renderer;
init();
animate;
function init(){
// Renderer - WebGL is primary Renderer for Three.JS
var renderer = new THREE.WebGLRenderer({antialias : true});
renderer.setClearColor(0xEEEEEE, 0.5);
// Selects and applies parameters to the 'Container' div
var container = document.querySelector("#container");
container.appendChild(renderer.domElement);
renderer.setSize(container.clientWidth, container.clientHeight);
// Perspective Camera (FOV, aspect ratio based on container, near, far)
var camera = new THREE.PerspectiveCamera( 75, container.clientWidth / container.clientHeight, 0.1, 1000);
camera.position.x = 750;
camera.position.y = 500;
camera.position.z = 1250;
// Scene will contain all objects in the world
var scene = new THREE.Scene();
//Lighting (Colour, intensity)
var light1Ambient = new THREE.AmbientLight(0xffffff , 0.3);
scene.add(light1Ambient);
var light1Point = new THREE.PointLight(0xfff2c1, 0.5, 0, 2);
scene.add(light1Point);
var light2Point = new THREE.PointLight(0xd6e3ff, 0.4, 0, 2);
scene.add(light2Point);
// All basic Geomety
var newPlane = new THREE.PlaneGeometry(250,250,100,100);
const mesh = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshBasicMaterial( {color: 0x00ff00} )
);
scene.add(mesh);
// Water
water = new THREE.Water(newPlane,
{
textureWidth: 512,
textureHeight: 512,
waterNormals: new THREE.TextureLoader().load( 'http://up826703.ct.port.ac.uk/CTPRO/textures/waternormals.jpg', function ( texture ) {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
} ),
alpha: 1.0,
sunDirection: light1Point.position.clone().normalize(),
sunColor: 0xffffff,
waterColor: 0x001e0f,
distortionScale: 0.5,
fog: scene.fog !== undefined
}
);
water.rotation.x = - Math.PI / 2;
scene.add( water );
// All Materials (Normal for Debugging) (Lambert: color)
var material = new THREE.MeshLambertMaterial({color: 0xF3FFE2});
var materialNew = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
// Skybox
var skybox = new THREE.BoxGeometry(1000,1000, 1000);
var skyboxMaterials =
[
new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load("http://up826703.ct.port.ac.uk/CTPRO/skybox/blue/bluecloud_ft.jpg"), side: THREE.DoubleSide }),
new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load("http://up826703.ct.port.ac.uk/CTPRO/skybox/blue/bluecloud_bk.jpg"), side: THREE.DoubleSide }),
new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load("http://up826703.ct.port.ac.uk/CTPRO/skybox/blue/bluecloud_up.jpg"), side: THREE.DoubleSide }),
new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load("http://up826703.ct.port.ac.uk/CTPRO/skybox/blue/bluecloud_dn.jpg"), side: THREE.DoubleSide }),
new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load("http://up826703.ct.port.ac.uk/CTPRO/skybox/blue/bluecloud_rt.jpg"), side: THREE.DoubleSide }),
new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load("http://up826703.ct.port.ac.uk/CTPRO/skybox/blue/bluecloud_lf.jpg"), side: THREE.DoubleSide }),
];
var skyboxMaterial = new THREE.MeshFaceMaterial(skyboxMaterials);
var skyMesh = new THREE.Mesh (skybox, skyboxMaterial);
scene.add(skyMesh);
//Grid Helper Beneath Ship
scene.add(new THREE.GridHelper(250, 250));
//OBJ Model Loading
var objLoader = new THREE.OBJLoader();
objLoader.load('http://up826703.ct.port.ac.uk/CTPRO/models/ship1.obj', function(object){
scene.add(object);
});
// Object positioning
water.position.y = -2.5;
// Misc Positioning
light1Point.position.z =20;
light1Point.position.x = 25;
// z - front-back position
light2Point.position.z = -400;
// x - left-right
light2Point.position.x = -25;
// y - up- down
light2Point.position.y = 250;
window.addEventListener("resize", onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(container.clientWidth, container.clientHeight);
};
};
// Canvas adapts size based on changing windows size
//Render loop
var animate = function(){
water.material.uniforms[ "time" ].value += 1.0 / 120.0;
function drawFrame(ts){
var center = new THREE.Vector2(0,0);
window.requestAnimationFrame(drawFrame);
var vLength = newPlane.geometry.vertices.length;
for (var i = 0; i < vLength; i++) {
var v = newPlane.geometry.vertices[i];
var dist = new THREE.Vector2(v.x, v.y).sub(center);
var size = 2.0;
var magnitude = 8;
v.z = Math.sin(dist.length()/-size + (ts/900)) * magnitude;
}
newPlane.geometry.verticesNeedUpdate = true;
};
requestAnimationFrame(animate)
renderer.render(scene, camera);
controls.update();
}
</script>
I'm no professional, so I'm sorry if this is super rough for those of you with experience!
I need to point out, before wrapping all of this in the init(); function, it was working perfectly.
When working, I should see a crudely modeled ship sitting in some water, with a cloud skybox. The controls were working and it would auto rotate.
Right now it does none of this. The obj loader is working as seen in the chrome console log OBJLoader: 1661.970703125ms but again, nothing is actually displayed, it's just a black screen.
Thanks to anyone who's able to help me out with this!
this line
animate;
needs to a function call
animate();
Also you probably need to change the code below where you create the animate function from
var animate = function(){
To this
function animate(){
The reason is named functions are defined when the code is loaded but variables var are created when the code is executed. So with code like this
init();
animate();
var animate = function(){ ...
animate doesn't actually exist at the point the code tries to call it whereas with this
init();
animate();
function animate(){ ...
it does exist
You could also re-arrange the code so for example define animate before you use it should work.
var animate = function(){
...
};
init();
animate();
It also appear some are declared inside init which means that are not available to animate. So for example
var renderer = new THREE.WebGLRenderer({antialias : true});
declares a new variable renderer that only init can see. You wanted to set the renderer variable that is outside of init so change the code to
renderer = new THREE.WebGLRenderer({antialias : true});
controls is never defined so you probably need to define it or comment out
controls.update();
to
// controls.update();
note: you might find these tutorials helpful although if you're new to JavaScript you should probably spend time learning JavaScript

Three.js ply colorless (all black)

I am trying to load my ply file using Three.js. It has worked but I almost don't see any colors. There are some glimpses here and there, but it's mostly black (the first image below). The image opens properly (with colors) in MeshLab (the second image below). I have tried vertexColors: THREE.VertexColors (as suggested in Three.js - ply files - why colorless?) and vertexColors: THREE.FaceColors but nothing seemed to help. I am a three.js newbie, so please tell me what am I doing wrong.
and my code:
<!doctype html>
<html lang="en">
<head>
<title>Icon 7</title>
<meta charset="utf-8">
</head>
<body style="margin: 0;">
<script src="js/three.min.js"></script>
<script src="js/PLYLoader.js"></script>
<script src="js/OrbitControls.js"></script>
<script>
// Set up the scene, camera, and renderer as global variables.
var scene, camera, renderer;
init();
animate();
// Sets up the scene.
function init() {
// Create the scene and set the scene size.
scene = new THREE.Scene();
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
// Create a renderer and add it to the DOM.
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(WIDTH, HEIGHT);
document.body.appendChild(renderer.domElement);
// Create a camera, zoom it out from the model a bit, and add it to the scene.
camera = new THREE.PerspectiveCamera(35, WIDTH / HEIGHT, 0.1, 100);
camera.position.set(0,0.15,3);
camera.lookAt(new THREE.Vector3(0,0,0));
scene.add(camera);
// Create an event listener that resizes the renderer with the browser window.
window.addEventListener('resize', function() {
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
});
// Set the background color of the scene.
renderer.setClearColor(0xd3d3d3, 1);
// Create a light, set its position, and add it to the scene.
var light = new THREE.PointLight(0xffffff);
light.position.set(0,200,100);
scene.add(light);
// Load in the mesh and add it to the scene.
var loader = new THREE.PLYLoader();
loader.load( './models/foot.ply', function ( geometry ) {
geometry.computeVertexNormals();
geometry.center();
var material = new THREE.MeshStandardMaterial ({ shininess: 1000,vertexColors: THREE.FaceColors } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.x = 0;
mesh.position.y = 0;
mesh.position.z = 0;
mesh.castShadow = false;
mesh.receiveShadow = false;
scene.add( mesh );
} );
// Add OrbitControls so that we can pan around with the mouse.
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.userPanSpeed = 0.05;
}
// Renders the scene and updates the render as needed.
function animate() {
// Read more about requestAnimationFrame at http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
requestAnimationFrame(animate);
// Render the scene.
renderer.render(scene, camera);
controls.update();
}
</script>
</body>
</html>
Edit: as I don't have separate textures, this is not a duplicate question.
Instead of using MeshStandardMaterial use MeshBasicMaterial

Does three.js renderer clone the objects positions?

I created a small scene with 3 spheres and a triangle connecting the 3 centers of the spheres, i.e. the triangle vertex positions are the same variables as the sphere positions.
Now I expected that if i change the position of one of the spheres, the triangle vertex should be moved together with it (since it's the same position object) and therefore still connect the three spheres.
However, if I do this coordinate change AFTER the renderer was called, the triangle is NOT changed. (Though it does change if I move the sphere BEFORE the renderer is called.)
This seems to indicate that the renderer doesnt use the original position objects but a clone of them.
Q: Is there a way to avoid this cloning behaviour (or whatever is the reason for the independent positions) so I can still change two objects with one variable change? Or am I doing something wrong?
The code:
var width = window.innerWidth;
var height = window.innerHeight;
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
var scene = new THREE.Scene;
var camera = new THREE.PerspectiveCamera(30, width / height, 0.1, 10000);
camera.position=new THREE.Vector3(50,50,50);
camera.lookAt(new THREE.Vector3(0,0,0));
scene.add(camera);
var pointLight = new THREE.PointLight(0xffffff);
pointLight.position=camera.position;
scene.add(pointLight);
var sphere=[];
var sphereGeometry = new THREE.SphereGeometry(1,8,8);
var sphereMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 });
var triGeom = new THREE.Geometry();
for (var i=0; i<3; i++) {
sphere[i] = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere[i].position=new THREE.Vector3(10*i,20+5*(i-1)^2,0);
scene.add(sphere[i]);
triGeom.vertices.push(sphere[i].position);
}
triGeom.faces.push( new THREE.Face3( 0, 1, 2 ) );
triGeom.computeFaceNormals();
var tri= new THREE.Mesh( triGeom, new THREE.MeshLambertMaterial({side:THREE.DoubleSide, color: 0x00ff00}) );
scene.add(tri);
sphere[0].position.x+=10; // this changes both sphere and triangle vertex
renderer.render(scene, camera);
sphere[1].position.x+=10; // this changes only the sphere
renderer.render(scene, camera);
This is probably because of geometry caching feature. You will have to set triGeom.verticesNeedUpdate = true every time you change vertex position.

Categories

Resources