Three 之 three.js (webgl)涉及的各种材质简单说明(常用材质配有效果图)

Three 之 three.js (webgl)涉及的各种材质简单说明(常用材质有效果图)

目录

Three 之 three.js (webgl)涉及的各种材质简单说明(常用材质配有效果图)

一、简单介绍

二、各种材质说明

1、MeshBasicMaterial 基础网格材质

2、MeshDepthMaterial 深度网格材质

3、MeshDistanceMaterial 距离网格材质

4、MeshLambertMaterial Lambert网格材质

5、MeshMatcapMaterial

6、MeshNormalMaterial 法线网格材质

扫描二维码关注公众号,回复: 13996215 查看本文章

7、MeshPhongMaterial Phong网格材质

8、MeshPhysicalMaterial 物理网格材质

9、MeshStandardMaterial 标准网格材质

10、MeshToonMaterial 卡通网格材质

11、PointsMaterial 点材质

12、RawShaderMaterial 原始着色器材质

13、ShaderMaterial 着色器材质

14、ShadowMaterial 阴影材质

15、SpriteMaterial 点精灵材质

16、LineBasicMaterial 基础线条材质

17、LineDashedMaterial 虚线材质


一、简单介绍

Three js 开发的一些知识整理,方便后期遇到类似的问题,能够及时查阅使用。

本节介绍, three.js (webgl)中有各种材质,不同材质又有不同的效果,这里做简单的介绍,如果有不足之处,欢迎指出,或者你有更好的方法,欢迎留言。

Materail 材料的抽象基类。

材料描述物体的外观。它们是以一种(主要)与渲染无关的方式定义的,所以如果你决定使用不同的渲染器,你不必重写材料。

以下属性和方法可以被所有其他材质类型继承(尽管它们可能有不同的默认值)。

属性 :

.alphaTest:Float

设置要在运行alpha测试时使用的alpha值。如果不透明度低于这个值,材质将不会被渲染。默认值为0。

.alphaToCoverage:Float

使alpha覆盖范围。只能在启用msaa的上下文中使用(意味着在创建渲染器时将antialias参数设置为true)。默认是假的。

.blendDst:Integer

混合的目的地。默认是OneMinusSrcAlphaFactor。请参阅所有可能值的目标因子常数。

材质的混合必须设置为customblend,这样才会有效果。

.blendDstAlpha:Integer

. blenddst的透明度。如果为空,则使用. blenddst值。默认为空。

方法:

EventDispatcher方法在这个类上可用。

.clone():Material

返回一个与此材料具有相同参数的新材料。

.copy(material : material):this

将参数从传递的材料复制到这个材料中。

.dispose():undefined

这就处理了材料。材料的纹理不会被丢弃。这些需要被纹理处理。

.onBeforeCompile(shader : Shader, renderer : WebGLRenderer ):undefined

一个可选的回调函数,在着色器程序编译之前立即执行。这个函数被shader源代码作为参数调用。用于修改内置材质。

等等,很多属性方法,这里不再一一介绍

可到官网查看:three.js docs

相关注意说明:以下涉及代码都基于 Threejs   GitHub - mrdoob/three.js: JavaScript 3D Library.

二、各种材质说明

1、MeshBasicMaterial 基础网格材质

一个以简单着色(平面或线框)方式来绘制几何体的材质。这种材质不受光照的影响。

MeshBasicMaterial( parameters : Object )

parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。

属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。

2、MeshDepthMaterial 深度网格材质

一种按深度绘制几何体的材质。深度基于相机远近平面。白色最近,黑色最远。

3、MeshDistanceMaterial 距离网格材质

MeshDistanceMaterial 在内部用于使用PointLight来实现阴影映射。 也可以用于通过将MeshDistanceMaterial实例指定给Object3D.customDistanceMaterial,来自定义物体阴影投射。

下列示例演示了这一方法,以确保物体的透明部分不投射阴影。

 

4、MeshLambertMaterial Lambert网格材质

一种非光泽表面的材质,没有镜面高光。

该材质使用基于非物理的Lambertian模型来计算反射率。 这可以很好地模拟一些表面(例如未经处理的木材或石材),但不能模拟具有镜面高光的光泽表面(例如涂漆木材)。

使用Gouraud着色模型计算着色。这将计算每个顶点的着色 (即在vertex shader中)并在多边形的面上插入结果。

由于反射率和光照模型的简单性,MeshPhongMaterial,MeshStandardMaterial或者MeshPhysicalMaterial 上使用这种材质时会以一些图形精度为代价,得到更高的性能。

5、MeshMatcapMaterial

MeshMatcapMaterial 由一个材质捕捉(MatCap,或光照球(Lit Sphere))纹理所定义,其编码了材质的颜色与明暗。

由于mapcap图像文件编码了烘焙过的光照,因此MeshMatcapMaterial 不对灯光作出反应。 它将会投射阴影到一个接受阴影的物体上(and shadow clipping works),但不会产生自身阴影或是接受阴影。

6、MeshNormalMaterial 法线网格材质

一种把法向量映射到RGB颜色的材质。

7、MeshPhongMaterial Phong网格材质

一种用于具有镜面高光的光泽表面的材质。

该材质使用非物理的Blinn-Phong模型来计算反射率。 与MeshLambertMaterial中使用的Lambertian模型不同,该材质可以模拟具有镜面高光的光泽表面(例如涂漆木材)。

使用Phong着色模型计算着色时,会计算每个像素的阴影(在fragment shader, AKA pixel shader中),与MeshLambertMaterial使用的Gouraud模型相比,该模型的结果更准确,但代价是牺牲一些性能。 MeshStandardMaterial和MeshPhysicalMaterial也使用这个着色模型。

在MeshStandardMaterial或MeshPhysicalMaterial上使用此材质时,性能通常会更高 ,但会牺牲一些图形精度。

8、MeshPhysicalMaterial 物理网格材质

MeshStandardMaterial的扩展,提供了更高级的基于物理的渲染属性:

  • Clearcoat: 有些类似于车漆,碳纤,被水打湿的表面的材质需要在面上再增加一个透明的,具有一定反光特性的面。而且这个面说不定有一定的起伏与粗糙度。Clearcoat可以在不需要重新创建一个透明的面的情况下做到类似的效果。
  • 基于物理的透明度:.opacity属性有一些限制:在透明度比较高的时候,反射也随之减少。使用基于物理的透光性.transmission属性可以让一些很薄的透明表面,例如玻璃,变得更真实一些。
  • 高级光线反射: 为非金属材质提供了更多更灵活的光线反射。

物理网格材质使用了更复杂的着色器功能,所以在每个像素的渲染都要比three.js中的其他材质更费性能,大部分的特性是默认关闭的,需要手动开启,每开启一项功能在开启的时候才会更耗性能。请注意,为获得最佳效果,您在使用此材质时应始终指定environment map。

9、MeshStandardMaterial 标准网格材质

一种基于物理的标准材质,使用Metallic-Roughness工作流程。

基于物理的渲染(PBR)最近已成为许多3D应用程序的标准,例如UnityUnreal3D Studio Max

这种方法与旧方法的不同之处在于,不使用近似值来表示光与表面的相互作用,而是使用物理上正确的模型。 我们的想法是,不是在特定照明下调整材质以使其看起来很好,而是可以创建一种材质,能够“正确”地应对所有光照场景。

在实践中,该材质提供了比MeshLambertMaterial 或MeshPhongMaterial 更精确和逼真的结果,代价是计算成本更高。

计算着色的方式与MeshPhongMaterial相同,都使用Phong着色模型, 这会计算每个像素的阴影(即在fragment shader, AKA pixel shader中), 与MeshLambertMaterial使用的Gouraud模型相比,该模型的结果更准确,但代价是牺牲一些性能。

请注意,为获得最佳效果,您在使用此材质时应始终指定environment map。

有关PBR概念的非技术性介绍以及如何设置PBR材质,请查看marmoset成员的这些文章:

在 three.js(以及其他大多数PBR系统)中使用方法的技术细节, 可以在Brent Burley撰写的paper from Disney (pdf) 中查看。

10、MeshToonMaterial 卡通网格材质

A material implementing toon shading.

11、PointsMaterial 点材质

Points使用的默认材质。

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - buffergeometry - particles</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">
	</head>
	<body>

		<div id="container"></div>
		<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - buffergeometry - particles</div>

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

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

		<script type="module">

			import * as THREE from 'three';

			import Stats from './jsm/libs/stats.module.js';

			let container, stats;

			let camera, scene, renderer;

			let points;

			init();
			animate();

			function init() {

				container = document.getElementById( 'container' );

				//

				camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 5, 3500 );
				camera.position.z = 2750;

				scene = new THREE.Scene();
				scene.background = new THREE.Color( 0x050505 );
				scene.fog = new THREE.Fog( 0x050505, 2000, 3500 );

				//

				const particles = 500000;

				const geometry = new THREE.BufferGeometry();

				const positions = [];
				const colors = [];

				const color = new THREE.Color();

				const n = 1000, n2 = n / 2; // particles spread in the cube

				for ( let i = 0; i < particles; i ++ ) {

					// positions

					const x = Math.random() * n - n2;
					const y = Math.random() * n - n2;
					const z = Math.random() * n - n2;

					positions.push( x, y, z );

					// colors

					const vx = ( x / n ) + 0.5;
					const vy = ( y / n ) + 0.5;
					const vz = ( z / n ) + 0.5;

					color.setRGB( vx, vy, vz );

					colors.push( color.r, color.g, color.b );

				}

				geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
				geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );

				geometry.computeBoundingSphere();

				//

				const material = new THREE.PointsMaterial( { size: 15, vertexColors: true } );

				points = new THREE.Points( geometry, material );
				scene.add( points );

				//

				renderer = new THREE.WebGLRenderer();
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );

				container.appendChild( renderer.domElement );

				//

				stats = new Stats();
				container.appendChild( stats.dom );

				//

				window.addEventListener( 'resize', onWindowResize );

			}

			function onWindowResize() {

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

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

			}

			//

			function animate() {

				requestAnimationFrame( animate );

				render();
				stats.update();

			}

			function render() {

				const time = Date.now() * 0.001;

				points.rotation.x = time * 0.25;
				points.rotation.y = time * 0.5;

				renderer.render( scene, camera );

			}

		</script>

	</body>
</html>

12、RawShaderMaterial 原始着色器材质

此类的工作方式与ShaderMaterial类似,不同之处在于内置的uniforms和attributes的定义不会自动添加到GLSL shader代码中。

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - raw shader</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">
	</head>
	<body>

		<div id="container"></div>
		<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - raw shader demo</div>

		<script id="vertexShader" type="x-shader/x-vertex">

			precision mediump float;
			precision mediump int;

			uniform mat4 modelViewMatrix; // optional
			uniform mat4 projectionMatrix; // optional

			attribute vec3 position;
			attribute vec4 color;

			varying vec3 vPosition;
			varying vec4 vColor;

			void main()	{

				vPosition = position;
				vColor = color;

				gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

			}

		</script>

		<script id="fragmentShader" type="x-shader/x-fragment">

			precision mediump float;
			precision mediump int;

			uniform float time;

			varying vec3 vPosition;
			varying vec4 vColor;

			void main()	{

				vec4 color = vec4( vColor );
				color.r += sin( vPosition.x * 10.0 + time ) * 0.5;

				gl_FragColor = color;

			}

		</script>

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

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

		<script type="module">

			import * as THREE from 'three';

			import Stats from './jsm/libs/stats.module.js';

			let container, stats;

			let camera, scene, renderer;

			init();
			animate();

			function init() {

				container = document.getElementById( 'container' );

				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 10 );
				camera.position.z = 2;

				scene = new THREE.Scene();
				scene.background = new THREE.Color( 0x101010 );

				// geometry
				// nr of triangles with 3 vertices per triangle
				const vertexCount = 200 * 3;

				const geometry = new THREE.BufferGeometry();

				const positions = [];
				const colors = [];

				for ( let i = 0; i < vertexCount; i ++ ) {

					// adding x,y,z
					positions.push( Math.random() - 0.5 );
					positions.push( Math.random() - 0.5 );
					positions.push( Math.random() - 0.5 );

					// adding r,g,b,a
					colors.push( Math.random() * 255 );
					colors.push( Math.random() * 255 );
					colors.push( Math.random() * 255 );
					colors.push( Math.random() * 255 );

				}

				const positionAttribute = new THREE.Float32BufferAttribute( positions, 3 );
				const colorAttribute = new THREE.Uint8BufferAttribute( colors, 4 );

				colorAttribute.normalized = true; // this will map the buffer values to 0.0f - +1.0f in the shader

				geometry.setAttribute( 'position', positionAttribute );
				geometry.setAttribute( 'color', colorAttribute );

				// material

				const material = new THREE.RawShaderMaterial( {

					uniforms: {
						time: { value: 1.0 }
					},
					vertexShader: document.getElementById( 'vertexShader' ).textContent,
					fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
					side: THREE.DoubleSide,
					transparent: true

				} );

				const mesh = new THREE.Mesh( geometry, material );
				scene.add( mesh );

				renderer = new THREE.WebGLRenderer();
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				container.appendChild( renderer.domElement );

				stats = new Stats();
				container.appendChild( stats.dom );

				window.addEventListener( 'resize', onWindowResize );

			}

			function onWindowResize() {

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

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

			}

			//

			function animate() {

				requestAnimationFrame( animate );

				render();
				stats.update();

			}

			function render() {

				const time = performance.now();

				const object = scene.children[ 0 ];

				object.rotation.y = time * 0.0005;
				object.material.uniforms.time.value = time * 0.005;

				renderer.render( scene, camera );

			}

		</script>

	</body>
</html>

13、ShaderMaterial 着色器材质

使用自定义shader渲染的材质。 shader是一个用GLSL编写的小程序 ,在GPU上运行。 您可能需要使用自定义shader,如果你要:

  • 要实现内置 materials 之外的效果。
  • 将许多对象组合成单个BufferGeometry以提高性能。

使用ShaderMaterial时需要注意以下注意事项:

  • ShaderMaterial 只有使用 WebGLRenderer 才可以绘制正常, 因为 vertexShaderfragmentShader 属性中GLSL代码必须使用WebGL来编译并运行在GPU中。
  • 从 THREE r72开始,不再支持在ShaderMaterial中直接分配属性。 必须使用 BufferGeometry实例,使用BufferAttribute实例来定义自定义属性。
  • 从 THREE r77开始,WebGLRenderTarget 或 WebGLCubeRenderTarget 实例不再被用作uniforms。 必须使用它们的texture 属性。
  • 内置attributes和uniforms与代码一起传递到shaders。 如果您不希望WebGLProgram向shader代码添加任何内容,则可以使用RawShaderMaterial而不是此类。
  • 您可以使用指令#pragma unroll_loop_start,#pragma unroll_loop_end 以便通过shader预处理器在GLSL中展开for循环。 该指令必须放在循环的正上方。循环格式必须与定义的标准相对应。
    • 循环必须标准化normalized
    • 循环变量必须是i
    • The value UNROLLED_LOOP_INDEX will be replaced with the explicity value of i for the given iteration and can be used in preprocessor statements.

 

<!DOCTYPE html>
<html lang="en">
	<head>
	<title>three.js webgl - buffergeometry - selective - draw</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">

	<script type="x-shader/x-vertex" id="vertexshader">
		attribute float visible;
		varying float vVisible;
		attribute vec3 vertColor;
		varying vec3 vColor;

		void main() {

			vColor = vertColor;
			vVisible = visible;
			gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

		}
	</script>
	<script type="x-shader/x-fragment" id="fragmentshader">
		varying float vVisible;
		varying vec3 vColor;

		void main() {

			if ( vVisible > 0.0 ) {

				gl_FragColor = vec4( vColor, 1.0 );

			} else {

				discard;

			}

		}
	</script>
	</head>
	<body>
		<div id="info">
			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> buffergeometry - selective - draw
			<div id="title"></div>
			<div id="ui"><a href="#" id="hideLines">CULL SOME LINES</a> - <a href="#" id="showAllLines">SHOW ALL LINES</a></div>
		</div>

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

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

		<script type="module">

			import * as THREE from 'three';

			import Stats from './jsm/libs/stats.module.js';

			let camera, scene, renderer, stats;
			let geometry, mesh;
			const numLat = 100;
			const numLng = 200;
			let numLinesCulled = 0;

			init();
			animate();

			function init() {

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

				scene = new THREE.Scene();

				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.01, 10 );
				camera.position.z = 3.5;

				scene.add( new THREE.AmbientLight( 0x444444 ) );

				stats = new Stats();
				document.body.appendChild( stats.dom );

				window.addEventListener( 'resize', onWindowResize );

				addLines( 1.0 );

				const hideLinesButton = document.getElementById( 'hideLines' );
				hideLinesButton.addEventListener( 'click', hideLines );

				const showAllLinesButton = document.getElementById( 'showAllLines' );
				showAllLinesButton.addEventListener( 'click', showAllLines );

			}

			function addLines( radius ) {

				geometry = new THREE.BufferGeometry();
				const linePositions = new Float32Array( numLat * numLng * 3 * 2 );
				const lineColors = new Float32Array( numLat * numLng * 3 * 2 );
				const visible = new Float32Array( numLat * numLng * 2 );

				for ( let i = 0; i < numLat; ++ i ) {

					for ( let j = 0; j < numLng; ++ j ) {

						const lat = ( Math.random() * Math.PI ) / 50.0 + i / numLat * Math.PI;
						const lng = ( Math.random() * Math.PI ) / 50.0 + j / numLng * 2 * Math.PI;

						const index = i * numLng + j;

						linePositions[ index * 6 + 0 ] = 0;
						linePositions[ index * 6 + 1 ] = 0;
						linePositions[ index * 6 + 2 ] = 0;
						linePositions[ index * 6 + 3 ] = radius * Math.sin( lat ) * Math.cos( lng );
						linePositions[ index * 6 + 4 ] = radius * Math.cos( lat );
						linePositions[ index * 6 + 5 ] = radius * Math.sin( lat ) * Math.sin( lng );

						const color = new THREE.Color( 0xffffff );

						color.setHSL( lat / Math.PI, 1.0, 0.2 );
						lineColors[ index * 6 + 0 ] = color.r;
						lineColors[ index * 6 + 1 ] = color.g;
						lineColors[ index * 6 + 2 ] = color.b;

						color.setHSL( lat / Math.PI, 1.0, 0.7 );
						lineColors[ index * 6 + 3 ] = color.r;
						lineColors[ index * 6 + 4 ] = color.g;
						lineColors[ index * 6 + 5 ] = color.b;

						// non-0 is visible
						visible[ index * 2 + 0 ] = 1.0;
						visible[ index * 2 + 1 ] = 1.0;

					}

				}

				geometry.setAttribute( 'position', new THREE.BufferAttribute( linePositions, 3 ) );
				geometry.setAttribute( 'vertColor', new THREE.BufferAttribute( lineColors, 3 ) );
				geometry.setAttribute( 'visible', new THREE.BufferAttribute( visible, 1 ) );

				geometry.computeBoundingSphere();

				const shaderMaterial = new THREE.ShaderMaterial( {

					vertexShader: document.getElementById( 'vertexshader' ).textContent,
					fragmentShader: document.getElementById( 'fragmentshader' ).textContent
				} );

				mesh = new THREE.LineSegments( geometry, shaderMaterial );
				scene.add( mesh );

				updateCount();

			}

			function updateCount() {

				const str = '1 draw call, ' + numLat * numLng + ' lines, ' + numLinesCulled + ' culled (<a target="_blank" href="http://callum.com">author</a>)';
				document.getElementById( 'title' ).innerHTML = str.replace( /\B(?=(\d{3})+(?!\d))/g, ',' );

			}

			function hideLines() {

				for ( let i = 0; i < geometry.attributes.visible.array.length; i += 2 ) {

					if ( Math.random() > 0.75 ) {

						if ( geometry.attributes.visible.array[ i + 0 ] ) {

							++ numLinesCulled;

						}

						geometry.attributes.visible.array[ i + 0 ] = 0;
						geometry.attributes.visible.array[ i + 1 ] = 0;

					}

				}

				geometry.attributes.visible.needsUpdate = true;

				updateCount();

			}

			function showAllLines() {

				numLinesCulled = 0;

				for ( let i = 0; i < geometry.attributes.visible.array.length; i += 2 ) {

					geometry.attributes.visible.array[ i + 0 ] = 1;
					geometry.attributes.visible.array[ i + 1 ] = 1;

				}

				geometry.attributes.visible.needsUpdate = true;

				updateCount();

			}

			function onWindowResize() {

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

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

			}

			function animate() {

				requestAnimationFrame( animate );

				const time = Date.now() * 0.001;

				mesh.rotation.x = time * 0.25;
				mesh.rotation.y = time * 0.5;

				stats.update();
				renderer.render( scene, camera );

			}

		</script>
	</body>
</html>

14、ShadowMaterial 阴影材质

此材质可以接收阴影,但在其他方面完全透明。

15、SpriteMaterial 点精灵材质

一种使用Sprite的材质。

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - sprites</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">
	</head>

	<body>
		<div id="info">
			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - sprites
		</div>

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

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

		<script type="module">

			import * as THREE from 'three';

			let camera, scene, renderer;
			let cameraOrtho, sceneOrtho;

			let spriteTL, spriteTR, spriteBL, spriteBR, spriteC;

			let mapC;

			let group;

			init();
			animate();

			function init() {

				const width = window.innerWidth;
				const height = window.innerHeight;

				camera = new THREE.PerspectiveCamera( 60, width / height, 1, 2100 );
				camera.position.z = 1500;

				cameraOrtho = new THREE.OrthographicCamera( - width / 2, width / 2, height / 2, - height / 2, 1, 10 );
				cameraOrtho.position.z = 10;

				scene = new THREE.Scene();
				scene.fog = new THREE.Fog( 0x000000, 1500, 2100 );

				sceneOrtho = new THREE.Scene();

				// create sprites

				const amount = 200;
				const radius = 500;

				const textureLoader = new THREE.TextureLoader();

				textureLoader.load( 'textures/sprite0.png', createHUDSprites );
				const mapB = textureLoader.load( 'textures/sprite1.png' );
				mapC = textureLoader.load( 'textures/sprite2.png' );

				group = new THREE.Group();

				const materialC = new THREE.SpriteMaterial( { map: mapC, color: 0xffffff, fog: true } );
				const materialB = new THREE.SpriteMaterial( { map: mapB, color: 0xffffff, fog: true } );

				for ( let a = 0; a < amount; a ++ ) {

					const x = Math.random() - 0.5;
					const y = Math.random() - 0.5;
					const z = Math.random() - 0.5;

					let material;

					if ( z < 0 ) {

						material = materialB.clone();

					} else {

						material = materialC.clone();
						material.color.setHSL( 0.5 * Math.random(), 0.75, 0.5 );
						material.map.offset.set( - 0.5, - 0.5 );
						material.map.repeat.set( 2, 2 );

					}

					const sprite = new THREE.Sprite( material );

					sprite.position.set( x, y, z );
					sprite.position.normalize();
					sprite.position.multiplyScalar( radius );

					group.add( sprite );

				}

				scene.add( group );

				// renderer

				renderer = new THREE.WebGLRenderer();
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.autoClear = false; // To allow render overlay on top of sprited sphere

				document.body.appendChild( renderer.domElement );

				//

				window.addEventListener( 'resize', onWindowResize );

			}

			function createHUDSprites( texture ) {

				const material = new THREE.SpriteMaterial( { map: texture } );

				const width = material.map.image.width;
				const height = material.map.image.height;

				spriteTL = new THREE.Sprite( material );
				spriteTL.center.set( 0.0, 1.0 );
				spriteTL.scale.set( width, height, 1 );
				sceneOrtho.add( spriteTL );

				spriteTR = new THREE.Sprite( material );
				spriteTR.center.set( 1.0, 1.0 );
				spriteTR.scale.set( width, height, 1 );
				sceneOrtho.add( spriteTR );

				spriteBL = new THREE.Sprite( material );
				spriteBL.center.set( 0.0, 0.0 );
				spriteBL.scale.set( width, height, 1 );
				sceneOrtho.add( spriteBL );

				spriteBR = new THREE.Sprite( material );
				spriteBR.center.set( 1.0, 0.0 );
				spriteBR.scale.set( width, height, 1 );
				sceneOrtho.add( spriteBR );

				spriteC = new THREE.Sprite( material );
				spriteC.center.set( 0.5, 0.5 );
				spriteC.scale.set( width, height, 1 );
				sceneOrtho.add( spriteC );

				updateHUDSprites();

			}

			function updateHUDSprites() {

				const width = window.innerWidth / 2;
				const height = window.innerHeight / 2;

				spriteTL.position.set( - width, height, 1 ); // top left
				spriteTR.position.set( width, height, 1 ); // top right
				spriteBL.position.set( - width, - height, 1 ); // bottom left
				spriteBR.position.set( width, - height, 1 ); // bottom right
				spriteC.position.set( 0, 0, 1 ); // center

			}

			function onWindowResize() {

				const width = window.innerWidth;
				const height = window.innerHeight;

				camera.aspect = width / height;
				camera.updateProjectionMatrix();

				cameraOrtho.left = - width / 2;
				cameraOrtho.right = width / 2;
				cameraOrtho.top = height / 2;
				cameraOrtho.bottom = - height / 2;
				cameraOrtho.updateProjectionMatrix();

				updateHUDSprites();

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

			}

			function animate() {

				requestAnimationFrame( animate );
				render();

			}

			function render() {

				const time = Date.now() / 1000;

				for ( let i = 0, l = group.children.length; i < l; i ++ ) {

					const sprite = group.children[ i ];
					const material = sprite.material;
					const scale = Math.sin( time + sprite.position.x * 0.01 ) * 0.3 + 1.0;

					let imageWidth = 1;
					let imageHeight = 1;

					if ( material.map && material.map.image && material.map.image.width ) {

						imageWidth = material.map.image.width;
						imageHeight = material.map.image.height;

					}

					sprite.material.rotation += 0.1 * ( i / l );
					sprite.scale.set( scale * imageWidth, scale * imageHeight, 1.0 );

					if ( material.map !== mapC ) {

						material.opacity = Math.sin( time + sprite.position.x * 0.01 ) * 0.4 + 0.6;

					}

				}

				group.rotation.x = time * 0.5;
				group.rotation.y = time * 0.75;
				group.rotation.z = time * 1.0;

				renderer.clear();
				renderer.render( scene, camera );
				renderer.clearDepth();
				renderer.render( sceneOrtho, cameraOrtho );

			}

		</script>
	</body>
</html>

16、LineBasicMaterial 基础线条材质

一种用于绘制线框样式几何体的材质。

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - buffergeometry - lines</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">
	</head>
	<body>

		<div id="container"></div>
		<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - buffergeometry - lines</div>

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

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

		<script type="module">

			import * as THREE from 'three';

			import Stats from './jsm/libs/stats.module.js';

			let container, stats, clock;

			let camera, scene, renderer;

			let line;

			const segments = 10000;
			const r = 800;
			let t = 0;

			init();
			animate();

			function init() {

				container = document.getElementById( 'container' );

				//

				camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 4000 );
				camera.position.z = 2750;

				scene = new THREE.Scene();

				clock = new THREE.Clock();

				const geometry = new THREE.BufferGeometry();
				const material = new THREE.LineBasicMaterial( { vertexColors: true } );

				const positions = [];
				const colors = [];

				for ( let i = 0; i < segments; i ++ ) {

					const x = Math.random() * r - r / 2;
					const y = Math.random() * r - r / 2;
					const z = Math.random() * r - r / 2;

					// positions

					positions.push( x, y, z );

					// colors

					colors.push( ( x / r ) + 0.5 );
					colors.push( ( y / r ) + 0.5 );
					colors.push( ( z / r ) + 0.5 );

				}

				geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
				geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
				generateMorphTargets( geometry );

				geometry.computeBoundingSphere();

				line = new THREE.Line( geometry, material );
				scene.add( line );

				//

				renderer = new THREE.WebGLRenderer();
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.outputEncoding = THREE.sRGBEncoding;

				container.appendChild( renderer.domElement );

				//

				stats = new Stats();
				container.appendChild( stats.dom );

				//

				window.addEventListener( 'resize', onWindowResize );

			}

			function onWindowResize() {

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

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

			}

			//

			function animate() {

				requestAnimationFrame( animate );

				render();
				stats.update();

			}

			function render() {

				const delta = clock.getDelta();
				const time = clock.getElapsedTime();

				line.rotation.x = time * 0.25;
				line.rotation.y = time * 0.5;

				t += delta * 0.5;
				line.morphTargetInfluences[ 0 ] = Math.abs( Math.sin( t ) );

				renderer.render( scene, camera );

			}

			function generateMorphTargets( geometry ) {

				const data = [];

				for ( let i = 0; i < segments; i ++ ) {

					const x = Math.random() * r - r / 2;
					const y = Math.random() * r - r / 2;
					const z = Math.random() * r - r / 2;

					data.push( x, y, z );

				}

				const morphTarget = new THREE.Float32BufferAttribute( data, 3 );
				morphTarget.name = 'target1';

				geometry.morphAttributes.position = [ morphTarget ];

			}

		</script>

	</body>
</html>

17、LineDashedMaterial 虚线材质

一种用于绘制虚线样式几何体的材质。

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - dashed lines</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">
	</head>

	<body>
		<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - dashed lines example</div>
		<div id="container"></div>

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

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

		<script type="module">

			import * as THREE from 'three';

			import Stats from './jsm/libs/stats.module.js';

			import * as GeometryUtils from './jsm/utils/GeometryUtils.js';

			let renderer, scene, camera, stats;
			const objects = [];

			const WIDTH = window.innerWidth, HEIGHT = window.innerHeight;

			init();
			animate();

			function init() {

				camera = new THREE.PerspectiveCamera( 60, WIDTH / HEIGHT, 1, 200 );
				camera.position.z = 150;

				scene = new THREE.Scene();
				scene.background = new THREE.Color( 0x111111 );
				scene.fog = new THREE.Fog( 0x111111, 150, 200 );

				const subdivisions = 6;
				const recursion = 1;

				const points = GeometryUtils.hilbert3D( new THREE.Vector3( 0, 0, 0 ), 25.0, recursion, 0, 1, 2, 3, 4, 5, 6, 7 );
				const spline = new THREE.CatmullRomCurve3( points );

				const samples = spline.getPoints( points.length * subdivisions );
				const geometrySpline = new THREE.BufferGeometry().setFromPoints( samples );

				const line = new THREE.Line( geometrySpline, new THREE.LineDashedMaterial( { color: 0xffffff, dashSize: 1, gapSize: 0.5 } ) );
				line.computeLineDistances();

				objects.push( line );
				scene.add( line );

				const geometryBox = box( 50, 50, 50 );

				const lineSegments = new THREE.LineSegments( geometryBox, new THREE.LineDashedMaterial( { color: 0xffaa00, dashSize: 3, gapSize: 1 } ) );
				lineSegments.computeLineDistances();

				objects.push( lineSegments );
				scene.add( lineSegments );

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( WIDTH, HEIGHT );

				const container = document.getElementById( 'container' );
				container.appendChild( renderer.domElement );

				stats = new Stats();
				container.appendChild( stats.dom );

				//

				window.addEventListener( 'resize', onWindowResize );

			}

			function box( width, height, depth ) {

				width = width * 0.5,
				height = height * 0.5,
				depth = depth * 0.5;

				const geometry = new THREE.BufferGeometry();
				const position = [];

				position.push(
					- width, - height, - depth,
					- width, height, - depth,

					- width, height, - depth,
					width, height, - depth,

					width, height, - depth,
					width, - height, - depth,

					width, - height, - depth,
					- width, - height, - depth,

					- width, - height, depth,
					- width, height, depth,

					- width, height, depth,
					width, height, depth,

					width, height, depth,
					width, - height, depth,

					width, - height, depth,
					- width, - height, depth,

					- width, - height, - depth,
					- width, - height, depth,

					- width, height, - depth,
					- width, height, depth,

					width, height, - depth,
					width, height, depth,

					width, - height, - depth,
					width, - height, depth
				 );

				geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( position, 3 ) );

				return geometry;

			}

			function onWindowResize() {

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

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

			}

			function animate() {

				requestAnimationFrame( animate );

				render();
				stats.update();

			}

			function render() {

				const time = Date.now() * 0.001;

				scene.traverse( function ( object ) {

					if ( object.isLine ) {

						object.rotation.x = 0.25 * time;
						object.rotation.y = 0.25 * time;

					}

				} );

				renderer.render( scene, camera );

			}

	</script>

</body>

</html>

猜你喜欢

转载自blog.csdn.net/u014361280/article/details/124416631