在这里,我尝试根据鼠标指针的位置放大对象(例如立方体)。在这里,我搜索了一个想法,认为它可以在D3 JS中实现,也可以通过捕获鼠标指针3D点并将其传递到鼠标滚轮功能中来实现。
这是小提琴https://jsfiddle.net/fpt9hswo/
var scene, renderer, camera;
var cube;
var controls;
var containerWidth = window.innerWidth,
containerHeight = window.innerHeight;
init();
animate();
function init() {
configureRenderer();
scene = new THREE.Scene();
configureCube();
configureCamera();
configureLight();
configureControls();
fitAll();
}
function configureRenderer() {
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(containerWidth, containerHeight);
document.body.appendChild(renderer.domElement);
}
function configureCube() {
var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
var cubeMaterial = new THREE.MeshLambertMaterial({
color: 0xff0000
});
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(50, 0, 0);
scene.add(cube);
}
function configureCamera() {
camera = new THREE.PerspectiveCamera(45, containerWidth / containerHeight, 1, 1000);
camera.position.set(0, 160, 400);
camera.lookAt(scene);
}
function configureLight() {
pointLight = new THREE.PointLight(0xffffff, 1.0, 100000);
pointLight.position.set(0, 300, 200);
scene.add(pointLight);
}
function configureControls() {
controls = new THREE.TrackballControls(camera, renderer.domElement);
// configuration of controls
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5.0;
controls.panSpeed = 2.0;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0;
}
function fitAll() {
// Calculate bounding box of the whole scene
var boundingBoxOfNode = new THREE.Box3().setFromObject(scene),
centerOfGravity = boundingBoxOfNode.getCenter();
/************* CAMERA *************************/
camera.position.addVectors(camera.position, centerOfGravity);
camera.lookAt(centerOfGravity);
//new camera positions will be set here
//Eg: camera.position.set(newCamera.x,newCamera.y,newCamera.z);
//Similarly new camera rotation and quaternion coordinates will be set
//Eg: camera.rotation.set(newCamera.rotatex,newCamera.rotatey,newCamera.rotatez);
//Eg: camera.quaternion.set(newCamera.qw,newCamera.qx,newCamera.qy,newCamera.qz);
/************* CONTROLS *************************/
controls.target.set(centerOfGravity.x, centerOfGravity.y, centerOfGravity.z);
//new controls.target values will be set here
//Eg: controls.target.set(newCamera.targetx,newCamera.targety,newCamera.targetz);
}
function animate() {
controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
预先感谢
答案 0 :(得分:2)
要执行所需的操作,您必须实现自己的鼠标滚轮事件,并且必须禁用THREE.TrackballControls
的默认缩放:
controls = new THREE.TrackballControls(camera, renderer.domElement);
//...
controls.zoomSpeed = 0.0;
添加车轮事件:
例如
renderer.domElement.addEventListener("wheel", event => {
const delta = event.deltaY;
// [...]
}
通过将照相机的位置移动到世界的深处,可以实现透视投影的放大。
如果要缩放到一个点,可以通过沿着光线从相机位置到光标(鼠标)位置移动相机并平行移动目标位置来实现。
在归一化设备空间中,可以轻松找到从相机到光标的光线点。在规范化的设备空间中,所有坐标都在[-1,1]范围内,并且所有具有相同 x 和 y 坐标的点都位于同一条射线中。如果 z 坐标为-1,则该点位于近平面上,如果 z 的坐标为1,则该点位于远平面上。
例如NDC点位于远平面上,并且通过光标位于射线上:
let x = 2 * event.clientX / window.innerWidth - 1;
let y = 1 - 2 * event.clientY / window.innerHeight;
let cursorpos = new THREE.Vector3(x, y, 1);
可以通过THREE.Vector3.unproject()
将规范化设备空间中的该点转换为世界空间中的一个点。函数的参数必须是THREE.Camera
,用于定义视图和投影:
cursorpos.unproject(camera);
摄影机的移动方向是从摄影机位置到世界空间中光标位置的归一化方向:
let dir = new THREE.Vector3().copy(cursorpos).sub(camera.position).normalize();
根据方向和鼠标滚轮增量计算运动并更新相机和THREE.TrackballControls
:
let shift = new THREE.Vector3().copy(dir).multiplyScalar(delta * 0.1);
camera.position.add(shift);
controls.position0.add(shift);
controls.target.add(shift);
请参见示例,其中我将建议应用于问题的代码:
var scene, renderer, camera;
var cube;
var controls;
var containerWidth = window.innerWidth,
containerHeight = window.innerHeight;
init();
animate();
function init() {
configureRenderer();
scene = new THREE.Scene();
configureCube();
configureCamera();
configureLight();
configureControls();
}
function configureRenderer() {
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(containerWidth, containerHeight);
document.body.appendChild(renderer.domElement);
window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
if (controls)
controls.handleResize();
}
renderer.domElement.addEventListener("wheel", event => {
const delta = event.deltaY;
let x = 2 * event.clientX / window.innerWidth - 1;
let y = 1 - 2 * event.clientY / window.innerHeight;
let cursorpos = new THREE.Vector3(x, y, 1);
cursorpos.unproject(camera);
let dir = new THREE.Vector3().copy(cursorpos).sub(camera.position).normalize();
let shift = new THREE.Vector3().copy(dir).multiplyScalar(delta * 0.1);
camera.position.add(shift);
controls.position0.add(shift);
controls.target.add(shift);
});
}
function configureCube() {
var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
var cubeMaterial = new THREE.MeshLambertMaterial({
color: 0xff0000
});
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(50, 0, 0);
scene.add(cube);
}
function configureCamera() {
camera = new THREE.PerspectiveCamera(45, containerWidth / containerHeight, 1, 1000);
camera.position.set(0, 160, 400);
camera.lookAt(scene);
}
function configureLight() {
pointLight = new THREE.PointLight(0xffffff, 1.0, 100000);
pointLight.position.set(0, 300, 200);
scene.add(pointLight);
}
function configureControls() {
controls = new THREE.TrackballControls(camera, renderer.domElement);
// configuration of controls
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 0.0;
controls.panSpeed = 2.0;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0;
}
function animate() {
controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>