当前位置: 首页 > article >正文

使用 three.js 渲染个blender模型

首先需要一个扫描模型,工业上有专门的设备去采集模型的面然后通过建模软件去处理外表面贴图

我们这里取了一个ford汽车的发动机模型

为了让three.js能够使用,使用blender把模型保存为glb格式

为了让页面加载glb模型更快,需要对模型文件进行压缩

压缩 GLB(GL Transmission Format Binary)模型可以通过多种技术来实现,以减少文件大小并提高加载速度。以下是一些常见的方法:

1. 几何数据简化

  • 网格简化:使用工具(如 Blender、MeshLab 或 Simplify3D)简化模型的几何结构,减少多边形数量。
  • LOD(Level of Detail):创建不同细节级别的模型,根据视距加载不同的细节级别。

2. 纹理压缩

  • 纹理分辨率:降低纹理的分辨率,尤其是在模型的细节不明显的部分。
  • 纹理格式:使用压缩纹理格式(如 DDS、KTX 或 ASTC)来减少纹理文件的大小。

3. 使用 Draco 压缩

  • Draco:Google 的 Draco 库可以对 3D 网格进行高效压缩。您可以使用 gltf-pipeline 工具将 GLB 模型与 Draco 压缩结合起来。

    npm install -g gltf-pipeline
    gltf-pipeline -i model.glb -o model-draco.glb -d

ford-engine-model-4.glb 是我压缩后的模型,把压缩好的模型文件放入项目中

这里直接贴代码了, three.js是纯js框架,所以没有用vue和react来集成

<!DOCTYPE html>
<html lang="en">
<head>
	<title>car engine gbl</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 {
			margin: 0 !important;
		}

		a {
			color: #2fa1d6;
		}

		p {
			max-width: 600px;
			margin-left: auto;
			margin-right: auto;
			padding: 0 2em;
		}

		body #info {
			position: fixed;
			font-size: 22px;
			width: 100%;
			right: 0;
			text-align: left;
		}

		.content-parent {
			padding: 0 40px;
			display: flex;
			justify-content: space-between;
		}

		.content > div {
			display: inline-block;
			font-size: 16px;
			font-weight: bold;
			/* color: tomato; */
		}

		.value {
			font-size: 16px;
			margin-left: 16px;
		}
	</style>
</head>

<body>

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

<script type="module">
	import * as THREE from 'three';
	import Stats from 'three/addons/libs/stats.module.js';
	import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
	import {GLTFLoader} from 'three/addons/loaders/GLTFLoader.js';
	import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
	import {TransformControls} from 'three/addons/controls/TransformControls.js';
	import { DRACOLoader } from "./jsm/loaders/DRACOLoader.js"

	function getRandomRGBColor() {  
		var r = Math.floor(Math.random() * 256);
		var g = Math.floor(Math.random() * 256);
		var b = Math.floor(Math.random() * 256);
		
		// 如果需要,可以转换为十六进制字符串  
		var hex = '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);  
	
		// 返回RGB对象或十六进制字符串,根据你的需要  
		// return { r, g, b }; // 返回RGB对象  
		return hex; // 返回十六进制字符串  
	}  
  
	// 使用函数
	console.log(getRandomRGBColor());  // 输出类似 #3A72FF 的随机颜色(十六进制字符串)

	let container, stats, clock, gui, mixer, actions, activeAction, orbitControls, transformControls;
	let camera, scene, renderer, model, dracoLoader;
	const OOI = {};

	init();
	initData();

	function initData() {
		fetch('../../data/data1.json')
		.then(response => response.json())
		.then(data => {
			setInterval(function(){
					const i = Math.floor(Math.random() * data.length);
					let item = data[i]
					let html = ''
					for (const key in item) {
						//debugger
						html += `<div>${key}: </div><span key='${key}' class='value' style='color: ${getRandomRGBColor()}'>${item[key]}</span><br/>`;
					}
					let contentElement = document.getElementById("content-left");
					contentElement.innerHTML = html
				}, 100)
		})
		.catch(error => {
			console.error('Error:', error);
		});
	}

	function init() {
		scene = new THREE.Scene();
		scene.background = new THREE.Color(0xe0e0e0);

		container = document.createElement('div');
		document.body.appendChild(container);

		//camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 8000 );
		camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 5000);
		camera.position.set(-40, 35, 50);
		//camera.lookAt( -5, -3, 0 );
		camera.lookAt(scene.position);


		//scene.fog = new THREE.Fog(0xe0e0e0, 20, 100);

		// const axesHelper = new THREE.AxesHelper(5);
		// scene.add(axesHelper);

		clock = new THREE.Clock();
		// lights
		// const hemiLight = new THREE.HemisphereLight( 0xffffff, 0x8d8d8d, 3 );
		// hemiLight.position.set( 0, 20, 0 );
		// scene.add( hemiLight );
		//
		const dirLight = new THREE.DirectionalLight(0xffffff, 8);
		dirLight.position.set(0, 20, 10);
		scene.add(dirLight);

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

		// const grid = new THREE.GridHelper(5, 40, 0x000000, 0x000000);
		// grid.material.opacity = 1;
		// grid.material.transparent = false;
		// scene.add(grid);

		renderer = new THREE.WebGLRenderer({antialias: true});
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(window.innerWidth, window.innerHeight);
		container.appendChild(renderer.domElement);
		window.addEventListener('resize', onWindowResize);

		// stats
		// stats = new Stats();
		// container.appendChild(stats.dom);
		dracoLoader = new DRACOLoader()
        // 设置解压路径,draco_decoder.js文件所在位置
		dracoLoader.setDecoderPath("https://www.gstatic.com/draco/v1/decoders/");
		dracoLoader.setDecoderConfig({ type: 'js' });
		dracoLoader.preload();
		const loader = new GLTFLoader();
		loader.setDRACOLoader(dracoLoader);

		loader.load('models/gltf/engine/ford-engine-model-4.glb', function (gltf) {
			model = gltf.scene;
			scene.add(model);
			//createGUI( model, gltf.animations );
			model.traverse(n => {
				if (n.name === 'Scene') OOI.Scene = n
			});
			const targetPosition = OOI.Scene.position.clone();
			orbitControls = new OrbitControls(camera, renderer.domElement);
			orbitControls.minDistance = 30;
			orbitControls.maxDistance = 50;
			orbitControls.enableDamping = false;
			orbitControls.enablePan = false;
			orbitControls.enableRotate = false;
			orbitControls.target.copy(targetPosition);
			// transformControls = new TransformControls(camera, renderer.domElement);
			// transformControls.size = 0.75;
			// transformControls.showX = false;
			// transformControls.showY = false;
			// transformControls.showZ = false;
			// transformControls.space = 'world';
			// transformControls.attach(OOI.Scene);
			// scene.add(transformControls);
			//transformControls.addEventListener('mouseDown', () => orbitControls.enabled = false);
			//transformControls.addEventListener('mouseUp', () => orbitControls.enabled = true);
			let angle = 0;
			const rotationSpeed = 0.0005; // 每帧旋转的角度

			animate = function() {
			  // 围绕 y 轴旋转
			  angle += rotationSpeed;
			  camera.position.x = Math.cos(angle) * orbitControls.minDistance;
			  camera.position.z = Math.sin(angle) * orbitControls.minDistance;
			  camera.lookAt(orbitControls.target);

			  orbitControls.update();
			  renderer.render(scene, camera);
			}
			renderer.setAnimationLoop(animate);

		}, undefined, function (e) {
			console.error(e);
		});
	}

	function fadeToAction(name, duration) {

		activeAction = actions[name];
		if (previousAction !== activeAction) {
			previousAction.fadeOut(duration);
		}
		activeAction
			.reset()
			.setEffectiveTimeScale(1)
			.setEffectiveWeight(1)
			.fadeIn(duration)
			.play();
	}

	function onWindowResize() {
		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();
		renderer.setSize(window.innerWidth, window.innerHeight);
	}

	//

	function animate() {
		const dt = clock.getDelta();
		if (mixer) mixer.update(dt);
		renderer.render(scene, camera);
		stats.update();
	}

</script>

</body>
</html>

贴一个three.js驱动ford-engine-model-4.glb 的页面效果,实现360°旋转

滚轮事件实现拉近

旋转到背面


http://www.kler.cn/a/370071.html

相关文章:

  • C#性能优化技巧:利用Lazy<T>实现集合元素的延迟加载
  • GD32L233RB 驱动数码管
  • 【MySQL】数据库基础知识
  • Flutter调用HarmonyOS NEXT原生相机拍摄相册选择照片视频
  • 编译chromium笔记
  • 系统思考—转型
  • 特定机器学习问题的基准测试数据
  • 【数据价值化】数据资产变现及管理规划
  • SQL语句优化之Sql执行顺序
  • 记录如何在RK3588板子上跑通paddle的OCR模型
  • 从零开始:使用Spring Boot搭建网上摄影工作室
  • c++二级指针
  • 数据结构作业day03
  • 我们正在谈论 CI/CD
  • SpringBoot框架下安康旅游网站的设计与实现
  • css实现立体骰子
  • jEasyUI 列运算
  • 基于SSM的在线旅游美食展现管理系统源码
  • 问:数据库存储过程优化实践~
  • 空值合并运算符(??) 可选链操作符(?.)
  • 使用常数指针作为函数参数
  • 聚观早报 | 荣耀Magic7朝霞金配色;一加13全球首发太阳显示技术
  • k8s 二进制部署安装(一)
  • 2020重新出发,MySql基础,MySql数据库备份与恢复
  • 交易所开发:开启数字金融新时代
  • ZooKeeper的应用场景:深入探讨分布式系统中的多样化应用