【技术调研】三维(6)-案例1:模型动态修改、模型动画

模型上色、换肤

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="utf-8">
	<title>My first three.js app</title>
	<style>
		body {
			margin: 0;
		}
		
		#process{
			position: absolute;
			top:0;
			left:0;
			font-size:20px;
			color: aliceblue;
		}
		
		#operation{
			position: absolute;
			top:0;
			right:20px;
			/* transform: translateX(-50%); */
		}
	</style>
</head>

<body>
	
	<script type="module">
		import * as THREE from "three";
		import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
		// import {Rhino3dmLoader} from 'three/examples/jsm/loaders/3DMLoader.js';
		import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
		
		const scene = new THREE.Scene();
		const camera = new THREE.PerspectiveCamera(
			75,
			window.innerWidth / window.innerHeight,
			0.1,
			1000
		);
		camera.position.set(5, 2, 0);
		camera.lookAt(0, 0, 0);

		const renderer = new THREE.WebGLRenderer({
			antialias: true
		})
		renderer.setSize(window.innerWidth, window.innerHeight);
		renderer.shadowMap.enabled = true;
		renderer.shadowMapType = THREE.PCFSoftShadowMap;
		document.body.appendChild(renderer.domElement);

		/**
		 *  创建地面
		 */
		const geometry2 = new THREE.PlaneGeometry(100, 100);
		const material2 = new THREE.MeshStandardMaterial({ color: 0xffffff });
		const plane = new THREE.Mesh(geometry2, material2);
		//旋转
		plane.rotation.x = -Math.PI / 2;
		plane.receiveShadow = true;
		scene.add(plane);

		/**
		 * 灯光
		 */
		//环境光
		const ambientLight = new THREE.AmbientLight(0x404040); // 柔和的白光
		scene.add(ambientLight);
		// 平行光
		const directionLight = new THREE.DirectionalLight(0xffffff, 1);
		directionLight.castShadow = true;
		//让阴影更清晰
		directionLight.shadow.mapSize.width = 2048;
		directionLight.shadow.mapSize.height = 2048;
		//不设置以下内容看不见
		directionLight.shadow.camera.left = -100;
		directionLight.shadow.camera.right = 100;
		directionLight.shadow.camera.top = 100;
		directionLight.shadow.camera.bottom = -100;
		directionLight.position.set(150, 20, 0);
		const directionalLightHelper = new THREE.DirectionalLightHelper(directionLight, 5);
		scene.add(directionLight);
		
		let model;
		let modelScene;
		
		
		/**
		 * 修改模型颜色
		 */
		const oInput = document.getElementById("color");
		//添加事件
		oInput.addEventListener('input',(event)=>{
			if(model){
				model.material.color.set(event.target.value);
			}
			
		})
		
		/**
		 * 修改整个加载进来的模型大小
		 */
		const fangdaButton = document.getElementById("fangda"); 
		fangdaButton.addEventListener('click',(event)=>{
			if(modelScene){
				modelScene.scene.scale.set(++modelScene.scene.scale.x,++modelScene.scene.scale.y,++modelScene.scene.scale.z);
			}
		})
		const suoxiaoButton = document.getElementById("suoxiao");    
		suoxiaoButton.addEventListener('click',(event)=>{
			if(modelScene && modelScene.scene.scale.x>1){
				modelScene.scene.scale.set(--modelScene.scene.scale.x,--modelScene.scene.scale.y,--modelScene.scene.scale.z);
			}
		})

		const gLTFLoader = new GLTFLoader();

		const oProcess = document.getElementById("process");  //用于显示加载进度

		gLTFLoader.load(
			"models/CesiumMan.glb",
			(gltf) =>{
				// console.log(1);
				console.log(gltf);
					// console.log(2);
				modelScene = gltf
					// gltf.scene.scale.set(10,10,10);
				model = gltf.scene.children[0].children[1];
				
				scene.add(gltf.scene);
				
			},
			(xhr) => {
				console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
				oProcess.textContent = ( xhr.loaded / xhr.total * 100 ) + '%'
			},
			(error) =>{
				console.log(error);
			}
		);
		const controls = new OrbitControls(camera, renderer.domElement);
		controls.enableDamping = true;

		const animete = () => {

			requestAnimationFrame(animete);
			renderer.render(scene, camera);
		};
		animete();

	</script>
	<p id="process"></p>
	<div id="operation">
		<input type="button" value="放大" id="fangda">
		<input type="button" value="缩小" id ="suoxiao">
		<input type="color" id="color">
	</div>
</body>

</html>

模型动画

按下W,控制动画。

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="utf-8">
	<title>My first three.js app</title>
	<style>
		body {
			margin: 0;
		}
		
		#process{
			position: absolute;
			top:0;
			left:0;
			font-size:20px;
			color: aliceblue;
		}
		
		#operation{
			position: absolute;
			top:0;
			right:20px;
			/* transform: translateX(-50%); */
		}
	</style>
</head>

<body>
	
	<script type="module">
		import * as THREE from "three";
		import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
		// import {Rhino3dmLoader} from 'three/examples/jsm/loaders/3DMLoader.js';
		import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
		
		const scene = new THREE.Scene();
		const camera = new THREE.PerspectiveCamera(
			75,
			window.innerWidth / window.innerHeight,
			0.1,
			1000
		);
		camera.position.set(5, 2, 0);
		camera.lookAt(0, 0, 0);
		
		// const cubeCamera = new THREE.Mesh(
		// 	new THREE.SphereGeometry(0.2),
		// 	new THREE.MeshBasicMaterial({color:0xff1ff1,wireframe:true})
		// );
		// //相机位置的向量,缩放0.6得到新的向量
		// const pVector = camera.position.clone().multiplyScalar(0.8);
		// cubeCamera.position.copy(pVector);
		// scene.add(cubeCamera);
		
		
		const renderer = new THREE.WebGLRenderer({
			antialias: true
		})
		renderer.setSize(window.innerWidth, window.innerHeight);
		renderer.shadowMap.enabled = true;
		renderer.shadowMapType = THREE.PCFSoftShadowMap;
		document.body.appendChild(renderer.domElement);

		/**
		 *  创建地面
		 */
		const geometry2 = new THREE.PlaneGeometry(100, 100);
		const material2 = new THREE.MeshStandardMaterial({ color: 0xffffff });
		const plane = new THREE.Mesh(geometry2, material2);
		//旋转
		plane.rotation.x = -Math.PI / 2;
		plane.receiveShadow = true;
		scene.add(plane);

		/**
		 *  创建立方体
		 */

		const cube1 = new THREE.Mesh(new THREE.BoxGeometry(3, 3, 3),new THREE.MeshStandardMaterial({color:0x404040}));
		const cube2 = new THREE.Mesh(new THREE.BoxGeometry(2, 5, 3),new THREE.MeshStandardMaterial({color:0x404040}));
		const cube3 = new THREE.Mesh(new THREE.BoxGeometry(3, 10, 4),new THREE.MeshStandardMaterial({color:0x404040}));
		const cube4 = new THREE.Mesh(new THREE.BoxGeometry(3, 3, 5),new THREE.MeshStandardMaterial({color:0x404040}));
		
		cube1.position.set(10, 0, 20);
		cube2.position.set(-10, 0, 20);
		cube3.position.set(10, 0, -20);
		cube4.position.set(-10, 0, -20);
		// cube1.castShadow = true;
		scene.add(cube1,cube2,cube3,cube4);
		
	
		
		
		/**
		 * 灯光
		 */
		//环境光
		const ambientLight = new THREE.AmbientLight(0x404040); // 柔和的白光
		scene.add(ambientLight);
		// 平行光
		const directionLight = new THREE.DirectionalLight(0xffffff, 3);
		directionLight.castShadow = true;
		//让阴影更清晰
		directionLight.shadow.mapSize.width = 2048;
		directionLight.shadow.mapSize.height = 2048;
		//不设置以下内容看不见
		directionLight.shadow.camera.left = -100;
		directionLight.shadow.camera.right = 100;
		directionLight.shadow.camera.top = 100;
		directionLight.shadow.camera.bottom = -100;
		directionLight.position.set(10, 20, 0);
		const directionalLightHelper = new THREE.DirectionalLightHelper(directionLight, 5);
		scene.add(directionLight);
		
		

		
		let materialmodel;
		let modelScene;
		/**
		 * 修改模型颜色
		 */
		const oInput = document.getElementById("color");
		//添加事件
		oInput.addEventListener('input',(event)=>{
			if(materialmodel){
				materialmodel.material.color.set(event.target.value);
			}
		})
		
		/**
		 * 修改整个加载进来的模型大小
		 */
		const fangdaButton = document.getElementById("fangda"); 
		fangdaButton.addEventListener('click',(event)=>{
			if(modelScene){
				modelScene.scene.scale.set(++modelScene.scene.scale.x,++modelScene.scene.scale.y,++modelScene.scene.scale.z);
			}
		})
		const suoxiaoButton = document.getElementById("suoxiao");    
		suoxiaoButton.addEventListener('click',(event)=>{
			if(modelScene && modelScene.scene.scale.x>1){
				modelScene.scene.scale.set(--modelScene.scene.scale.x,--modelScene.scene.scale.y,--modelScene.scene.scale.z);
			}
			// if(action) action.stop();
		})
		/**
		 * 换肤
		 */
		const huanfuButton = document.getElementById("huanfu");
		huanfuButton.addEventListener('click',(event)=>{
			if(materialmodel){
				// 创建一个纹理贴图
				const textureLoader = new THREE.TextureLoader();
				const name = Math.floor(Math.random() * 55) + 1;
				const texture = textureLoader.load('./img/'+name+'.jpg');
				materialmodel.material.map = texture;
				 mesh.material.needsUpdate = true;
			}
		})


		const gLTFLoader = new GLTFLoader();

		const oProcess = document.getElementById("process");  //用于显示加载进度
		
		
		let mixer;  //动画用
		let action;
		gLTFLoader.load(
			"models/CesiumMan.glb",
			(gltf) =>{
				console.log(gltf);
				modelScene = gltf
				materialmodel = gltf.scene.children[0].children[1];
				
				//获取动作
				const realmodel = gltf.scene;
				const animations = gltf.animations;
				mixer = new THREE.AnimationMixer(realmodel);
;				const runClip = animations.find(clip => clip.name==="animation_0");
				if(runClip){
				    action = mixer.clipAction(runClip);
					// action.play();
					// action.reset();
					// action.stop();
				}
				scene.add(gltf.scene);
				
			},
			(xhr) => {
				console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
				oProcess.textContent = ( xhr.loaded / xhr.total * 100 ) + '%'
			},
			(error) =>{
				console.log(error);
			}
		);
		
		/**
		 * 键盘控制动作
		 * 
		 */
		window.addEventListener("keydown",(event)=>{
			
			if(event.code ==="KeyW" && !action.isRunning()){
				// if(!action.isScheduled()){
				// 	action.play();
				// 	action.fadeIn(0.5); 
				// }
				action.reset().fadeIn(0.5).play(); 
				console.log(event.code);
				//重置后慢慢启动动作
			}
		})
		
		window.addEventListener("keyup",(event)=>{
				
			if(event.code ==="KeyW"){	
				action.fadeOut(0.5);
			}
		})
		
		
		
		const controls = new OrbitControls(camera, renderer.domElement);
		controls.enableDamping = true;
		controls.addEventListener("change",()=>{
			//获取合适的位置坐标
			// console.log(camera.position);
		})
		const clock = new THREE.Clock();
		const animete = () => {
			//动画用
			const elapsedTime = clock.getDelta();
			// console.log(elapsedTime);
			if(mixer) {
				mixer.update(elapsedTime);
			}
			requestAnimationFrame(animete);
			renderer.render(scene, camera);
			
		};
		animete();

	</script>
	<p id="process"></p>
	<div id="operation">
		<input type="button" value="放大" id="fangda">
		<input type="button" value="缩小" id ="suoxiao">
		<input type="button" value="换肤" id="huanfu">
		<!-- <input type="button" value="换肤" id="stop"> -->
		<input type="color" id="color">
	</div>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值