Rotating icosahedron with circles located at every vertex in three.js - javascript

I have an icosahedron mesh which I am rotating and then adding circle geometries and setting their location to each vertex at every frame in the animation loop.
geometry = new THREE.IcosahedronGeometry(isoRadius, 1);
var material = new THREE.MeshBasicMaterial({
color: wireframeColor,
wireframe: true
});
isoMesh = new THREE.Mesh(geometry, material);
scene.add(isoMesh);
Set each circle geometries location as the icosahedron mesh rotates:
function animate() {
isoMesh.rotation.x += 0.005;
isoMesh.rotation.y += 0.002;
// update vertices
isoMesh.updateMatrix();
isoMesh.geometry.applyMatrix(isoMesh.matrix);
isoMesh.rotation.set(0, 0, 0);
for (var i = 0; i < geometry.vertices.length; i++) {
nodes[i].position.copy(geometry.vertices[i]);
nodes[i].lookAt(camera.position);
}
Where var geometry is the geometry of the icosahedron. If I remove the line "isoMesh.rotation.set(0, 0, 0);", the icosahedron rotates correctly, but the rotation of the nodes compounds and spins way too quickly. If I add that line, the nodes rotate correctly, but the icosahedron does not move at all.
I do not understand three.js well enough yet to understand what is happening. Why would adding and removing this affect the nodes' and icosahedron's rotations separately? I believe it has something to do with the difference between the mesh and the geometry since I am using the geometry to position the nodes, but the rotation of the mesh is what shows visually. Any idea what is happening here?

The solution it multi-layered.
Your Icosahedron:
You were half-way there with rotating your icosahedron and its vertices. Rather than applying the rotation to all the vertices (which would actually cause some pretty extreme rotation), apply the rotation to the mesh only. But that doesn't update the vertices, right? Right. More on that in a moment.
Your Circles:
You have the right idea of placing them at each vertex, but as WestLangley said, you can't use lookAt for objects with rotated/translated parents, so you'll need to add them directly to the scene. Also, if you can't get the new positions of the vertices for the rotated icosahedron, the circles will simply remain in place. So let's get those updated vertices.
Getting Updated Vertex Positions:
Like I said above, rotating the mesh updates its transformation matrix, not the vertices. But we can USE that updated transformation matrix to get the updated matrix positions for the circles. Object3D.localToWorld allows us to transform a local THREE.Vector3 (like your icosahedron's vertices) into world coordinates. (Also note that I did a clone of each vertex, because localToWorld overwrites the given THREE.Vector3).
Takeaways:
I've tried to isolate the parts relative to your question into the JavaScript portion of the snippet below.
Try not to update geometry unless you have to.
Only use lookAt with objects in the world coordinate system
Use localToWorld and worldToLocal to transform vectors between
coordinate systems.
// You already had this part
var geometry = new THREE.IcosahedronGeometry(10, 1);
var material = new THREE.MeshBasicMaterial({
color: "blue",
wireframe: true
});
var isoMesh = new THREE.Mesh(geometry, material);
scene.add(isoMesh);
// Add your circles directly to the scene
var nodes = [];
for(var i = 0, l = geometry.vertices.length; i < l; ++i){
nodes.push(new THREE.Mesh(new THREE.CircleGeometry(1, 32), material));
scene.add(nodes[nodes.length - 1]);
}
// This is called in render. Get the world positions of the vertices and apply them to the circles.
var tempVector = new THREE.Vector3();
function updateVertices(){
if(typeof isoMesh !== "undefined" && typeof nodes !== "undefined" && nodes.length === isoMesh.geometry.vertices.length){
isoMesh.rotation.x += 0.005;
isoMesh.rotation.y += 0.002;
for(var i = 0, l = nodes.length; i < l; ++i){
tempVector.copy(isoMesh.geometry.vertices[i]);
nodes[i].position.copy(isoMesh.localToWorld(tempVector));
nodes[i].lookAt(camera.position);
}
}
}
html *{
padding: 0;
margin: 0;
width: 100%;
overflow: hidden;
}
#host {
width: 100%;
height: 100%;
}
<script src="http://threejs.org/build/three.js"></script>
<script src="http://threejs.org/examples/js/controls/TrackballControls.js"></script>
<script src="http://threejs.org/examples/js/libs/stats.min.js"></script>
<div id="host"></div>
<script>
// INITIALIZE
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight,
FOV = 35,
NEAR = 1,
FAR = 1000;
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
document.getElementById('host').appendChild(renderer.domElement);
var stats= new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0';
document.body.appendChild(stats.domElement);
var camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
camera.position.z = 50;
var trackballControl = new THREE.TrackballControls(camera, renderer.domElement);
trackballControl.rotateSpeed = 5.0; // need to speed it up a little
var scene = new THREE.Scene();
var light = new THREE.PointLight(0xffffff, 1, Infinity);
camera.add(light);
scene.add(light);
function render(){
if(typeof updateVertices !== "undefined"){
updateVertices();
}
renderer.render(scene, camera);
stats.update();
}
function animate(){
requestAnimationFrame(animate);
trackballControl.update();
render();
}
animate();
</script>

Related

smooth terrain from height map three js

I am currently trying to create some smooth terrain using the PlaneBufferGeometry of three.js from a height map I got from Google Images:
https://forums.unrealengine.com/filedata/fetch?id=1192062&d=1471726925
but the result is kinda choppy..
(Sorry, this is my first question and evidently I need 10 reputation to post images, otherwise I would.. but here's an even better thing: a live demo! left click + drag to rotate, scroll to zoom)
I want, like i said, a smooth terrain, so am I doing something wrong or is this just the result and i need to smoothen it afterwards somehow?
Also here is my code:
const IMAGE_SRC = 'terrain2.png';
const SIZE_AMPLIFIER = 5;
const HEIGHT_AMPLIFIER = 10;
var WIDTH;
var HEIGHT;
var container = jQuery('#wrapper');
var scene, camera, renderer, controls;
var data, plane;
image();
// init();
function image() {
var image = new Image();
image.src = IMAGE_SRC;
image.onload = function() {
WIDTH = image.width;
HEIGHT = image.height;
var canvas = document.createElement('canvas');
canvas.width = WIDTH;
canvas.height = HEIGHT;
var context = canvas.getContext('2d');
console.log('image loaded');
context.drawImage(image, 0, 0);
data = context.getImageData(0, 0, WIDTH, HEIGHT).data;
console.log(data);
init();
}
}
function init() {
// initialize camera
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, .1, 100000);
camera.position.set(0, 1000, 0);
// initialize scene
scene = new THREE.Scene();
// initialize directional light (sun)
var sun = new THREE.DirectionalLight(0xFFFFFF, 1.0);
sun.position.set(300, 400, 300);
sun.distance = 1000;
scene.add(sun);
var frame = new THREE.SpotLightHelper(sun);
scene.add(frame);
// initialize renderer
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x000000);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.append(renderer.domElement);
// initialize controls
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = .05;
controls.rotateSpeed = .1;
// initialize plane
plane = new THREE.PlaneBufferGeometry(WIDTH * SIZE_AMPLIFIER, HEIGHT * SIZE_AMPLIFIER, WIDTH - 1, HEIGHT - 1);
plane.castShadow = true;
plane.receiveShadow = true;
var vertices = plane.attributes.position.array;
// apply height map to vertices of plane
for(i=0, j=2; i < data.length; i += 4, j += 3) {
vertices[j] = data[i] * HEIGHT_AMPLIFIER;
}
var material = new THREE.MeshPhongMaterial({color: 0xFFFFFF, side: THREE.DoubleSide, shading: THREE.FlatShading});
var mesh = new THREE.Mesh(plane, material);
mesh.rotation.x = - Math.PI / 2;
mesh.matrixAutoUpdate = false;
mesh.updateMatrix();
plane.computeFaceNormals();
plane.computeVertexNormals();
scene.add(mesh);
animate();
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
controls.update();
}
The result is jagged because the height map has low color depth. I took the liberty of coloring a portion of the height map (Paint bucket in Photoshop, 0 tolerance, non-continuous) so you can see for yourself how large are the areas which have the same color value, i.e. the same height.
The areas of the same color will create a plateau in your terrain. That's why you have plateaus and sharp steps in your terrain.
What you can do is either smooth out the Z values of the geometry or use a height map which utilizes 16bits or event 32bits for height information. The current height map only uses 8bits, i.e. 256 values.
One thing you could do to smooth things out a bit is to sample more than just a single pixel from the heightmap. Right now, the vertex indices directly correspond to the pixel position in the data-array. And you just update the z-value from the image.
for(i=0, j=2; i < data.length; i += 4, j += 3) {
vertices[j] = data[i] * HEIGHT_AMPLIFIER;
}
Instead you could do things like this:
get multiple samples with certain offsets along the x/y axes
compute an (weighted) average value from the samples
That way you would get some smoothing at the borders of the same-height areas.
The second option is to use something like a blur-kernel (gaussian blur is horribly expensive, but maybe something like a fast box-blur would work for you).
As you are very limited in resolution due to just using a single byte, you should convert that image to float32 first:
const highResData = new Float32Array(data.length / 4);
for (let i = 0; i < highResData.length; i++) {
highResData[i] = data[4 * i] / 255;
}
Now the data is in a format that allows for far higher numeric resolution, so we can smooth that now. You could either adjust something like the StackBlur for the float32 use-case, use ndarrays and ndarray-gaussian-filter or implement something simple yourself. The basic idea is to find an average value for all the values in those uniformly colored plateaus.
Hope that helps, good luck :)

Incrementally display three.js TubeGeometry

I am able to display a THREE.TubeGeometry figure as follows
Code below, link to jsbin
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r75/three.js"></script>
<script>
// global variables
var renderer;
var scene;
var camera;
var geometry;
var control;
var count = 0;
var animationTracker;
init();
drawSpline();
function init()
{
// create a scene, that will hold all our elements such as objects, cameras and lights.
scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// create a render, sets the background color and the size
renderer = new THREE.WebGLRenderer();
renderer.setClearColor('lightgray', 1.0);
renderer.setSize(window.innerWidth, window.innerHeight);
// position and point the camera to the center of the scene
camera.position.x = 0;
camera.position.y = 40;
camera.position.z = 40;
camera.lookAt(scene.position);
// add the output of the renderer to the html element
document.body.appendChild(renderer.domElement);
}
function drawSpline(numPoints)
{
var numPoints = 100;
// var start = new THREE.Vector3(-5, 0, 20);
var start = new THREE.Vector3(-5, 0, 20);
var middle = new THREE.Vector3(0, 35, 0);
var end = new THREE.Vector3(5, 0, -20);
var curveQuad = new THREE.QuadraticBezierCurve3(start, middle, end);
var tube = new THREE.TubeGeometry(curveQuad, numPoints, 0.5, 20, false);
var mesh = new THREE.Mesh(tube, new THREE.MeshNormalMaterial({
opacity: 0.9,
transparent: true
}));
scene.add(mesh);
renderer.render(scene, camera);
}
</script>
</body>
</html>
However, I would like to display incrementally, as in, like an arc that is loading, such that it starts as the start point, draws incrementally and finally looks the below arc upon completion.
I have been putting in some effort, and was able to do this by storing all the points/coordinates covered by the arc, and drawing lines between the consecutive coordinates, such that I get the 'arc loading incrementally' feel. However, is there a better way to achieve this? This is the link to jsbin
Adding the code here as well
<!DOCTYPE html>
<html>
<head>
<title>Incremental Spline Curve</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r75/three.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<script>
// global variables
var renderer;
var scene;
var camera;
var splineGeometry;
var control;
var count = 0;
var animationTracker;
// var sphereCamera;
var sphere;
var light;
function init() {
// create a scene, that will hold all our elements such as objects, cameras and lights.
scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// create a render, sets the background color and the size
renderer = new THREE.WebGLRenderer();
// renderer.setClearColor(0x000000, 1.0);
renderer.setClearColor( 0xffffff, 1 );
renderer.setSize(window.innerWidth, window.innerHeight);
// position and point the camera to the center of the scene
camera.position.x = 0;
camera.position.y = 40;
camera.position.z = 40;
camera.lookAt(scene.position);
// add the output of the renderer to the html element
document.body.appendChild(renderer.domElement);
// //init for sphere
// sphereCamera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
// sphereCamera.position.y = -400;
// sphereCamera.position.z = 400;
// sphereCamera.rotation.x = .70;
sphere = new THREE.Mesh(new THREE.SphereGeometry(0.8,31,31), new THREE.MeshLambertMaterial({
color: 'yellow',
}));
light = new THREE.DirectionalLight('white', 1);
// light.position.set(0,-400,400).normalize();
light.position.set(0,10,10).normalize();
//get points covered by Spline
getSplineData();
}
//save points in geometry.vertices
function getSplineData() {
var curve = new THREE.CubicBezierCurve3(
new THREE.Vector3( -5, 0, 10 ),
new THREE.Vector3(0, 20, 0 ),
new THREE.Vector3(0, 20, 0 ),
new THREE.Vector3( 2, 0, -25 )
);
splineGeometry = new THREE.Geometry();
splineGeometry.vertices = curve.getPoints( 50 );
animate();
}
//scheduler loop
function animate() {
if(count == 50)
{
cancelAnimationFrame(animationTracker);
return;
}
//add line to the scene
drawLine();
renderer.render(scene, camera);
// renderer.render(scene, sphereCamera);
count += 1;
// camera.position.z -= 0.25;
// camera.position.y -= 0.25;
animationTracker = requestAnimationFrame(animate);
}
function drawLine() {
var lineGeometry = new THREE.Geometry();
var lineMaterial = new THREE.LineBasicMaterial({
color: 0x0000ff
});
console.log(splineGeometry.vertices[count]);
console.log(splineGeometry.vertices[count+1]);
lineGeometry.vertices.push(
splineGeometry.vertices[count],
splineGeometry.vertices[count+1]
);
var line = new THREE.Line( lineGeometry, lineMaterial );
scene.add( line );
}
// calls the init function when the window is done loading.
window.onload = init;
</script>
<body>
</body>
</html>
Drawback : The drawback of doing it the above way is that, end of the day, I'm drawing a line between consecutive points, and so I lose out on a lot of the effects possible in TubeGeometry such as, thickness, transparency etc.
Please suggest me an alternative way to get a smooth incremental load for the TubeGeometry.
THREE.TubeGeometry returns a THREE.BufferGeometry.
With THREE.BufferGeometry, you have access to a property drawRange that you can set to animate the drawing of the mesh:
let nEnd = 0, nMax, nStep = 90; // 30 faces * 3 vertices/face
...
const geometry = new THREE.TubeGeometry( path, pathSegments, tubeRadius, radiusSegments, closed );
nMax = geometry.attributes.position.count;
...
function animate() {
requestAnimationFrame( animate );
nEnd = ( nEnd + nStep ) % nMax;
mesh.geometry.setDrawRange( 0, nEnd );
renderer.render( scene, camera );
}
EDIT: For another approach, see this SO answer.
three.js r.144
Normally you would be able to use the method .getPointAt() to "get a vector for point at relative position in curve according to arc length" to get a point at a certain percentage of the length of the curve.
So normally if you want to draw 70% of the curve and a full curve is drawn in 100 segments. Then you could do:
var percentage = 70;
var curvePath = new THREE.CurvePath();
var end, start = curveQuad.getPointAt( 0 );
for(var i = 1; i < percentage; i++){
end = curveQuad.getPointAt( percentage / 100 );
lineCurve = new THREE.LineCurve( start, end );
curvePath.add( lineCurve );
start = end;
}
But I think this is not working for your curveQuad since the getPointAt method is not implemented for this type. A work around is to get a 100 points for your curve in an array like this:
points = curve.getPoints(100);
And then you can do almost the same:
var percentage = 70;
var curvePath = new THREE.CurvePath();
var end, start = points[ 0 ];
for(var i = 1; i < percentage; i++){
end = points[ percentage ]
lineCurve = new THREE.LineCurve( start, end );
curvePath.add( lineCurve );
start = end;
}
now your curvePath holds the line segments you want to use for drawing the tube:
// draw the geometry
var radius = 5, radiusSegments = 8, closed = false;
var geometry = new THREE.TubeGeometry(curvePath, percentage, radius, radiusSegments, closed);
Here a fiddle with a demonstration on how to use this dynamically
I'm not really that familiar with three.js. But I think I can be of assistance. I have two solutions for you. Both based on the same principle: build a new TubeGeometry or rebuild the current one, around a new curve.
Solution 1 (Simple):
var CurveSection = THREE.Curve.create(function(base, from, to) {
this.base = base;
this.from = from;
this.to = to;
}, function(t) {
return this.base.getPoint((1 - t) * this.from + t * this.to);
});
You define a new type of curve which just selects a segment out of a given curve. Usage:
var curve = new CurveSection(yourCurve, 0, .76); // Where .76 is your percentage
Now you can build a new tube.
Solution 2 (Mathematics!):
You are using for your arc a quadratic bezier curve, that's awesome! This curve is a parabola. You want just a segment of that parabola and that is again a parabola, just with other bounds.
What we need is a section of the bezier curve. Let's say the curve is defined by A (start), B (direction), C (end). If we want to change the start to a point D and the end to a point F we need the point E that is the direction of the curve in D and F. So the tangents to our parabola in D and F have to intersect in E. So the following code will give us the desired result:
// Calculates the instersection point of Line3 l1 and Line3 l2.
function intersection(l1, l2) {
var A = l1.start;
var P = l2.closestPointToPoint(A);
var Q = l1.closestPointToPoint(P);
var l = P.distanceToSquared(A) / Q.distanceTo(A);
var d = (new THREE.Vector3()).subVectors(Q, A);
return d.multiplyScalar(l / d.length()).add(A);
}
// Calculate the tangentVector of the bezier-curve
function tangentQuadraticBezier(bezier, t) {
var s = bezier.v0,
m = bezier.v1,
e = bezier.v2;
return new THREE.Vector3(
THREE.CurveUtils.tangentQuadraticBezier(t, s.x, m.x, e.x),
THREE.CurveUtils.tangentQuadraticBezier(t, s.y, m.y, e.y),
THREE.CurveUtils.tangentQuadraticBezier(t, s.z, m.z, e.z)
);
}
// Returns a new QuadraticBezierCurve3 with the new bounds.
function sectionInQuadraticBezier(bezier, from, to) {
var s = bezier.v0,
m = bezier.v1,
e = bezier.v2;
var ns = bezier.getPoint(from),
ne = bezier.getPoint(to);
var nm = intersection(
new THREE.Line3(ns, tangentQuadraticBezier(bezier, from).add(ns)),
new THREE.Line3(ne, tangentQuadraticBezier(bezier, to).add(ne))
);
return new THREE.QuadraticBezierCurve3(ns, nm, ne);
}
This is a very mathematical way, but if you should need the special properties of a Bezier curve, this is the way to go.
Note: The first solution is the simplest. I am not familiar with Three.js so I wouldn't know what the most efficient way to implement the animation is. Three.js doesn't seem to use the special properties of a bezier curve so maybe solution 2 isn't that useful.
I hope you have gotten something useful out of this.

Why is this simple THREE.js javascript particle system not working?

Are there any errors is this code? I am using a new version of Chrome to test on. I've written a similar program that displays a wireframe cube, with no issues. It ran well. I'm thinking I may have written or structured my code incorrectly.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(50,window.innerWidth/window.innerHeight, 1, 10000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// create the particle variables
var particleCount = 1000;
var particles = new THREE.Geometry();
var pMaterial = new THREE.ParticleBasicMaterial({
color: 'red',
size: 20
});
// create the individual particles
for (var p = 0; p < particleCount; p++) {
var pX = Math.random()*500 - 250;
var pY = Math.random()*500 - 250;
var pZ = Math.random()*500 - 250;
var particle = new THREE.Vertex(
new THREE.Vector3(pX, pY, pZ)
);
particles.vertices.push(particle);
}
// create the particle system
var particleSystem = new THREE.ParticleSystem(
particles,
pMaterial);
// add the particle system to the scene
scene.add(particleSystem);
function render() {
particleSystem.rotation.y += 0.01;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
I'm not seeing any results, so to speak - just a black canvas element on the page.
Your code looks outdated -- as if you copied something from the net, or from an outdated book.
Update to the current version of three.js, and learn from the current three.js examples.
Create your particles like so:
var particle = new THREE.Vector3( pX, pY, pZ );
Also, ParticleSystem is now PointCloud, and ParticleBasicMaterial is now PointCloudMaterial.
three.js r.69

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.

three.js showing 3d objects in same perspective

I am new to three.js,
what I am trying to achieve is ti have multiple cubes with same perspective
var g = new THREE.CubeGeometry(200, 200, 200, 1, 1, 1);
cube1 = new THREE.Mesh(g, new THREE.MeshFaceMaterial(materials));
cube1.position.set(0,0,0);
cube2 = new THREE.Mesh(g, new THREE.MeshFaceMaterial(materials));
cube2.position.set(300,0,0);
This will give me x align cubes but cube2 is rotated slightly!
Advice on what to look for would be really helpful, Thanks!
Use orthographic camera instead of perspective camera. Your camera initializiation will look something like this:
var camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, near, far );
where width and length are dimensions of canvas. Near and far define maximum and minimum distance from the camera (objects not within this range will not be rendered)
with orthographic camera boxes of same size and rotation will appear exactly same no matter of their position.
Create a function that creates cubes and then call it in a loop. Not tested but something like this should give you the desired result:
// Function to create cubes
function create_cube(x,y,z,rx,ry,rz,color) {
var geometry, material;
geometry = new THREE.CubeGeometry(5,5,5);
material = new THREE.MeshLambertMaterial({color: color});
cube = new THREE.Mesh(geometry, material);
cube.position.x += x;
cube.position.y += y;
cube.position.z += z;
cube.rotation.x += rx;
cube.rotation.y += ry;
cube.rotation.z += rz;
cube.castShadow = true;
return cube;
}
// Create 10 cubes
var n=10;
for (var i = 0; i < n; i++) {
cube = create_cube(10*i,10*i,10*i,i,i,i,0xffffff);
scene.add(cube)
}
You can use the value of i to control how each successive cube differs from the last.

Categories

Resources