THREE.CameraDolly is not a constructor (Three.js & dolly.js) - javascript

I'm really confused, nothing works. I always get the error "THREE.CameraDolly is not a constructor". I'm using Three.js if someone haven't already noticed it.
My script:
var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 45, WIDTH / HEIGHT, 1, 1000 );
var cameraDolly = new THREE.PerspectiveCamera( 45, WIDTH / HEIGHT, 1, 1000);
var renderer = new THREE.WebGLRenderer();
...
//LookAt & Camera Position Points
var points = {
"camera": [
{
"x": 100,
"y": 60,
"z": 40
},
{
"x": -20,
"y": 5,
"z": -10
},
{
"x": 30,
"y": 10,
"z": -5
}
],
"lookat": [
{
"x": 50,
"y": 30,
"z": 35
},
{
"x": 0,
"y": 2,
"z": 0
},
{
"x": 12,
"y": 8,
"z": -0.2
}
]
};
//Clock
var clock = new THREE.Clock( true );
//CameraDolly
***var dolly = new THREE.CameraDolly ( cameraDolly, scene, points );***//Here I got the error
scene.add(dolly, 'cameraPosition', 0, 1);
scene.add(dolly, 'lookatPosition', 0, 1);
function update() {
requestAnimationFrame(update);
render( cameraDolly, 0.75, 0, 0.25, 0.25 );
var delta = clock.getElapsedTime() * 0.2;
var position = THREE.Math.mapLinear(Math.sin(delta), -1, 1, 0, 1);
dolly.cameraPosition = position;
dolly.lookatPosition = position;
dolly.update();
};
function render() {
renderer.render(scene, cameraDolly);
};
render();
update();
And dolly.js:
/**
* #author DPR / http://ivxvixviii.io
*/
THREE.CameraDolly = function ( camera, scene, points ){
this.cameraPosition = 0;
this.lookatPosition = 0;
this.camera = camera;
this.scene = scene;
this.cameraPoints = points.camera;
this.lookatPoints = points.lookat;
this.bounds = 100;
}
// Lookat position Marker
this.lookatPositionMarker = this.createMarker(0xFF0000);
this.scene.add(this.lookatPositionMarker);
// Camera path markers
this.markers = [];
if(this.gui){
var cameraPointsFolder = this.gui.addFolder('cameraPointsFolder');
cameraPointsFolder.open();
}
var _this = this;
for( var i = 0; i < this.cameraPoints.length; ++i){
if(this.gui){
var point = this.cameraPoints[i];
var folder = cameraPointsFolder.addFolder('marker-' + i);
folder.add(point, 'x', -this.bounds, this.bounds).onChange(function(){
_this.createCurves();
});
folder.add(point, 'y', -this.bounds, this.bounds).onChange(function(){
_this.createCurves();
});
folder.add(point, 'z', -this.bounds, this.bounds).onChange(function(){
_this.createCurves();
});
// folder.open();
}
var marker = this.createMarker(0x00FF00);
this.scene.add( marker );
this.markers.push( marker );
};
// Camera lookat path markers
this.lookatMarkers = [];
if(this.gui){
var lookatPointsFolder = this.gui.addFolder('lookatPointsFolder');
lookatPointsFolder.open();
}
for( var i = 0; i < this.lookatPoints.length; ++i){
if(this.gui){
var point = this.lookatPoints[i];
var folder = lookatPointsFolder.addFolder('marker-' + i);
folder.add(point, 'x', -this.bounds, this.bounds).onChange(function(){
_this.createCurves();
});
folder.add(point, 'y', -this.bounds, this.bounds).onChange(function(){
_this.createCurves();
});
folder.add(point, 'z', -this.bounds, this.bounds).onChange(function(){
_this.createCurves();
});
// folder.open();
}
var marker = this.createMarker(0x0000FF);
this.scene.add( marker );
this.lookatMarkers.push( marker );
};
this.createCurves();
this.update();
};
THREE.CameraDolly.prototype.createCurves = function(){
// Camera curve
this.scene.remove(this.pathCurve);
var points = [];
for (var i = 0; i < this.cameraPoints.length ; ++i) {
var point = this.cameraPoints[i];
var vec = new THREE.Vector3( point.x, point.y, point.z );
this.markers[i].position.set( point.x, point.y, point.z );
points.push(vec);
};
var spline = this.createSpline( points );
var points = spline.getPoints( 50 );
this.cameraSpline = this.createSpline(points);
var geometry = new THREE.Geometry();
var material = new THREE.LineBasicMaterial( { 0xFFFFFF*Math.random() } /*{ transparent: true, opacity: 0 }*/ );
points.forEach(function(point){
geometry.vertices.push( point.clone() );
});
this.pathCurve = new THREE.Line( geometry, material );
this.scene.add( this.pathCurve );
// Lookat curve
this.scene.remove(this.pathLookatCurve);
var points = [];
for (var i = 0; i < this.lookatPoints.length ; ++i) {
var point = this.lookatPoints[i];
var vec = new THREE.Vector3( point.x, point.y, point.z );
this.lookatMarkers[i].position.set( point.x, point.y, point.z );
points.push(vec);
};
var spline = this.createSpline( points );
var points = spline.getPoints( 50 );
this.cameralookatSpline = this.createSpline(points);
var geometry = new THREE.Geometry();
var material = new THREE.LineBasicMaterial( { 0xFFFFFF*Math.random() } /*{ transparent: true, opacity: 0 }*/ );
points.forEach(function(point){
geometry.vertices.push( point.clone() );
});
this.pathLookatCurve = new THREE.Line( geometry, material );
this.scene.add( this.pathLookatCurve );
this.update();
};
THREE.CameraDolly.prototype.createSpline = function( points ) {
var tmp = [];
for( var i = 0; i < points.length; ++i){
tmp.push( points[i].clone() );
};
return new THREE.SplineCurve3( tmp );
}
THREE.CameraDolly.prototype.createMarker = function(color){
var geometry = new THREE.SphereGeometry( 1, 4, 4 );
var material = new THREE.MeshBasicMaterial({color: color /*transparent: true, opacity: 0*/ });
return new THREE.Mesh(geometry, material);
};
THREE.CameraDolly.prototype.update = function(){
var position = this.cameraSpline.getPointAt( this.cameraPosition );
this.camera.position.copy( position );
position = this.cameralookatSpline.getPointAt( this.lookatPosition );
this.lookatPositionMarker.position.copy( position );
this.camera.lookAt( this.lookatPositionMarker.position );
};
THREE.CameraDolly.prototype.exportPositions = function(){
var data = {
camera: [],
lookat: []
};
this.cameraPoints.forEach(function(point){
data.camera.push({
x: point.x,
y: point.y,
z: point.z
})
});
this.lookatPoints.forEach(function(point){
data.lookat.push({
x: point.x,
y: point.y,
z: point.z
})
});
var json = JSON.stringify( data, undefined, 4 );
window.prompt('Copy to clipboard: Ctrl+C, Enter', json );
};
I have already looked up on Google but I didn't find anything that could help me continous. I have everything included, I also tried it with a onload function and I renamed the variables, too!

Your dolly.js is altered and contains some errors. Debug it first if you are responsible for this, or just replace it with the original dolly.js file.
Doing so you will run you into this error:
THREE.Object3D.add:" Object { […] } "is not an instance of THREE.Object3D.
You cant add the dolly object to the THREE.Scene, the author of this script is adding it to his GUI. Please look at the example he provided and try to understand whats happening. Adapt your code from there.
The dolly helper is a third-party addon written for r68 and is not officialy supported by three.js, so you should report bugs at the projects github page.

Related

Raycaster with Three.js and whitestormJS

I'm having an issue with Raycasting with Three.js and WhitestormJS.
Maybe I didn't understood well some of the underlying principle of this particular element.
What I'm trying to do is syncing the direction of the raycaster with my camera.
So, once it intersect an element, this element will be added to the intersect array.
The problem is that my "intersect" array stay empty even if I move my camera in the direction of an element.
On codepen : https://codepen.io/paulbonneau/pen/zdVeJx?editors=1111
My code :
const app = new WHS.App([
new WHS.ElementModule({
container: document.getElementById('app')
}),
new WHS.SceneModule(),
new WHS.DefineModule('camera', new WHS.PerspectiveCamera({
position: new THREE.Vector3(0, 6, 18),
far: 10000
})),
new WHS.CameraModule({
position: {
y: 2,
z: 2,
x: 1,
},
}),
new WHS.RenderingModule({
bgColor: 0x162129,
renderer: {
antialias: true,
shadowmap: {
type: THREE.PCFSoftShadowMap
}
}
}, {shadow: true}),
new WHS.OrbitControlsModule(
),
new WHS.ResizeModule()
]);
app.modules[5].controls.enableZoom = false
var camera = app.get('camera');
crosshair = new THREE.Vector2(0,0);
// Rendu de la skybox càd l'environnement dans lequel se déroule le jeu
var path = "img/skybox/";
var format = '.jpg';
var urls = [
'./skybox/EH_0.front.jpg',
'./skybox/EH_0.back.jpg' ,
'./skybox/EH_0.top.jpg',
'./skybox/EH_0.bottom.jpg',
'./skybox/EH_0.left.jpg',
'./skybox/EH_0.right.jpg',
];
var reflectionCube = THREE.ImageUtils.loadTextureCube(urls, null);
reflectionCube.format = THREE.RGBFormat;
var shader = THREE.ShaderLib[ "cube" ];
shader.uniforms[ "tCube" ].value = reflectionCube;
var material = new THREE.ShaderMaterial( {
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
uniforms: shader.uniforms,
depthWrite: false,
side: THREE.BackSide
});
//End test
const world = new WHS.Box({ // Create box to contain the 3D space where the game happen
geometry: {
width: 100,
height: 100,
depth: 100
},
material: material
});
world.addTo(app);
var material = new THREE.MeshBasicMaterial( { color: 0xffffff, envMap: reflectionCube } );
var points = [];
for ( var deg = 0; deg <= 180; deg += 6 ) {
var rad = Math.PI * deg / 180;
var point = new THREE.Vector2( ( 0.72 + .08 * Math.cos( rad ) ) * Math.sin( rad ), - Math.cos( rad ) ); // the "egg equation"
//console.log( point ); // x-coord should be greater than zero to avoid degenerate triangles; it is not in this formula.
points.push( point );
}
const sphere = new WHS.Sphere({
geometry: {
radius: 100
},
material: new THREE.MeshBasicMaterial({
color: 0xffffff
}),
position: {
y: 1,
x: 1,
z: 0
}
});
for (var i = 0; i < 20; i++) {
egg_size = Math.random() * 10-2;
egg = new WHS.Lathe({
geometry: {
points: points
},
material: material,
position: {
y: Math.random() * 100 - 50,
x: Math.random() * 100 - 50 ,
z: Math.random() * 100 - 50
},
rotation: {
x: Math.random() * Math.PI/2,
y: Math.random() * Math.PI/2,
z: Math.random() * Math.PI/2
},
scale:{
x : egg_size,
z : egg_size,
y : egg_size
}
});
egg.addTo(sphere);
}
sphere.addTo(world);
raycaster = new THREE.Raycaster(camera, camera.position);
var intersects = raycaster.intersectObjects( app.children );
new WHS.Loop(() => {
raycaster.setFromCamera( camera.position , camera );
sphere.rotation.x += 0.01;
sphere.rotation.y += 0.01;
for (var i = 0; i < sphere.children.length-1; i++) {
sphere.children[i].rotation.x += 0.05;
sphere.children[i].rotation.y += 0.05;
sphere.children[i].rotation.z += 0.05;
}
}).start(app);
// Start the app
app.start();
You're constructing the raycaster in the wrong way (as of r87).
raycaster = new THREE.Raycaster(camera, camera.position);
As shown in the documentation, the raycaster is constructed like so:
var raycaster = new THREE.Raycaster();
The rest of the code looks correct, so I assume that is the problem.
Here's a working example

How do I plot random meshes on top of a terrain using a heightmap in three.js?

So as the title states I'd like to know how to plot randomly generated meshes at the y-position that matches the terrain's corresponding y-position in three.js. I've looked through the docs and feel like using a raycaster might work, but I can only see examples that uses the detection as a mouse event, and not before render, so I'm not sure how to implement it.
Here is my code for the terrain, heightmap, and mesh plotting so far. It all works technically, but as you can see the plotAssets meshes y-positions are just sitting at zero right now. Any insights would be very much appreciated, I'm pretty new to three.js.
Terrain:
var heightmaploader = new THREE.ImageLoader();
heightmaploader.load(
"assets/noisemaps/cloud.png",
function(img) {
data = getHeightData(img);
var terrainG = new THREE.PlaneBufferGeometry(700, 700, worldWidth - 1, worldDepth - 1);
terrainG.rotateX(-Math.PI / 2);
var vertices = terrainG.attributes.position.array;
for (var i = 0, j = 0, l = vertices.length; i < l; i++, j += 3) {
vertices[j + 1] = data[i] * 5;
}
terrainG.computeFaceNormals();
terrainG.computeVertexNormals();
var material = new THREE.MeshLambertMaterial({
map: terrainT,
//side: THREE.DoubleSide,
color: 0xffffff,
transparent: false,
});
terrain = new THREE.Mesh(terrainG, material);
terrain.receiveShadow = true;
terrain.castShadow = true;
terrain.position.y = 0;
scene.add(terrain);
plotAsset('boulder-photo-01.png', 30, 18, data);
plotAsset('boulder-outline-01.png', 20, 20, data);
plotAsset('birch-outline-01.png', 10, 50, data);
plotAsset('tree-photo-01.png', 20, 50, data);
plotAsset('grass-outline-01.png', 10, 20, data);
plotAsset('grass-outline-02.png', 10, 20, data);
}
);
Plot Assets:
function plotAsset(texturefile, amount, size, array) {
console.log(array);
var loader = new THREE.TextureLoader();
loader.load(
"assets/textures/objects/" + texturefile,
function(texturefile) {
var geometry = new THREE.PlaneGeometry(size, size, 10, 1);
var material = new THREE.MeshBasicMaterial({
color: 0xFFFFFF,
map: texturefile,
side: THREE.DoubleSide,
transparent: true,
depthWrite: false,
depthTest: false,
alphaTest: 0.5,
});
var uniforms = { texture: { value: texturefile } };
var vertexShader = document.getElementById( 'vertexShaderDepth' ).textContent;
var fragmentShader = document.getElementById( 'fragmentShaderDepth' ).textContent;
// add bunch o' stuff
for (var i = 0; i < amount; i++) {
var scale = Math.random() * (1 - 0.8 + 1) + 0.8;
var object = new THREE.Mesh(geometry, material);
var x = Math.random() * 400 - 400 / 2;
var z = Math.random() * 400 - 400 / 2;
object.rotation.y = 180 * Math.PI / 180;
//object.position.y = size * scale / 2;
object.position.x = x;
object.position.z = z;
object.position.y = 0;
object.castShadow = true;
object.scale.x = scale; // random scale
object.scale.y = scale;
object.scale.z = scale;
scene.add(object);
object.customDepthMaterial = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
side: THREE.DoubleSide
} );
}
}
);
}
Height Data:
function getHeightData(img) {
var canvas = document.createElement('canvas');
canvas.width = 2048 / 8;
canvas.height = 2048 / 8;
var context = canvas.getContext('2d');
var size = 2048 / 8 * 2048 / 8,
data = new Float32Array(size);
context.drawImage(img, 0, 0);
for (var i = 0; i < size; i++) {
data[i] = 0
}
var imgd = context.getImageData(0, 0, 2048 / 8, 2048 / 8);
var pix = imgd.data;
var j = 0;
for (var i = 0, n = pix.length; i < n; i += (4)) {
var all = pix[i] + pix[i + 1] + pix[i + 2];
data[j++] = all / 40;
}
return data;
}
Yes, using of THREE.Raycaster() works well.
A raycaster has the .set(origin, direction) method. The only thing you have to do here is to set the point of origin higher than the highest point of the height map.
var n = new THREE.Mesh(...); // the object we want to aling along y-axis
var collider = new THREE.Raycaster();
var shiftY = new THREE.Vector3();
var colliderDir = new THREE.Vector3(0, -1, 0); // down along y-axis to the mesh of height map
shiftY.set(n.position.x, 100, n.position.z); // set the point of the origin
collider.set(shiftY, colliderDir); //set the ray of the raycaster
colliderIntersects = collider.intersectObject(plane); // plane is the mesh of height map
if (colliderIntersects.length > 0){
n.position.y = colliderIntersects[0].point.y; // set the position of the object
}
jsfiddle example

how to i get position when clicked object or sprite in three.js?

i'm not good at javascript... T_T
can i get position(x,y,z) where i clicked sprite (or object) ?????
below my code.. help me!!
//sprite
var spriteMap = new THREE.TextureLoader().load( 'tag.png' );
var spriteMaterial = new THREE.SpriteMaterial( { map: spriteMap, color: 0xffffff } );
var sprite = new THREE.Sprite( spriteMaterial );
sprite.scale.set(3, 3, 1)
sprite.position.set(25, 20, 20)
scene.add( sprite );
objects.push(sprite);
//sprite( text )
var spritey = makeTextSprite( " spritey ",
{ fontsize: 24, borderColor: {r:255, g:0, b:0, a:1.0}, backgroundColor: {r:255, g:100, b:100, a:1.0} } );
spritey.position.set(-85,105,55);
scene.add( spritey );
console.log(makeTextSprite);
objects.push(spritey);
///////////////////skip some codes//////////////////////////////////
function onDocumentMouseUp(event) {
event.preventDefault();
var vector = new THREE.Vector3((event.clientX / window.innerWidth) * 2-1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5);
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(objects);
if (intersects.length > 0) {
window.open(intersects[0].object.userData.URL);
console.log(intersects.length)
}
}
if you want the position where you clicked:
var position = intersects[0].point
if you want the position of the object:
var position = intersects[0].object.position

JavaScript Double Click Function Three.js

I've got a double click function to allow the user to double click on a car model and it displays which objects have been intersected; e.g. wipers, grille, tyres and so on, and this function displays them in a list with the number of items the double click intersected with.
However, I am now trying to get it so that when a certain part of the car is clicked, for example, the tyres, it will display a paragraph with information on them. I can see how this is just a case of checking the name of the intersecting object and then displaying the relevant text if it intersects it, but every time I go to do what I think is right, it just breaks the already existing function to the point where the whole thing won't run.
I'm not exactly a JavaScript or Three.js pro at all, but trying to progress my function further is proving to be rather difficult.
Any suggestions? I've included the entire double click function, however it's when it's checking if there has been intersections near the bottom that is where the alterations need to be.
// On Mouse double click event function
function onDoubleClick(event) {
// Set the mouse down flag to false
mouseDown = false;
// Canvas x (left) and y (top) position
var canvasLeft = 0;
var canvasTop = 0;
// "event.clientX" is the mouse x position. "event.clientY" is the mouse y position
var tempX = event.clientX - canvasLeft;
var tempY = event.clientY - canvasTop;
// Create a normalised vector in 2d space
var vector = new THREE.Vector3((tempX / window.innerWidth) * 2 - 1, - (tempY / innerHeight) * 2 + 1, 0.5);
// Unproject a 2D point into the 3D word
// Use the camera projection matrix to transform the vector to the 3D world space
vector.unproject(camera);
// Send a ray in the direction the user has clicked from the cameras position
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
// Check if the ray has intersected with any objects and get intersections
var intersects = raycaster.intersectObjects(objects, true);
// Check if intersected with objects
if (intersects.length > 0) {
var tempStr = "Number of items: " + intersects.length + " ";
// List the items that were hit
for(var i=0; i < intersects.length; i++){
if(intersects[i].object.name != ""){
// The mesh name set above
tempStr += " | Name: " + intersects[i].object.name;
} else {
// The names inside the model
tempStr += " | Name: " + intersects[i].object.parent.name;
}
}
//Debug information
document.getElementById("debugInfo").innerHTML = tempStr + ".<br>";
//END
}
}
EDIT:
This is the entire code for the javascript file, as altering elements of the double click function seems to stop the page from loading.
window.onload = init;
// declare variables
var scene,camera,renderer, container;
var controls, guiControls, datGUI;
var grid, color;
var cube, cubeGeometry, cubeMaterial;
var plane, planeGeometry, planeMaterial;
var skyBoxMesh, texture_placeholder;
var spotLight;
var stats;
// Handles the mouse events.
var mouseOverCanvas;
var mouseDown;
// An array of objects that can be clicked on
var objects = [];
//DAE models
var showroom ,carOld, carNew;
var daeObject;
var animations;
var kfAnimations = [];
var kfAnimationsLength = 0;
var lastFrameCurrentTime = [];
var clock = new THREE.Clock();
var mouseOverCanvas, mouseDown;
var objectsClick=[];
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
//creates empty scene
scene = new THREE.Scene();
//camera
camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, .1, 500);
camera.position.x = 40;
camera.position.y = 40;
camera.position.z = 40;
camera.lookAt(scene.position);
//renderer
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setClearColor(0xe6f2ff);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMapSoft = true;
container.appendChild( renderer.domElement );
// Add an event to set if the mouse is over our canvas
renderer.domElement.onmouseover=function(e){ mouseOverCanvas = true; }
renderer.domElement.onmousemove=function(e){ mouseOverCanvas = true; }
renderer.domElement.onmouseout=function(e){ mouseOverCanvas = false; }
renderer.domElement.onmousedown=function(e){ mouseDown = true; }
renderer.domElement.onmouseup=function(e){ mouseDown = false; }
// Double Click Event. Set a function called "onDoubleClick"
renderer.domElement.ondblclick=onDoubleClick;
// stats
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
//adds controls
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.addEventListener('change', render);
var ambient = new THREE.AmbientLight( 0xadad85 );
scene.add( ambient );
//---------- creates grid ---------------
grid = new THREE.GridHelper(50,5);
color= new THREE.Color("rgb(255,0,0)");
grid.setColors( 0x000000);
scene.add(grid);
//----------- creates cube --------------
cubeGeometry = new THREE.BoxGeometry(5,5,5);
cubeMaterial = new THREE.MeshPhongMaterial({color: 0xff3300});
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.x = 0;
cube.position.y = 6;
cube.position.z = 2.5;
cube.castShadow = true;
scene.add(cube);
//----------- creates plane ---------------
planeGeomenty= new THREE.PlaneGeometry(100,100,100);
planeMaterial = new THREE.MeshLambertMaterial({color: 0x00cc00});
plane = new THREE.Mesh(planeGeomenty, planeMaterial);
//position the add objects to the scene
plane.rotation.x = -.5*Math.PI;
plane.receiveShadow = true;
scene.add(plane);
//------------- skyBox --------------
texture_placeholder = document.createElement('canvas');
texture_placeholder.width = 128;
texture_placeholder.height = 128;
var context = texture_placeholder.getContext('2d');
context.fillStyle = 'rgb(200,200, 200)';
context.fillRect(0, 0,texture_placeholder.width, texture_placeholder.height);
var materials = [
loadTexture('images/skybox/posX.jpg'),
loadTexture('images/skybox/negX.jpg'),
loadTexture('images/skybox/posY.jpg'),
loadTexture('images/skybox/negY.jpg'),
loadTexture('images/skybox/posZ.jpg'),
loadTexture('images/skybox/negZ.jpg')
];
skyBoxMesh = new THREE.Mesh(new THREE.BoxGeometry(500,500,500,7,7,7),
new THREE.MeshFaceMaterial(materials));
skyBoxMesh.scale.x = -1;
scene.add(skyBoxMesh);
//---------- loads collada files -----------
loadCollada();
daeObject = cube;
// initialise datGUI controls values
guiControls = new function() {
this.rotationY = 0.0;
this.positionX = 0.0;
this.positionY = 0.0;
this.positionZ = -10;
this.lightX = 20;
this.lightY = 35;
this.lightZ = 40;
this.intensity = 1;
this.distance = 0;
this.angle = 1.570;
this.target = cube;
}
//add spotLight with starting parameters
spotLight = new THREE.SpotLight(0xffffff);
spotLight.castShadow = true;
spotLight.position.set(20,35,40);
spotLight.intensity = guiControls.intensity;
spotLight.distance = guiControls.distance;
spotLight.angle = guiControls.angle;
scene.add(spotLight);
//adds controls on the scene
datGUI = new dat.GUI();
// datGUI.add(guiControls, 'positionZ', 0, 1);
datGUI.add(guiControls, 'positionZ', -10, 25, 0.5). name("Move the car");
datGUI.add(guiControls, 'rotationY', 0, 1).name('Rotate the car');
datGUI.add(guiControls, 'lightX', -60, 180);
datGUI.add(guiControls, 'lightY', 0, 180);
datGUI.add(guiControls, 'lightZ', -60, 180);
datGUI.add(guiControls, 'target',[ 'cube','Modern Mini', 'Classic Mini']).onChange(function() {
if(guiControls.target == 'cube'){
spotLight.target = cube;
daeObject = cube;
}
else if(guiControls.target == 'Classic Mini'){
spotLight.target = carOld;
daeObject = carOld;
}
else if(guiControls.target = 'Modern Mini'){
spotLight.target = carNew;
daeObject = carNew;
}
});
datGUI.add(guiControls, 'intensity', 0.01, 5).onChange(function (value){
spotLight.intensity = value;
});
datGUI.add(guiControls, 'distance', 0, 1000).onChange(function (value){
spotLight.distance = value;
});
datGUI.add(guiControls, 'angle', 0.001, 1.570).onChange(function (value){
spotLight.angle = value;
});
datGUI.close();
container.appendChild(renderer.domElement);
window.addEventListener( 'resize', onWindowResize, false );
}
//------------------------- END INIT() ----------------------------
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function loadCollada() {
//--- Loads the Classic Mini ---
colladaLoader = new THREE.ColladaLoader();
colladaLoader.options.convertUpAxis = true;
colladaLoader.load( 'dae_files/ClassicMini.dae', function ( collada ) {
carOld = collada.scene; // stores dae file to a global variable
carOld.position.set( 14.5, 1.8, -10 );
carOld.scale.set( 0.04, 0.04, 0.04 );
carOld.traverse(function (child) {
child.castShadow = true;
child.receiveShadow = true;
});
carOld.updateMatrix();
carOld.name = "Classic";
scene.add( carOld );
objects.push( carOld );
} );
//--- loads Modern Mini ---
colladaLoader = new THREE.ColladaLoader();
colladaLoader.options.convertUpAxis = true;
colladaLoader.load( 'dae_files/ModernMini.dae', function ( collada ) {
carNew = collada.scene;
carNew.position.set( -14.5, 6.3, -10 );
carNew.scale.set( 0.06, 0.06, 0.06 );
// creates shadow
carNew.traverse(function (child) {
child.castShadow = true;
child.receiveShadow = true;
});
carNew.updateMatrix();
carNew.name = "Modern";
scene.add( carNew );
objects.push( carNew );
} );
//--- loads the Showroom ---
colladaLoader = new THREE.ColladaLoader();
colladaLoader.options.convertUpAxis = true;
colladaLoader.load( 'dae_files/roomAnim2.dae', function collada( collada ) {
showroom = collada.scene;
animations = collada.animations;
kfAnimationsLength = animations.length;
// Initialise last frame current time.
for ( var i = 0; i < kfAnimationsLength; i++ ) {
lastFrameCurrentTime[i] = 0;
}
// Get all the key frame animations.
for ( var i = 0; i < kfAnimationsLength; i++ ) {
var anim = animations[ i ];
var keyFrameAnim = new THREE.KeyFrameAnimation( anim );
keyFrameAnim.timeScale = 1;
keyFrameAnim.loop = false;
kfAnimations.push( keyFrameAnim );
anim = kfAnimations[i];
anim.play();
}
showroom.position.set(0, 0, -20);
showroom.scale.set(0.06, 0.06, 0.06);
showroom.traverse(function (child) {
child.castShadow = true;
child.receiveShadow = true;
});
showroom.updateMatrix();
scene.add( showroom );
animate();
} );
}
// On Mouse double click event function
function onDoubleClick(event) {
// Set the mouse down flag to false
mouseDown = false;
// Canvas x (left) and y (top) position
var canvasLeft = 0;
var canvasTop = 0;
// "event.clientX" is the mouse x position. "event.clientY" is the mouse y position
var tempX = event.clientX - canvasLeft;
var tempY = event.clientY - canvasTop;
// Create a normalised vector in 2d space
var vector = new THREE.Vector3((tempX / window.innerWidth) * 2 - 1, - (tempY / innerHeight) * 2 + 1, 0.5);
// Unproject a 2D point into the 3D word
// Use the camera projection matrix to transform the vector to the 3D world space
vector.unproject(camera);
// Send a ray in the direction the user has clicked from the cameras position
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
// Check if the ray has intersected with any objects and get intersections
var intersects = raycaster.intersectObjects(objects, true);
// Check if intersected with objects
if (intersects.length > 0) {
var tempStr = "Number of items: " + intersects.length + " ";
// List the items that were hit
for(var i=0; i < intersects.length; i++){
if(intersects[i].object.name != ""){
// The mesh name set above
tempStr += " | Name: " + intersects[i].object.name;
} else {
// The names inside the model
tempStr += " | Name: " + intersects[i].object.parent.name;
}
}
//Debug information
document.getElementById("debugInfo").innerHTML = tempStr + ".<br>";
//END
}
}
function loopAnimations(){
// Loop through all animations
for ( var i = 0; i < kfAnimationsLength; i++ ) {
// Check if the animation is player and not paused.
if(kfAnimations[i].isPlaying && !kfAnimations[i].isPaused){
if(kfAnimations[i].currentTime == lastFrameCurrentTime[i]) {
kfAnimations[i].stop();
//kfAnimations[i].play();
lastFrameCurrentTime[i] = 0;
}
}
}
}
function play_pauseAnim() {
//checks is there animation and is it paused
if(kfAnimationsLength > 0) {
if(kfAnimations[0].isPlaying) {
for(i = 0; i < kfAnimationsLength; i++){
kfAnimations[i].stop();
}
}else {
for(i = 0; i < kfAnimationsLength; i++) {
lastFrameCurrentTime[i] = 0;
//kfAnimations[i].play(kfAnimations[i].currentTime);
kfAnimations[i].play(0);
}
}
}
}
function checkTime(){
if(kfAnimationsLength > 0) {
if(kfAnimations[0].isPlaying) {
if(kfAnimations[0].currentTime > 3){
play_pauseAnim();
}
}
}
}
// create a render loop to draw the scene 60 times per second
function render() {
//checkTime();
daeObject.rotation.y += guiControls.rotationY;
//if (daeObject.position.z < 25) {
daeObject.position.z = guiControls.positionZ;
//}
spotLight.rotation.x += guiControls.rotationX;
spotLight.rotation.y += guiControls.rotationY;
spotLight.rotation.z += guiControls.rotationZ;
stats.update();
}
function animate () {
var deltaTime = clock.getDelta();
for ( var i = 0; i < kfAnimationsLength; i++ ) {
// Get a key frame animation.
var anim = kfAnimations[i];
anim.update( deltaTime );
}
loopAnimations();
requestAnimationFrame(animate);
// Update last frame current time.
for ( var i = 0; i < kfAnimationsLength; i++ ) {
lastFrameCurrentTime[i] = kfAnimations[i].currentTime;
}
render();
renderer.render(scene, camera);
}
// Loads skybox texture
function loadTexture(path) {
var texture = new THREE.Texture(texture_placeholder);
var material = new THREE.MeshBasicMaterial({
map: texture,
overdraw: 0.5
});
var image = new Image();
image.onload = function() {
texture.image = this;
texture.needsUpdate = true;
};
image.src = path;
return material;
}
Macast,
Please, check if you haven't forgotten in your code:
var objets = [];
var raycaster = new THREE.Raycaster();
And for each part of the car this line :
objects.push( mesh );
Ex:
var geometry = new THREE.RingGeometry( 1, 5, 32 );
var material = new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide } );
var simpleTire = new THREE.Mesh( geometry, material );
simpleTire.name = 'tire';
objects.push( simpleTire );
scene.add( simpleTire );
Then, it's simple :
if ( intersects.length > 0 ) {
switch(intersects[0].object.name){
case 'tire':
console.log('A pretty red tire');
break;
case 'motor':
console.log('An electric motor');
break;
}
}

How to constrain objects in a box/cylinder container in Physijs (with Three.js)

I wrote a program to randomly generate and put ConvexGeometry object into a box container based on Physijs's example shapes.
Everything goes well until too many objects are put into the container, objects just struggle to fly out of the box .
Here is the code to initialize scene:
initScene = function() {
TWEEN.start();
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
document.getElementById( 'viewport' ).appendChild( renderer.domElement );
render_stats = new Stats();
render_stats.domElement.style.position = 'absolute';
render_stats.domElement.style.top = '0px';
render_stats.domElement.style.zIndex = 100;
document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
physics_stats = new Stats();
physics_stats.domElement.style.position = 'absolute';
physics_stats.domElement.style.top = '50px';
physics_stats.domElement.style.zIndex = 100;
document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
scene = new Physijs.Scene({ fixedTimeStep: 1 / 120 });
scene.setGravity(new THREE.Vector3( 0, -30, 0 ));
scene.addEventListener(
'update',
function() {
scene.simulate( undefined, 2 );
physics_stats.update();
}
);
camera = new THREE.PerspectiveCamera(
35,
window.innerWidth / window.innerHeight,
1,
1000
);
camera.position.set( 150, 120, 150 );
camera.lookAt( scene.position );
scene.add( camera );
// Materials
wall_material = Physijs.createMaterial(
new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true, transparent: true, opacity: 1 } )
);
ground_material = Physijs.createMaterial(
new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/rocks.jpg' ) }),
.8, // high friction
.4 // low restitution
);
ground_material.map.wrapS = ground_material.map.wrapT = THREE.RepeatWrapping;
ground_material.map.repeat.set( 2.5, 2.5 );
// Ground
ground = new Physijs.BoxMesh(
new THREE.BoxGeometry(50, 1, 50),
//new THREE.PlaneGeometry(50, 50),
ground_material,
0 // mass
);
ground.receiveShadow = true;
scene.add( ground );
// Bumpers
var bumper,
bumper_geom = new THREE.BoxGeometry(1, 50, 50);
// Back left
bumper = new Physijs.BoxMesh( bumper_geom, ground_material, 0, { restitution: .2 } );
bumper.position.y = 25;
bumper.position.x = -25;
bumper.receiveShadow = true;
bumper.castShadow = true;
scene.add( bumper );
// Front right
bumper = new Physijs.BoxMesh( bumper_geom, wall_material, 0, { restitution: .2 } );
bumper.position.y = 25;
bumper.position.x = 25;
bumper.receiveShadow = true;
bumper.castShadow = true;
scene.add( bumper );
// Back right
bumper = new Physijs.BoxMesh( bumper_geom, wall_material, 0, { restitution: .2 } );
bumper.position.y = 25;
bumper.position.z = -25;
bumper.rotation.y = Math.PI / 2;
bumper.receiveShadow = true;
bumper.castShadow = true;
scene.add( bumper );
// Front left
bumper = new Physijs.BoxMesh( bumper_geom, wall_material, 0, { restitution: .2 } );
bumper.position.y = 25;
bumper.position.z = 25;
bumper.rotation.y = Math.PI / 2;
bumper.receiveShadow = true;
bumper.castShadow = true;
scene.add( bumper );
// Top
bumper = new Physijs.BoxMesh( bumper_geom, wall_material, 0, { restitution: .2 } );
bumper.position.y = 50;
bumper.position.x = 0;
bumper.position.z = 0;
bumper.rotation.z = Math.PI / 2;
bumper.receiveShadow = true;
bumper.castShadow = true;
scene.add( bumper );
requestAnimationFrame( render );
scene.simulate();
createShape();
};
Create shapes:
createShape = (function() {
var addshapes = true,
doCreateShape;
setTimeout(
function addListener() {
var button = document.getElementById( 'stop' );
if ( button ) {
button.addEventListener( 'click', function() { addshapes = false; } );
} else {
setTimeout( addListener );
}
}
);
doCreateShape = function() {
var shape, material = new THREE.MeshLambertMaterial({ opacity: 0, transparent: true });
var minR = 5, maxR = 10;
var minVertices = 4, maxVertices = 6;
var sphere = randomSphereInBox(minR, maxR, {vertex3A: new THREE.Vector3(0, 0, 0), vertex3B: new THREE.Vector3(50, 50, 50)});
var convex_geometry = randomConvexInSphere(minVertices, maxVertices, sphere);
shape = new Physijs.BoxMesh(
convex_geometry,
material
);
shape.material.color.setRGB( Math.random() * 100 / 100, Math.random() * 100 / 100, Math.random() * 100 / 100 );
shape.castShadow = false;
shape.receiveShadow = false;
shape.position.set(
Math.random() * 30 - 15,
40,
Math.random() * 30 - 15
);
if ( addshapes ) {
shape.addEventListener( 'ready', createShape );
}
scene.add( shape );
new TWEEN.Tween(shape.material).to({opacity: 1}, 500).start();
document.getElementById( 'shapecount' ).textContent = ( ++shapes ) + ' shapes created';
};
return function() {
setTimeout( doCreateShape, 10 );
};
})();
Is there any way to constrain all the objects within the container?
Well, the fact that the objects are bouncing out of the box is because you are overloading it to the point where the objects altogether are "too big" for the containement box, leading to leaks. I don't think there is a real fix to this as this is always a problem in physics engines, but it doesn't hurt to try and plug a hole, right?
You could try using the object's own addEventListener method to check for collisions with the containement box and if so, set the position of itself to the center of the containement box, avoiding any extra collisions for a while:
doCreateShape = function(){
// ...
shape.addEventListener('collision', function(collidedWith, lineVel, angleVel){
if(collidedWith.material == wall_material){ // If it actually collided with a wall
this.__dirtyPosition = true; // To actively change the object position
this.position.x = 0;
this.position.y = 40;
this.position.z = 0;
}
});
scene.add(shape);
// ...
}
Just make sure that the wall_material variable is global.
Also, setting the restitution of all objects to 0 will lessen bouncing inside the container.

Categories