ThreeJS官方案例学习 webgl - materials - car

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - materials - car</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 {
				color: #bbbbbb;
				background: #333333;
			}
			a {
				color: #08f;
			}
			.colorPicker {
				display: inline-block;
				margin: 0 10px
			}
		</style>
	</head>

	<body>
		<div id="info">
			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> car materials<br/>
			Ferrari 458 Italia model by <a href="https://sketchfab.com/models/57bf6cc56931426e87494f554df1dab6" target="_blank" rel="noopener">vicent091036</a>
			<br><br>

			<span class="colorPicker"><input id="body-color" type="color"  value="#ff0000"></input><br/>Body</span>
			<span class="colorPicker"><input id="details-color" type="color" value="#ffffff"></input><br/>Details</span>
			<span class="colorPicker"><input id="glass-color" type="color" value="#ffffff"></input><br/>Glass</span>
		</div>

		<div id="container"></div>

		<!-- Import maps polyfill -->
		<!-- Remove this when import maps will be widely supported -->
		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

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

		<script type="module">

			import * as THREE from 'three';

			//stats查看threejs渲染帧率
			import Stats from 'three/addons/libs/stats.module.js';

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

			import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
			import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
			import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';

			let camera, scene, renderer;
			let stats;

			let grid;
			let controls;

			const wheels = [];

			function init() {

				const container = document.getElementById( 'container' );

				// 创建渲染器对象
				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				//定义输出画布的尺寸
				renderer.setSize( window.innerWidth, window.innerHeight );
				//动画
				renderer.setAnimationLoop( render );
				//塑造出更加真实的效果
				renderer.toneMapping = THREE.ACESFilmicToneMapping;
				//色调映射的曝光级别
				renderer.toneMappingExposure = 0.85;
				container.appendChild( renderer.domElement );

				window.addEventListener( 'resize', onWindowResize );

				//创建stats对象
				stats = new Stats();
				container.appendChild( stats.dom );

				//创建相机(透视相机)模拟人眼所看到的的画面
				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 0.1, 100 );
				//设置相机的位置
				camera.position.set( 4.25, 1.4, - 4.5 );

				//设置相机控件轨道控制器
				controls = new OrbitControls( camera, container );
				// 能够将相机向外移动多少(仅适用于PerspectiveCamera)
				controls.maxDistance = 9;
				//够垂直旋转的角度的上限
				controls.maxPolarAngle = THREE.MathUtils.degToRad( 90 );
				controls.target.set( 0, 0.5, 0 );
				controls.update();

				//创建场景
				scene = new THREE.Scene();
				//设置背景颜色
				scene.background = new THREE.Color( 0x333333 );
				//设置环境贴图
				scene.environment = new RGBELoader().load( 'textures/equirectangular/venice_sunset_1k.hdr' );
				scene.environment.mapping = THREE.EquirectangularReflectionMapping;
				//雾
				scene.fog = new THREE.Fog( 0x333333, 10, 15 );

				//创建坐标格辅助对象 
				grid = new THREE.GridHelper( 20, 40, 0xffffff, 0xffffff );
				//设置透明度
				grid.material.opacity = 0.2;
				//渲染此材质是否对深度缓冲区有任何影响
				grid.material.depthWrite = false;
				//开启透明度
				grid.material.transparent = true;
				//添加到场景
				scene.add( grid );

				// materials

				//设置车身的材质 颜色(红色) 金属度 粗糙度 
				//物体表面清漆层(可以用来模拟物体表面一层透明图层,就好比你在物体表面刷了一层透明清漆,喷了点水)
				//清漆层的粗糙度
				const bodyMaterial = new THREE.MeshPhysicalMaterial( {
					color: 0xff0000, metalness: 1.0, roughness: 0.5, clearcoat: 1.0, clearcoatRoughness: 0.03
				} );

				//设置车轮与车座细节的材质属性
				const detailsMaterial = new THREE.MeshStandardMaterial( {
					color: 0xffffff, metalness: 1.0, roughness: 0.5
				} );

				//设置挡风玻璃的材质属性 颜色 金属度 粗糙度 透光率(透射率)
				const glassMaterial = new THREE.MeshPhysicalMaterial( {
					color: 0xffffff, metalness: 0.25, roughness: 0, transmission: 1.0
				} );

				
				//将更改的颜色体现出来
				const bodyColorInput = document.getElementById( 'body-color' );
				bodyColorInput.addEventListener( 'input', function () {

					bodyMaterial.color.set( this.value );

				} );

				const detailsColorInput = document.getElementById( 'details-color' );
				detailsColorInput.addEventListener( 'input', function () {

					detailsMaterial.color.set( this.value );

				} );

				const glassColorInput = document.getElementById( 'glass-color' );
				glassColorInput.addEventListener( 'input', function () {

					glassMaterial.color.set( this.value );

				} );

				// Car

				const shadow = new THREE.TextureLoader().load( 'models/gltf/ferrari_ao.png' );

				const dracoLoader = new DRACOLoader();
				dracoLoader.setDecoderPath( 'jsm/libs/draco/gltf/' );

				const loader = new GLTFLoader();
				loader.setDRACOLoader( dracoLoader );

				loader.load( 'models/gltf/ferrari.glb', function ( gltf ) {

					const carModel = gltf.scene.children[ 0 ];

					carModel.getObjectByName( 'body' ).material = bodyMaterial;

					carModel.getObjectByName( 'rim_fl' ).material = detailsMaterial;
					carModel.getObjectByName( 'rim_fr' ).material = detailsMaterial;
					carModel.getObjectByName( 'rim_rr' ).material = detailsMaterial;
					carModel.getObjectByName( 'rim_rl' ).material = detailsMaterial;
					carModel.getObjectByName( 'trim' ).material = detailsMaterial;

					carModel.getObjectByName( 'glass' ).material = glassMaterial;

					wheels.push(
						carModel.getObjectByName( 'wheel_fl' ),
						carModel.getObjectByName( 'wheel_fr' ),
						carModel.getObjectByName( 'wheel_rl' ),
						carModel.getObjectByName( 'wheel_rr' )
					);

					// shadow
					//渲染出车子的底部阴影  
					const mesh = new THREE.Mesh(
						new THREE.PlaneGeometry( 0.655 * 4, 1.3 * 4 ),
						new THREE.MeshBasicMaterial( {
							map: shadow, blending: THREE.MultiplyBlending, toneMapped: false, transparent: true
						} )
					);
					//将该阴影旋转90度 与地面平齐  
					mesh.rotation.x = - Math.PI / 2;
					//这个值将使得scene graph(场景图)中默认的的渲染顺序被覆盖, 即使不透明对象和透明对象保持独立顺序。 渲染顺序是由低到高来排序的,默认值为0。
					mesh.renderOrder = 2;
					//将阴影添加到模型中
					carModel.add( mesh );

					//将模型添加到场景中
					scene.add( carModel );

				} );

			}

			//设置渲染的画布随着窗口尺寸的大小变化
			function onWindowResize() {
				//全屏情况下:设置观察范围长宽比aspect为窗口宽高比
				camera.aspect = window.innerWidth / window.innerHeight;
				// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
    			// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
    			// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
				camera.updateProjectionMatrix();

				// 重置渲染器输出画布canvas尺寸
				renderer.setSize( window.innerWidth, window.innerHeight );

			}

			function render() {

				controls.update();

				const time = - performance.now() / 1000;

				for ( let i = 0; i < wheels.length; i ++ ) {

					wheels[ i ].rotation.x = time * Math.PI * 2;

				}
				
				//坐标格辅助对象随着时间逐渐向后移动 造成车子往前走的景象
				grid.position.z = - ( time ) % 1;

				//执行渲染操作
				renderer.render( scene, camera );

				stats.update();

			}

			init();

		</script>

	</body>
</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值