How to move camera along a simple path - three.js

How can I move the camera along a simple path (created by an array of vertices/points)? I need to move it automatically, not by keyboard/mouse events, like in a first person shoter game?
Looked for this example: http://threejs.org/examples/webgl_geometry_extrude_splines.html and it's realy good (and complex), but I need something simple, as a person who is just starting to learn Three.js

So, the best and simplest solution (based on my errors and researches - maybe you can find even a simpler solution) is to use PathControls; you can find the library here: https://github.com/mrdoob/three.js/blob/master/examples/js/controls/PathControls.js
This simple solution is based on the book: Learning Three.js: "The JavaScript 3D Library for WebGL"; it's very good to learn something on Three and I recommend you to read it; First we add the PathControls.js to our document:
<script src="js/PathControls.js"></script>
then we add some variables, before out init() function:
var controls;
var clock = new THREE.Clock();
var pathControls;
now we need some work to do on our init() function, after creating the scene, camera, lights, etc:
controls = new function () {
this.numberOfPoints = 5;
this.segments = 64;
this.radius = 3;
this.radiusSegments = 5;
this.closed = false;
this.points = getPoints();
//you can take out this last one: it shows you the path on which the camera is moving
generatePoints(this.points, this.segments, this.radius, this.radiusSegments, this.closed);
}
pathControls = new THREE.PathControls(camera);
// configure the controller
pathControls.duration = 70
//speed, so you will not have the dash effect on a curve
pathControls.useConstantSpeed = true;
pathControls.lookSpeed = 0.1;
pathControls.lookVertical = true;
pathControls.lookHorizontal = true;
pathControls.verticalAngleMap = {srcRange: [ 0, 2 * Math.PI ], dstRange: [ 1.1, 3.8 ]};
pathControls.horizontalAngleMap = {srcRange: [ 0, 2 * Math.PI ], dstRange: [ 0.3, Math.PI - 0.3 ]};
pathControls.lon = 300;
pathControls.lat = 40;
// add the path
controls.points.forEach(function(e) {
pathControls.waypoints.push([e.x, e.y, e.z]) });
// when done configuring init the control
pathControls.init();
// add the animationParent to the scene and start the animation
scene.add(pathControls.animationParent);
pathControls.animation.play(true, 0 );
Lastly you need this 3 lines in you animate() function so the camera actually will move based on time:
var delta = clock.getDelta();
THREE.AnimationHandler.update(delta);
pathControls.update(delta);
As regards the support functions (I have this one that is just an array on 5 points, but you can use many more and more complex: it's up to you):
function getPoints() {
var points = [];
points.push(new THREE.Vector3(0, 20, 0));
points.push(new THREE.Vector3(100, 25, 0));
points.push(new THREE.Vector3(100, 20, 100));
points.push(new THREE.Vector3(0, 25, 100));
points.push(new THREE.Vector3(0, 20, 0));
return points;
}
And those are the functions to show/draw a tube on the path you picked so you can see how actually the camera is moving (not needed for the whole code to work):
function generatePoints(points, segments, radius, radiusSegments, closed) {
var tube = new THREE.TubeGeometry(new THREE.SplineCurve3(points), segments, radius, radiusSegments, false, closed);
var tubeMesh = createMesh(tube);
scene.add(tubeMesh);
}
function createMesh(geom) {
mesh = THREE.SceneUtils.createMultiMaterialObject( geom, [
new THREE.MeshLambertMaterial({color: 0x00ff00, transparent: true}),
new THREE.MeshBasicMaterial({color: 0x000000, opacity: 0.3, wireframe: true, transparent: true})]);
return mesh;
}
Hope it will be useful to someone; for the whole code, you'll find it here: https://github.com/MarcinKwiatkowski1988/learningThreeJs/blob/master/movingCameraOnPath/myTry1_simply.html

Related

Three.js: Rotate object with lookAt() while located at the current lookAt() position

I'm trying to implement a simple turn-around-and-move feature with Three.js. On mouse click, the object is supposed to first turn around and then move to the clicked location.
Codepen
The rotation is achieved with raycasting and lookAt(). It works by itself and it always works on the first click. If you remove the translation, it works continuously. The issue occurs when rotation and translation are implemented together. If you click a second time, after the object has moved to the previous clicked location, it doesn't rotate as expected. Depending on the mouse location it can flip to the other side without rotating at all.
Clarification: When you click the first time, notice how the object slowly and steadily turns around to face that direction? But the second time, after the object has moved, the rotation is quicker and/or flimsier or it simply flips over and there is no rotation at all. It depends on where you click in relation to the object.
I believe the issue stems from trying to implement lookAt while being located at the current lookAt location? If I stop the translation half way, the next rotation will work better. But of course I need it to go all the way.
I'm somewhat lost on how to proceed with this issue. Any help would be appreciated.
/*** Setup scene ***/
let width = 800
let height = 600
let scene
let renderer
let worldAxis
let box
let angle
let boxAxes
scene = new THREE.Scene()
worldAxis = new THREE.AxesHelper(200);
scene.add(worldAxis);
// Setup renderer
renderer = new THREE.WebGLRenderer({alpha: true, antialias: true})
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(width, height)
document.body.appendChild(renderer.domElement)
// Setup camera
const camera = new THREE.OrthographicCamera(
width / - 2, // left
width / 2, // right
height / 2, // top
height / - 2, // bottom
0, // near
1000 ); // far
camera.position.set(0, 0, 500)
camera.updateProjectionMatrix()
// Setup box
let geometry = new THREE.BoxGeometry( 15, 15, 15 );
let material = new THREE.MeshBasicMaterial( { color: "grey" } );
box = new THREE.Mesh( geometry, material );
box.position.set(100, 150, 0)
box.lookAt(getPointOfIntersection(new THREE.Vector2(0, 0)))
addAngle()
boxAxes = new THREE.AxesHelper(50);
box.add(boxAxes)
scene.add(box)
renderer.render(scene, camera);
/*** Setup animation ***/
let animate = false
let currentlyObservedPoint = new THREE.Vector2();
let rotationIncrement = {}
let translationIncrement = {}
let frameCount = 0
document.addEventListener('click', (event) => {
let mousePosForRotate = getMousePos(event.clientX, event.clientY)
rotationIncrement.x = (mousePosForRotate.x - currentlyObservedPoint.x)/100
rotationIncrement.y = (mousePosForRotate.y - currentlyObservedPoint.y)/100
let mousePosForTranslate = getMousePosForTranslate(event)
translationIncrement.x = (mousePosForTranslate.x - box.position.x)/100
translationIncrement.y = (mousePosForTranslate.y - box.position.y)/100
animate = true
})
function animationLoop() {
if (animate === true) {
if (frameCount < 100) {
rotate()
} else if (frameCount < 200) {
translate()
} else {
animate = false
frameCount = 0
}
frameCount++
renderer.render(scene, camera)
}
requestAnimationFrame(animationLoop)
}
function rotate() {
currentlyObservedPoint.x += rotationIncrement.x
currentlyObservedPoint.y += rotationIncrement.y
let pointOfIntersection = getPointOfIntersection(currentlyObservedPoint)
box.lookAt(pointOfIntersection)
addAngle()
}
function translate() {
box.position.x += translationIncrement.x
box.position.y += translationIncrement.y
}
function getMousePos(x, y) {
let mousePos = new THREE.Vector3(
(x / width) * 2 - 1,
- (y / height) * 2 + 1,
0)
return mousePos
}
function getMousePosForTranslate(event) {
let rect = event.target.getBoundingClientRect();
let mousePos = { x: event.clientX - rect.top, y: event.clientY - rect.left }
let vec = getMousePos(mousePos.x, mousePos.y)
vec.unproject(camera);
vec.sub(camera.position).normalize();
let distance = - camera.position.z / vec.z;
let pos = new THREE.Vector3(0, 0, 0);
pos.copy(camera.position).add(vec.multiplyScalar(distance));
return pos
}
function getPointOfIntersection(mousePos) {
let plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
let pointOfIntersection = new THREE.Vector3()
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mousePos, camera)
raycaster.ray.intersectPlane(plane, pointOfIntersection)
return pointOfIntersection
}
function addAngle() {
let angle = box.rotation.x - 32
box.rotation.x = angle
}
animationLoop()
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/105/three.min.js'></script>

Change from Three.js v122 to v123 hides the shadows on a custom layer for Mapbox

I'm adding a custom layer to mapbox using three.js, using the official example from mapbox. I found that the shadows that worked perfectly in v122 are not working in v123. After reading carefully the release changelog for v123 and and the migration guide from v122, I cannot find any related commit or change that is making the shadows disappear. I also tested with the latest build available of three.js and it happens the same, but I found the change happens between these two releases. I have tested with different materials apart from ShadowMaterial but same result.
Exactly the same code, just changing the package version from:
https://unpkg.com/three#0.122.0/examples/js/loaders/GLTFLoader.js
https://unpkg.com/three#0.122.0/build/three.min.js
to
https://unpkg.com/three#0.123.0/examples/js/loaders/GLTFLoader.js
https://unpkg.com/three#0.123.0/build/three.min.js
From this:
Here is the Fiddle v122
To this...
Here is the Fiddle v123
Code is exactly the same:
mapboxgl.accessToken = 'pk.eyJ1IjoianNjYXN0cm8iLCJhIjoiY2s2YzB6Z25kMDVhejNrbXNpcmtjNGtpbiJ9.28ynPf1Y5Q8EyB_moOHylw';
var map = (window.map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v10',
zoom: 18,
center: [148.9819, -35.3981],
pitch: 60,
bearing: 45,
antialias: true // create the gl context with MSAA antialiasing, so custom layers are antialiased
}));
// parameters to ensure the model is georeferenced correctly on the map
var modelOrigin = [148.9819, -35.39847];
var modelAltitude = 0;
var modelRotate = [Math.PI / 2, 0, 0];
var modelAsMercatorCoordinate = mapboxgl.MercatorCoordinate.fromLngLat(
modelOrigin,
modelAltitude
);
// transformation parameters to position, rotate and scale the 3D model onto the map
var modelTransform = {
translateX: modelAsMercatorCoordinate.x,
translateY: modelAsMercatorCoordinate.y,
translateZ: modelAsMercatorCoordinate.z,
rotateX: modelRotate[0],
rotateY: modelRotate[1],
rotateZ: modelRotate[2],
/* Since our 3D model is in real world meters, a scale transform needs to be
* applied since the CustomLayerInterface expects units in MercatorCoordinates.
*/
scale: modelAsMercatorCoordinate.meterInMercatorCoordinateUnits()
};
var THREE = window.THREE;
// configuration of the custom layer for a 3D model per the CustomLayerInterface
var customLayer = {
id: '3d-model',
type: 'custom',
renderingMode: '3d',
onAdd: function(map, gl) {
this.camera = new THREE.Camera();
this.scene = new THREE.Scene();
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(0, 70, 100);
let d = 100;
let r = 2;
let mapSize = 1024;
dirLight.castShadow = true;
dirLight.shadow.radius = r;
dirLight.shadow.mapSize.width = mapSize;
dirLight.shadow.mapSize.height = mapSize;
dirLight.shadow.camera.top = dirLight.shadow.camera.right = d;
dirLight.shadow.camera.bottom = dirLight.shadow.camera.left = -d;
dirLight.shadow.camera.near = 1;
dirLight.shadow.camera.far = 400;
dirLight.shadow.camera.visible = true;
this.scene.add(dirLight);
this.scene.add(new THREE.DirectionalLightHelper(dirLight, 10));
this.scene.add(new THREE.CameraHelper(dirLight.shadow.camera))
// use the three.js GLTF loader to add the 3D model to the three.js scene
var loader = new THREE.GLTFLoader();
loader.load(
'https://docs.mapbox.com/mapbox-gl-js/assets/34M_17/34M_17.gltf',
function(gltf) {
gltf.scene.traverse(function(model) {
if (model.isMesh) {
model.castShadow = true;
}
});
this.scene.add(gltf.scene);
// we add the shadow plane automatically
const s = new THREE.Box3().setFromObject(gltf.scene).getSize(new THREE.Vector3(0, 0, 0));
const sizes = [s.x, s.y, s.z];
const planeSize = Math.max(...sizes) * 10;
const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
//const planeMat = new THREE.MeshStandardMaterial({ color: 0xffffff, side: THREE.DoubleSide});
const planeMat = new THREE.ShadowMaterial();
planeMat.opacity = 0.5;
let plane = new THREE.Mesh(planeGeo, planeMat);
plane.rotateX(-Math.PI / 2);
//plane.layers.enable(1); plane.layers.disable(0); // it makes the object invisible for the raycaster
plane.receiveShadow = true;
this.scene.add(plane);
}.bind(this)
);
this.map = map;
// use the Mapbox GL JS map canvas for three.js
this.renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl,
antialias: true
});
this.renderer.autoClear = false;
this.renderer.shadowMap.enabled = true;
},
render: function(gl, matrix) {
var rotationX = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(1, 0, 0),
modelTransform.rotateX
);
var rotationY = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(0, 1, 0),
modelTransform.rotateY
);
var rotationZ = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(0, 0, 1),
modelTransform.rotateZ
);
var m = new THREE.Matrix4().fromArray(matrix);
var l = new THREE.Matrix4()
.makeTranslation(
modelTransform.translateX,
modelTransform.translateY,
modelTransform.translateZ
)
.scale(
new THREE.Vector3(
modelTransform.scale,
-modelTransform.scale,
modelTransform.scale
)
)
.multiply(rotationX)
.multiply(rotationY)
.multiply(rotationZ);
this.camera.projectionMatrix = m.multiply(l);
this.renderer.state.reset();
this.renderer.render(this.scene, this.camera);
this.map.triggerRepaint();
}
};
map.on('style.load', function() {
map.addLayer(customLayer, 'waterway-label');
});
It seems like a bug, but honestly I'd love is something I'm missing or I didn't realize. I even checked if with the files from different CDNs happens the same, and yes, it happens the same. Hoping one of the Three.js contributors or other devs can help me with this as I'm completely blocked with this and stopping me to migrate
Thanks in advance for any pointer!
A new implementation of WebGLState.reset() will be available with r126. It does not only reset engine internal state flags but also calls WebGL commands to reset the actual WebGL state. This approach should solve the reported issue.
Link to the PR at GitHub: https://github.com/mrdoob/three.js/pull/21281
I included this suggestion in the comments for the pull request on github https://github.com/mrdoob/three.js/pull/20732, but I'll add it here as well incase someone only finds this Stack Overflow question when searching.
I ran into a similar issue using another library that was sharing the WebGL context. What I found was that the other library (imgui-js) was setting gl.BLEND to true and then, with the change in the mentioned pull request, WebGLState.Reset() is now setting currentBlendingEnabled to null.
This caused a lot of textures in my scene to be displayed incorrectly because when setBlending is subsequently called on the WebGLState, it assumes that if the desired blending method is NoBlending and currentBlendingEnabled is null, that gl.BLEND is already disabled:
function setBlending(blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha) {
if (blending === NoBlending) {
if ( currentBlendingEnabled ) {
disable(3042);
However, with reset nulling the currentBlendingEnabled value each frame but not setting gl.BLEND to false, I believe this assumption is no longer correct. Looking closer, even after removing the external library I was using that sets the gl.BLEND value to true, I found that the change in the pull request was having a negative impacting some of the textures in my scene. In my case I found that updating the setBlending function to honor NoBlending requests, including when currentBlendingEnabled is null, seems to have remedied the situation. Maybe that will work in your case too?
function setBlending(blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha) {
if (blending === NoBlending) {
if (currentBlendingEnabled !== false) {
disable(3042);

Raycaster fails to detect Cubes

How do you combine a Square and a Rectangle into one object that a Raycaster can detect successfully?
I created a custom “Tree” object by making a “Trunk” - which is just a long rectangle, and then sticking a Square object on top of that Trunk.
I then “planted” that Tree on top of a Sphere, and I'm trying to get my raycaster to detect it.
It’s not working.
Here’s my code:
// My custom “Tree” Object:
var Tree = function(treeColor) {
this.mesh = new THREE.Object3D();
this.mesh.name = "tree";
// I start with the TRUNK - which is just an elongated Cube - meaning a Rectangle:
var trunkGeometry = new THREE.CubeGeometry(0.2, 0.5, 0.2);
var trunkMaterial = new THREE.MeshBasicMaterial({ color: "blue", wireframe: false });
var treeTrunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
treeTrunk.position.set(0, 0, 0);
treeTrunk.rotation.x = -Math.PI * 0.5;
this.mesh.add(treeTrunk);
// Then I create the FOLIAGE - which is just a regular Cube:
var foliageGeometry = new THREE.CubeGeometry(0.5, 0.5, 0.5);
var foliageMaterial = new THREE.MeshBasicMaterial({ color: treeColor, wireframe: false });
var treeFoliage = new THREE.Mesh(foliageGeometry, foliageMaterial);
treeFoliage.position.set(0, 0.5, 0);
// And then I attach/add the FOLIAGE to the TRUNK:
treeTrunk.add(treeFoliage);
}
// Next I make a basic Sphere:
theSun = new THREE.Mesh(new THREE.SphereGeometry(3, 32, 24), new THREE.MeshBasicMaterial( {color: "white", wireframe: false} ));
scene.add(theSun);
// And then I make a Tree and add it to my Sphere (`theSun`):
var oneTree = new Tree("red");
let rx = Math.random() * Math.PI * 2;
let ry = Math.random() * Math.PI;
oneTree.mesh.position.setFromSphericalCoords(3.2, ry, rx);
oneTree.mesh.lookAt(theSun.position);
theSun.add(oneTree.mesh);
// Next I add both theSun and the Tree to my “objectsForRayCasterArray” - a global var I use in my raycaster test:
objectsForRayCasterArray.push(oneTree);
objectsForRayCasterArray.push(theSun);
// In my render() function, I do the usual raycasting business:
rayCaster = new THREE.Raycaster();
function render() {
requestAnimationFrame(render);
controls.update();
renderer.render(scene, camera);
// Raycasting stuff:
rayCaster.setFromCamera(mousePosition, camera);
var intersectingObjectsArray = rayCaster.intersectObjects(objectsForRayCasterArray);
if (intersectingObjectsArray.length > 0) {
if (intersectedObject != intersectingObjectsArray[0].object) {
console.log(“Intersected!”);
}
}
NOTE: when I use this same code but instead of a Tree I just place a regular Cube on my Sphere object, everything works just fine. The raycaster detects the Cube and fires the Alert.
My best guess is that since you're nesting the treeFoliage inside treeTrunk, and that inside mesh, you're going to have to use a recursive intersection test.
According to the docs, intersectObjects() accepts a second argument to perform a recursive hit-test. This means it will iterate through all descendants, instead of just doing a shallow check of top-level objects:
rayCaster.intersectObjects(objectsForRayCasterArray, true);

how to draw a flat shape in 3-space in three.js?

I'm trying to construct a collection of flat shapes in three.js. Each one is defined as a series of coplanar Vector3 points, but the shapes are not all coplanar. Imagine two flat rectangles as the roof of a house, but with much more complex shapes.
I can make flat Shape objects and then rotate and position them, but since my shapes are conceived in 3d coordinates, it would be much simpler to keep it all in 3-space, which the Shape object doesn't like.
Is there some much more direct way to simply specify an array of coplanar Vector3's, and let three.js do the rest of the work?
I thought about this problem and came up with the idea, when you have a set of co-planar points and you know the normal of the plane (let's name it normal), which your points belong to.
We need to rotate our set of points to make it parallel to the xy-plane, thus the normal of that plane is [0, 0, 1] (let's name it normalZ). To do it, we find quaternions with .setFromUnitVectors() of THREE.Quaternion():
var quaternion = new THREE.Quaternion().setFromUnitVectors(normal, normalZ);
var quaternionBack = new THREE.Quaternion().setFromUnitVectors(normalZ, normal);
Apply quaternion to our set of points
As it's parallel to xy-plane now, z-coordinates of points don't matter, so we can now create a THREE.Shape() object of them. And then create THREE.ShapeGeometry() (name it shapeGeom) from given shape, which will triangulate our shape.
We need to put our points back to their original positions, so we'll apply quaternionBack to them.
After all, we'll assign our set of points to the .vertices property of the shapeGeom.
That's it. If it'll work for you, let me know ;)
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 20, 40);
camera.lookAt(scene.position);
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);
controls.target = new THREE.Vector3(10, 0, 10);
controls.update();
var grid = new THREE.GridHelper(50, 50, 0x808080, 0x202020); // xy-grid
grid.geometry.rotateX(Math.PI * 0.5);
scene.add(grid);
var points = [ // all of them are on the xz-plane
new THREE.Vector3(5, 0, 5),
new THREE.Vector3(25, 0, 5),
new THREE.Vector3(25, 0, 15),
new THREE.Vector3(15, 0, 15),
new THREE.Vector3(15, 0, 25),
new THREE.Vector3(5, 0, 25),
new THREE.Vector3(5, 0, 5)
]
var geom = new THREE.BufferGeometry().setFromPoints(points);
var pointsObj = new THREE.Points(geom, new THREE.PointsMaterial({
color: "red"
}));
scene.add(pointsObj);
var line = new THREE.LineLoop(geom, new THREE.LineBasicMaterial({
color: "aqua"
}));
scene.add(line);
// normals
var normal = new THREE.Vector3(0, 1, 0); // I already know the normal of xz-plane ;)
scene.add(new THREE.ArrowHelper(normal, new THREE.Vector3(10, 0, 10), 5, 0xffff00)); //yellow
var normalZ = new THREE.Vector3(0, 0, 1); // base normal of xy-plane
scene.add(new THREE.ArrowHelper(normalZ, scene.position, 5, 0x00ffff)); // aqua
// 1 quaternions
var quaternion = new THREE.Quaternion().setFromUnitVectors(normal, normalZ);
var quaternionBack = new THREE.Quaternion().setFromUnitVectors(normalZ, normal);
// 2 make it parallel to xy-plane
points.forEach(p => {
p.applyQuaternion(quaternion)
});
// 3 create shape and shapeGeometry
var shape = new THREE.Shape(points);
var shapeGeom = new THREE.ShapeGeometry(shape);
// 4 put our points back to their origins
points.forEach(p => {
p.applyQuaternion(quaternionBack)
});
// 5 assign points to .vertices
shapeGeom.vertices = points;
var shapeMesh = new THREE.Mesh(shapeGeom, new THREE.MeshBasicMaterial({
color: 0x404040
}));
scene.add(shapeMesh);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.90.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.90.0/examples/js/controls/OrbitControls.js"></script>

CubeGeometry equivalent using CSS3DRenderer, Three.JS

Following my previous question at SO, Creating a CubeGeometry equivilent using CSS3DRenderer I am trying to build a flexible 3D cube which would work under CSS3DRenderer.
Here is the current status, also available at http://jsfiddle.net/RJv3b/2/
There is a 3D cube which is create by WebGL in the example below, I would like to create a cube using CSS3D which would perfectly match the wireframe.
var camera, scene, renderer;
var geometry, material, mesh;
var scene2, renderer2;
var controls;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 400, 400, 400 );
controls = new THREE.OrbitControls( camera );
controls.noZoom = false;
controls.noPan = false;
scene = new THREE.Scene();
geometry = new THREE.CubeGeometry( 200, 300, 400 );
material = new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true, wireframeLinewidth: 1 } );
mesh = new THREE.Mesh( geometry, material );
mesh.position.set(50,100,70)
mesh.rotation.x = Math.PI/3;
mesh.rotation.y = Math.PI/4;
mesh.rotation.z = Math.PI/5;
scene.add( mesh );
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene2 = new THREE.Scene();
// params
var r = Math.PI / 2;
var width = 200;
var height = 300;
var depth = 400;
var x = 50
var y = 100
var z = 70
var pos = [ [ x+width/2, -y+height/2, z ], [ -depth, y/2, x/2 ], [ 0, height/2+y, x/2 ], [ depth, -y/2, x/2 ], [ x, y/2, depth/2+x/2 ], [ 0, y/2, -depth/2 +x/2] ];
var rot = [ [ 0, r, 0 ], [ 0, -r, 0 ], [ -r, 0, 0 ], [ r, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, 0 ] ];
// cube
var cube = new THREE.Object3D();
scene2.add( cube );
// sides
for ( var i = 0; i < 6; i ++ ) {
var txt = document.createTextNode("side:"+i);
var element = document.createElement( 'div' );
element.style.width = width+'px';
element.appendChild(txt);
element.style.height = height+'px';
element.style.background = new THREE.Color( Math.random() * 0xffffff ).getStyle();
element.style.opacity = '0.8';
var object = new THREE.CSS3DObject( element );
object.position.fromArray( pos[ i ] );
object.rotation.fromArray( rot[ i ] );
cube.add( object );
}
renderer2 = new THREE.CSS3DRenderer();
renderer2.setSize( window.innerWidth, window.innerHeight );
renderer2.domElement.style.position = 'absolute';
renderer2.domElement.style.top = 0;
document.body.appendChild( renderer2.domElement );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
renderer2.render( scene2, camera );
}
I am in the process of attempting to knock out something similar to what you are looking to do. I can't give you a polished answer, but as soon as I finish my development I can come back and update with what really works.
To dynamically integrate data into your scene, which is what I believe you are trying to accomplish, try approaching the problem utilizing the power behind D3.js
D3 will allow you to create editable DOM elements. It also pairs really well with three.js.
Add
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
to your page or download the library and call it in to your page however you would like.
Using the code you have above, you could manipulate the DOM with something like this:
d3.selectAll("div")
.data([4, 8, 15, 16, 23, 42])
.style("font-size", function(d) { return d + "px"; });
and then end up with a result with which you can make further edits via CSS if need be.
As far as opting for a JUST CSS3D render, then simply edit your renderer to be exactly that, CSS3D.
Here is a link to D3.js: http://d3js.org/
Here is a link to D3.js integrated with three.js and rendered via CSS3D: http://www.delimited.io/blog/2014/3/14/d3js-threejs-and-css-3d-transforms
Hope this helps!
Actually here's a much better answer:
Ran into this while building my site. Thought of you! Cheers!
First off make sure you're using the three.js library as your WebGL API. For WebGL development in building for sites versus an app or video game, it's one of the most well documented and built upon libraries that currently exist.
With three.js up, now you can use some wonderful plugins. The one that directly solves your problem was written by the incredible developers over at THREEX.
Here's a link to the site so you can see all the plugins they have written:
http://www.threejsgames.com
Click Extensions. I know Icoulve just linked you to extensions, but I respect the work they put into the homepage. Showing it off for em'.
The Extension you are looking for is the "Dynamic Texture" extension. If viewing the extension from their site, you get a nice description/tutorial and an example to play with.
Otherwise you can just check out the plugin over at Github:
https://github.com/jeromeetienne/threex.dynamictexture
Hope this helps!

Resources