Threejs -渲染不同的模型和动画



我有一个三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 );
}

最新更新