three.js官方案例(animation / skinning / ik)webgl_animation_skinning_ik.html学习记录
目录
1 WebGLCubeRenderTarget
球体亮
//WebGLCubeRenderTarget(size : Number, options : Object)
//size - the size, in pixels. Default is 1.
//options - (可选)一个保存着自动生成的目标纹理的纹理参数以及表示是否使用深度缓存/模板缓存的布尔值的对象。
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 1024 );
mirrorSphereCamera = new THREE.CubeCamera( 0.05, 50, cubeRenderTarget );//创建6个渲染到WebGLCubeRenderTarget的摄像机
scene.add( mirrorSphereCamera );
const mirrorSphereMaterial = new THREE.MeshBasicMaterial( { envMap: cubeRenderTarget.texture } );
OOI.sphere.material = mirrorSphereMaterial;//球体材质设置
2 TransformControls
可以用来拖拽模型
transformControls = new TransformControls( camera, renderer.domElement );//camera是渲染场景的相机 renderer.domElement是控制器附加到的html元素
transformControls.size = 0.75;//以像素为单位的变换控制器的大小
transformControls.showX = false;//指示是否显示沿 X轴的控制手柄。
transformControls.space = 'world';//指定变换空间(‘local’ 或 ‘world’),其中应用变换
transformControls.attach( OOI.target_hand_l );//将控制器附加到指定的对象以进行操作
scene.add( transformControls );
3 CCDIKSolver
CCDIKSolver 用 CCD 算法解决逆运动学问题。 CCDIKSolver 设计用于与 SkinnedMesh 配合使用,但也可与 MMDLoader 或 GLTFLoader 配合使用。
构造函数
CCDIKSolver( mesh : SkinnedMesh, iks : Array )
mesh — SkinnedMesh 用于 CCDIKSolver 解决 IK 问题
iks — 指定 IK 参数的对象 Object 数组。target、effector 和 link-index 是 .sculptor.bones 中的索引整数。骨骼关系从父级到子级的顺序应为“links[ n ]、 links[ n - 1 ]、...、 links[ 0 ]、effector”。
- target — 目标骨骼
- effector — 效应器骨
- links — 指定链接骨骼的对象Object 数组
- index — 链接骨骼
- limitation — (可选)旋转轴。默认值 undefined
- rotationMin — (可选)旋转最小限制。默认值 undefined
- rotationMax — (可选)旋转最大限制。默认值 undefined
- enabled — (可选)默认值为 true。
- iteration — (可选)计算的迭代次数。越小速度越快,但精度较差。默认值为 1。
- minAngle — (可选)一步中的最小旋转角度。默认值 undefined
- maxAngle — (可选)一步中的最大旋转角度。默认值 undefined
4 CCDIKHelper
IKSolver = new CCDIKSolver( OOI.kira, iks );//动画
const ccdikhelper = new CCDIKHelper( OOI.kira, iks, 0.01 );//辅助
scene.add( ccdikhelper );
4 全部脚本
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - animation - skinning - ik</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<meta name="author" content="Antoine BERNIER (abernier)" />
<link type="text/css" rel="stylesheet" href="main.css">
<style>
body {color:white;}
#info a {
color:#4d6675;
}
</style>
</head>
<body>
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - webgl - inverse kinematics<br />
Character model by <a href="https://assetstore.unity.com/packages/3d/characters/humanoids/humans/kira-lowpoly-character-100303" target="_blank" rel="noopener">Aki</a>, furnitures from <a href="https://poly.pizza" target="_blank" rel="noopener">poly.pizza</a>, scene by <a href="https://abernier.name/three.js/examples/webgl_esher.html" target="_blank" rel="noopener">abernier</a>. CC0.
</div>
<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';//控制器引入
import { TransformControls } from 'three/addons/controls/TransformControls.js';//转换控件 控制器 交互操作
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';//GLTF模型加载器
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';//一个用于加载经过Draco压缩的图形库 和GLTFLoader 一同出现
import { CCDIKSolver, CCDIKHelper } from './jsm/animation/CCDIKSolver.js';//动画相关库 一种基于 CCD Algorithm 的 IK 解算器
import Stats from 'three/addons/libs/stats.module.js';//性能检测
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';//UI
let scene, camera, renderer, orbitControls, transformControls,transformControls2 ;
let mirrorSphereCamera;
const OOI = {};
let IKSolver;
let stats, gui, conf;
const v0 = new THREE.Vector3();
init().then( animate );//先后顺序
async function init() {
conf = {
followSphere: false,
turnHead: true,
ik_solver: true,
update: updateIK
};//定义一些用到的字段
//场景
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0xffffff, .17 );
scene.background = new THREE.Color( 0xffffff );
//相机
camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.001, 5000 );
camera.position.set( 0.9728517749133652, 1.1044765132727201, 0.7316689528482836 );
camera.lookAt( scene.position );
//灯光
const ambientLight = new THREE.AmbientLight( 0xffffff, 8 ); // soft white light
scene.add( ambientLight );
//渲染器
renderer = new THREE.WebGLRenderer( { antialias: true, logarithmicDepthBuffer: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
//性能检测
stats = new Stats();
document.body.appendChild( stats.dom );
//控制器
orbitControls = new OrbitControls( camera, renderer.domElement );
orbitControls.minDistance = 0.2;
orbitControls.maxDistance = 1.5;
orbitControls.enableDamping = true;
//orbitControls.addEventListener( 'change', animate );
//开始下载模型
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath( 'jsm/libs/draco/' );
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader( dracoLoader );
const gltf = await gltfLoader.loadAsync( 'models/gltf/kira.glb' );//异常加载
console.log(OOI);
console.log(gltf.scene);
gltf.scene.traverse( n => {
if ( n.name === 'head' ) OOI.head = n;//头
if ( n.name === 'lowerarm_l' ) OOI.lowerarm_l = n;
if ( n.name === 'Upperarm_l' ) OOI.Upperarm_l = n;
if ( n.name === 'hand_l' ) OOI.hand_l = n;
if ( n.name === 'target_hand_l' ) OOI.target_hand_l = n;
if ( n.name === 'boule' ) OOI.sphere = n;//球
if ( n.name === 'Kira_Shirt_left' ) OOI.kira = n;
} );
scene.add( gltf.scene );
//orbitControls.target.copy( new THREE.Vector3(1.7835944890975952,1.023118257522583,-0.25029030442237854) );
orbitControls.target.copy( OOI.sphere.position ); // orbit controls lookAt the sphere 看向球
OOI.hand_l.attach( OOI.sphere );//.attach ( object : Object3D ) : 将object作为子级来添加到该对象中,同时保持该object的世界变换。
// // mirror sphere cube-camera
//WebGLCubeRenderTarget(size : Number, options : Object)
//size - the size, in pixels. Default is 1.
//options - (可选)一个保存着自动生成的目标纹理的纹理参数以及表示是否使用深度缓存/模板缓存的布尔值的对象。
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 1024 );
mirrorSphereCamera = new THREE.CubeCamera( 0.05, 50, cubeRenderTarget );//创建6个渲染到WebGLCubeRenderTarget的摄像机
scene.add( mirrorSphereCamera );
const mirrorSphereMaterial = new THREE.MeshBasicMaterial( { envMap: cubeRenderTarget.texture } );
OOI.sphere.material = mirrorSphereMaterial;//球体材质设置
transformControls = new TransformControls( camera, renderer.domElement );//camera是渲染场景的相机 renderer.domElement是控制器附加到的html元素
transformControls.size = 0.75;//以像素为单位的变换控制器的大小
transformControls.showX = false;//指示是否显示沿 X轴的控制手柄。
transformControls.space = 'world';//指定变换空间(‘local’ 或 ‘world’),其中应用变换
transformControls.attach( OOI.target_hand_l );//将控制器附加到指定的对象以进行操作
scene.add( transformControls );
// disable orbitControls while using transformControls
transformControls.addEventListener( 'mouseDown', () => orbitControls.enabled = false );//鼠标按下时 控制器失效
transformControls.addEventListener( 'mouseUp', () => orbitControls.enabled = true );
OOI.kira.add( OOI.kira.skeleton.bones[ 0 ] );//骨骼
const iks = [
{
target: 22, // "target_hand_l"
effector: 6, // "hand_l"
links: [
{
index: 5, // "lowerarm_l"
rotationMin: new THREE.Vector3( 1.2, - 1.8, - .4 ),
rotationMax: new THREE.Vector3( 1.7, - 1.1, .3 )
},
{
index: 4, // "Upperarm_l"
rotationMin: new THREE.Vector3( 0.1, - 0.7, - 1.8 ),
rotationMax: new THREE.Vector3( 1.1, 0, - 1.4 )
},
],
}
];
IKSolver = new CCDIKSolver( OOI.kira, iks );//动画
const ccdikhelper = new CCDIKHelper( OOI.kira, iks, 0.01 );//辅助
scene.add( ccdikhelper );
//UI部分
gui = new GUI();
gui.add( conf, 'followSphere' ).name( 'follow sphere' );//跟随球体
gui.add( conf, 'turnHead' ).name( 'turn head' );//转动头
gui.add( conf, 'ik_solver' ).name( 'IK auto update' );//自动更新
gui.add( conf, 'update' ).name( 'IK manual update()' );//
gui.open();
window.addEventListener( 'resize', onWindowResize, false );
const geometry = new THREE.BoxGeometry();
const spherMaterial = new THREE.MeshLambertMaterial({ color: 'red' });
const mesh=new THREE.Mesh(geometry,spherMaterial);
mesh.position.set(0,1,-1);
scene.add(mesh);
transformControls2 = new TransformControls( camera, renderer.domElement );//camera是渲染场景的相机 renderer.domElement是控制器附加到的html元素
transformControls2.size = 0.75;//以像素为单位的变换控制器的大小
//transformControls2.showX = false;//指示是否显示沿 X轴的控制手柄。
transformControls2.space = 'world';//指定变换空间(‘local’ 或 ‘world’),其中应用变换
transformControls2.attach( mesh );//将控制器附加到指定的对象以进行操作
scene.add( transformControls2 );
transformControls2.addEventListener('dragging-changed',function(event){
orbitControls.enabled=!event.value;
});
}
function animate( ) {
if ( OOI.sphere && mirrorSphereCamera ) {
OOI.sphere.visible = false;
OOI.sphere.getWorldPosition( mirrorSphereCamera.position );
mirrorSphereCamera.update( renderer, scene );
OOI.sphere.visible = true;
}
if ( OOI.sphere && conf.followSphere ) {
// orbitControls follows the sphere
OOI.sphere.getWorldPosition( v0 );
orbitControls.target.lerp( v0, 0.1 );
}
if ( OOI.head && OOI.sphere && conf.turnHead ) {
// turn head
OOI.sphere.getWorldPosition( v0 );
OOI.head.lookAt( v0 );
OOI.head.rotation.set( OOI.head.rotation.x, OOI.head.rotation.y + Math.PI, OOI.head.rotation.z );
}
if ( conf.ik_solver ) {
updateIK();
}
orbitControls.update();
renderer.render( scene, camera );
stats.update(); // fps stats
requestAnimationFrame( animate );
}
function updateIK() {
//IKSolver.update () : this 通过求解 CCD 算法更新 IK 骨骼四元数
if ( IKSolver ) IKSolver.update();
scene.traverse( function ( object ) {
//计算边界球体,更新 .boundingSphere 属性。
//默认情况下不计算边界球体。它们需要显式计算,否则它们是 . 如果 SkinnedMesh 的实例是动画的,则应按帧调用此方法以计算正确的边界球体。null
if ( object.isSkinnedMesh ) object.computeBoundingSphere();
} );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
</script>
</body>
</html>
原文地址:https://blog.csdn.net/hemiaoyuan1989/article/details/139302013
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!