我使用正交摄影机拍摄了Three.js场景
this.camera = new THREE.OrthographicCamera(this.width / - 2, this.width / 2, this.height / 2, this.height / - 2, 1, 1000);
this.camera.position.z = this.width / 2;
this.scene.add(this.camera);
然后我有一个立方体(红色),我想将其定位在某些2D坐标(绿色)上。我目前正在使用此功能将2D坐标转换为3D坐标。
from2Dto3D( position2d ) {
var vector = new THREE.Vector3(),
camera = this.camera,
x = (position2d.x / this.width) * 2 - 1,
y = (position2d.y / this.height) * 2 + 1;
vector.set(x, y, 0.5);
vector.unproject(this.camera);
var direction = vector.sub(this.camera.position).normalize(),
distance = - this.camera.position.z / direction.z,
scaled = direction.multiplyScalar(distance),
coords = this.camera.position.clone().add(scaled);
return new THREE.Vector3(coords.x, coords.y, 0);
}
...
let position3d = this.from2Dto3D(position2d);
...
this.cube.position.x = position3d.x; // updating only x position for the moment
如何将立方体精确定位在2D位置?
您需要显示更多代码。我们如何知道问题出在您的鼠标位置计算上?
这里的代码无论相机的方向如何,只要没有对画布应用css转换,就可以工作。
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
// get a canvas content pixel position
const {width, height} = renderer.domElement;
const canvasX = (e.clientX - rect.left) * width / rect.width;
const canvasY = (e.clientY - rect.top) * height / rect.height;
const clipX = (canvasX / width) * 2 - 1;
const clipY = (canvasY / height) * -2 + 1;
// get the object's clip space Z
const clipPos = new THREE.Vector3();
mesh.getWorldPosition(clipPos);
clipPos.project(camera);
const pos = new THREE.Vector3(clipX, clipY, clipPos.z);
pos.unproject(camera);
mesh.position.copy(pos);
render();
});
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const size = 5;
const near = 5;
const far = 50;
const camera = new THREE.OrthographicCamera(-size, size, size, -size, near, far);
camera.position.set(5, 7, 12);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
scene.background = new THREE.Color('white');
const gridHelper = new THREE.GridHelper(10, 10);
scene.add(gridHelper);
const cubeSize = 1;
const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
const cubeMat = new THREE.MeshBasicMaterial({color: 'red'});
const mesh = new THREE.Mesh(cubeGeo, cubeMat);
scene.add(mesh);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const aspect = renderer.domElement.clientWidth / renderer.domElement.clientHeight;
camera.left = -size * aspect;
camera.right = size * aspect;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
}
render();
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
// get a canvas content pixel position
const {width, height} = renderer.domElement;
const canvasX = (e.clientX - rect.left) * width / rect.width;
const canvasY = (e.clientY - rect.top) * height / rect.height;
const clipX = (canvasX / width) * 2 - 1;
const clipY = (canvasY / height) * -2 + 1;
// get the object's clip space Z
const clipPos = new THREE.Vector3();
mesh.getWorldPosition(clipPos);
clipPos.project(camera);
// note this code moves the object in the plane
// of the camera, not the plane of the grid
const pos = new THREE.Vector3(clipX, clipY, clipPos.z);
pos.unproject(camera);
mesh.position.copy(pos);
render();
});
window.addEventListener('resize', render);
}
main();
html, body {
margin: 0;
height: 100%;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r112/build/three.min.js"></script>
<canvas id="c"></canvas>
请注意,相同的代码也适用于PerspecitveCamera
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 60;
const near = 0.1;
const far = 50;
const camera = new THREE.PerspectiveCamera(fov, 1, near, far);
camera.position.set(2, 5, 10);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
scene.background = new THREE.Color('white');
const gridHelper = new THREE.GridHelper(10, 10);
scene.add(gridHelper);
const cubeSize = 1;
const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
const cubeMat = new THREE.MeshBasicMaterial({color: 'red'});
const mesh = new THREE.Mesh(cubeGeo, cubeMat);
scene.add(mesh);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
camera.aspect = renderer.domElement.clientWidth / renderer.domElement.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
}
render();
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
// get a canvas content pixel position
const {width, height} = renderer.domElement;
const canvasX = (e.clientX - rect.left) * width / rect.width;
const canvasY = (e.clientY - rect.top) * height / rect.height;
const clipX = (canvasX / width) * 2 - 1;
const clipY = (canvasY / height) * -2 + 1;
// get the object's clip space Z
const clipPos = new THREE.Vector3();
mesh.getWorldPosition(clipPos);
clipPos.project(camera);
// note: this code moves the object in the plane
// of the camera not the plane of the grid
const pos = new THREE.Vector3(clipX, clipY, clipPos.z);
pos.unproject(camera);
mesh.position.copy(pos);
render();
});
window.addEventListener('resize', render);
}
main();
html, body {
margin: 0;
height: 100%;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r112/build/three.min.js"></script>
<canvas id="c"></canvas>
如果您的画布是CSS转换的,则see this
请注意,如果要在网格(或任何任意平面)上移动对象,则不可行的解决方案是对不可见的平面使用RayCaster。
此外,如果您的对象在场景中具有被平移,旋转或缩放的父对象,则只是
const parent = object.parent;
scene.attach(object);
// move the object as above
parent.attach(object);
事实证明,正交摄影机不需要此功能。我们只需要将屏幕系统坐标转换为three.js系统坐标即可。可以使用以下功能:
convertCoords(x, y, z) {
return {
x: x - this.width / 2,
y: -1*y + this.height / 2,
z
}
}