three.js官方案例(animation / skinning / ik)webgl_animation_skinning_ik.html学习记录

目录

1 WebGLCubeRenderTarget

2 TransformControls   

3 CCDIKSolver

4 CCDIKHelper

4 全部脚本


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>

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hemy1989

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值