我有一个三ejs项目,我想渲染一个模型,并使用鼠标围绕它旋转。
就是这种想法https://www.leroymerlin.fr/big2/guides-2021/experience-inspiration.html
我有一个工作的例子,但是控件是由点击和拖动绑定的。
- 目标是渲染一个模型
- 有能力点击一个按钮,将旋转相机和渲染一个新的模型,因为旧的消散(目前有一个下拉切换模型)
- 当鼠标悬停在模型上时,渲染动作调用/特殊鼠标动画,作为链接
- 能够使用鼠标移动(而不是点击拖动)来平移模型。
——我先玩这个演示https://threejs.org/examples/webgl_animation_keyframes.html
我试着添加一些东西,比如这里的鼠标
let mouseX = 0, mouseY = 0;
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX - windowHalfX );
mouseY = ( event.clientY - windowHalfY );
}
function render() {
camera.position.x += ( mouseX - camera.position.x ) * 0.05;
camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
但它发生故障,导致模型旋转得太快,放大得太大。
这是最新的代码
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - animation - keyframes</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
<style>
body {
background-color: #bfe3dd;
color: #000;
}
a {
color: #2983ff;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info">
<!--
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - animation - keyframes<br/>
Model: <a href="https://www.artstation.com/artwork/1AGwX" target="_blank" rel="noopener">Littlest Tokyo</a> by
<a href="https://www.artstation.com/glenatron" target="_blank" rel="noopener">Glen Fox</a>, CC Attribution.
-->
<select id="models">
<option value="models/gltf/LittlestTokyo.glb">LittlestTokyo</option>
<option value="models/gltf/Flamingo.glb" selected="selected">Flamingo</option>
</select>
</div>
<script type="module">
import * as THREE from '../build/three.module.js';
//import Stats from './jsm/libs/stats.module.js';
import { OrbitControls } from './jsm/controls/OrbitControls.js';
import { RoomEnvironment } from './jsm/environments/RoomEnvironment.js';
import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from './jsm/loaders/DRACOLoader.js';
let mixer;
const clock = new THREE.Clock();
const container = document.getElementById( 'container' );
//const stats = new Stats();
//container.appendChild( stats.dom );
const renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.outputEncoding = THREE.sRGBEncoding;
container.appendChild( renderer.domElement );
const pmremGenerator = new THREE.PMREMGenerator( renderer );
const scene = new THREE.Scene();
scene.background = new THREE.Color( 0xbfe3dd );
scene.environment = pmremGenerator.fromScene( new RoomEnvironment(), 0.04 ).texture;
const camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 100 );
camera.position.set( 5, 2, 8 );
const controls = new OrbitControls( camera, renderer.domElement );
controls.target.set( 0, 0.5, 0 );
controls.update();
controls.enablePan = false;
controls.enableDamping = true;
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath( 'js/libs/draco/gltf/' );
const loader = new GLTFLoader();
loader.setDRACOLoader( dracoLoader );
loadModel('models/gltf/Flamingo.glb')
function loadModel(path){
loader.load(path, function ( gltf ) {
//remove model
// remove last model
// if(model) model.parent.remove(model)
scene.clear();
//add model
add(gltf)
}, undefined, function ( e ) {
console.error(e);
});
}
window.onresize = function () {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
};
function add(gltf){
let model = gltf.scene;
model.position.set( 1, 1, 0 );
model.scale.set( 0.01, 0.01, 0.01 );
scene.add( model );
mixer = new THREE.AnimationMixer( model );
mixer.clipAction( gltf.animations[ 0 ] ).play();
animate();
}
function load(path) {
console.log("loading", path)
loadModel(path)
}
document.getElementById('models').addEventListener('change', function() {
console.log('You selected: ', this.value);
console.log("model", window.model)
load(this.value)
});
function animate() {
requestAnimationFrame( animate );
const delta = clock.getDelta();
mixer.update( delta );
controls.update();
//stats.update();
renderer.render( scene, camera );
}
</script>
</body>
</html>
当你做camera.position.x += mouseX - camera.position.x
时,你正在使用x位置来设置自己。这些自引用的值会给你带来不稳定的行为。试试更简单的:
camera.position.x = mouseX * 0.05;
或者如果你想要一个平滑的动画,你可以在两个值之间做线性插值:
let mouseXTarget = 0, mouseX = 0;
function onDocumentMouseMove( event ) {
mouseXTarget = ( event.clientX - windowHalfX ) * 0.05;
}
function render() {
// mouseX will smoothly try to reach its target
mouseX = THREE.MathUtils.lerp(mouseX, mouseXTarget, 0.1);
camera.position.x += mouseX;
camera.lookAt( scene.position );
}