threejs 粒子系统和材质贴图

Posted qianbo_insist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了threejs 粒子系统和材质贴图相关的知识,希望对你有一定的参考价值。

例子系统

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - buffer geometry custom attributes - particles</title>
		<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>

材质贴图

高光网格材质 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(`$assetPathskybox3_`).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(`$assetPathTexturesCom_Orange_512_albedo.jpg`);
  const normalMap = new THREE.TextureLoader().load(`$assetPathTexturesCom_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( 以上是关于threejs 粒子系统和材质贴图的主要内容,如果未能解决你的问题,请参考以下文章

threejs里怎么解决网格贴图闪烁

ThreeJS——精灵模型实现下雨场景效果

unity3d 4.3.1,怎么k粒子系统材质的透明度

Unity3d-Particle System系统的学习

threejs学习day5:网格

ThreeJS——创建纹理贴图