I'm trying to get a mesh's position to change constantly so that it moves at a constant velocity. The console shows that the position Vector3 is changing, but the actual scene shows all of the meshes remaining static. This is the code I tried:
let ball = new THREE.Mesh();
let equator = new THREE.Mesh()
for (let i = 1; i <= 12; i++) {
let scale = Math.floor(Math.random() * 3) + 1
let pos_x = Math.floor(Math.random() * 10) * 5 - 25
let pos_y = Math.floor(Math.random() * 10) * 5 - 25
let pos_z = Math.floor(Math.random() * 10) * 5 - 25
pos = new THREE.Vector3(pos_x, pos_y, pos_z)
loader.load( './ball.gltf', function ( gltf ) { //load sphere
gltf.scene.traverse(function(model) {
if (model.isMesh) {
model.castShadow = true;
model.material = sphereMaterial;
pos_arr.push(model)
}
});
ball = gltf.scene
ball.position.set(pos_x, pos_y, pos_z)
ball.scale.set(scale, scale, scale)
scene.add( ball );
}, undefined, function ( error ) {
console.error( error );
} );
loader.load( './equator.gltf', function ( gltf2 ) {
gltf2.scene.traverse(function(model) { //for gltf shadows!
if (model.isMesh) {
model.castShadow = true
model.material = equatorMaterial
}
});
equator = gltf2.scene
equator.position.set(pos_x, pos_y, pos_z)
equator.scale.set(scale, scale, scale)
scene.add( equator )
}, undefined, function ( error ) {
console.error( error )
} );
pos_arr.push([ball, equator, pos])
}
//light
const light = new THREE.AmbientLight( 0xffffff );
scene.add( light );
let y_axis_dist = []
for (let j = 0; j < pos_arr.length; j++) {
y_axis_dist.push(pos_arr[j][2].distanceTo(new THREE.Vector3(0, pos_arr[j][2].y , 0)))
}
//render
console.log(pos_arr)
function animate() {
requestAnimationFrame( animate );
pos_arr[0][1].position.x += 0.1
console.log(pos_arr[0][1].position)
renderer.render( scene, camera );
}
animate()
If anyone knows what I'm doing wrong, I will appreciate it a lot.
Related
I am having trouble getting the MTLLoader to work correctly. I have already been able to use the OBJLoader by itself to load the 3d object and I have a camera that works properly too in my scene. When I try and use the MTLLoader with the OBJLoader the object loads but it breaks my other three.js code. I get these errors:
three.js:24415 Uncaught TypeError: Cannot set property 'value' of undefined
at initMaterial (three.js:24415)
at setProgram (three.js:24493)
at WebGLRenderer.renderBufferDirect (three.js:23552)
at renderObject (three.js:24269)
at renderObjects (three.js:24239)
at WebGLRenderer.render (three.js:24037)
at render (demo2.html:480)
The object loads and it looks like some textures load but the textures don't look right, the camera breaks. I have been having trouble with this and could really use some guidance.
Here is my MTLLoader code by itself
var mesh = null;
var mtlLoader = new THREE.MTLLoader();
mtlLoader.load( 'dapHouseGood5.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.load( 'dapHouseGood5.obj', function ( object ) {
mesh = object;
scene.add( mesh );
} );
Here is the rest of my three.js code for reference
<script>
/* global THREE */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const renderer2 = new THREE.WebGLRenderer({canvas});
var kitchenCameraActive = false;
document.getElementById("roomSelect").addEventListener("change", changeIt);
function changeIt(e) {
document.getElementById(e.target.value).click();
console.log(e);
}
var fov = 45;
var aspect = 2; // the canvas default
var near = 0.1;
var far = 100;
var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(-97.570, 5.878, -5.289);
camera.rotation.set(0,0,0);
const controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(0, 5, 0);
controls.update();
document.getElementById("kitchen").addEventListener("click", changeCamera);
document.getElementById("bathroom").addEventListener("click", changeCamera);
document.getElementById("deck").addEventListener("click", changeCamera);
document.getElementById("livingRoom").addEventListener("click", changeCamera);
document.getElementById("bedRoom").addEventListener("click", changeCamera);
document.getElementById("walkway").addEventListener("click", changeCamera);
document.getElementById("sideHouse").addEventListener("click", changeCamera);
document.getElementById("frontPorch").addEventListener("click", changeCamera);
document.getElementById("garageDoor").addEventListener("click", changeCamera);
document.getElementById("insideGarage").addEventListener("click", changeCamera);
function changeCamera(e) {
camera.rotation.set(e.toElement.attributes[5].nodeValue,
e.toElement.attributes[6].nodeValue, e.toElement.attributes[7].nodeValue);
camera.fov = e.toElement.attributes[4].nodeValue;
camera.position.set(e.toElement.attributes[1].nodeValue,
e.toElement.attributes[2].nodeValue, e.toElement.attributes[3].nodeValue);
camera.updateProjectionMatrix();
if (e.target.id == "walkway" || e.target.id == "frontPorch" || e.target.id ==
"garageDoor" || e.target.id == "insideGarage")
{
controls.target.set(0, 5, 0);
controls.update();
}
if(e.target.id == "kitchen"){
controls.target.set(7, 6, 7);
}
if(e.target.id == "bathroom"){
controls.target.set(-9,15,-7);
}
if(e.target.id == "deck"){
controls.target.set(31, 7, 1);
}
if(e.target.id == "livingRoom"){
controls.target.set(-12.5, 1.5, -18.5);
}
if(e.target.id == "bedRoom"){
controls.target.set(-15.7, 14, -21);
}
if(e.target.id == "insideGarage"){
controls.target.set(24.405, 6.733, -6.425);
}
controls.update();
console.log(e);
}
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
{
const planeSize = 40;
}
{
const skyColor = 0xB1E1FF; // light blue
const groundColor = 0xB97A20; // brownish orange
const intensity = 1;
const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
scene.add(light);
}
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(5, 10, 2);
scene.add(light);
scene.add(light.target);
}
var mesh = null;
var mtlLoader = new THREE.MTLLoader();
mtlLoader.load( 'dapHouseGood5.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.load( 'dapHouseGood5.obj', function ( object ) {
mesh = object;
scene.add( mesh );
} );
} );
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function onPositionChange(o) {
console.log("position changed in object");
console.log(o);
console.log('camera_default: '+camera.position.x+', '+camera.position.y+',
'+camera.position.z);
console.log('camera_default: '+camera.rotation.x+', '+camera.rotation.y+',
'+camera.rotation.z);
console.log(camera.fov);
console.log('quaternion_default: '+camera.quaternion.x+', '+
camera.quaternion.y+', '+camera.quaternion.z+', '+camera.quaternion.w);
}
controls.addEventListener('change', onPositionChange);
var mouse = new THREE.Vector2();
var raycaster, mouse = { x : 0, y : 0};
init();
function init () {
//Usual setup code here.
raycaster = new THREE.Raycaster();
renderer.domElement.addEventListener( 'click', raycast, false );
}
function raycast ( e ) {
//1. sets the mouse position with a coordinate system where the center
// of the screen is the origin
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
//2. set the picking ray from the camera position and mouse coordinates
raycaster.setFromCamera( mouse, camera );
//var mouse3D = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, -(
event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
//raycaster.setFromCamera( mouse3D, camera );
//3. compute intersections
var intersects = raycaster.intersectObjects( scene.children, true );
for ( var i = 0; i < intersects.length; i++ ) {
console.log( intersects[ i ].object.name );
}
}
}
main();
</script>
I have a particle system where all the particles are positioned at the same coordinates and one after another, in random directions, they (should) start orbiting the center of the scene forming a sphere.
What I managed to achieve until now is a group of Vector3 objects (the particles) that one after another start orbiting the center along the Z axis simply calculating their sine and cosine based on the current angle.
I'm not that good at math and I don't even know what to look for precisely.
Here's what I wrote:
var scene = new THREE.Scene();
let container = document.getElementById('container'),
loader = new THREE.TextureLoader(),
renderer,
camera,
maxParticles = 5000,
particlesDelay = 50,
radius = 50,
sphereGeometry,
sphere;
loader.crossOrigin = true;
function init() {
let vw = window.innerWidth,
vh = window.innerHeight;
renderer = new THREE.WebGLRenderer();
renderer.setSize(vw, vh);
renderer.setPixelRatio(window.devicePixelRatio);
camera = new THREE.PerspectiveCamera(45, vw / vh, 1, 1000);
camera.position.z = 200;
camera.position.x = 30;
camera.position.y = 30;
camera.lookAt(scene.position);
scene.add(camera);
let controls = new THREE.OrbitControls(camera, renderer.domElement);
let axisHelper = new THREE.AxisHelper(50);
scene.add(axisHelper);
container.appendChild(renderer.domElement);
window.addEventListener('resize', onResize, false);
}
function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function draw() {
sphereGeometry = new THREE.Geometry();
sphereGeometry.dynamic = true;
let particleTexture = loader.load('https://threejs.org/examples/textures/particle2.png'),
material = new THREE.PointsMaterial({
color: 0xffffff,
size: 3,
transparent: true,
blending: THREE.AdditiveBlending,
map: particleTexture,
depthWrite: false
});
for ( let i = 0; i < maxParticles; i++ ) {
let vertex = new THREE.Vector3(radius, 0, 0);
vertex.delay = Date.now() + (particlesDelay * i);
vertex.angle = 0;
sphereGeometry.vertices.push(vertex);
}
sphere = new THREE.Points(sphereGeometry, material);
scene.add(sphere);
}
function update() {
for ( let i = 0; i < maxParticles; i++ ) {
let particle = sphereGeometry.vertices[i];
if ( Date.now() > particle.delay ) {
let angle = particle.angle += 0.01;
particle.x = radius * Math.cos(angle);
if ( i % 2 === 0 ) {
particle.y = radius * Math.sin(angle);
} else {
particle.y = -radius * Math.sin(angle);
}
}
}
sphere.geometry.verticesNeedUpdate = true;
}
function render() {
update();
renderer.render(scene, camera);
requestAnimationFrame(render);
}
init();
draw();
render();
And here's the JSFiddle if you want to see it live:
https://jsfiddle.net/kekkorider/qs6s0wv2/
EDIT: Working example
Can someone please give me a hand?
Thanks in advance!
You want each particle to rotate around a specific random axis. You can either let them follow a parametric equation of a circle in 3D space, or you can make use of THREE.js rotation matrices.
Right now all your particles are rotating round the vector (0, 0, 1). Since your particles start off on the x-axis, you want them all to rotate around a random vector in the y-z plane (0, y, z). This can be defined during the creation of the vertices:
vertex.rotationAxis = new THREE.Vector3(0, Math.random() * 2 - 1, Math.random() * 2 - 1);
vertex.rotationAxis.normalize();
now you can just call the THREE.Vector3.applyAxisAngle(axis, angle) method on each of your particles with the random rotation axis you created each update:
particle.applyAxisAngle(particle.rotationAxis, 0.01);
To sum up, this is how it should look like:
draw():
...
for ( let i = 0; i < maxParticles; i++ ) {
let vertex = new THREE.Vector3(radius, 0, 0);
vertex.delay = Date.now() + (particlesDelay * i);
vertex.rotationAxis = new THREE.Vector3(0, Math.random() * 2 - 1, Math.random() * 2 - 1);
vertex.rotationAxis.normalize();
sphereGeometry.vertices.push(vertex);
}
...
update():
...
for ( let i = 0; i < maxParticles; i++ ) {
let particle = sphereGeometry.vertices[i];
if ( Date.now() > particle.delay ) {
particle.applyAxisAngle(particle.rotationAxis, 0.01);
}
}
...
I unable to intersect Three.Points but i am able to intersect THREE.Mesh, below is my code: Can someone please help me to understand what mistake i am making. When i intersect the Points all i get is 0.
function init()
{
geometry = new THREE.Geometry();
vertex = new THREE.Vector3();
vertex.x=( [i + 3 ] * 140 ) - 1330;
vertex.y = - ( [i + 3 ] * 180 ) + 990;
vertex.z = 100;
geometry.vertices.push(vertex);
var particleTexture = THREE.ImageUtils.loadTexture(imgstr);
var materials = new THREE.PointsMaterial({
map:particleTexture,
size: 150
});
particles = new THREE.Points(geometry, materials);
scene.add(particles);
targetList.push(particles);
}
function onDocumentMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function onDocumentMouseDown(event){
var projector = new THREE.Projector();
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(targetList);
console.log(intersects.length);
}
function onDocumentMouseDown( event ) {
event.preventDefault();
if(event.which == 1) {
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera( mouse, camera );
raycaster.params.Points.threshold = 100000; // bigger number = bigger sensitivity
var intersects = raycaster.intersectObjects( myobjectsarray,false); // myobject array is array of THREE.Points object
if ( intersects.length > 0 ) {console.log('tadaah',intersects);}
}
}
I've been doing a ThreeJS project and using raycasting to interesect with objects within the canvas.
I have 4 computers to test it on, all updated with the latest repo.
On one of the computers the raycasting is off from where the mouse are... and I have no idea what is causing it to behave differently from the others.
Any ideas?
The code:
// Performs a Raycast for Ortho camera type
PerformOrthographicRaycast: function (event, canvas, renderer, camera, objects) {
var vector = new THREE.Vector3(0, 0, 0);
var dir = new THREE.Vector3(0, 0, 0);
vector.x = ((event.clientX - canvas.getBoundingClientRect().left) / renderer.domElement.width) * 2 - 1;
vector.y = -((event.clientY - canvas.getBoundingClientRect().top) / renderer.domElement.height) * 2 + 1;;
vector.z = -1; // z = - 1 important!
vector.unproject(camera);
dir.set(0, 0, -1).transformDirection(camera.matrixWorld);
this._Raycaster.set(vector, dir);
var intersects = this._Raycaster.intersectObjects(objects, true);
if (intersects.length) {
return intersects;
}
else
return null;
},
See this example. Look at messages in the console.
<script src="js/controls/EventsControls.js"></script>
EventsControls = new EventsControls( camera, renderer.domElement );
EventsControls.draggable = false;
EventsControls.mouseOver = function () {
this.container.style.cursor = 'pointer';
this.mouseOvered.currentHex = this.mouseOvered.material.emissive.getHex();
this.mouseOvered.material.emissive.setHex( 0xff0000 );
console.log( 'the key at number ' + this.mouseOveredItem + ' is select' );
}
//
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
EventsControls.attach( mesh );
//
function render() {
EventsControls.update();
controls.update();
renderer.render(scene, camera);
}
I found out that the problem was with Windows "enlarge" or "scale" users can set in their theme settings.
In the renderer you can find the pixelratio which is modified when the scaling has been changed. The following solution works for me:
vector.x = renderer.devicePixelRatio * ((event.clientX - canvas.getBoundingClientRect().left) / renderer.domElement.width) * 2 - 1;
vector.y = renderer.devicePixelRatio * -((event.clientY - canvas.getBoundingClientRect().top) / renderer.domElement.height) * 2 + 1;;
I for now work on a 3D engine for an amateur video game, and i want to add to him tons of features to get the best performances & gameplay. But i've got serious problems to get an "on click event" with lod meshes.
For the "lod" part, no problem for now, he's integrated, but i found no solution to apply that exemple with him :
https://stackoverflow.com/a/12808987/3379444
Did i must push the "lod" object, or every mesh individually ?
a part of my code :
var i, j, mesh, lod;
for ( j = 0; j <= 42; j++) {
lod = new THREE.LOD();
//Here, it's just var for place my mesh into a circle
rayonSysteme = Math.floor(Math.random() * 10000) + 2500;
angleSysteme = Math.random() * 360;
for ( i = 0; i < geometry.length; i ++ ) {
mesh = new THREE.Mesh( geometry[ i ][ 0 ], material );
mesh.scale.set( 1.5, 1.5, 1.5 );
mesh.updateMatrix();
mesh.matrixAutoUpdate = false;
//Callback here ?
mesh.callback = function() { console.log( this.name ); }
lod.addLevel( mesh, geometry[ i ][ 1 ] );
}
lod.position.x = rayonSysteme * Math.cos(angleSysteme);
lod.position.y = Math.floor(Math.random() * 1000)-500;
lod.position.z = rayonSysteme * Math.sin(angleSysteme);
//Or here ?
lod.updateMatrix();
lod.matrixAutoUpdate = false;
gravity = drawCircle("XZ", 64, 500, 360);
gravity.position.x = lod.position.x;
gravity.position.y = lod.position.y;
gravity.position.z = lod.position.z;
scene.add( lod );
//objects.push( lod );
scene.add( gravity );
};
Raycaster will test the mesh that should be used based on the distance to the ray origin.
This is the relevant code inside Raycaster:
} else if ( object instanceof THREE.LOD ) {
matrixPosition.setFromMatrixPosition( object.matrixWorld );
var distance = raycaster.ray.origin.distanceTo( matrixPosition );
intersectObject( object.getObjectForDistance( distance ), raycaster, intersects );
}