three.js官方案例(animation / multiple)webgl_animation_multiple.html学习笔记

目录

​编辑

1 骨架工具(SkeletonUtils)

 1.1 clone方法

2 蒙皮网格(SkinnedMesh)

3 自测

4 webgl_animation_multiple.html全部脚本


1 骨架工具(SkeletonUtils)

用于操控 Skeleton、 SkinnedMesh、和 Bone 的实用方法。

SkeletonUtils 是一个附加组件,必须显式导入。 See Installation / Addons.

import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.js';

 1.1 clone方法

//.clone ( object : Object3D ) : Object3D

///克隆给定对象及其后代,确保任何 SkinnedMesh 实例都与其骨骼正确关联。同时,骨骼也会被克隆,且必须是传递给此方法的物体的后代。而其他数据,如几何形状和材料,是通过引用来实现重复使用的

2 蒙皮网格(SkinnedMesh)

  console.log('model:',model);

  console.log('动画:',animations);

3 自测

测试蒙皮网格的一些脚本

只把蒙皮添加到scene里:

把model和蒙皮都添加到scene里:

把骨骼加到场景里

把雾的一行注掉,加上控制器,鼠标滚动视角边远看着是如下图所示:

修正模型大小:

model3.bindMode = THREE.DetachedBindMode;//注掉后模型也会变大

参考博客:

深度解析3D骨骼系统中骨骼运动对几何体顶点运动的影响

介绍了 D骨骼系统中骨骼几何体顶点的影响。

console.log(params);

这里是UI切换时的参数打印

4 webgl_animation_multiple.html全部脚本

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>Multiple animated skinned meshes</title>
		<meta charset="utf-8">
		<meta content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" name="viewport">
		<link type="text/css" rel="stylesheet" href="main.css">
	</head>
	<body>
		<div id="info">
			This demo shows the usage of <strong>SkeletonUtils.clone()</strong> and how to setup a shared skeleton.<br/>
			Soldier model from <a href="https://www.mixamo.com" target="_blank" rel="noopener">https://www.mixamo.com</a>.
		</div>

		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js",
					"three/addons/": "./jsm/"
				}
			}
		</script>

		<script type="module">

			import * as THREE from 'three';
            //gltf模型下载器
			import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
			//骨架工具
			import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.js';
			//ui
			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

			 //控制器
			 //控制器
			 import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

			let camera, scene, renderer, clock;
			let model, animations;
			let controls;

			const mixers = [], objects = [];

			const params = {
				sharedSkeleton: false
			};

			init();
			animate();

			function init() {
                //相机
				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
				camera.position.set( 2, 3, - 6 );
				camera.lookAt( 0, 1, 0 );

				clock = new THREE.Clock();
                //场景
				scene = new THREE.Scene();
				scene.background = new THREE.Color( 0xa0a0a0 );
				//scene.fog = new THREE.Fog( 0xa0a0a0, 10, 50 );
                //半球光  (不能投射阴影)
				const hemiLight = new THREE.HemisphereLight( 0xffffff, 0x8d8d8d, 3 );
				hemiLight.position.set( 0, 20, 0 );
				scene.add( hemiLight );
                //模拟的太阳
				const dirLight = new THREE.DirectionalLight( 0xffffff, 3 );
				dirLight.position.set( - 3, 10, - 10 );
				dirLight.castShadow = true;
				dirLight.shadow.camera.top = 4;
				dirLight.shadow.camera.bottom = - 4;
				dirLight.shadow.camera.left = - 4;
				dirLight.shadow.camera.right = 4;
				dirLight.shadow.camera.near = 0.1;
				dirLight.shadow.camera.far = 40;
				scene.add( dirLight );


			

				// scene.add( new THREE.CameraHelper( dirLight.shadow.camera ) );

				// ground 地面

				const mesh = new THREE.Mesh( new THREE.PlaneGeometry( 200, 200 ), new THREE.MeshPhongMaterial( { color: 0xcbcbcb, depthWrite: false } ) );
				mesh.rotation.x = - Math.PI / 2;
				mesh.receiveShadow = true;
				scene.add( mesh );

				const loader = new GLTFLoader();
				loader.load( 'models/gltf/Soldier.glb', function ( gltf ) {

					model = gltf.scene;
					animations = gltf.animations;
					console.log('model:',model);
					console.log('动画:',animations);
					model.traverse( function ( object ) {

						if ( object.isMesh ) object.castShadow = true;

					} );

					setupDefaultScene();
                    
					//测试
					// const shareSkinnedMesh = model.getObjectByName( 'vanguard_Mesh' ); //获取蒙皮
					// const shareSkinnedMesh2 = model.getObjectByName( 'vanguard_visor' ); //获取蒙皮
				    // const sharedSkeleton = shareSkinnedMesh.skeleton; //.skeleton 用于表示蒙皮网格中骨骼的层次结构的Skeleton(骨架)
				    // const sharedParentBone = model.getObjectByName( 'mixamorigHips' );//骨骼
				    // scene.add( sharedParentBone );

					// model.scale.setScalar( 0.01 );
				    // model.rotation.x = - Math.PI * 0.5;  //这没起作用

					// scene.add(model);
				    // const model1=shareSkinnedMesh.clone()
					// model1.bindMode = THREE.DetachedBindMode;
					// shareSkinnedMesh.clone().position.x=1;
					// const identity = new THREE.Matrix4();//骨骼的变换
				    // model1.bind( sharedSkeleton, identity );//绑定
				    // model1.position.x = - 2;

		
					

					// model1.scale.setScalar( 0.01 );
				    // model1.rotation.x = - Math.PI * 0.5; //变正常了
					// scene.add(model1);

				} );
                //渲染器
				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.shadowMap.enabled = true;
				document.body.appendChild( renderer.domElement );

				controls=new OrbitControls(camera, renderer.domElement);

				window.addEventListener( 'resize', onWindowResize );

				//UI部分
				const gui = new GUI();

				gui.add( params, 'sharedSkeleton' ).onChange( function () {

					clearScene();//
			        console.log(params);
					if ( params.sharedSkeleton === true ) {

						setupSharedSkeletonScene();

					} else {

						setupDefaultScene();

					}
			
				} );
				gui.open();

			}

			function clearScene() {

				for ( const mixer of mixers ) {

					mixer.stopAllAction();//停止所有动作

				}

				mixers.length = 0;

				//

				for ( const object of objects ) {

					scene.remove( object );

					scene.traverse( function ( child ) {

						//蒙皮网格 SkinnedMesh
						//.skeleton 用于表示蒙皮网格中骨骼的层次结构的Skeleton(骨架)
						//dispose 释放该实例分配的GPU相关资源。每当您的应用程序中不再使用此实例时,请调用此方法
						if ( child.isSkinnedMesh ) child.skeleton.dispose();

					} );

				}

			}

			function setupDefaultScene() {

				// three cloned models with independent skeletons.三个具有单个共享骨架的克隆模型。
				// each model can have its own animation state  每个模型都可以有自己的动画状态
				

				//.clone ( object : Object3D ) : Object3D
//克隆给定对象及其后代,确保任何 SkinnedMesh 实例都与其骨骼正确关联。同时,骨骼也会被克隆,且必须是传递给此方法的物体的后代。而其他数据,如几何形状和材料,是通过引用来实现重复使用的。
				const model1 = SkeletonUtils.clone( model );
				const model2 = SkeletonUtils.clone( model );
				const model3 = SkeletonUtils.clone( model );
				const model4 = SkeletonUtils.clone( model );

				model1.position.x = - 2;
				model2.position.x = 0;
				model3.position.x = 2;
				model4.position.z = 2;
//分别获取每个的动画混合器
				const mixer1 = new THREE.AnimationMixer( model1 );
				const mixer2 = new THREE.AnimationMixer( model2 );
				const mixer3 = new THREE.AnimationMixer( model3 );
				const mixer4 = new THREE.AnimationMixer( model4 );
                
				mixer1.clipAction( animations[ 0 ] ).play(); // idle
				mixer2.clipAction( animations[ 1 ] ).play(); // run
				mixer3.clipAction( animations[ 3 ] ).play(); // walk
				mixer4.clipAction( animations[ 2 ] ).play(); //Tpose

				scene.add( model1, model2, model3,model4 );//加到场景里
			
				objects.push( model1, model2, model3, model4);
				mixers.push( mixer1, mixer2, mixer3, mixer4);

			}

			function setupSharedSkeletonScene() {

				// three cloned models with a single shared skeleton. 三个具有单个共享骨架的克隆模型。
				// all models share the same animation state 。所有模型共享相同的动画状态

				const sharedModel = SkeletonUtils.clone( model );
				const shareSkinnedMesh = sharedModel.getObjectByName( 'vanguard_Mesh' ); //获取蒙皮
				const sharedSkeleton = shareSkinnedMesh.skeleton; //.skeleton 用于表示蒙皮网格中骨骼的层次结构的Skeleton(骨架)
				const sharedParentBone = sharedModel.getObjectByName( 'mixamorigHips' );//骨骼
				scene.add( sharedParentBone ); // the bones need to be in the scene for the animation to work 骨骼需要在场景中才能使动画工作

				const model1 = shareSkinnedMesh.clone();//这里是对蒙皮进行克隆
				const model2 = shareSkinnedMesh.clone();
				const model3 = shareSkinnedMesh.clone();
				const model4 = shareSkinnedMesh.clone();

				//bindMode表示蒙皮网格 与骷髅共享相同的世界空间
				model1.bindMode = THREE.DetachedBindMode; 绑定模式
				model2.bindMode = THREE.DetachedBindMode;
				model3.bindMode = THREE.DetachedBindMode;//注掉后模型也会变大
				model4.bindMode = THREE.DetachedBindMode;

				const identity = new THREE.Matrix4();// 绑定的矩阵

				model1.bind( sharedSkeleton, identity );//绑定
				model2.bind( sharedSkeleton, identity );
				model3.bind( sharedSkeleton, identity );
				model4.bind( sharedSkeleton, identity );

				model1.position.x = - 2;
				model2.position.x = 0;
				model3.position.x = 2;
				model4.position.z = 2;

				// apply transformation from the glTF asset 应用glTF资产的转换

				model1.scale.setScalar( 0.01 );
				model1.rotation.x = - Math.PI * 0.5;
				model2.scale.setScalar( 0.01 );
				model2.rotation.x = - Math.PI * 0.5;
				model3.scale.setScalar( 0.01 );
				model3.rotation.x = - Math.PI * 0.5;

				model4.scale.setScalar( 0.01 );
				model4.rotation.x = - Math.PI * 0.5;
				

				const mixer = new THREE.AnimationMixer( sharedParentBone );
				mixer.clipAction( animations[ 1 ] ).play();

				scene.add( sharedParentBone, model1, model2, model3 , model4);
			
				objects.push( sharedParentBone, model1, model2, model3, model4 );
				mixers.push( mixer );

			}

			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

			}

			function animate() {

				requestAnimationFrame( animate );

				const delta = clock.getDelta();

				for ( const mixer of mixers ) mixer.update( delta );

				renderer.render( scene, camera );

				controls.update();

			}

		</script>

	</body>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/688982.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring AI 第二讲 之 Chat Model API 第八节Anthropic 3 Chat

Anthropic Claude 是一系列基础人工智能模型&#xff0c;可用于各种应用。对于开发人员和企业来说&#xff0c;您可以利用 API 访问&#xff0c;直接在 Anthropic 的人工智能基础架构之上进行构建。 Spring AI 支持用于同步和流式文本生成的 Anthropic 消息 API。 Anthropic …

因为宇宙一片漆黑,所以地球才有昼夜之分,宇宙为什么是黑的?

因为宇宙一片漆黑&#xff0c;所以地球才有昼夜之分&#xff0c;宇宙为什么是黑的&#xff1f; 地球为何会有昼夜之分&#xff1f; 乍一看&#xff0c;这个问题很是简单&#xff0c;当然是因为地球一直在自转了&#xff0c;当地球的一部分被太阳照射时就是白昼&#xff0c;而…

Servlet搭建博客系统

现在我们可以使用Servlet来搭建一个动态(前后端可以交互)的博客系统了(使用Hexo只能实现一个纯静态的网页,即只能在后台自己上传博客)。有一种"多年媳妇熬成婆"的感觉。 一、准备工作 首先创建好项目,引入相关依赖。具体过程在"Servlet的创建"中介绍了。…

【Vue】单页应用程序介绍

通常基于Vue去开发一整个网站&#xff0c;开发出来的这整个网站应用&#xff0c;我们都会叫做单页应用程序 概念 单页应用程序&#xff1a;SPA【Single Page Application】是指所有的功能都在一个html页面上实现 我们可以将页面共用的部分封装成组件&#xff0c;底下要切换的也…

A6500-LC LVDT 前置器,用于A6500-UM, 导轨安装

电源 22.5V to 32VDC <30mA <0.1%/V <60V( 使用SELV/PELV 供电电源) 约2.2Vrms,5kHz IP20 IEC 60529 -35C to 75C(-31F to 167F) -35C to 85C(-31F to 185F) 电流损耗 供电电压对 运行温度 存储温度 0.35mm(0.014 in ),10 to 55Hz 15g 根据 EN 60068-2-27 根据IEC 613…

nginx配置WebSocket参数wss连接

目录 一、原文连接 二、 配置参数 三、实践 四、重启nginx 五、连接websocket 一、原文连接 nginx配置websocket支持wss-腾讯云开发者社区-腾讯云 二、 配置参数 map $http_upgrade $connection_upgrade { default upgrade; close; } upstream websocket { se…

大数据处理学习笔记

sudo tar -zxvf hadoop-1.1.2.tar.gz -C / #解压到/usr/local目录下 sudo mv hadoop-1.1.2 hadoop #重命名为hadoop sudo chown -R python ./hadoop #修改文件权限 //java安装同上给hadoop配置环境变量&#xff0c;将下面代…

Thinkphp使用Elasticsearch查询

在Thinkphp中调用ES&#xff0c;如果自己手写json格式的query肯定是很麻烦的。我这里使用的是ONGR ElasticsearchDSL 构建 ES 查询。ongr ElasticsearchDSL 的开源项目地址&#xff1a;GitHub - ongr-io/ElasticsearchDSL: Query DSL library for Elasticsearch。ONGR Elastics…

分布式数据库架构:从单实例到分布式,开发人员需及早掌握?

现在互联网应用已经普及,数据量不断增大。对淘宝、美团、百度等互联网业务来说,传统单实例数据库很难支撑其性能和存储的要求,所以分布式架构得到了很大发展。而开发人员、项目经理,一定要认识到数据库技术正在经历一场较大的变革,及早掌握好分布式架构设计,帮助公司从古…

DSP28335模块配置模板系列——定时器中断配置模板

一、配置步骤&#xff1a; 1.使能定时器时钟 EALLOW;SysCtrlRegs.PCLKCR3.bit.CPUTIMER2ENCLK 1; // CPU Timer 2EDIS; 2.设置定时器的中断向量 EALLOW;PieVectTable.TINT2 &TIM2_IRQn;EDIS;其中TIM2_IRQn时定时器中断服务程序的名称 &#xff0c;将中断服务函数的地址…

【回溯算法】N皇后问题·构建多叉决策树,遍历决策节点,做出决策(边),收集答案

0、前言 在由树形解空间入手&#xff0c;深入分析回溯、动态规划、分治算法的共同点和不同点这篇博客&#xff0c;其实已经对回溯算法的思想、做题框架做出了详细的阐述。这篇文章我们再从N皇后问题&#xff0c;加深我们对其理解。 这里在简单再次对其进行概述&#xff1a; …

dataphin是什么及其简单使用示例

1.1dataphin是什么&#xff1f; Dataphin是由阿里研发的智能大数据建设平台&#xff0c;提供一站式数据中台&#xff08;大数据平台&#xff09;建设服务。Dataphin通过沙箱&#xff08;项目&#xff09;实现业务及作业资源隔离&#xff0c;运行更快&#xff0c;且数据同步到D…

代码随想录算法训练营第四十八 | ● 121. 买卖股票的最佳时机 ● 122.买卖股票的最佳时机II

121. 买卖股票的最佳时机 买卖股票的最佳时机 视频讲解&#xff1a;https://www.bilibili.com/video/BV1Xe4y1u77q https://programmercarl.com/0121.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BA.html class Solution { public:int ma…

因你而变 共赴新程 | AidLux全新版本震撼发布!

历经400多个日夜&#xff0c;AidLux 2.0&#xff08;基础版&#xff09;终于要与大家见面了。 开发者们问过无数次&#xff0c;新版本何时发布&#xff0c;期待的功能何时上线……在此&#xff0c;让我先真诚地感谢大家长期以来的期待与关心&#xff01; 一年多以来&#xff…

如何从官网下载 mysql 二进制安装包

一.下载二进行包 1. 官网网址: https://www.mysql.com/ 如图所示进入官网 2. 点击 DOWNLOADS ,进入如下图 在该页面找到 MySQL Community (GPL) Downloads 点进去 如上图页面&#xff0c;找到 MySQL Community Server 在点进去 下载 linux 通用版 点击最下面 Compressed …

服务监控-微服务小白入门(5)

背景 什么是服务监控 监视当前系统应用状态、内存、线程、堆栈、日志等等相关信息&#xff0c;主要目的在服务出现问题或者快要出现问题时能够准确快速地发现以减小影响范围。 为什么要使用服务监控 服务监控在微服务改造过程中的重要性不言而喻&#xff0c;没有强大的监控…

kafka-生产者拦截器(SpringBoot整合Kafka)

文章目录 1、生产者拦截器1.1、创建生产者拦截器1.2、KafkaTemplate配置生产者拦截器1.3、使用Java代码创建主题分区副本1.4、application.yml配置----v1版1.5、屏蔽 kafka debug 日志 logback.xml1.6、引入spring-kafka依赖1.7、控制台日志 1、生产者拦截器 1.1、创建生产者拦…

SkyWalking之P0核心业务场景输出调用链路应用

延伸扩展&#xff1a;XX核心业务场景 路由标签打标、传播、检索 链路标签染色与传播 SW: SkyWalking的简写 用户请求携带HTTP头信息X-sw8-correlation “X-sw8-correlation: key1value1,key2value2,key3value3” 网关侧读取解析HTTP头信息X-sw8-correlation&#xff0c;然后通…

Dokcer 基础使用 (4) 网络管理

文章目录 Docker 网络管理需求Docker 网络架构认识Docker 常见网络类型1. bridge 网络2. host 网络3. container 网络4. none 网络5. overlay 网络 Docker 网路基础指令Docker 网络管理实操 其他相关链接 Docker 基础使用(0&#xff09;基础认识 Docker 基础使用(1&#xff09;…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(十三)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 20 - 21节&#xff09; P20《19.ArkUI-属性动画和显式动画》 本节先来学习属性动画和显式动画&#xff1a; 在代码中定义动画&am…