Keep Object in Room - javascript

i have a 3D Room that i create and a shelf in my Room that i can move arround.
I want to make all the objects i have in my Room to stay in my room, the user should not be able to drag anything out of it.
I have tried multiple ways to make it work but nothing i did worked well enough.
At the moment the shelf goes a bit out of the room and as soon as it is out i cant move it anymore. I should still be able to drag it while the mouse is clicked.
I hope someone can help me. i worked way to long on this topic and my brain just starts to give up :)
At the moment my code looks like this:
on Mouse Move:
let bb = this.selectedHelper.geometry.boundingBox;
let originPoint = this.selected.position.clone();
originPoint.y = bb.getSize().y / 2;
originPoint.z += bb.getSize().z / 2;
this.raycasterLeft.set(originPoint, new THREE.Vector3(-1, 0, 0));
this.raycasterRight.set(new THREE.Vector3(originPoint.x + bb.getSize().x, originPoint.y, originPoint.z), new THREE.Vector3(1, 0, 0));
this.raycasterFront.set(new THREE.Vector3(originPoint.x + bb.getSize().x / 2, originPoint.y, originPoint.z + bb.getSize().z / 2), new THREE.Vector3(0, 0, 1));
this.raycasterBack.set(new THREE.Vector3(originPoint.x + bb.getSize().x / 2, originPoint.y, originPoint.z - bb.getSize().z / 2), new THREE.Vector3(0, 0, -1));
this.intersectionLeft = this.raycasterLeft.intersectObjects(this.walls, true);
this.intersectionRight = this.raycasterRight.intersectObjects(this.walls, true);
this.intersectionFront = this.raycasterFront.intersectObjects(this.walls, true);
this.intersectionBack = this.raycasterBack.intersectObjects(this.walls, true);
if (this.oktomove) {
this.selected.position.x = this.intersection.sub(this.offsetControls).x;
this.selected.position.z = this.intersection.z;
if (this.selected.name != "door" && this.selected.name != "regal") this.selected.position.y = this.intersection.y;
else { this.selected.position.y = 0; }
}
if (this.intersectionLeft.length > 0
&& this.intersectionRight.length > 0
&& this.intersectionFront.length > 0
&& this.intersectionBack.length > 0) {
if (this.intersectionLeft[0].distance >= 10
|| this.intersectionRight[0].distance >= 10
|| this.intersectionFront[0].distance >= 10
|| this.intersectionBack[0].distance >= 10) {
this.oktomove = true;
}
}
else {
console.log("drauflen")
this.oktomove = false;
}
this.showCasters(this.raycasterLeft, this.raycasterRight, this.raycasterFront, this.raycasterBack);
and on mouse Down
this.oktomove = true;
this.orbitControl.enabled = false;
if (intersectRegal[intersectRegal.length - 1].object.parent.name == "regal") {
this.selected = intersectRegal[intersectRegal.length - 1].object.parent;
}
else if (intersectRegal[intersectRegal.length - 1].object.parent.parent.name == "regal") {
this.selected = intersectRegal[intersectRegal.length - 1].object.parent.parent;
}
else if (intersectRegal[intersectRegal.length - 1].object.parent.parent.parent.name == "regal") {
this.selected = intersectRegal[intersectRegal.length - 1].object.parent.parent.parent;
}
this.selectedHelper = new THREE.BoxHelper(this.selected);
this.selectedHelper.geometry.computeBoundingBox();
let bb = this.selectedHelper.geometry.boundingBox;
let originPoint = this.selected.position.clone();
originPoint.y = bb.getSize().y / 2;
originPoint.z += bb.getSize().z / 2;
this.raycasterLeft = new THREE.Raycaster(originPoint, new THREE.Vector3(-1, 0, 0));
this.raycasterRight = new THREE.Raycaster(new THREE.Vector3(originPoint.x + bb.getSize().x, originPoint.y, originPoint.z), new THREE.Vector3(1, 0, 0));
this.raycasterFront = new THREE.Raycaster(new THREE.Vector3(originPoint.x + bb.getSize().x / 2, originPoint.y, originPoint.z + bb.getSize().z / 2), new THREE.Vector3(0, 0, 1));
this.raycasterBack = new THREE.Raycaster(new THREE.Vector3(originPoint.x + bb.getSize().x / 2, originPoint.y, originPoint.z - bb.getSize().z / 2), new THREE.Vector3(0, 0, -1));
this.intersectionLeft = this.raycasterLeft.intersectObjects(this.walls, true);
this.intersectionRight = this.raycasterRight.intersectObjects(this.walls, true);
this.intersectionFront = this.raycasterFront.intersectObjects(this.walls, true);
this.intersectionBack = this.raycasterBack.intersectObjects(this.walls, true);
this.showCasters( this.raycasterLeft , this.raycasterRight , this.raycasterFront , this.raycasterBack);
here are some screenshots from my scene:
so the problem is that the shelf stops to late and once it stops i cant move it anymore. The arrows are my raycasters
i could not add the pictures so i created a imgur album
https://imgur.com/a/xOd98hc

Here is just an option, made from a scratch.
The idea is to use .clamp(min, max) method of THREE.Vector3().
It may look complicated, but most of the stuff here is made for visualization, important parts are marked with comments:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 5, 5);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var roomGeom = new THREE.BoxGeometry(7, 2, 7);
roomGeom.translate(0, 1, 0);
var room = new THREE.Mesh(roomGeom, [
new THREE.MeshBasicMaterial({
color: "red",
side: THREE.BackSide
}),
new THREE.MeshBasicMaterial({
color: "red",
side: THREE.BackSide
}),
new THREE.MeshBasicMaterial({
color: "green",
side: THREE.BackSide
}),
new THREE.MeshBasicMaterial({
color: "green",
side: THREE.BackSide
}),
new THREE.MeshBasicMaterial({
color: "blue",
side: THREE.BackSide
}),
new THREE.MeshBasicMaterial({
color: "blue",
side: THREE.BackSide
})
]);
scene.add(room);
var objGeom = new THREE.CylinderGeometry(1, 1, 2);
objGeom.translate(0, 1, 0);
var moveObj = new THREE.Mesh(objGeom, new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
}));
moveObj.position.set(1, 0, 0);
scene.add(moveObj);
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var intersects = [];
var isDragging = false;
var plane = new THREE.Plane();
var planePoint = new THREE.Vector3();
var planeNormal = new THREE.Vector3(0, 1, 0);
var movePoint = new THREE.Vector3();
var moveObjBox = new THREE.Box3();
var moveObjBoxSize = new THREE.Vector3();
moveObjBox.setFromObject(moveObj);
var boxHelper = new THREE.Box3Helper(moveObjBox, "yellow");
scene.add(boxHelper);
var moveObjShift = new THREE.Vector3();
var roomBox = new THREE.Box3().setFromObject(room);
var roomBoxMin = new THREE.Vector3();
var roomBoxMax = new THREE.Vector3();
renderer.domElement.addEventListener("mousedown", onMouseDown, false);
renderer.domElement.addEventListener("mousemove", onMouseMove, false);
renderer.domElement.addEventListener("mouseup", onMouseUp, false);
function onMouseDown(event) {
setPlane(event);
}
function onMouseMove(event) {
if (!isDragging) return;
setMouse(event);
raycaster.setFromCamera(mouse, camera);
raycaster.ray.intersectPlane(plane, movePoint);
moveObj.position.copy(movePoint).sub(moveObjShift).clamp(roomBoxMin, roomBoxMax); // clamp the position of an object
moveObjBox.setFromObject(moveObj);
}
function onMouseUp() {
isDragging = false;
}
function setPlane(event) {
setMouse(event);
raycaster.setFromCamera(mouse, camera);
moveObjBox.setFromObject(moveObj);
raycaster.ray.intersectBox(moveObjBox, planePoint)
isDragging = true;
plane.setFromNormalAndCoplanarPoint(planeNormal, planePoint);
moveObjShift.copy(planePoint).sub(moveObj.position);
roomBoxMin.copy(roomBox.min);
roomBoxMax.copy(roomBox.max);
moveObjBox.getSize(moveObjBoxSize);
// adjust clamping vectors
roomBoxMin.x += moveObjBoxSize.x * 0.5;
roomBoxMin.z += moveObjBoxSize.z * 0.5;
roomBoxMax.x -= moveObjBoxSize.x * 0.5;
roomBoxMax.z -= moveObjBoxSize.z * 0.5;
}
function setMouse(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>

They implemented placement restrictions in here. Maybe you'll find it useful:
http://furnishup.github.io/blueprint3d/example/

Related

Accessing the vertices using the new PlaneBufferGeometry in ThreeJS

I understand PlaneGeometry has been deprecated and we should use PlaneBufferGeometry with the latest releases. The following code worked with the build before R125, I just don't know how to tweak the code to make it work with PlaneBufferGeometry:
var flagGeom = new THREE.PlaneBufferGeometry(4.5, 2.2, 40, 100, 200); // Replaced "PlaneGeometry " with "PlaneBufferGeometry" here.
flagGeom.translate(2.2, 1.1, 0);
flagGeom.vertices.forEach(v => { // Undefined error here.
v.init = v.clone()
});
Looks like your question is related to this forum topic.
You can do the things this way (just an option, not the ultimate solution): use an additional array stored in userData, and use .setXYZ() method.
body{
overflow: hidden;
margin: 0;
}
<script src="https://josephg.github.io/noisejs/perlin.js"></script>
<script type="module">
console.clear();
import * as THREE from 'https://cdn.skypack.dev/three#0.129.0/build/three.module.js';
import { OrbitControls } from 'https://cdn.skypack.dev/three#0.129.0/examples/jsm/controls/OrbitControls.js';
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(-1, 0.5, 2).setLength(2.5);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x401000);
document.body.appendChild(renderer.domElement);
var controls = new OrbitControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xff5500, 2);
light.position.setScalar(10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xff0000, 1));
var loader = new THREE.TextureLoader();
// flag
var flagGeom = new THREE.PlaneGeometry(4, 2, 40, 20);
flagGeom.translate(2, 1, 0);
let pos = flagGeom.attributes.position;
flagGeom.userData = {
init: []
}
for(let i = 0; i < pos.count; i++){
flagGeom.userData.init.push(new THREE.Vector3().fromBufferAttribute(pos, i));
}
console.log(flagGeom.userData.init);
var flagMat = new THREE.MeshStandardMaterial({
color: 0x777777,
map: loader.load("https://cywarr.github.io/small-shop/PW_flag/PW_flag_map.png"),
alphaMap: loader.load("https://cywarr.github.io/small-shop/PW_flag/PW_flag_alphaMap.png"),
alphaTest: 0.5,
side: THREE.DoubleSide,
metalness: 0.5,
roughness: 0.5
});
var flag = new THREE.Mesh(flagGeom, flagMat);
flag.position.set(-2, -1, 0);
flag.rotation.x = THREE.Math.degToRad(-18);
scene.add(flag);
// staff
var staff = new THREE.Mesh(new THREE.CylinderGeometry(0.04, 0.04, 4, 8), new THREE.MeshStandardMaterial({
color: "black"
}));
flag.add(staff);
// background canvas texture
var canvas = document.createElement("canvas");
canvas.width = 128;
canvas.height = 64;
var ctx = canvas.getContext('2d');
var image = ctx.createImageData(canvas.width, canvas.height);
var data = image.data;
var canvasTexture = new THREE.CanvasTexture(canvas);
scene.background = canvasTexture;
window.addEventListener( 'resize', onWindowResize );
var clock = new THREE.Clock();
var delta = 0;
var time = 0;
var v = new THREE.Vector3();
render();
function render() {
requestAnimationFrame(render);
delta = clock.getDelta();
time += delta;
flagGeom.userData.init.forEach( (vi, idx) => {
v.copy(vi);
let yFade = Math.sin(v.y / flagGeom.parameters.height * Math.PI) * 0.25;
v.x = v.x + yFade;
let xFade = (v.x / flagGeom.parameters.width);
v.z = noise.perlin2((v.x - (time * 2)) / flagGeom.parameters.width * 4, v.y / flagGeom.parameters.height * 2) * xFade;
pos.setXYZ(idx, v.x, v.y, v.z);
});
flagGeom.computeVertexNormals();
pos.needsUpdate = true;
drawFrame(time);
canvasTexture.needsUpdate = true;
renderer.render(scene, camera);
}
function drawFrame(time) {
var cWidth = canvas.width;
var cHeight = canvas.height;
for (var x = 0; x < cWidth; x++) {
for (var y = 0; y < cHeight; y++) {
var value = Math.abs(noise.simplex3(x / cWidth, y / cHeight, time * 0.25));
var cell = (x + y * cWidth) * 4;
data[cell] = 128 + Math.floor(128 * value);
data[cell + 1] = Math.floor(256 * value);
data[cell + 2] = 0;
data[cell + 3] = 255; // alpha.
}
}
ctx.fillColor = 'black';
ctx.fillRect(0, 0, 100, 100);
ctx.putImageData(image, 0, 0);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
</script>

Cannon.js + Three.js: Minimal car + physics

I'm trying to figure out how to create a minimal car with physics using Three.js and Cannon.js. I have created my visual and physics-based elements of my car and wheels, and my car responds to up arrow and left/right arrow commands to speed up and turn:
var container = document.querySelector('body'),
w = container.clientWidth,
h = container.clientHeight,
scene = new THREE.Scene(),
camera = new THREE.PerspectiveCamera(75, w/h, 0.001, 100),
renderConfig = {antialias: true, alpha: true},
renderer = new THREE.WebGLRenderer(renderConfig);
camera.position.set(0, 1, -10);
camera.lookAt(0,0,0);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(w, h);
container.appendChild(renderer.domElement);
window.addEventListener('resize', function() {
w = container.clientWidth;
h = container.clientHeight;
camera.aspect = w/h;
camera.updateProjectionMatrix();
renderer.setSize(w, h);
})
var geometry = new THREE.PlaneGeometry(10, 10, 10);
var material = new THREE.MeshBasicMaterial({color: 0xff0000, side: THREE.DoubleSide});
var plane = new THREE.Mesh(geometry, material);
plane.rotation.x = Math.PI/2;
scene.add(plane);
var sunlight = new THREE.DirectionalLight(0xffffff, 1.0);
sunlight.position.set(-10, 10, 0);
scene.add(sunlight)
/**
* Physics
**/
var world = new CANNON.World();
world.broadphase = new CANNON.SAPBroadphase(world);
world.gravity.set(0, -10, 0);
world.defaultContactMaterial.friction = 0;
var groundMaterial = new CANNON.Material('groundMaterial');
var wheelMaterial = new CANNON.Material('wheelMaterial');
var wheelGroundContactMaterial = new CANNON.ContactMaterial(wheelMaterial, groundMaterial, {
friction: 0.3,
restitution: 0,
contactEquationStiffness: 1000,
});
world.addContactMaterial(wheelGroundContactMaterial);
// car physics body
var chassisShape = new CANNON.Box(new CANNON.Vec3(1, 0.3, 2));
var chassisBody = new CANNON.Body({mass: 150});
chassisBody.addShape(chassisShape);
chassisBody.position.set(0, 0.2, 0);
chassisBody.angularVelocity.set(0, 0, 0); // initial velocity
// car visual body
var geometry = new THREE.BoxGeometry(2, 0.6, 4); // double chasis shape
var material = new THREE.MeshBasicMaterial({color: 0xffff00, side: THREE.DoubleSide});
var box = new THREE.Mesh(geometry, material);
scene.add(box);
// parent vehicle object
vehicle = new CANNON.RaycastVehicle({
chassisBody: chassisBody,
indexRightAxis: 0, // x
indexUpAxis: 1, // y
indexForwardAxis: 2, // z
});
// wheel options
var options = {
radius: 0.3,
directionLocal: new CANNON.Vec3(0, -1, 0),
suspensionStiffness: 45,
suspensionRestLength: 0.4,
frictionSlip: 5,
dampingRelaxation: 2.3,
dampingCompression: 4.5,
maxSuspensionForce: 200000,
rollInfluence: 0.01,
axleLocal: new CANNON.Vec3(-1, 0, 0),
chassisConnectionPointLocal: new CANNON.Vec3(1, 1, 0),
maxSuspensionTravel: 0.25,
customSlidingRotationalSpeed: -30,
useCustomSlidingRotationalSpeed: true,
};
var axlewidth = 0.7;
options.chassisConnectionPointLocal.set(axlewidth, 0, -1);
vehicle.addWheel(options);
options.chassisConnectionPointLocal.set(-axlewidth, 0, -1);
vehicle.addWheel(options);
options.chassisConnectionPointLocal.set(axlewidth, 0, 1);
vehicle.addWheel(options);
options.chassisConnectionPointLocal.set(-axlewidth, 0, 1);
vehicle.addWheel(options);
vehicle.addToWorld(world);
// car wheels
var wheelBodies = [],
wheelVisuals = [];
vehicle.wheelInfos.forEach(function(wheel) {
var shape = new CANNON.Cylinder(wheel.radius, wheel.radius, wheel.radius / 2, 20);
var body = new CANNON.Body({mass: 1, material: wheelMaterial});
var q = new CANNON.Quaternion();
q.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), Math.PI / 2);
body.addShape(shape, new CANNON.Vec3(), q);
wheelBodies.push(body);
// wheel visual body
var geometry = new THREE.CylinderGeometry( wheel.radius, wheel.radius, 0.4, 32 );
var material = new THREE.MeshPhongMaterial({
color: 0xd0901d,
emissive: 0xaa0000,
side: THREE.DoubleSide,
flatShading: true,
});
var cylinder = new THREE.Mesh(geometry, material);
wheelVisuals.push(cylinder);
scene.add(cylinder);
});
// update the wheels to match the physics
world.addEventListener('postStep', function() {
for (var i=0; i<vehicle.wheelInfos.length; i++) {
vehicle.updateWheelTransform(i);
var t = vehicle.wheelInfos[i].worldTransform;
// update wheel physics
wheelBodies[i].position.copy(t.position);
wheelBodies[i].quaternion.copy(t.quaternion);
// update wheel visuals
wheelVisuals[i].position.copy(t.position);
wheelVisuals[i].quaternion.copy(t.quaternion);
}
});
var q = plane.quaternion;
var planeBody = new CANNON.Body({
mass: 0, // mass = 0 makes the body static
material: groundMaterial,
shape: new CANNON.Plane(),
quaternion: new CANNON.Quaternion(-q._x, q._y, q._z, q._w)
});
world.add(planeBody)
/**
* Main
**/
function updatePhysics() {
world.step(1/60);
// update the chassis position
box.position.copy(chassisBody.position);
box.quaternion.copy(chassisBody.quaternion);
}
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
updatePhysics();
}
function navigate(e) {
if (e.type != 'keydown' && e.type != 'keyup') return;
var keyup = e.type == 'keyup';
vehicle.setBrake(0, 0);
vehicle.setBrake(0, 1);
vehicle.setBrake(0, 2);
vehicle.setBrake(0, 3);
var engineForce = 800,
maxSteerVal = 0.3;
switch(e.keyCode) {
case 38: // forward
vehicle.applyEngineForce(keyup ? 0 : -engineForce, 2);
vehicle.applyEngineForce(keyup ? 0 : -engineForce, 3);
break;
case 40: // backward
vehicle.applyEngineForce(keyup ? 0 : engineForce, 2);
vehicle.applyEngineForce(keyup ? 0 : engineForce, 3);
break;
case 39: // right
vehicle.setSteeringValue(keyup ? 0 : -maxSteerVal, 2);
vehicle.setSteeringValue(keyup ? 0 : -maxSteerVal, 3);
break;
case 37: // left
vehicle.setSteeringValue(keyup ? 0 : maxSteerVal, 2);
vehicle.setSteeringValue(keyup ? 0 : maxSteerVal, 3);
break;
}
}
window.addEventListener('keydown', navigate)
window.addEventListener('keyup', navigate)
render();
* {
margin: 0;
padding: 0;
overflow: hidden;
}
html,
body,
canvas {
width: 100%;
height: 100%;
background: #aaa;
}
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.js'></script>
I'm now trying to figure out how to rotate the wheels so they roll like proper tires. Previously, inside the world.addEventListener('postStep') callback, I was manually running wheelVisuals[i].rotation.z = Math.PI/2 after setting the wheel's quaternion. That worked fine until I turned the car, at which point the tires were thrown out of alignment...
If anyone could give a little pointer on how one is meant to configure the wheels with Cannon.js, I'd be super grateful!
Aha, I was applying the hacky rotation to the mesh when I should have been applying it to the geometry!
The answer below just adds one line to the vehicle.wheelInfos loop:
cylinder.geometry.rotateZ(Math.PI/2);
var container = document.querySelector('body'),
w = container.clientWidth,
h = container.clientHeight,
scene = new THREE.Scene(),
camera = new THREE.PerspectiveCamera(75, w/h, 0.001, 100),
renderConfig = {antialias: true, alpha: true},
renderer = new THREE.WebGLRenderer(renderConfig);
camera.position.set(0, 1, -10);
camera.lookAt(0,0,0);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(w, h);
container.appendChild(renderer.domElement);
window.addEventListener('resize', function() {
w = container.clientWidth;
h = container.clientHeight;
camera.aspect = w/h;
camera.updateProjectionMatrix();
renderer.setSize(w, h);
})
var geometry = new THREE.PlaneGeometry(10, 10, 10);
var material = new THREE.MeshBasicMaterial({color: 0xff0000, side: THREE.DoubleSide});
var plane = new THREE.Mesh(geometry, material);
plane.rotation.x = Math.PI/2;
scene.add(plane);
var sunlight = new THREE.DirectionalLight(0xffffff, 1.0);
sunlight.position.set(-10, 10, 0);
scene.add(sunlight)
/**
* Physics
**/
var world = new CANNON.World();
world.broadphase = new CANNON.SAPBroadphase(world);
world.gravity.set(0, -10, 0);
world.defaultContactMaterial.friction = 0;
var groundMaterial = new CANNON.Material('groundMaterial');
var wheelMaterial = new CANNON.Material('wheelMaterial');
var wheelGroundContactMaterial = new CANNON.ContactMaterial(wheelMaterial, groundMaterial, {
friction: 0.3,
restitution: 0,
contactEquationStiffness: 1000,
});
world.addContactMaterial(wheelGroundContactMaterial);
// car physics body
var chassisShape = new CANNON.Box(new CANNON.Vec3(1, 0.3, 2));
var chassisBody = new CANNON.Body({mass: 150});
chassisBody.addShape(chassisShape);
chassisBody.position.set(0, 0.2, 0);
chassisBody.angularVelocity.set(0, 0, 0); // initial velocity
// car visual body
var geometry = new THREE.BoxGeometry(2, 0.6, 4); // double chasis shape
var material = new THREE.MeshBasicMaterial({color: 0xffff00, side: THREE.DoubleSide});
var box = new THREE.Mesh(geometry, material);
scene.add(box);
// parent vehicle object
vehicle = new CANNON.RaycastVehicle({
chassisBody: chassisBody,
indexRightAxis: 0, // x
indexUpAxis: 1, // y
indexForwardAxis: 2, // z
});
// wheel options
var options = {
radius: 0.3,
directionLocal: new CANNON.Vec3(0, -1, 0),
suspensionStiffness: 45,
suspensionRestLength: 0.4,
frictionSlip: 5,
dampingRelaxation: 2.3,
dampingCompression: 4.5,
maxSuspensionForce: 200000,
rollInfluence: 0.01,
axleLocal: new CANNON.Vec3(-1, 0, 0),
chassisConnectionPointLocal: new CANNON.Vec3(1, 1, 0),
maxSuspensionTravel: 0.25,
customSlidingRotationalSpeed: -30,
useCustomSlidingRotationalSpeed: true,
};
var axlewidth = 0.7;
options.chassisConnectionPointLocal.set(axlewidth, 0, -1);
vehicle.addWheel(options);
options.chassisConnectionPointLocal.set(-axlewidth, 0, -1);
vehicle.addWheel(options);
options.chassisConnectionPointLocal.set(axlewidth, 0, 1);
vehicle.addWheel(options);
options.chassisConnectionPointLocal.set(-axlewidth, 0, 1);
vehicle.addWheel(options);
vehicle.addToWorld(world);
// car wheels
var wheelBodies = [],
wheelVisuals = [];
vehicle.wheelInfos.forEach(function(wheel) {
var shape = new CANNON.Cylinder(wheel.radius, wheel.radius, wheel.radius / 2, 20);
var body = new CANNON.Body({mass: 1, material: wheelMaterial});
var q = new CANNON.Quaternion();
q.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), Math.PI / 2);
body.addShape(shape, new CANNON.Vec3(), q);
wheelBodies.push(body);
// wheel visual body
var geometry = new THREE.CylinderGeometry( wheel.radius, wheel.radius, 0.4, 32 );
var material = new THREE.MeshPhongMaterial({
color: 0xd0901d,
emissive: 0xaa0000,
side: THREE.DoubleSide,
flatShading: true,
});
var cylinder = new THREE.Mesh(geometry, material);
cylinder.geometry.rotateZ(Math.PI/2);
wheelVisuals.push(cylinder);
scene.add(cylinder);
});
// update the wheels to match the physics
world.addEventListener('postStep', function() {
for (var i=0; i<vehicle.wheelInfos.length; i++) {
vehicle.updateWheelTransform(i);
var t = vehicle.wheelInfos[i].worldTransform;
// update wheel physics
wheelBodies[i].position.copy(t.position);
wheelBodies[i].quaternion.copy(t.quaternion);
// update wheel visuals
wheelVisuals[i].position.copy(t.position);
wheelVisuals[i].quaternion.copy(t.quaternion);
}
});
var q = plane.quaternion;
var planeBody = new CANNON.Body({
mass: 0, // mass = 0 makes the body static
material: groundMaterial,
shape: new CANNON.Plane(),
quaternion: new CANNON.Quaternion(-q._x, q._y, q._z, q._w)
});
world.add(planeBody)
/**
* Main
**/
function updatePhysics() {
world.step(1/60);
// update the chassis position
box.position.copy(chassisBody.position);
box.quaternion.copy(chassisBody.quaternion);
}
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
updatePhysics();
}
function navigate(e) {
if (e.type != 'keydown' && e.type != 'keyup') return;
var keyup = e.type == 'keyup';
vehicle.setBrake(0, 0);
vehicle.setBrake(0, 1);
vehicle.setBrake(0, 2);
vehicle.setBrake(0, 3);
var engineForce = 800,
maxSteerVal = 0.3;
switch(e.keyCode) {
case 38: // forward
vehicle.applyEngineForce(keyup ? 0 : -engineForce, 2);
vehicle.applyEngineForce(keyup ? 0 : -engineForce, 3);
break;
case 40: // backward
vehicle.applyEngineForce(keyup ? 0 : engineForce, 2);
vehicle.applyEngineForce(keyup ? 0 : engineForce, 3);
break;
case 39: // right
vehicle.setSteeringValue(keyup ? 0 : -maxSteerVal, 2);
vehicle.setSteeringValue(keyup ? 0 : -maxSteerVal, 3);
break;
case 37: // left
vehicle.setSteeringValue(keyup ? 0 : maxSteerVal, 2);
vehicle.setSteeringValue(keyup ? 0 : maxSteerVal, 3);
break;
}
}
window.addEventListener('keydown', navigate)
window.addEventListener('keyup', navigate)
render();
* {
margin: 0;
padding: 0;
overflow: hidden;
}
html,
body,
canvas {
width: 100%;
height: 100%;
background: #aaa;
}
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.js'></script>

Javascript Issues. Not working in a class section

I got this javascript code from somewhere, but i'm not sure how assigning js codes to classes work. I'm not so good with Js..any help will be greatly appreciated.
I would like for the js to be assigned to the 'intro-section' class. Its 3D butterfly animation.
Initially though, I wanted it to be assigned to an entire page..and maybe make it stick to the back and not move when the page scrolls down.
Index.html
<!-- Intro section start -->
<section class="intro-section sp-pad spad" id="demo">
<div class="container-fluid">
<div class="row">
<div class="col-xl-5 intro-text">
<span class="sp-sub-title">Play, Learn & Grow Together.</span>
<h3 class="sp-title">Welcome To Bright Beginnings</h3>
<p>The atmosphere of the school will be relaxed and will encourage freedom of expression as a means
to individual growth. Children should be free to be children – to act, choose, explore, test,
investigate, react, and experiment. Hence, children grow naturally in their new awareness of
themselves, their relationships towards/with others, and with the world around them.</p>
Read More
</div>
<div class="col-xl-6 offset-xl-1">
<figure class="intro-img mt-5 mt-xl-0">
<img src="img/intro.jpg" alt="">
</figure>
</div>
</div>
</div>
</section>
<!-- Intro section end -->
Javascript:
const nbButterflies = 100;
var conf, scene, camera, cameraCtrl, light, renderer;
var whw, whh;
var butterflies;
var bodyTexture, wingTexture1, wingTexture2, wingTexture3, bodyTexture4, wingTexture4;
var destination = new THREE.Vector3();
var mouse = new THREE.Vector2();
var mouseOver = false;
var mousePlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
var mousePosition = new THREE.Vector3();
var raycaster = new THREE.Raycaster();
function init() {
conf = {
attraction: 0.03,
velocityLimit: 1.2,
move: true,
followMouse: true,
shuffle: shuffle
};
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
cameraCtrl = new THREE.OrbitControls(camera);
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
initScene();
const gui = new dat.GUI();
gui.add(conf, 'move');
gui.add(conf, 'followMouse');
gui.add(conf, 'attraction', 0.01, 0.1);
gui.add(conf, 'velocityLimit', 0.1, 2);
gui.add(conf, 'shuffle');
gui.close();
onWindowResize();
window.addEventListener('resize', onWindowResize, false);
document.addEventListener('mousemove', onMouseMove, false);
// document.addEventListener('mouseover', function () { mouseOver = true; }, false);
document.addEventListener('mouseout', function () { mouseOver = false; }, false);
animate();
};
function initScene() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
camera.position.z = 75;
bodyTexture = new THREE.TextureLoader().load('https://klevron.github.io/codepen/butterflies/b1.png');
wingTexture1 = new THREE.TextureLoader().load('https://klevron.github.io/codepen/butterflies/b1w.png');
wingTexture2 = new THREE.TextureLoader().load('https://klevron.github.io/codepen/butterflies/b2w.png');
wingTexture3 = new THREE.TextureLoader().load('https://klevron.github.io/codepen/butterflies/b3w.png');
bodyTexture4 = new THREE.TextureLoader().load('https://klevron.github.io/codepen/butterflies/b4.png');
wingTexture4 = new THREE.TextureLoader().load('https://klevron.github.io/codepen/butterflies/b4w.png');
butterflies = [];
for (var i = 0; i < nbButterflies; i++) {
var b = new Butterfly();
butterflies.push(b);
scene.add(b.o3d);
}
shuffle();
}
function animate() {
requestAnimationFrame(animate);
TWEEN.update();
cameraCtrl.update();
if (conf.move) {
for (var i = 0; i < butterflies.length; i++) {
butterflies[i].move();
}
}
renderer.render(scene, camera);
};
function shuffle() {
for (var i = 0; i < butterflies.length; i++) {
butterflies[i].shuffle();
}
}
function Butterfly() {
this.minWingRotation = -Math.PI / 6;
this.maxWingRotation = Math.PI / 2 - 0.1;
this.wingRotation = 0;
this.velocity = new THREE.Vector3(rnd(1, true), rnd(1, true), rnd(1, true));
this.destination = destination;
var confs = [
{ bodyTexture: bodyTexture, bodyW: 10, bodyH: 15, wingTexture: wingTexture1, wingW: 10, wingH: 15, wingX: 5.5 },
{ bodyTexture: bodyTexture, bodyW: 6, bodyH: 9, wingTexture: wingTexture2, wingW: 15, wingH: 20, wingX: 7.5 },
{ bodyTexture: bodyTexture, bodyW: 8, bodyH: 12, wingTexture: wingTexture3, wingW: 10, wingH: 15, wingX: 5.5 },
{ bodyTexture: bodyTexture4, bodyW: 6, bodyH: 10, bodyY: 2, wingTexture: wingTexture4, wingW: 15, wingH: 20, wingX: 8 },
];
this.init(confs[Math.floor(rnd(4))]);
}
Butterfly.prototype.init = function (bconf) {
var geometry = new THREE.PlaneGeometry(bconf.wingW, bconf.wingH);
var material = new THREE.MeshBasicMaterial({ transparent: true, map: bconf.wingTexture, side: THREE.DoubleSide, depthTest: false });
var lwmesh = new THREE.Mesh(geometry, material);
lwmesh.position.x = -bconf.wingX;
this.lwing = new THREE.Object3D();
this.lwing.add(lwmesh);
var rwmesh = new THREE.Mesh(geometry, material);
rwmesh.rotation.y = Math.PI;
rwmesh.position.x = bconf.wingX;
this.rwing = new THREE.Object3D();
this.rwing.add(rwmesh);
geometry = new THREE.PlaneGeometry(bconf.bodyW, bconf.bodyH);
material = new THREE.MeshBasicMaterial({ transparent: true, map: bconf.bodyTexture, side: THREE.DoubleSide, depthTest: false });
this.body = new THREE.Mesh(geometry, material);
if (bconf.bodyY) this.body.position.y = bconf.bodyY;
// this.body.position.z = -0.1;
this.group = new THREE.Object3D();
this.group.add(this.body);
this.group.add(this.lwing);
this.group.add(this.rwing);
this.group.rotation.x = Math.PI / 2;
this.group.rotation.y = Math.PI;
this.setWingRotation(this.wingRotation);
this.initTween();
this.o3d = new THREE.Object3D();
this.o3d.add(this.group);
};
Butterfly.prototype.initTween = function () {
var duration = limit(conf.velocityLimit - this.velocity.length(), 0.1, 1.5) * 1000;
this.wingRotation = this.minWingRotation;
this.tweenWingRotation = new TWEEN.Tween(this)
.to({ wingRotation: this.maxWingRotation }, duration)
.repeat(1)
.yoyo(true)
// .easing(TWEEN.Easing.Cubic.InOut)
.onComplete(function(object) {
object.initTween();
})
.start();
};
Butterfly.prototype.move = function () {
var destination;
if (mouseOver && conf.followMouse) {
destination = mousePosition;
} else {
destination = this.destination;
}
var dv = destination.clone().sub(this.o3d.position).normalize();
this.velocity.x += conf.attraction * dv.x;
this.velocity.y += conf.attraction * dv.y;
this.velocity.z += conf.attraction * dv.z;
this.limitVelocity();
// update position & rotation
this.setWingRotation(this.wingRotation);
this.o3d.lookAt(this.o3d.position.clone().add(this.velocity));
this.o3d.position.add(this.velocity);
};
Butterfly.prototype.limitVelocity = function (y) {
this.velocity.x = limit(this.velocity.x, -conf.velocityLimit, conf.velocityLimit);
this.velocity.y = limit(this.velocity.y, -conf.velocityLimit, conf.velocityLimit);
this.velocity.z = limit(this.velocity.z, -conf.velocityLimit, conf.velocityLimit);
};
Butterfly.prototype.setWingRotation = function (y) {
this.lwing.rotation.y = y;
this.rwing.rotation.y = -y;
};
Butterfly.prototype.shuffle = function () {
this.velocity = new THREE.Vector3(rnd(1, true), rnd(1, true), rnd(1, true));
var p = new THREE.Vector3(rnd(1, true), rnd(1, true), rnd(1, true)).normalize().multiplyScalar(100);
this.o3d.position.set(p.x, p.y, p.z);
var scale = rnd(0.4) + 0.1;
this.o3d.scale.set(scale, scale, scale);
}
function limit(number, min, max) {
return Math.min(Math.max(number, min), max);
}
function rnd(max, negative) {
return negative ? Math.random() * 2 * max - max : Math.random() * max;
}
function onWindowResize() {
whw = window.innerWidth / 2;
whh = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onMouseMove(event) {
// if (cameraCtrl.getState()!=-1) return;
var v = new THREE.Vector3();
camera.getWorldDirection(v);
v.normalize();
// console.log(v);
mousePlane.normal = v;
mouseOver = true;
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
raycaster.ray.intersectPlane(mousePlane, mousePosition);
}
init();

Highlighting the nearest edge from mouse pointer in three js

In threejs webgl I want to highlight the nearest edge from my mouse pointer and select it to get the length of the edge.
I am using Edgesgeometry to create the edges.
var edgeGeometry = new THREE.EdgesGeometry(meshes[meshIndex]); // or WireframeGeometry
var edgeMaterial = new THREE.LineBasicMaterial({ color: 0x00000, linewidth: 2 });
var wireframe = new THREE.LineSegments(edgeGeometry, edgeMaterial);
var object = new THREE.Mesh(meshes[meshIndex], material);
object.add(wireframe);
Just an idea.
You know which face you're intesecting and you have its edges, you can use THREE.Line3(), built from vertices of each edge (thus you'll use THREE.Line3() three times). Then, you know the point of intersection and have three lines of THREE.Line3(), now you can find the nearest edge by choosing the closest line to the point of intersection, and .closestPointToPoint() method will help. This method returns the closes point on an edge relatively to the point of intersection.
Means, that you just find three distances from the point of intersection to three edges of the face. And you'll highlight the edge with the minimal distance from it to the point of intersection.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geom = new THREE.PlaneBufferGeometry(8, 8).toNonIndexed();
var mat = new THREE.MeshBasicMaterial({
color: "blue"
});
var mesh = new THREE.Mesh(geom, mat);
scene.add(mesh);
renderer.domElement.addEventListener("mousemove", onMouseMove, false);
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var intersects = [];
var localPoint = new THREE.Vector3();
let closestPoint = new THREE.Vector3();
var edgeGeom = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(),
new THREE.Vector3()
]);
var edge = new THREE.Line(edgeGeom, new THREE.LineBasicMaterial({
color: "aqua"
}));
scene.add(edge);
var pos = mesh.geometry.attributes.position;
function onMouseMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
intersects = raycaster.intersectObject(mesh);
if (intersects.length === 0) return;
let faceIdx = intersects[0].faceIndex;
let lines = [
new THREE.Line3(
new THREE.Vector3().fromBufferAttribute(pos, faceIdx * 3 + 0),
new THREE.Vector3().fromBufferAttribute(pos, faceIdx * 3 + 1)
),
new THREE.Line3(
new THREE.Vector3().fromBufferAttribute(pos, faceIdx * 3 + 1),
new THREE.Vector3().fromBufferAttribute(pos, faceIdx * 3 + 2)
),
new THREE.Line3(
new THREE.Vector3().fromBufferAttribute(pos, faceIdx * 3 + 2),
new THREE.Vector3().fromBufferAttribute(pos, faceIdx * 3 + 0)
)
];
let edgeIdx = 0;
mesh.worldToLocal(localPoint.copy(intersects[0].point));
let minDistance = 1000;
for (let i = 0; i < 3; i++) {
lines[i].closestPointToPoint(localPoint, true, closestPoint);
let dist = localPoint.distanceTo(closestPoint);
if (dist < minDistance) {
minDistance = dist;
edgeIdx = i;
}
}
let pStart = mesh.localToWorld(lines[edgeIdx].start);
let pEnd = mesh.localToWorld(lines[edgeIdx].end);
edgeGeom.attributes.position.setXYZ(0, pStart.x, pStart.y, pStart.z);
edgeGeom.attributes.position.setXYZ(1, pEnd.x, pEnd.y, pEnd.z);
edgeGeom.attributes.position.needsUpdate = true;
}
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body{
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.min.js"></script>

Object on camera rotation isn't centered three js

I've created a 3D marquee by bending two meshes into a circle, however I'm having trouble getting them to center to the camera.
Please reference https://jsfiddle.net/siiiick/1jh49e1u/
var text = "EXPRESS FREE SHIPPING WORLDWIDE OVER 200€ / 200% 150$ ";
var geoParams = {
size: 208,
height: 1,
curveSegments: 4,
font: "junicode",
// bevelEnabled: false,
// bevelThickness: 1,
// bevelSize: 1,
}
var textMaterial = new THREE.MeshPhongMaterial({
color: 0x000000
});
var deg = Math.PI / 4.8;
var geoTop = new THREE.TextGeometry(text, geoParams);
var textTop = new THREE.Mesh(geoTop, textMaterial);
geoTop.computeBoundingBox();
textWidth = geoTop.boundingBox.max.x - geoTop.boundingBox.min.x;
controls.target.set(-textWidth * .1 - 10, 0, -textWidth / 3.8);
textTop.rotation.y = Math.PI;
modifier.set(new THREE.Vector3(0, 0, -1), new THREE.Vector3(0, 1, 0), deg).modify(textTop.geometry);
modifier.set(new THREE.Vector3(0, 0, -1), new THREE.Vector3(0, 1, 0), deg).modify(textTop.geometry);
textTop.position.set(-0.5 * textWidth + textWidth * .867, 0, -textWidth * .577);
var geoBot = new THREE.TextGeometry(text, geoParams);
var textBot = new THREE.Mesh(geoBot, textMaterial);
modifier.set(new THREE.Vector3(0, 0, -1), new THREE.Vector3(0, 1, 0), deg).modify(textBot.geometry);
modifier.set(new THREE.Vector3(0, 0, -1), new THREE.Vector3(0, 1, 0), deg).modify(textBot.geometry);
textBot.position.set(-0.5 * textWidth, 0, 0);
scene.add(textTop);
scene.add(textBot);
As you can see after a few seconds the the marquee isn't centered. Do you think it's as a result of the camera positioning or the mesh positioning?
Thanks
//Testing some easy camera centering code...
var renderer = new THREE.WebGLRenderer();
var w = 300;
var h = 200;
renderer.setSize(w, h);
document.body.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
45, // Field of view
w / h, // Aspect ratio
0.1, // Near
10000 // Far
);
camera.position.set(15, 10, 15);
camera.lookAt(scene.position);
controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.PointLight(0xFFFF00);
light.position.set(20, 20, 20);
scene.add(light);
var light1 = new THREE.AmbientLight(0x808080);
light1.position.set(20, 20, 20);
scene.add(light1);
var light2 = new THREE.PointLight(0x00FFFF);
light2.position.set(-20, 20, -20);
scene.add(light2);
var light3 = new THREE.PointLight(0xFF00FF);
light3.position.set(-20, -20, -20);
scene.add(light3);
var sphereGeom = new THREE.SphereGeometry(5, 16, 16);
var material = new THREE.MeshLambertMaterial({
color: 0x808080
});
var mesh = new THREE.Mesh(sphereGeom, material);
scene.add(mesh);
var mesh1 = new THREE.Mesh(sphereGeom, material);
mesh1.position.x += 5;
mesh.add(mesh1);
var mesh2 = new THREE.Mesh(sphereGeom, material);
mesh2.position.y += 5;
mesh2.position.x += 9;
mesh.add(mesh2);
var grp0 = mesh;
var mesh = new THREE.Mesh(sphereGeom, material);
scene.add(mesh);
mesh.position.x += 30;
var mesh1 = new THREE.Mesh(sphereGeom, material);
mesh1.position.x += 15;
mesh.add(mesh1);
var mesh2 = new THREE.Mesh(sphereGeom, material);
mesh2.position.y += 12;
mesh2.position.x += 9;
mesh.add(mesh2);
renderer.setClearColor(0xdddddd, 1);
var grp1 = mesh;
var curGrp;
var targPos;
var targLook;
var tmp = new THREE.Vector3();
var vbox;
function focusCam(targ) {
const boundingBox = new THREE.Box3();
boundingBox.setFromObject(targ)
var center = boundingBox.getCenter(new THREE.Vector3())
var sz = boundingBox.getSize(new THREE.Vector3());
var minZ = sz.length() + camera.near;
var lookOffset = new THREE.Vector3(0, 0, 1);
lookOffset.applyQuaternion(camera.quaternion);
lookOffset.multiplyScalar(minZ)
targLook = center.clone();
targPos = new THREE.Vector3().copy(center).add(lookOffset)
if (!vbox) {
vbox = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material.clone())
vbox.material.transparent = true;
vbox.material.opacity = 0.15;
scene.add(vbox)
}
vbox.scale.copy(sz);
vbox.position.copy(center);
}
renderer.domElement.onclick = (evt) => {
if (!curGrp) {
curGrp = grp0;
} else if (curGrp === grp0) {
curGrp = grp1
} else if (curGrp === grp1) {
curGrp = grp0
}
focusCam(curGrp);
}
(function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
if (targPos) {
tmp.copy(targPos).sub(camera.position).multiplyScalar(0.01)
if (tmp.length() > 0.01) {
camera.position.add(tmp)
controls.target.add(tmp);//copy(targLook);
//camera.lookAt(targLook);
} else targPos = undefined;
}
})();
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>

Categories