• threejs 粒子系统和材质贴图


    例子系统

    在这里插入图片描述

    DOCTYPE html>
    <html lang="en">
    	<head>
    		<title>three.js webgl - buffer geometry custom attributes - particlestitle>
    		<meta charset="utf-8">
    		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    		<style>
    			body {
    				color: #ffffff;
    				background-color: #000000;
    				margin: 0px;
    				overflow: hidden;
    			}
    			#info {
    				position: absolute;
    				top: 0px;
    				width: 100%;
    				padding: 5px;
    				font-family: Monospace;
    				font-size: 13px;
    				text-align: center;
    				font-weight: bold;
    			}
    			a {
    				color: #fff;
    			}
    		style>
    	head>
     
    	<body>
    		<div id="container">div>
    		<script src="../build/three.js">script>
    		<script type="x-shader/x-vertex" id="vertexshader">
     
    			attribute float size;
    			attribute vec3 customColor;
     
    			varying vec3 vColor;
     
    			void main() {
     
    				vColor = customColor;
     
    				vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
     
    				gl_PointSize = size * ( 300.0 / mvPosition.x );
     
    				gl_Position = projectionMatrix * mvPosition;
     
    			}
     
    		script>
     
    		<script type="x-shader/x-fragment" id="fragmentshader">
     
    			uniform sampler2D texture;
     
    			varying vec3 vColor;
     
    			void main() {
    				gl_FragColor = vec4( vColor, 1.0 );
    				gl_FragColor = gl_FragColor * texture2D( texture, gl_PointCoord );
     
    			}
     
    		script>
     
    		<script>
     
    		var renderer, scene, camera, stats;
     
    		var particleSystem, uniforms, geometry;
     
    		var particles = 200;
     
    		var WIDTH = window.innerWidth;
    		var HEIGHT = window.innerHeight;
     
    		init();
    		animate();
     
    		function init() {
     
    			camera = new THREE.PerspectiveCamera( 40, WIDTH / HEIGHT, 1, 10000 );
    			camera.position.z = 500;
    			scene = new THREE.Scene();
    			uniforms = {
    				texture:   { value: new THREE.TextureLoader().load( "textures/sprites/spark1.png" ) }
    			};
    			var shaderMaterial = new THREE.ShaderMaterial( {
     
    				uniforms:       uniforms,
    				vertexShader:   document.getElementById( 'vertexshader' ).textContent,
    				fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
    				transparent:    true
    			});
     
    			var radius = 400;
    			var geometry = new THREE.BufferGeometry();
    			var positions = new Float32Array( particles * 3 );
    			var colors = new Float32Array( particles * 3 );
    			var sizes = new Float32Array( particles );
    			for ( var i = 0, i3 = 0; i < particles; i ++, i3 += 3 ) {
    				positions[ i3 + 0 ] = ( Math.random() * 2 - 1 ) * radius;
    				positions[ i3 + 1 ] = ( Math.random() * 2 - 1 ) * radius;
    				positions[ i3 + 2 ] = 0;
    				colors[ i3 + 0 ] = 1;
    				colors[ i3 + 1 ] = 1;
    				colors[ i3 + 2 ] = 1;
    				sizes[ i ] = 10;
    			}
    			geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
    			geometry.addAttribute( 'customColor', new THREE.BufferAttribute( colors, 3 ) );
    			geometry.addAttribute( 'size', new THREE.BufferAttribute( sizes, 1 ) );
    			particleSystem = new THREE.Points( geometry, shaderMaterial );
    			scene.add( particleSystem );
    			renderer = new THREE.WebGLRenderer();
    			renderer.setPixelRatio( window.devicePixelRatio );
    			renderer.setSize( WIDTH, HEIGHT );
     
    			var container = document.getElementById( 'container' );
    			container.appendChild( renderer.domElement );
     
    			window.addEventListener( 'resize', onWindowResize, false );
     
    		}
     
    		function onWindowResize() {
    			camera.aspect = window.innerWidth / window.innerHeight;
    			camera.updateProjectionMatrix();
    			renderer.setSize( window.innerWidth, window.innerHeight );
    		}
     
    		function animate() {
    			requestAnimationFrame( animate );
    			renderer.render( scene, camera );
     
    		}
     
    	script>
     
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143

    材质贴图

    高光网格材质 MeshPhongMaterial、标准网格材质MeshStandardMaterial、物理网格材质MeshPhysicalMaterial,次时代、PBR
    在这里插入图片描述

    次时代和 PBR

    如果你想展示一个三维场景,比如一辆轿车,首先需要 3D 美术建模和烘培,然后程序员通过 Three.js 引擎加载解析显示出来。

    对于3D美术来说烘培的时候有次时代、PBR 两种流程,这两种所谓的流程,对应的就是 Three.js 的高光网格材质 MeshPhongMaterial、基于物理的材质MeshStandardMaterial或MeshPhysicalMaterial。

    对于程序员而言,如果你不想深入理解什么是高光网格材质,什么是基于物理的材质,每种材质对应的着色器代码应该如何编写,这种情况下,你只需要会选择使用哪种网格材质就可以。

    如果3D美术烘培的时候是次时代流程,也就是贴图中你可以看到高光贴图 .specularMap,你需要选择高光网格材质 MeshPhongMaterial 渲染该模型,如果3D美术烘培的时候是PBR流程,也就是贴图中你可以看到金属度贴图 .metalnessMap 和粗糙度贴图 .roughnessMap,你需要选择基于物理的材质 MeshStandardMaterial或 MeshPhysicalMaterial 解析渲染。

    质感
    如果展示一个物体,需要很好的质感,比如轿车、珠宝等产品展示,可以让 3D 美术选择 PBR 流程烘培导出贴图,程序员使用基于物理的材质 MeshStandardMaterial 或 MeshPhysicalMaterial 进行解析渲染。

    var scene, camera, renderer, envMap, phongMaterial, standardMaterial, params1, params2, faceNormalsHelper, vertexNormalsHelper;
    
    init();
    
    function init(){
      const assetPath = 'https://your path/';
      
      envMap = new THREE.CubeTextureLoader().setPath(`${assetPath}skybox3_`).load([
        'px.jpg', 'nx.jpg', 
        'py.jpg', 'ny.jpg', 
        'pz.jpg', 'nz.jpg'
      ])
      scene = new THREE.Scene();
      scene.background = envMap;
      
      camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 );
      camera.position.set(0, 0, 10);
      
      const ambient = new THREE.HemisphereLight(0xffffbb, 0x080820);
      scene.add(ambient);
      
      const light = new THREE.DirectionalLight(0xFFFFFF, 3);
      light.position.set(0,4,4);
      scene.add(light);
      
      const albedoMap = new THREE.TextureLoader().load(`${assetPath}TexturesCom_Orange_512_albedo.jpg`);
      const normalMap = new THREE.TextureLoader().load(`${assetPath}TexturesCom_Orange_512_normal.jpg`);
      
      renderer = new THREE.WebGLRenderer();
      renderer.setSize( window.innerWidth, window.innerHeight );
      document.body.appendChild( renderer.domElement );
      
      const controls = new THREE.OrbitControls( camera, renderer.domElement );
      
      //Add meshes here
      const geometry = new THREE.SphereGeometry(1, 30, 20);
      phongMaterial = new THREE.MeshPhongMaterial();
      standardMaterial = new THREE.MeshStandardMaterial();
      
      const phongSphere = new THREE.Mesh( geometry, phongMaterial);
      const standardSphere = new THREE.Mesh( geometry, standardMaterial);
      
      for(let xPos=-3; xPos<3; xPos+=3){
        const sphereA = phongSphere.clone();
        sphereA.position.set(xPos, 1.5, 0);
        scene.add(sphereA);
        
        if (xPos==0){
          faceNormalsHelper = new THREE.FaceNormalsHelper(sphereA, 0.25);
          vertexNormalsHelper = new THREE.VertexNormalsHelper(sphereA, 0.25);
          faceNormalsHelper.visible = false;
          vertexNormalsHelper.visible = false;
          scene.add(faceNormalsHelper);
          scene.add(vertexNormalsHelper);
        }
        
        const sphereB = standardSphere.clone();
        sphereB.position.set(xPos, -1.5, 0);
        scene.add(sphereB);
      }
      
      params1 = {
        color: 0xffffff,
        envMap: 'none',
        reflectivity: 1,
        albedoMap: 'none',
        normalMap: 'none',
        normalScale: 1,
        shininess: 30,
        facetted: false,
        normals: 'none'
      }
      params2 = {
        color: 0xffffff,
        emissive: 0,
        envMap: 'none',
        reflectivity: 1,
        albedoMap: 'none',
        normalMap: 'none',
        normalScale: 1,
        roughness: 0.5,
        metalness: 0.5,
        facetted: false
      }
      
      const gui = new dat.gui.GUI();
      
      gui.add(params1, 'normals', ['none', 'face', 'vertex']).onChange(function(value){
        faceNormalsHelper.visible = false;
        vertexNormalsHelper.visible = false;
        phongMaterial.wireframe = false;
        switch(value){
          case 'face':
            faceNormalsHelper.visible = true;
            phongMaterial.wireframe = true;
            break;
          case 'vertex':
            vertexNormalsHelper.visible = true;
            phongMaterial.wireframe = true;
            break;
        }
      });
      const f1 = gui.addFolder('Phong Material');
      f1.addColor(params1, 'color').onChange( function() { phongMaterial.color.set( params1.color ); } );
      f1.add(params1, 'envMap', ['none', 'cathedral']).onChange( function(){
        switch (params1.envMap){
          case 'cathedral':
            phongMaterial.envMap = envMap;
            break;
          default:
            phongMaterial.envMap = null;
            break;
        }
        phongMaterial.needsUpdate = true;
      });
      f1.add(params1, 'reflectivity').min(0).max(1).step(0.01).onChange( function(){ phongMaterial.reflectivity = params1.reflectivity });
      f1.open();
      f1.add(params1, 'albedoMap', ['none', 'orange']).onChange( function(value){
        switch (value){
          case 'orange':
            phongMaterial.map = albedoMap;
            break;
          default:
            phongMaterial.map = null;
            break;
        }
        phongMaterial.needsUpdate = true;
      });
      f1.add(params1, 'normalMap', ['none', 'dimples']).onChange( function(value){
        switch (value){
          case 'dimples':
            phongMaterial.normalMap = normalMap;
            break;
          default:
            phongMaterial.normalMap = null;
            break;
        }
        phongMaterial.needsUpdate = true;
      });
      f1.add(params1, 'normalScale').min(0).max(1).step(0.01).onChange( function(value){ phongMaterial.normalScale.x = value;
    phongMaterial.normalScale.y = value;                                });
      f1.add(params1, 'shininess').min(0).max(255).step(0.5).onChange( function(value){ phongMaterial.shininess = value });
      f1.add(params1, 'facetted').onChange( function(value){ 
        phongMaterial.flatShading = value;
        phongMaterial.needsUpdate = true;
      });
      
      const f2 = gui.addFolder('Standard Material');
       f2.addColor(params2, 'color').onChange( function(value) { standardMaterial.color.set( value ); } );
      f2.addColor(params2, 'emissive').onChange( function(value) { standardMaterial.emissive.set( value ); } );
      f2.add(params2, 'envMap', ['none', 'cathedral']).onChange( function(value){
        switch (value){
          case 'cathedral':
            standardMaterial.envMap = envMap;
            break;
          default:
            standardMaterial.envMap = null;
            break;
        }
        standardMaterial.needsUpdate = true;
      });
      f2.add(params2, 'albedoMap', ['none', 'orange']).onChange( function(value){
        switch (value){
          case 'orange':
            standardMaterial.map = albedoMap;
            break;
          default:
            standardMaterial.map = null;
            break;
        }
        standardMaterial.needsUpdate = true;
      });
      f2.add(params2, 'normalMap', ['none', 'dimples']).onChange( function(value){
        switch (value){
          case 'dimples':
            standardMaterial.normalMap = normalMap;
            break;
          default:
            standardMaterial.normalMap = null;
            break;
        }
        standardMaterial.needsUpdate = true;
      });
      f2.add(params2, 'normalScale').min(0).max(1).step(0.01).onChange( function(value){ standardMaterial.normalScale.x = value;
    standardMaterial.normalScale.y = value;                                });
      f2.add(params2, 'roughness').min(0).max(1).step(0.01).onChange( function(value){ standardMaterial.roughness = value });
      f2.add(params2, 'metalness').min(0).max(1).step(0.01).onChange( function(value){ standardMaterial.metalness = value });
      f2.add(params1, 'facetted').onChange( function(value){ 
        standardMaterial.flatShading = value;
        standardMaterial.needsUpdate = true;
      });
      
      window.addEventListener( 'resize', resize, false);
      
      update();
    }
    
    function update(){
      requestAnimationFrame( update );
    	renderer.render( scene, camera );
    }
    
    function resize(){
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize( window.innerWidth, window.innerHeight );
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
  • 相关阅读:
    LeetCode算法心得——和为k的子数组(前缀和+HashMap)
    80W美团架构师整理分享出了Spring5企业级开发实战文档
    LAMP架构
    Java内存模型
    百度云下载不限速方式集合
    【社媒营销】Facebook速推帖子如何运作?值得吗?
    安装 paddlepaddle paddleocr库,避坑指南
    工程化分类面试题
    Mac mini 2018 VS MacBookPro M1Pro 代码打包编译速度对比
    使用C++11实现对象池
  • 原文地址:https://blog.csdn.net/qianbo042311/article/details/126570420