How to rotate gltf model while scrolling the page - javascript

I'm trying to make the gltf model rotate smoothly while scrolling.
I managed to create a function that converts pageYOffset from pixels to radians
let scroollPositionRad = 0;
window.addEventListener("scroll", onWindowScroll );
function onWindowScroll(){
let scroollPosition = Math.round(pageYOffset);
let limit = document.body.offsetHeight - window.innerHeight;
scroollPositionRad = (scroollPosition * 2* Math.PI) / limit;
}
and a function that rotates and centers the model
function centerObj(rad){
obj.rotation.y = rad;
let box = new THREE.Box3().setFromObject( obj );
let center = box.getCenter( new THREE.Vector3() );
obj.position.x += ( obj.position.x - center.x );
obj.position.y += ( obj.position.y - center.y );
obj.position.z += ( obj.position.z - center.z );
}
if i try to call centerObj(scrollPositionRad) as animation, gltf model disappears
renderer.setAnimationLoop(_ => {
centerObj(scroollPositionRad);
renderer.render(scene, camera);
})
model loading code after scene creation
let loader = new THREE.GLTFLoader();
let obj = null;
loader.load('https://raw.githubusercontent.com/aaadraniki/projects/web-pages/assets/models/fender_br/scene.gltf', function(gltf) {
obj = gltf.scene;
scene.add(obj);
function centerObj(rad){
obj.rotation.y = rad;
let box = new THREE.Box3().setFromObject( obj );
let center = box.getCenter( new THREE.Vector3() );
obj.position.x += ( obj.position.x - center.x );
obj.position.y += ( obj.position.y - center.y );
obj.position.z += ( obj.position.z - center.z );
}
centerObj(0.8);
let scroollPositionRad = 0;
window.addEventListener("scroll", onWindowScroll );
function onWindowScroll(){
let scroollPosition = Math.round(pageYOffset);
let limit = document.body.offsetHeight - window.innerHeight;
scroollPositionRad = (scroollPosition * 2* Math.PI) / limit;
}
renderer.setAnimationLoop(_ => {
centerObj(scroollPositionRad);
renderer.render(scene, camera);
})
});

window.onscroll = (e) => {
scene.rotation.y = this.scrollY / 700.0;
}

Related

Trying to simulate a 3D effect via Three.js

I'm trying to achieve something akin to this amazing effect : https://www.cobosrl.co/
Here's what I have so far : https://codepen.io/routsou/pen/ZEGWJgR?editors=0010
/*--------------------
Setup
--------------------*/
console.clear();
const canvas = document.querySelector('#bubble');
//wobble
let mouseDown = false;
let howMuch = 0;
let howMuchLimit = 0.25;
//ripple
let rippleAmount = 0;
let rippleRatio = 5;
let step = 0;
let sphereVerticesArray = [];
let sphereVerticesNormArray = [];
//raycaster
let raycaster;
let INTERSECTED = null;
let width = canvas.offsetWidth,
height = canvas.offsetHeight;
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
alpha: true
});
const scene = new THREE.Scene();
const setup = () => {
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(width, height);
renderer.setClearColor(0xebebeb, 0);
renderer.shadowMap.enabled = true;
renderer.shadowMapSoft = true;
scene.fog = new THREE.Fog(0x000000, 10, 950);
const aspectRatio = width / height;
const fieldOfView = 100;
const nearPlane = 0.1;
const farPlane = 10000;
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane
);
raycaster = new THREE.Raycaster();
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 300;
}
setup();
/*--------------------
Lights
--------------------*/
let hemispshereLight, shadowLight, light2;
const createLights = () => {
hemisphereLight = new THREE.HemisphereLight(0xffffff,0x000000, .5)
shadowLight = new THREE.DirectionalLight(0x666666, .4);
shadowLight.position.set(0, 450, 350);
shadowLight.castShadow = true;
shadowLight.shadow.camera.left = -650;
shadowLight.shadow.camera.right = 650;
shadowLight.shadow.camera.top = 650;
shadowLight.shadow.camera.bottom = -650;
shadowLight.shadow.camera.near = 1;
shadowLight.shadow.camera.far = 1000;
shadowLight.shadow.mapSize.width = 4096;
shadowLight.shadow.mapSize.height = 4096;
light2 = new THREE.DirectionalLight(0x666666, .25);
light2.position.set(-600, 350, 350);
light3 = new THREE.DirectionalLight(0x666666, .15);
light3.position.set(0, -250, 300);
scene.add(hemisphereLight);
scene.add(shadowLight);
scene.add(light2);
scene.add(light3);
}
createLights();
/*--------------------
Bubble
--------------------*/
const vertex = width > 575 ? 80 : 40;
const bubbleGeometry = new THREE.SphereGeometry( 150, vertex, vertex );
let bubble;
const createBubble = () => {
for(let i = 0; i < bubbleGeometry.vertices.length; i++) {
let vector = bubbleGeometry.vertices[i];
vector.original = vector.clone();
}
const bubbleMaterial = new THREE.MeshStandardMaterial({
emissive: 0x91176b,
emissiveIntensity: 0.85,
roughness: 0.55,
metalness: 0.51,
side: THREE.FrontSide,
});
// save points for later calculation
for (var i = 0; i < bubbleGeometry.vertices.length; i += 1) {
var vertex = bubbleGeometry.vertices[i];
var vec = new THREE.Vector3(vertex.x, vertex.y, vertex.z);
sphereVerticesArray.push(vec);
var mag = vec.x * vec.x + vec.y * vec.y + vec.z * vec.z;
mag = Math.sqrt(mag);
var norm = new THREE.Vector3(vertex.x / mag, vertex.y / mag, vertex.z / mag);
sphereVerticesNormArray.push(norm);
}
bubble = new THREE.Mesh(bubbleGeometry, bubbleMaterial);
bubble.castShadow = true;
bubble.receiveShadow = false;
bubble.rotation.y = -90;
scene.add(bubble);
}
createBubble();
/*--------------------
Plane
--------------------*/
const createPlane = () => {
const planeGeometry = new THREE.PlaneBufferGeometry( 2000, 2000 );
const planeMaterial = new THREE.ShadowMaterial({
opacity: 0.15
});
const plane = new THREE.Mesh( planeGeometry, planeMaterial );
plane.position.y = -150;
plane.position.x = 0;
plane.position.z = 0;
plane.rotation.x = Math.PI / 180 * -90;
plane.receiveShadow = true;
scene.add(plane);
}
createPlane();
/*--------------------
Map
--------------------*/
const map = (num, in_min, in_max, out_min, out_max) => {
return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
/*--------------------
Distance
--------------------*/
const distance = (a, b) => {
const dx = a.x - b.x;
const dy = a.y - b.y;
const d = Math.sqrt( dx * dx + dy * dy );
return d;
}
/*--------------------
Mouse
--------------------*/
let mouse = new THREE.Vector2(0, 0);
const onMouseMove = (e) => {
TweenMax.to(mouse, 0.8, {
x : ( e.clientX / window.innerWidth ) * 2 - 1,
y: - ( e.clientY / window.innerHeight ) * 2 + 1,
ease: Power2.easeOut
});
raycaster.setFromCamera( mouse, camera );
let intersects = raycaster.intersectObjects( scene.children );
try{
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
INTERSECTED.material.emissive.setHex( 0x000000 );
document.body.style.cursor = 'pointer';
}
} else {
if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
INTERSECTED = null;
document.body.style.cursor = 'auto';
}
}catch(e){
}
};
['mousemove', 'touchmove'].forEach(event => {
window.addEventListener(event, onMouseMove);
});
/*--------------------
Spring
--------------------*/
let spring = {
scale: 1
};
const clicking = {
down: () => {
mouseDown = true;
},
up: () => {
mouseDown = false;
}
};
['mousedown', 'touchstart'].forEach(event => {
window.addEventListener(event, clicking.down);
});
['mouseup', 'touchend'].forEach(event => {
window.addEventListener(event, clicking.up);
});
/*--------------------
Resize
--------------------*/
const onResize = () => {
canvas.style.width = '';
canvas.style.height = '';
width = canvas.offsetWidth;
height = canvas.offsetHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
maxDist = distance(mouse, {x: width / 2, y: height / 2});
renderer.setSize(width, height);
}
let resizeTm;
window.addEventListener('resize', function(){
resizeTm = clearTimeout(resizeTm);
resizeTm = setTimeout(onResize, 200);
});
/*--------------------
Noise
--------------------*/
let dist = new THREE.Vector2(0, 0);
let maxDist = distance(mouse, {x: width / 2, y: height / 2});
const updateVertices = (time) => {
dist = distance(mouse, {x: width / 2, y: height / 2});
dist /= maxDist;
dist = map(dist, 1, 0, 0, 1);
for(let i = 0; i < bubbleGeometry.vertices.length; i++) {
let vector = bubbleGeometry.vertices[i];
vector.copy(vector.original);
let perlin = noise.simplex3(
(vector.x * 0.006) + (time * 0.0005),
(vector.y * 0.006) + (time * 0.0005),
(vector.z * 0.006)
);
let ratio = ((perlin * 0.3 * (howMuch + 0.1)) + 0.9);
vector.multiplyScalar(ratio);
}
bubbleGeometry.verticesNeedUpdate = true;
}
/*--------------------
Animate
--------------------*/
const render = (a) => {
step +=1;
requestAnimationFrame(render);
//bubble.scale.set(spring.scale, spring.scale, spring.scale);
updateVertices(a);
renderer.clear();
renderer.render(scene, camera);
//Activate on mouse down
if(mouseDown && howMuch < howMuchLimit)
howMuch += 0.01;
else if (howMuch > 0)
howMuch -= 0.01;
if(INTERSECTED){
if(rippleAmount < 10)
rippleAmount += 0.05;
}else if(rippleAmount > 0)
rippleAmount -= 0.05;
doRipple();
}
requestAnimationFrame(render);
renderer.render(scene, camera);
/*--------------------
Helpers
--------------------*/
function fbm(p) {
var result = noise.simplex3(p._x, p._y, p._z);
return result;
}
function addPoint(arr) {
var r = new Point(0, 0, 0);
var len = arr.length;
for (var i = 0; i < len; i += 1) {
r._x += arr[i]._x;
r._y += arr[i]._y;
r._z += arr[i]._z;
}
return r;
}
function Point(_x=0, _y=0, _z=0) {
this._x = _x;
this._y = _y;
this._z = _z;
}
function ripple(p) {
var q = new Point(fbm(addPoint([p, new Point(0, 0, 0)])),
fbm(addPoint([p, new Point(0, 1, 0)])),
fbm(addPoint([p, new Point(0, 0, 1)])));
return fbm(addPoint([p, new Point(0.5 * q._x, 0.5 * q._y, 0.5 * q._z)]));
}
function doRipple(){
//ripple
for (var i = 0; i < bubbleGeometry.vertices.length; i += 1) {
var vertex = bubbleGeometry.vertices[i];
// var value = pn.noise((vertex.x + step)/ 10, vertex.y / 10, vertex.z / 10);
var value = ripple(new Point((vertex.x + step) / 100.0), vertex.y / 100.0, vertex.z / 100.0);
vertex.x = sphereVerticesArray[i].x + sphereVerticesNormArray[i].x * value * rippleAmount;
vertex.y = sphereVerticesArray[i].y + sphereVerticesNormArray[i].y * value * rippleAmount;
vertex.z = sphereVerticesArray[i].z + sphereVerticesNormArray[i].z * value * rippleAmount;
}
bubbleGeometry.computeFaceNormals();
bubbleGeometry.computeVertexNormals();
bubbleGeometry.verticesNeedUpdate = true;
bubbleGeometry.normalsNeedUpdate = true;
}
Any help, particularly about the mouse pointer "sculpting the geometry", and the waves being more natural and from the pointer?
Thank you very much in advance
I've investigated and found you're intersecting with all children (6) in the scene, including the bubble shadow and the lights. The shadow seems to also intersect with the mouse triggering a false contact.
About "sculpting the geometry" I noticed you hardcode the ripple effect from one specific point of the bubble during initial construction and that's why the sculpting effect is always from that same point. This is my recommendation:
Remove the hard-coded sphereVerticesArray and sphereVerticesNormArray.
After computing the intersection with the mouse, find out the face of the bubble getting hit: intersections[0].point provides the point of intersection, in world coordinates. Use this to find out the face of contact.
During ripple effect use the normal of the contact face as starting point and orientation of the ripple.
This is the code to fix the shadow intersection issue including some comments:
/*--------------------
Setup
--------------------*/
console.clear();
const canvas = document.querySelector('#bubble');
//wobble
let mouseDown = false;
let howMuch = 0;
let howMuchLimit = 0.25;
//ripple
let rippleAmount = 0;
let rippleRatio = 5;
let step = 0;
let sphereVerticesArray = [];
let sphereVerticesNormArray = [];
//raycaster
let raycaster;
let isIntersectingWithBubble = false;
let width = canvas.offsetWidth,
height = canvas.offsetHeight;
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
alpha: true
});
const scene = new THREE.Scene();
const setup = () => {
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(width, height);
renderer.setClearColor(0xebebeb, 0);
renderer.shadowMap.enabled = true;
renderer.shadowMapSoft = true;
scene.fog = new THREE.Fog(0x000000, 10, 950);
const aspectRatio = width / height;
const fieldOfView = 100;
const nearPlane = 0.1;
const farPlane = 10000;
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane
);
raycaster = new THREE.Raycaster();
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 300;
}
setup();
/*--------------------
Lights
--------------------*/
let hemispshereLight, shadowLight, light2;
const createLights = () => {
hemisphereLight = new THREE.HemisphereLight(0xffffff,0x000000, .5)
shadowLight = new THREE.DirectionalLight(0x666666, .4);
shadowLight.position.set(0, 450, 350);
shadowLight.castShadow = true;
shadowLight.shadow.camera.left = -650;
shadowLight.shadow.camera.right = 650;
shadowLight.shadow.camera.top = 650;
shadowLight.shadow.camera.bottom = -650;
shadowLight.shadow.camera.near = 1;
shadowLight.shadow.camera.far = 1000;
shadowLight.shadow.mapSize.width = 4096;
shadowLight.shadow.mapSize.height = 4096;
light2 = new THREE.DirectionalLight(0x666666, .25);
light2.position.set(-600, 350, 350);
light3 = new THREE.DirectionalLight(0x666666, .15);
light3.position.set(0, -250, 300);
scene.add(hemisphereLight);
scene.add(shadowLight);
scene.add(light2);
scene.add(light3);
}
createLights();
/*--------------------
Bubble
--------------------*/
const vertex = width > 575 ? 80 : 40;
const bubbleGeometry = new THREE.SphereGeometry( 150, vertex, vertex );
const bubbleEmissive = 0x91176b;
const bubbleEmissiveOnContact = 0x000000;
const createBubble = () => {
for(let i = 0; i < bubbleGeometry.vertices.length; i++) {
let vector = bubbleGeometry.vertices[i];
vector.original = vector.clone();
}
const bubbleMaterial = new THREE.MeshStandardMaterial({
emissive: bubbleEmissive,
emissiveIntensity: 0.85,
roughness: 0.55,
metalness: 0.51,
side: THREE.FrontSide,
});
// save points for later calculation
for (var i = 0; i < bubbleGeometry.vertices.length; i += 1) {
var vertex = bubbleGeometry.vertices[i];
var vec = new THREE.Vector3(vertex.x, vertex.y, vertex.z);
sphereVerticesArray.push(vec);
var mag = vec.x * vec.x + vec.y * vec.y + vec.z * vec.z;
mag = Math.sqrt(mag);
var norm = new THREE.Vector3(vertex.x / mag, vertex.y / mag, vertex.z / mag);
sphereVerticesNormArray.push(norm);
}
const _bubble = new THREE.Mesh(bubbleGeometry, bubbleMaterial);
_bubble.castShadow = true;
_bubble.receiveShadow = false;
_bubble.rotation.y = -90;
scene.add(_bubble);
return _bubble;
}
const bubble = createBubble();
/*--------------------
Plane
--------------------*/
const createPlane = () => {
const planeGeometry = new THREE.PlaneBufferGeometry( 2000, 2000 );
const planeMaterial = new THREE.ShadowMaterial({
opacity: 0.15
});
const plane = new THREE.Mesh( planeGeometry, planeMaterial );
plane.position.y = -150;
plane.position.x = 0;
plane.position.z = 0;
plane.rotation.x = Math.PI / 180 * -90;
plane.receiveShadow = true;
scene.add(plane);
}
createPlane();
/*--------------------
Map
--------------------*/
const map = (num, in_min, in_max, out_min, out_max) => {
return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
/*--------------------
Distance
--------------------*/
const distance = (a, b) => {
const dx = a.x - b.x;
const dy = a.y - b.y;
const d = Math.sqrt( dx * dx + dy * dy );
return d;
}
/*--------------------
Mouse
--------------------*/
let mouse = new THREE.Vector2(0, 0);
const onMouseMove = (e) => {
TweenMax.to(mouse, 0.8, {
x : ( e.clientX / window.innerWidth ) * 2 - 1,
y: - ( e.clientY / window.innerHeight ) * 2 + 1,
ease: Power2.easeOut
});
raycaster.setFromCamera( mouse, camera );
isIntersectingWithBubble = raycaster.intersectObject( bubble ).length > 0; // we are only interested in intersections with the bubble object
try {
if (isIntersectingWithBubble) {
// is intersecting: change color, change pointer, change point of contact
bubble.material.emissive.setHex(bubbleEmissiveOnContact);
document.body.style.cursor = 'pointer';
} else {
// is not intersecting: restore color, restore pointer, remove point of contact
bubble.material.emissive.setHex(bubbleEmissive);
document.body.style.cursor = 'auto';
}
} catch (e) {
}
};
['mousemove', 'touchmove'].forEach(event => {
window.addEventListener(event, onMouseMove);
});
/*--------------------
Spring
--------------------*/
let spring = {
scale: 1
};
const clicking = {
down: () => {
mouseDown = true;
},
up: () => {
mouseDown = false;
}
};
['mousedown', 'touchstart'].forEach(event => {
window.addEventListener(event, clicking.down);
});
['mouseup', 'touchend'].forEach(event => {
window.addEventListener(event, clicking.up);
});
/*--------------------
Resize
--------------------*/
const onResize = () => {
canvas.style.width = '';
canvas.style.height = '';
width = canvas.offsetWidth;
height = canvas.offsetHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
maxDist = distance(mouse, {x: width / 2, y: height / 2});
renderer.setSize(width, height);
}
let resizeTm;
window.addEventListener('resize', function(){
resizeTm = clearTimeout(resizeTm);
resizeTm = setTimeout(onResize, 200);
});
/*--------------------
Noise
--------------------*/
let dist = new THREE.Vector2(0, 0);
let maxDist = distance(mouse, {x: width / 2, y: height / 2});
const updateVertices = (time) => {
dist = distance(mouse, {x: width / 2, y: height / 2});
dist /= maxDist;
dist = map(dist, 1, 0, 0, 1);
for(let i = 0; i < bubbleGeometry.vertices.length; i++) {
let vector = bubbleGeometry.vertices[i];
vector.copy(vector.original);
let perlin = noise.simplex3(
(vector.x * 0.006) + (time * 0.0005),
(vector.y * 0.006) + (time * 0.0005),
(vector.z * 0.006)
);
let ratio = ((perlin * 0.3 * (howMuch + 0.1)) + 0.9);
vector.multiplyScalar(ratio);
}
bubbleGeometry.verticesNeedUpdate = true;
}
/*--------------------
Animate
--------------------*/
const render = (a) => {
step +=1;
requestAnimationFrame(render);
//bubble.scale.set(spring.scale, spring.scale, spring.scale);
updateVertices(a);
renderer.clear();
renderer.render(scene, camera);
//Activate on mouse down
if(mouseDown && howMuch < howMuchLimit)
howMuch += 0.01;
else if (howMuch > 0)
howMuch -= 0.01;
if(isIntersectingWithBubble){
if(rippleAmount < 10)
rippleAmount += 0.05;
}else if(rippleAmount > 0)
rippleAmount -= 0.05;
doRipple();
}
requestAnimationFrame(render);
renderer.render(scene, camera);
/*--------------------
Helpers
--------------------*/
function fbm(p) {
var result = noise.simplex3(p._x, p._y, p._z);
return result;
}
function addPoint(arr) {
var r = new Point(0, 0, 0);
var len = arr.length;
for (var i = 0; i < len; i += 1) {
r._x += arr[i]._x;
r._y += arr[i]._y;
r._z += arr[i]._z;
}
return r;
}
function Point(_x=0, _y=0, _z=0) {
this._x = _x;
this._y = _y;
this._z = _z;
}
function ripple(p) {
var q = new Point(fbm(addPoint([p, new Point(0, 0, 0)])),
fbm(addPoint([p, new Point(0, 1, 0)])),
fbm(addPoint([p, new Point(0, 0, 1)])));
return fbm(addPoint([p, new Point(0.5 * q._x, 0.5 * q._y, 0.5 * q._z)]));
}
function doRipple(){
//ripple
for (var i = 0; i < bubbleGeometry.vertices.length; i += 1) {
var vertex = bubbleGeometry.vertices[i];
// var value = pn.noise((vertex.x + step)/ 10, vertex.y / 10, vertex.z / 10);
var value = ripple(new Point((vertex.x + step) / 100.0), vertex.y / 100.0, vertex.z / 100.0);
vertex.x = sphereVerticesArray[i].x + sphereVerticesNormArray[i].x * value * rippleAmount;
vertex.y = sphereVerticesArray[i].y + sphereVerticesNormArray[i].y * value * rippleAmount;
vertex.z = sphereVerticesArray[i].z + sphereVerticesNormArray[i].z * value * rippleAmount;
}
bubbleGeometry.computeFaceNormals();
bubbleGeometry.computeVertexNormals();
bubbleGeometry.verticesNeedUpdate = true;
bubbleGeometry.normalsNeedUpdate = true;
}

How to shoot bullets

I'm trying to create a browser VR game, I have set up the world, the VR controllers, I have created the fire event but each time I pull the trigger, the bullet that was fired before disappears. How do I make the bullets "stay" in the scene and keep moving, while I fire new ones?
I'm following this example https://threejs.org/examples/#webvr_ballshooter but it's not exactly what I need
var geometry_bullet = new THREE.IcosahedronBufferGeometry( radius, 2 );
var bullet1 = new THREE.Mesh( geometry_bullet, new THREE.MeshLambertMaterial( { color: 0x2661b9 } ) );
bullet1.userData.velocity = new THREE.Vector3();
bullet1.userData.velocity.x = 10;
bullet1.userData.velocity.y = 10;
bullet1.userData.velocity.z = 10;
var bullet2 = new THREE.Mesh( geometry_bullet, new THREE.MeshLambertMaterial( { color: 0xee2f2f } ) );
bullet2.userData.velocity = new THREE.Vector3();
bullet2.userData.velocity.x = 1;
bullet2.userData.velocity.y = 1;
bullet2.userData.velocity.z = 1;
...
function handleController( controller ) {
if ( controller1.userData.isSelecting ) {
bullet1.position.set(controller1.position.x , controller1.position.y + 0.018 , controller1.position.z );
bullet1.userData.velocity.x = 0;
bullet1.userData.velocity.y = 10;
bullet1.userData.velocity.z = 10;
bullet1.userData.velocity.applyQuaternion( controller1.quaternion );
}
if ( controller2.userData.isSelecting ) {
bullet2.position.set(controller2.position.x , controller2.position.y + 0.018 , controller2.position.z );
bullet2.userData.velocity.x = 0;
bullet2.userData.velocity.y = 10;
bullet2.userData.velocity.z = 10;
bullet2.userData.velocity.applyQuaternion( controller2.quaternion );
}
} ...
function render() { ...
handleController( controller1 );
handleController( controller2 ); ...
bullet1.position.x -= bullet1.userData.velocity.x * delta;
bullet1.position.y -= bullet1.userData.velocity.y * delta;
bullet1.position.z -= bullet1.userData.velocity.z * delta;
scene.add(bullet1);
bullet2.position.x -= bullet2.userData.velocity.x * delta;
bullet2.position.y -= bullet2.userData.velocity.y * delta;
bullet2.position.z -= bullet2.userData.velocity.z * delta;
scene.add(bullet2);
...
renderer.render( scene, camera );
}

Camera position and device controls using the waves example

I have a website where i need to use threejs. I used the waves example in a landing page and it is working well on desktop/laptop.
However, I need to be able to move the waves (same behaviour as mouse in desktop) but with the device gyroscope/accelerometer and it is working using the devicecontrols that i found in another example. The problem is that it is my first time using three and working with 3d and i am lost. The dots are really small they only seem to move in a very small line and i dont know how or where the camera should look.
For example,
Desired behaviour (https://www.dropbox.com/s/d11srwqww8jtuda/PhoneWanted.png?dl=0)
Current on desktop (https://www.dropbox.com/s/x3rpcnovrfr2v1x/Desktop.png?dl=0)
Current on mobile (https://www.dropbox.com/s/c9c1mojgi5zt55y/IMG_2385.jpeg?dl=0)
On mobile should look the same as on desktop and move the waves but only horizontally...
Is this possible?
Mobile Script
<script>
if (screen && screen.width < 900) {
//alert("Mobile");
if ( WEBGL.isWebGLAvailable() === false ) {
document.body.appendChild( WEBGL.getWebGLErrorMessage() );
}
var SEPARATION = 100, AMOUNTX = 50, AMOUNTY = 50;
var container;
var camera, scene, renderer, controls;
var particles, count = 0;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
controls = new THREE.DeviceOrientationControls( camera );
camera.position.z = 1000;
scene = new THREE.Scene();
//
var numParticles = AMOUNTX * AMOUNTY;
var positions = new Float32Array( numParticles * 3 );
var scales = new Float32Array( numParticles );
var i = 0, j = 0;
for ( var ix = 0; ix < AMOUNTX; ix ++ ) {
for ( var iy = 0; iy < AMOUNTY; iy ++ ) {
positions[ i ] = ix * SEPARATION - ( ( AMOUNTX * SEPARATION ) / 2 ); // x
positions[ i + 1 ] = 0; // y
positions[ i + 2 ] = iy * SEPARATION - ( ( AMOUNTY * SEPARATION ) / 2 ); // z
scales[ j ] = 1;
i += 3;
j ++;
}
}
var geometry = new THREE.BufferGeometry();
geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
geometry.addAttribute( 'scale', new THREE.BufferAttribute( scales, 1 ) );
var material = new THREE.ShaderMaterial( {
uniforms: {
color: { value: new THREE.Color( 0xffffff ) },
},
vertexShader: document.getElementById( 'vertexshader' ).textContent,
fragmentShader: document.getElementById( 'fragmentshader' ).textContent
} );
particles = new THREE.Points( geometry, material );
scene.add( particles );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
window.addEventListener( 'resize', onWindowResize, false );
}
function animate() {
window.requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
}
</script>
Solution
console.log("Desktop");
if (WEBGL.isWebGLAvailable() === false) {
document.body.appendChild(WEBGL.getWebGLErrorMessage());
}
var SEPARATION = 100,
AMOUNTX = 50,
AMOUNTY = 50;
var container;
var camera, scene, renderer, controls;
var particles, count = 0;
var mouseX = 0,
mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
// var isMobile = isOSMobile();
var isMobile = true;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(75, window.innerWidth /
window.innerHeight, 1, 10000);
if (isMobile) {
controls = new THREE.DeviceOrientationControls(camera);
}
camera.position.z = 1000;
scene = new THREE.Scene();
//
var numParticles = AMOUNTX * AMOUNTY;
var positions = new Float32Array(numParticles * 3);
var scales = new Float32Array(numParticles);
var i = 0,
j = 0;
for (var ix = 0; ix < AMOUNTX; ix++) {
for (var iy = 0; iy < AMOUNTY; iy++) {
positions[i] = ix * SEPARATION - ((AMOUNTX *
SEPARATION) / 2); // x
positions[i + 1] = 0; // y
positions[i + 2] = iy * SEPARATION - ((AMOUNTY *
SEPARATION) / 2); // z
scales[j] = 1;
i += 3;
j++;
}
}
var geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.BufferAttribute(
positions, 3));
geometry.addAttribute('scale', new THREE.BufferAttribute(scales,
1));
var material = new THREE.ShaderMaterial({
uniforms: {
color: {
value: new THREE.Color(isMobile ? 0xffffff : 0x8D8D8F)
},
},
vertexShader: document.getElementById(
'vertexshader').textContent,
fragmentShader: document.getElementById(
'fragmentshader').textContent
});
particles = new THREE.Points(geometry, material);
scene.add(particles);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
document.addEventListener('mousemove', onDocumentMouseMove,
false);
window.addEventListener('resize', onWindowResize, false);
if (isMobile) {
window.addEventListener("deviceorientation", handleOrientation, true);
}
}
function handleOrientation(e) {
var absolute = e.absolute;
var alpha = e.alpha;// x -90 ... 90
var beta = e.beta;// y 180 ... 0
var gamma = e.gamma;// x -90 ... 90
mouseX = -5 * windowHalfX * (gamma / 90);
//mouseY = -windowHalfY * ((beta - 90) / 90);
// console.log(mouseX.toFixed(2), ' x ', mouseY.toFixed(2));
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
//
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
//
function animate() {
requestAnimationFrame(animate);
render();
if (isMobile) {
controls.update();
}
}
function render() {
camera.position.x += (mouseX - camera.position.x) * .05;
if(isMobile) {
camera.position.y = 550;
} else {
camera.position.y += (-mouseY - camera.position.y) * .05;
}
camera.lookAt(scene.position);
var positions = particles.geometry.attributes.position.array;
var scales = particles.geometry.attributes.scale.array;
var i = 0,
j = 0;
for (var ix = 0; ix < AMOUNTX; ix++) {
for (var iy = 0; iy < AMOUNTY; iy++) {
positions[i + 1] = (Math.sin((ix + count) * 0.3) * 50) +
(Math.sin((iy + count) * 0.5) * 50);
scales[j] = (Math.sin((ix + count) * 0.3) + 1) * 8 +
(Math.sin((iy + count) * 0.5) + 1) * 8;
i += 3;
j++;
}
}
particles.geometry.attributes.position.needsUpdate = true;
particles.geometry.attributes.scale.needsUpdate = true;
renderer.render(scene, camera);
count += 0.1;
}
function isOSMobile() {
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
if (/android/i.test(userAgent)) {
return true;
}
if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
return true;
}
return false;
}
Thank you!
Fixed it. Code works, Y axis movement is disabled.
console.log("Desktop");
if (WEBGL.isWebGLAvailable() === false) {
document.body.appendChild(WEBGL.getWebGLErrorMessage());
}
var SEPARATION = 100,
AMOUNTX = 50,
AMOUNTY = 50;
var container;
var camera, scene, renderer, controls;
var particles, count = 0;
var mouseX = 0,
mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
// var isMobile = isOSMobile();
var isMobile = true;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(75, window.innerWidth /
window.innerHeight, 1, 10000);
if (isMobile) {
controls = new THREE.DeviceOrientationControls(camera);
}
camera.position.z = 1000;
scene = new THREE.Scene();
//
var numParticles = AMOUNTX * AMOUNTY;
var positions = new Float32Array(numParticles * 3);
var scales = new Float32Array(numParticles);
var i = 0,
j = 0;
for (var ix = 0; ix < AMOUNTX; ix++) {
for (var iy = 0; iy < AMOUNTY; iy++) {
positions[i] = ix * SEPARATION - ((AMOUNTX *
SEPARATION) / 2); // x
positions[i + 1] = 0; // y
positions[i + 2] = iy * SEPARATION - ((AMOUNTY *
SEPARATION) / 2); // z
scales[j] = 1;
i += 3;
j++;
}
}
var geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.BufferAttribute(
positions, 3));
geometry.addAttribute('scale', new THREE.BufferAttribute(scales,
1));
var material = new THREE.ShaderMaterial({
uniforms: {
color: {
value: new THREE.Color(isMobile ? 0xffffff : 0x8D8D8F)
},
},
vertexShader: document.getElementById(
'vertexshader').textContent,
fragmentShader: document.getElementById(
'fragmentshader').textContent
});
particles = new THREE.Points(geometry, material);
scene.add(particles);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
document.addEventListener('mousemove', onDocumentMouseMove,
false);
window.addEventListener('resize', onWindowResize, false);
if (isMobile) {
window.addEventListener("deviceorientation", handleOrientation, true);
}
}
function handleOrientation(e) {
var absolute = e.absolute;
var alpha = e.alpha;// x -90 ... 90
var beta = e.beta;// y 180 ... 0
var gamma = e.gamma;// x -90 ... 90
mouseX = -5 * windowHalfX * (gamma / 90);
//mouseY = -windowHalfY * ((beta - 90) / 90);
// console.log(mouseX.toFixed(2), ' x ', mouseY.toFixed(2));
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
//
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
//
function animate() {
requestAnimationFrame(animate);
render();
if (isMobile) {
controls.update();
}
}
function render() {
camera.position.x += (mouseX - camera.position.x) * .05;
if(isMobile) {
camera.position.y = 550;
} else {
camera.position.y += (-mouseY - camera.position.y) * .05;
}
camera.lookAt(scene.position);
var positions = particles.geometry.attributes.position.array;
var scales = particles.geometry.attributes.scale.array;
var i = 0,
j = 0;
for (var ix = 0; ix < AMOUNTX; ix++) {
for (var iy = 0; iy < AMOUNTY; iy++) {
positions[i + 1] = (Math.sin((ix + count) * 0.3) * 50) +
(Math.sin((iy + count) * 0.5) * 50);
scales[j] = (Math.sin((ix + count) * 0.3) + 1) * 8 +
(Math.sin((iy + count) * 0.5) + 1) * 8;
i += 3;
j++;
}
}
particles.geometry.attributes.position.needsUpdate = true;
particles.geometry.attributes.scale.needsUpdate = true;
renderer.render(scene, camera);
count += 0.1;
}
function isOSMobile() {
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
if (/android/i.test(userAgent)) {
return true;
}
if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
return true;
}
return false;
}

THREE.JS: objects that should not appear as visible appear as visible

I'm in the process of tinkering together a solar system simulator and it is all going well with the exception of one part: when a moon or a planet goes behind its parent body, you can still see it!
There are no transparent objects in the scene, and I have not made any modifications to the order in which objects are rendered, so I'm at a loss as to why objects appear when they are behind another object.
I'm using three.js r71 (problem still appears in r84, though).
To see where it goes wrong: check out http:mrhuffman.net/projects/gp and pick the Martian system; you will see how Phobos or Deimos are still visible even though they are behind Mars.
Here's the code for the scene. It's not as tidy as it could be as I just started working on it, so if you need clarifications or have questions, shoot!
import THREE from '../vendor/three';
import OrbitControls from '../vendor/OrbitControlsES6';
import ColladaLoader from '../vendor/ColladaLoaderES6';
import nBodyProblem from '../algorithms/nBodyProblem';
const scene = ( function () {
//Full screen action
let w = window.innerWidth;
let h = window.innerHeight;
let requestAnimationFrameId = null;
let scene = null;
let camera = null;
let controls = null;
let renderer = null;
let system = null;
let dae = null;
let cameraControlsWrapper = null;
let orbitButton = null;
let view3DButton = null;
let pathCanvas = document.createElement( 'canvas' );
pathCanvas.style.display = 'none';
pathCanvas.style.backgroundImage = 'url(misc/starfield.jpg)';
let ctxPath = pathCanvas.getContext( '2d' );
let massCanvas = document.createElement( 'canvas' );
massCanvas.style.display = 'none';
massCanvas.style.position = 'absolute';
massCanvas.style.zIndex = 2;
massCanvas.style.top = 0;
massCanvas.style.bottom = 0;
let ctxMass = massCanvas.getContext( '2d' );
pathCanvas.width = w;
pathCanvas.height = h;
massCanvas.width = w;
massCanvas.height = h;
ctxPath.translate( w / 2, h / 2 );
ctxMass.translate( w / 2, h / 2 );
function showOrbits() {
orbitButton.style.display = 'none';
cameraControlsWrapper.style.display = 'none';
pathCanvas.style.display = 'block';
massCanvas.style.display = 'block';
view3DButton.style.display = 'block';
}
function hideOrbits() {
view3DButton.style.display = 'none';
pathCanvas.style.display = 'none';
massCanvas.style.display = 'none';
orbitButton.style.display = 'block';
cameraControlsWrapper.style.display = 'block';
}
function createBody( radius, name, type ) {
let segments = type !== 'asteroid' ? 32 : 6;
let geometry = new THREE.SphereGeometry( radius, segments, segments );
let map;
let bumpMap;
switch( type ) {
case 'asteroid':
map = THREE.ImageUtils.loadTexture('textures/Phobos.jpg');
bumpMap = THREE.ImageUtils.loadTexture('textures/PhobosBump.jpg');
break;
case 'custom':
map = THREE.ImageUtils.loadTexture('textures/Acid.jpg');
break;
case 'star':
map = THREE.ImageUtils.loadTexture('textures/Sun.jpg');
break;
case 'spacecraft':
scene.add( dae );
return dae;
default:
map = THREE.ImageUtils.loadTexture('textures/' + name + '.jpg');
bumpMap = THREE.ImageUtils.loadTexture('textures/Phobos.jpg');
}
let material = new THREE.MeshPhongMaterial( { map: map, bumpMap: bumpMap, bumpScale: 0.02 } );
let mesh = new THREE.Mesh( geometry, material );
mesh.rotation.x = 1.5;
scene.add( mesh );
return mesh;
}
function sceneSetup( callback, scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls ) {
if ( scenario.model === undefined ) {
callback( scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls );
return;
}
let loader = new ColladaLoader();
loader.options.convertUpAxis = true;
loader.load( './models/' + scenario.model + '/' + scenario.model + '.dae', ( collada ) => {
dae = collada.scene;
dae.scale.setScalar( 1 / 800 );
callback( scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls );
});
}
function initSimulation( scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls ) {
cameraControlsWrapper = cameraControls;
orbitButton = viewOrbits;
orbitButton.addEventListener( 'click', showOrbits, false );
view3DButton = view3D;
view3DButton.addEventListener( 'click', hideOrbits, false );
hideOrbits();
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, w / h, 0.000001, 1500 );
//Prevent rolling of the camera when you view a body from another
camera.up.set( 0, 0, 1 );
camera.position.set( 0, 90, 150 );
var light = new THREE.AmbientLight(0x404040);
scene.add(light);
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(w, h);
renderer.setClearColor(0x000000);
container.appendChild( pathCanvas );
container.appendChild( massCanvas );
container.appendChild( renderer.domElement );
controls = new OrbitControls( camera, renderer.domElement );
//Create a new n-body problem from the selected scenario
system = new nBodyProblem( {
g: scenario.g,
law: scenario.law,
dt: scenario.dt,
masses: scenario.masses
});
//Create visual manifestations of the planets, asteroids and star(s)
for (let i = 0; i < system.masses.length; i++) {
let mass = system.masses[ i ];
mass.manifestation = createBody( mass.radius, mass.name, mass.type );
}
const render = function () {
requestAnimationFrameId = requestAnimationFrame( render );
//Update state vectors system.updatePositionVectors().updateVelocityVectors().updateBarycenter().calculateElapsedTime();
//Check if a rocket should be fired and if so check if it should be fired in this iteration; should that be the case, fire!
if ( scenario.rocketBurn === true ) {
if ( system.elapsedTime === scenario.rocketBurnTime ) {
for ( let i = 0; i < system.masses.length; i++ ) {
if ( system.masses[ i ].type === 'spacecraft' ) {
system.masses[ i ].vx = scenario.afterRocketBurnVelocity.vx;
system.masses[ i ].vy = scenario.afterRocketBurnVelocity.vy;
system.masses[ i ].vz = scenario.afterRocketBurnVelocity.vz;
}
}
}
}
ctxMass.clearRect( -0.5 * w, -0.5 * h, w, h );
//Put all the masses in their new positions and set camera position and focus
for (let i = 0; i < system.masses.length; i++) {
let mass = system.masses[ i ];
let x = mass.x * scenario.scale;
let y = mass.y * scenario.scale;
let z = mass.z * scenario.scale;
mass.manifestation.position.set( x, y, z );
let camR = camPos.value;
let name = mass.name;
if ( camR === name ) {
camera.position.set( x, y, z + ( mass.radius * 1.2 ) );
controls.enabled = false;
} else if ( camR === 'free' ) {
controls.enabled = true;
}
if ( camFocus.value === name ) {
camera.lookAt( new THREE.Vector3( x, y, z ) );
//If the camera mode is free, the user can pan, orbit and have fun
if ( camPos === 'free' ) controls.target = new THREE.Vector3( x, y, z );
}
ctxPath.fillStyle = mass.color;
ctxPath.fillRect( x, y, 1, 1 );
ctxMass.beginPath();
ctxMass.fillStyle = mass.color;
ctxMass.arc( x, y, 6, 0, 2 * Math.PI );
ctxMass.fill();
ctxMass.font = "14px Arial";
ctxMass.fillText( mass.name, x + 8, y );
}
//Put the barycenter of the system in its new position
let barycenterX = system.x * scenario.scale;
let barycenterY = system.y * scenario.scale;
ctxMass.strokeStyle = 'limegreen';
ctxMass.lineWidth = 2;
ctxMass.beginPath();
ctxMass.moveTo( barycenterX - 20, barycenterY );
ctxMass.lineTo( barycenterX + 20, barycenterY );
ctxMass.moveTo( barycenterX, barycenterY - 20 );
ctxMass.lineTo( barycenterX, barycenterY + 20 );
ctxMass.stroke();
ctxMass.fillStyle = 'limegreen';
ctxMass.font = "14px Arial";
ctxMass.fillText( 'Barycenter', barycenterX, barycenterY - 25 );
renderer.render( scene, camera );
};
//Makes the scene responsive
//Note that traces are cleared when the size of the viewport changes
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize() {
w = window.innerWidth;
h = window.innerHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize( w, h );
pathCanvas.width = w;
pathCanvas.height = h;
massCanvas.width = w;
massCanvas.height = h;
ctxPath.clearRect( -0.5 * w, -0.5 * h, w, h );
ctxMass.clearRect( -0.5 * w, -0.5 * h, w, h );
ctxPath.translate( w / 2, h / 2 );
ctxMass.translate( w / 2, h / 2 );
}
render();
}
//Tidy up
function resetSimulation() {
orbitButton.removeEventListener( 'click', showOrbits );
view3DButton.removeEventListener( 'click', hideOrbits );
cancelAnimationFrame( requestAnimationFrameId );
ctxPath.clearRect( -0.5 * w, -0.5 * h, w, h );
renderer.domElement.parentNode.removeChild( renderer.domElement );
pathCanvas.parentNode.removeChild( pathCanvas );
massCanvas.parentNode.removeChild( massCanvas );
}
//API
return {
startSimulation: ( scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls ) => {
sceneSetup( initSimulation, scenario, container, camPos, camFocus, viewOrbits, view3D, cameraControls );
},
resetSimulation: resetSimulation
};
}());
export default scene;

Canvas Birds density

I have a bird script taken from the project "three.js". Now, there's the issue: There are so many birds flying around, it's not realistic anymore. I have tried to adjust many options but I can't seem to find the right one. Note that I'm a noob in this code.
var Boid = function() {
var vector = new THREE.Vector3(),
_acceleration, _width = 500, _height = 500, _depth = 200, _goal, _neighborhoodRadius = 50,
_maxSpeed = 4, _maxSteerForce = 0.1, _avoidWalls = false;
this.position = new THREE.Vector3();
this.velocity = new THREE.Vector3();
_acceleration = new THREE.Vector3();
this.setGoal = function ( target ) {
_goal = target;
}
this.setAvoidWalls = function ( value ) {
_avoidWalls = value;
}
this.setWorldSize = function ( width, height, depth ) {
_width = width;
_height = height;vector
_depth = depth;
}
this.run = function ( boids ) {
if ( _avoidWalls ) {
vector.set( - _width, this.position.y, this.position.z );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.addSelf( vector );
vector.set( _width, this.position.y, this.position.z );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.addSelf( vector );
vector.set( this.position.x, - _height, this.position.z );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.addSelf( vector );
vector.set( this.position.x, _height, this.position.z );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.addSelf( vector );
vector.set( this.position.x, this.position.y, - _depth );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.addSelf( vector );
vector.set( this.position.x, this.position.y, _depth );
vector = this.avoid( vector );
vector.multiplyScalar( 5 );
_acceleration.addSelf( vector );
}/* else {
this.checkBounds();
}
*/
if ( Math.random() > 0.5 ) {
this.flock( boids );
}
this.move();
}
this.flock = function ( boids ) {
if ( _goal ) {
_acceleration.addSelf( this.reach( _goal, 0.005 ) );
}
_acceleration.addSelf( this.alignment( boids ) );
_acceleration.addSelf( this.cohesion( boids ) );
_acceleration.addSelf( this.separation( boids ) );
}
this.move = function () {
this.velocity.addSelf( _acceleration );
var l = this.velocity.length();
if ( l > _maxSpeed ) {
this.velocity.divideScalar( l / _maxSpeed );
}
this.position.addSelf( this.velocity );
_acceleration.set( 0, 0, 0 );
}
this.checkBounds = function () {
if ( this.position.x > _width ) this.position.x = - _width;
if ( this.position.x < - _width ) this.position.x = _width;
if ( this.position.y > _height ) this.position.y = - _height;
if ( this.position.y < - _height ) this.position.y = _height;
if ( this.position.z > _depth ) this.position.z = - _depth;
if ( this.position.z < - _depth ) this.position.z = _depth;
}
//
this.avoid = function ( target ) {
var steer = new THREE.Vector3();
steer.copy( this.position );
steer.subSelf( target );
steer.multiplyScalar( 1 / this.position.distanceToSquared( target ) );
return steer;
}
this.repulse = function ( target ) {
var distance = this.position.distanceTo( target );
if ( distance < 150 ) {
var steer = new THREE.Vector3();
steer.sub( this.position, target );
steer.multiplyScalar( 0.5 / distance );
_acceleration.addSelf( steer );
}
}
this.reach = function ( target, amount ) {
var steer = new THREE.Vector3();
steer.sub( target, this.position );
steer.multiplyScalar( amount );
return steer;
}
this.alignment = function ( boids ) {
var boid, velSum = new THREE.Vector3(),
count = 0;
for ( var i = 0, il = boids.length; i < il; i++ ) {
if ( Math.random() > 0.6 ) continue;
boid = boids[ i ];
distance = boid.position.distanceTo( this.position );
if ( distance > 0 && distance <= _neighborhoodRadius ) {
velSum.addSelf( boid.velocity );
count++;
}
}
if ( count > 0 ) {
velSum.divideScalar( count );
var l = velSum.length();
if ( l > _maxSteerForce ) {
velSum.divideScalar( l / _maxSteerForce );
}
}
return velSum;
}
this.cohesion = function ( boids ) {
var boid, distance,
posSum = new THREE.Vector3(),
steer = new THREE.Vector3(),
count = 0;
for ( var i = 0, il = boids.length; i < il; i ++ ) {
if ( Math.random() > 0.6 ) continue;
boid = boids[ i ];
distance = boid.position.distanceTo( this.position );
if ( distance > 0 && distance <= _neighborhoodRadius ) {
posSum.addSelf( boid.position );
count++;
}
}
if ( count > 0 ) {
posSum.divideScalar( count );
}
steer.sub( posSum, this.position );
var l = steer.length();
if ( l > _maxSteerForce ) {
steer.divideScalar( l / _maxSteerForce );
}
return steer;
}
this.separation = function ( boids ) {
var boid, distance,
posSum = new THREE.Vector3(),
repulse = new THREE.Vector3();
for ( var i = 0, il = boids.length; i < il; i ++ ) {
if ( Math.random() > 0.6 ) continue;
boid = boids[ i ];
distance = boid.position.distanceTo( this.position );
if ( distance > 0 && distance <= _neighborhoodRadius ) {
repulse.sub( this.position, boid.position );
repulse.normalize();
repulse.divideScalar( distance );
posSum.addSelf( repulse );
}
}
return posSum;
}
}
</script>
<script>
var SCREEN_WIDTH = window.innerWidth,
SCREEN_HEIGHT = window.innerHeight,
SCREEN_WIDTH_HALF = SCREEN_WIDTH / 2,
SCREEN_HEIGHT_HALF = SCREEN_HEIGHT / 2;
var camera, scene, renderer,
birds, bird;
var boid, boids;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000 );
camera.position.z = 450;
scene = new THREE.Scene();
birds = [];
boids = [];
for ( var i = 0; i < 200; i ++ ) {
boid = boids[ i ] = new Boid();
boid.position.x = Math.random() * 400 - 200;
boid.position.y = Math.random() * 400 - 200;
boid.position.z = Math.random() * 400 - 200;
boid.velocity.x = Math.random() * 2 - 1;
boid.velocity.y = Math.random() * 2 - 1;
boid.velocity.z = Math.random() * 2 - 1;
boid.setAvoidWalls( true );
boid.setWorldSize( 500, 500, 400 );
bird = birds[ i ] = new THREE.Mesh( new Bird(), new THREE.MeshBasicMaterial( { color:Math.random() * 0xffffff, side: THREE.DoubleSide } ) );
bird.phase = Math.floor( Math.random() * 62.83 );
bird.position = boids[ i ].position;
scene.add( bird );
}
renderer = new THREE.CanvasRenderer();
// renderer.autoClear = false;
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.body.appendChild( renderer.domElement );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
var vector = new THREE.Vector3( event.clientX - SCREEN_WIDTH_HALF, - event.clientY + SCREEN_HEIGHT_HALF, 0 );
for ( var i = 0, il = boids.length; i < il; i++ ) {
boid = boids[ i ];
vector.z = boid.position.z;
boid.repulse( vector );
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
for ( var i = 0, il = birds.length; i < il; i++ ) {
boid = boids[ i ];
boid.run( boids );
bird = birds[ i ];
color = bird.material.color;
color.r = color.g = color.b = ( 500 - bird.position.z ) / 1000;
bird.rotation.y = Math.atan2( - boid.velocity.z, boid.velocity.x );
bird.rotation.z = Math.asin( boid.velocity.y / boid.velocity.length() );
bird.phase = ( bird.phase + ( Math.max( 0, bird.rotation.z ) + 0.1 ) ) % 62.83;
bird.geometry.vertices[ 5 ].y = bird.geometry.vertices[ 4 ].y = Math.sin( bird.phase ) * 5;
}
renderer.render( scene, camera );
}
My guess is the for loop in the init()
for ( var i = 0; i < 200; i ++ ) { <-- reduce the 200

Categories

Resources