我用三个j创建了一个房间,并在其中添加了各种对象。但, 物体正在走出房间。这是我的代码运行的URL:
答案 0 :(得分:2)
为了防止物体离开房间或相互碰撞,您必须至少有一种简单的碰撞检测形式。包括three.js在内的大多数3D引擎都具有用于创建的所有3d对象的轴对齐边界框(或AABB)。在三个.js中访问边界框,最简单的方法是调用
var boundingBoxHelperObject = new THREE.BoundingBoxHelper( object )
如果将其添加到场景中,它将显示为紧密围绕对象的线框灰色框。如果您在帮助程序上调用update(正如您将很快看到的那样),它将实时更新为3d对象的尺寸和移动 - 非常酷!
然后,要对所有这些框执行碰撞检测,请调用
boundingBoxHelperObject.box.intersectsBox( anotherBoxHelperObject.box )
如果发生碰撞则输出true,如果没有碰撞则输出false。然后执行适当的操作,例如将框移回框架以防止它逃离房间或穿透另一个固体物体,或更换两个碰撞的物体。颜色,或任何你想要的。
这是最后的代码示例,其中包含了您在几个月前发布的最后一篇文章中更正的选取/拖动代码,以及新的边界框和碰撞测试代码:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html">
<head lang="en">
<meta charset="UTF-8">
<title>Room</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r75/three.js"></script>
<script src="http://alexan0308.github.io/threejs/examples/js/loaders/OBJLoader.js"></script>
<script src="http://alexan0308.github.io/threejs/examples/js/loaders/MTLLoader.js"></script>
<script src="http://alexan0308.github.io/threejs/examples/js/loaders/OBJMTLLoader.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="workspace"></div>
<script>
//define global variables here
var container, renderer;
var camera, scene, projector, mouseVector, controls;
var mouseX, mouseY, draggable;
var pen, c_mesh, interactiveObj = [], rotateObj = [], groundRaycastObj = [];
var wallWidth = 1200;
var wallHeight = 400;
var chair_model, sofa_model;
var chair_selected = false;
var sofa_selected = false;
var raycaster;
var mouse = new THREE.Vector2(), INTERSECTED;
var radius = 100, theta = 0;
var oldIntersectPoint = new THREE.Vector3();
var newIntersectPoint = new THREE.Vector3();
var intersectOffset = new THREE.Vector3();
var chairOldPosition = new THREE.Vector3();
var sofaOldPosition = new THREE.Vector3();
var chair_rotate = false;
var walls;
var mesh_box;
var wallright, wallleft, wallback, wallfront, ceiling, ground;
var strDownloadMime = "image/octet-stream";
var chairBox, sofaBox;
var wallrightBox, wallleftBox, wallbackBox, wallfrontBox;
init();
animate();
function init() {
container = document.getElementById('workspace'); //document.createElement('div');
document.body.appendChild(container);
//camera
//camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 10, 10000);
// camera.position.set(0, -wallHeight / 2 + 10, wallWidth);
// camera.lookAt(new THREE.Vector3(10, 10, 10));
//renderer
renderer = new THREE.WebGLRenderer({preserveDrawingBuffer: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x889988);
renderer.shadowMapEnabled = true;
container.appendChild(renderer.domElement);
scene = new THREE.Scene();
raycaster = new THREE.Raycaster();
var ambient = new THREE.AmbientLight(0xffffff);
scene.add(ambient);
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z= wallWidth;
camera.position.y= wallWidth/2;
controls = new THREE.OrbitControls( camera, renderer.domElement );
//controls.addEventListener( 'change', render ); // add this only if there is no animation loop (requestAnimationFrame)
controls.enableDamping = true;
controls.dampingFactor = 0.25;
//controls.enableZoom = false;
//walls
walls = new THREE.Object3D();
var groundGeo_2 = new THREE.PlaneGeometry(wallWidth, wallWidth); //for roof and floor
var groundGeo = new THREE.PlaneGeometry(wallWidth, wallHeight);
var wallTextureRight = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/rainbow.jpg')
});
wallTextureRight.map.needsUpdate = true;
var wallTextureLeft = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/rainbow.jpg')
});
var wallTextureFront = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/wall4.jpg')
});
var wallTextureBack = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/wall3.png')
});
var floorTexture = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/floor.jpg')
});
floorTexture.map.needsUpdate = true;
var ceilTexture = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('textures/walls/wall4.jpg')
});
ground = new THREE.Mesh(groundGeo_2, floorTexture);
ground.overdraw = true;
ground.position.set(0, 0, 0);
ground.rotation.x = -Math.PI / 2;
walls.add(ground);
console.log(ground);
wallleft = new THREE.Mesh(groundGeo, wallTextureLeft);
wallleft.overdraw = true;
wallleft.position.set(-wallWidth / 2, wallHeight / 2, 0);
wallleft.rotation.y = Math.PI / 2;
walls.add(wallleft);
wallleftBox = new THREE.BoundingBoxHelper( wallleft );
wallleftBox.update(wallleft);
//wallleftBox.box.min.x -= 0.1;
//wallleftBox.box.max.x += 0.1;
//scene.add(wallleftBox);
wallright = new THREE.Mesh(groundGeo, wallTextureRight);
wallright.overdraw = true;
wallright.position.set(wallWidth / 2, wallHeight / 2, 0);
wallright.rotation.y = -Math.PI / 2;
walls.add(wallright);
wallrightBox = new THREE.BoundingBoxHelper( wallright );
wallrightBox.update(wallright);
//wallrightBox.box.min.x -= 0.1;
//wallrightBox.box.max.x += 0.1;
//scene.add(wallrightBox);
wallback = new THREE.Mesh(groundGeo, wallTextureBack);
wallback.overdraw = true;
wallback.position.set(0, wallHeight / 2, -wallWidth / 2);
walls.add(wallback);
wallbackBox = new THREE.BoundingBoxHelper( wallback );
wallbackBox.update(wallback);
//scene.add(wallbackBox);
wallfront = new THREE.Mesh(groundGeo, wallTextureFront);
wallfront.overdraw = true;
wallfront.position.set(0, wallHeight / 2, wallWidth / 2);
wallfront.rotation.y = -Math.PI;
walls.add(wallfront);
wallfrontBox = new THREE.BoundingBoxHelper( wallfront );
wallfrontBox.update(wallfront);
//scene.add(wallfrontBox);
ceiling = new THREE.Mesh(groundGeo_2, ceilTexture);
ceiling.position.set(0, wallHeight, 0);
ceiling.rotation.x = Math.PI / 2;
walls.add(ceiling);
scene.add(walls);
groundRaycastObj.push(walls);
//load bed texture
var bed_texture = new THREE.ImageUtils.loadTexture("textures/cb-rochelle-gray_baked.png");
var bedMaterial = new THREE.MeshBasicMaterial({
map: bed_texture,
side: THREE.DoubleSide
});
//load bed
var loader = new THREE.JSONLoader();
loader.load('js/sofa.js', function (geometry) {
sofa_model = new THREE.Mesh(geometry, bedMaterial);
for (var i = 0; i < sofa_model.children.length; i++) {
sofa_model.children[i].material = material;
sofa_model.children[i].userDataParent = sofa_model;
sofa_model.children[i].name = 'sofa_model';
}
sofa_model.position.set(200,0, -200);
sofa_model.rotation.set(0, 0, 0);
sofa_model.scale.set(3, 3, 3);
sofa_model.name = 'sofa_model';
interactiveObj.push(sofa_model);
scene.add(sofa_model);
sofaBox = new THREE.BoundingBoxHelper( sofa_model );
// comment next line out if you don't want to see the wireframe sofa boxHelper
scene.add(sofaBox);
});
//load chair texture
var chair_texture = new THREE.ImageUtils.loadTexture("textures/chair.png");
var chairMaterial = new THREE.MeshBasicMaterial({
map: chair_texture,
side: THREE.DoubleSide
});
//load chair
var loader = new THREE.JSONLoader();
loader.load('js/chair_model.js', function (geometry) {
chair_model = new THREE.Mesh(geometry, chairMaterial);
for (var i = 0; i < chair_model.children.length; i++) {
chair_model.children[i].material = material;
chair_model.children[i].userDataParent = sofa_model;
chair_model.children[i].name = 'chair_model';
}
chair_model.position.set(-300,0, -200);
chair_model.rotation.set(0, 0, 0);
chair_model.scale.set(3, 3, 3);
chair_model.name = 'chair_model';
interactiveObj.push(chair_model);
scene.add(chair_model);
chairBox = new THREE.BoundingBoxHelper( chair_model );
// comment next line out if you don't want to see the wireframe chair boxHelper
scene.add(chairBox);
});
//IE, Chrome, Safari, Opera
document.addEventListener('mousewheel', onDocumentMouseWheel, false);
//Firefox
document.addEventListener('DOMMouseScroll', onDocumentMouseWheel, false);
document.addEventListener('mousemove', onDocumentMouseMove, false);
document.addEventListener('mousedown', onDocumentMouseDown, false);
document.addEventListener('mouseup', onDocumentMouseUp, false);
window.addEventListener('resize', onWindowResize, false);
}
function animate() {
requestAnimationFrame(animate);
chair_model.rotation.y += 0.02;
chairBox.update(chair_model);
sofaBox.update(sofa_model);
//wallrightBox.update(wallright);
//wallleftBox.update(wallleft);
//wallfrontBox.update(wallfront);
//wallbackBox.update(wallback);
controls.update();
// Render the frame
//Don't render twice, it will slow down your animation!
//render();
renderer.render(scene, camera);
}
function render() {
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
//controls.handleResize();
}
function onDocumentMouseDown(event) {
draggable = true;
event.preventDefault();
var testIntersects;
testIntersects = raycaster.intersectObjects(groundRaycastObj, true);
if (testIntersects.length > 0)
oldIntersectPoint.copy(testIntersects[0].point);
// find intersections
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(interactiveObj, true);
if (intersects.length > 0) {
controls.enabled=false;
if (intersects[0].object.name == 'chair_model') {
container.style.cursor = 'pointer';
chair_selected = true;
//oldIntersectPoint.copy(chair_model.position);
chairBox.material.color.set('white');
} else if (intersects[0].object.name == 'sofa_model') {
container.style.cursor = 'pointer';
sofa_selected = true;
//oldIntersectPoint.copy(sofa_model.position);
sofaBox.material.color.set('white');
}
else {
chair_selected = false;
sofa_selected = false;
}
draggable = false;
}
}
function onDocumentMouseUp(event) {
draggable = false;
chair_selected = false;
sofa_selected = false;
chair_rotate = false;
container.style.cursor = 'auto';
controls.enabled=true;
oldIntersectPoint.set(0,0,0);
newIntersectPoint.set(0,0,0);
intersectOffset.set(0,0,0);
chairBox.material.color.set('grey');
sofaBox.material.color.set('grey');
}
function onDocumentMouseMove(event) {
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = -( event.clientY / window.innerHeight ) * 2 + 1;
var deltaX = event.clientX - mouseX;
var deltaY = event.clientY - mouseY;
var testIntersects;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(interactiveObj, true);
if (intersects.length > 0) {
container.style.cursor = 'pointer';
//addRotationLine(intersects[0].object);
} else {
container.style.cursor = 'auto';
}
if (draggable) {
} else if (chair_selected == true) {
testIntersects = raycaster.intersectObjects(groundRaycastObj, true);
if (testIntersects.length > 0) {
var okToMove = true;
chairOldPosition.copy(chair_model.position);
newIntersectPoint.copy(testIntersects[0].point);
intersectOffset.copy(newIntersectPoint);
intersectOffset.sub(oldIntersectPoint);
//uncomment below if you want more precision mouse movements of objects
//intersectOffset.multiplyScalar(0.1);
// store old intersect point for next frame
oldIntersectPoint.copy(newIntersectPoint);
chair_model.position.add(intersectOffset);
chair_model.updateMatrixWorld(true);
//chairBox.updateMatrixWorld(true);
chairBox.update(chair_model);
// default
chairBox.material.color.set('white');
if( chairBox.box.intersectsBox(sofaBox.box) ) {
okToMove = false;
chairBox.material.color.set('red');
}
else if( chairBox.box.intersectsBox(wallrightBox.box) ) {
okToMove = false;
chairBox.material.color.set('red');
}
else if( chairBox.box.intersectsBox(wallleftBox.box) ) {
okToMove = false;
chairBox.material.color.set('red');
}
else if( chairBox.box.intersectsBox(wallfrontBox.box) ) {
okToMove = false;
chairBox.material.color.set('red');
}
else if( chairBox.box.intersectsBox(wallbackBox.box) ) {
okToMove = false;
chairBox.material.color.set('red');
}
// if NOT ok to move and chair is hitting something,
if ( !okToMove ) {
// put chair back where it was
chair_model.position.copy(chairOldPosition);
}
}
// clamp chair position to the ground
chair_model.position.y = 0;
} else if (chair_rotate == true) {
rotate_object(chair_model, event);
}
else if (sofa_selected == true) {
testIntersects = raycaster.intersectObjects(groundRaycastObj, true);
if (testIntersects.length > 0) {
var okToMove = true;
sofaOldPosition.copy(sofa_model.position);
newIntersectPoint.copy(testIntersects[0].point);
intersectOffset.copy(newIntersectPoint);
intersectOffset.sub(oldIntersectPoint);
//uncomment below if you want more precision mouse movements of objects
//intersectOffset.multiplyScalar(0.1);
oldIntersectPoint.copy(newIntersectPoint);
sofa_model.position.add(intersectOffset);
sofa_model.updateMatrixWorld(true);
//sofaBox.updateMatrixWorld(true);
sofaBox.update(sofa_model);
// default
sofaBox.material.color.set('white');
if( sofaBox.box.intersectsBox(chairBox.box) ) {
okToMove = false;
sofaBox.material.color.set('red');
}
else if( sofaBox.box.intersectsBox(wallrightBox.box) ) {
okToMove = false;
sofaBox.material.color.set('red');
}
else if( sofaBox.box.intersectsBox(wallleftBox.box) ) {
okToMove = false;
sofaBox.material.color.set('red');
}
else if( sofaBox.box.intersectsBox(wallfrontBox.box) ) {
okToMove = false;
sofaBox.material.color.set('red');
}
else if( sofaBox.box.intersectsBox(wallbackBox.box) ) {
okToMove = false;
sofaBox.material.color.set('red');
}
// if NOT ok to move and sofa is hitting something,
if ( !okToMove ) {
// put sofa back where it was
sofa_model.position.copy(sofaOldPosition);
}
}
// clamp sofa position to the ground
sofa_model.position.y = 0;
}
mouseX = event.clientX;
mouseY = event.clientY;
//render(); // no need to render
}
function onDocumentMouseWheel(event) {
// This is automatically handled for you by orbitControls.js,
// but you can't disable zoom on the controls - so don't type controls.enableZoom = false;
//mouseDelta = (-event.wheelDeltaY || event.detail);
//camera.position.z += mouseDelta * 1;
//render(); // no need to render
}
function addRotationLine(objModel) {
var material = new THREE.LineBasicMaterial({
color: 0x0000ff,
linewidth: 6
});
var geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(-10, 500, 0),
new THREE.Vector3(1000, 500, 0)
);
var line = new THREE.Line(geometry, material);
objModel.add(line);
}
function rotate_object(object, event) {
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = -( event.clientY / window.innerHeight ) * 2 + 1;
var deltaX = event.clientX - mouseX;
var deltaY = event.clientY - mouseY;
object.rotation.y += deltaX * 0.02;
object.rotation.y += deltaY * 0.01;
}
</script>
</body>
</html>
希望这适合你! :)