ThreeJs 学习之旅(十二)—Particle(粒子)

  • Post author:
  • Post category:其他


点(Points)

一个用于显示点的类。 由WebGLRenderer渲染的点使用

gl.POINTS

构造器

Points( geometry : Geometry, material : Material )

geometry —— (可选)是一个Geometry或者BufferGeometry的实例,默认值是一个新的BufferGeometry。

material —— (可选) 是一个对象,默认值是一个具有随机颜色的新的PointsMaterial。

点材质(PointsMaterial)

Points使用的默认材质。

PointsMaterial( parameters : Object )

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

属性color例外,其可以作为十六进制字符串传递,默认情况下为

0xffffff

(白色),内部调用Color.set(color)。

利用 形状 创建粒子

例:

const count=50
const particlesGeometry=new THREE.SphereBufferGeometry(1,32,32);
const particlesMaterial=new THREE.PointsMaterial();
particlesMaterial.size=0.2;
particlesMaterial.sizeAttenuation=false
const particles=new THREE.Points(particlesGeometry,particlesMaterial)
scene.add(particles)

.

sizeAttenuation

: Boolean

指定点的大小是否因相机深度而衰减。(仅限透视摄像头。)默认为true。

particlesMaterial.sizeAttenuation=true

利用数组创建粒子

const count=500
// const particlesGeometry=new THREE.SphereBufferGeometry(1,32,32);
const particlesGeometry=new THREE.BufferGeometry();
const positions=new Float32Array(count*3)
for(let i=0;i<count*3;i++){
  positions[i]=Math.random()
}
particlesGeometry.setAttribute("position",
  new THREE.BufferAttribute(positions,3)
)
 
const particlesMaterial=new THREE.PointsMaterial();
particlesMaterial.size=0.2;
particlesMaterial.sizeAttenuation=false
const particles=new THREE.Points(particlesGeometry,particlesMaterial)
scene.add(particles)

设置例子材质贴图

贴纸素材:

const textureLoader=new THREE.TextureLoader();
const textures=textureLoader.load('textures/particles/2.png')
const count=50000
// const particlesGeometry=new THREE.SphereBufferGeometry(1,32,32);
const particlesGeometry=new THREE.BufferGeometry();
const positions=new Float32Array(count*3)
for(let i=0;i<count*3;i++){
  positions[i]=(Math.random()-0.5)*10
}
particlesGeometry.setAttribute("position",
  new THREE.BufferAttribute(positions,3)
)
 
const particlesMaterial=new THREE.PointsMaterial();
particlesMaterial.size=0.2;
particlesMaterial.sizeAttenuation=true
particlesMaterial.color=new THREE.Color('red')
particlesMaterial.map=textures
const particles=new THREE.Points(particlesGeometry,particlesMaterial)
scene.add(particles)

问题 存在着边缘

加入alphMap

const textureLoader=new THREE.TextureLoader();
const textures=textureLoader.load('textures/particles/2.png')
particlesMaterial.transparent=true
particlesMaterial.alphaMap=textures

好了一些但是依然存在

.

alphaTest

: Float

设置运行alphaTest时要使用的alpha值。如果不透明度低于此值,则不会渲染材质。默认值为

0

particlesMaterial.alphaTest=0.001;

这样就好了很多

但是依然有边出现

 particlesMaterial.depthWrite=false;



.depthTest : Boolean

是否在渲染此材质时启用深度测试。默认为

true

.

depthWrite

: Boolean

渲染此材质是否对深度缓冲区有任何影响。默认为

true

这样就没有问题了

让每个小圈圈不同颜色

.

blending

: Blending

在使用此材质显示对象时要使用何种混合。

必须将其设置为CustomBlending才能使用自定义blendSrc, blendDst 或者 [page:Constant blendEquation]。 混合模式所有可能的取值请参阅constants。默认值为NormalBlending。

.

vertexColors

: Integer

是否使用顶点着色。默认值为THREE.NoColors。 其他选项有THREE.VertexColors 和 THREE.FaceColors。

const textureLoader=new THREE.TextureLoader();
const textures=textureLoader.load('textures/particles/2.png')
const count=5000
// const particlesGeometry=new THREE.SphereBufferGeometry(1,32,32);
const particlesGeometry=new THREE.BufferGeometry();
const positions=new Float32Array(count*3)
const colors=new Float32Array(count*3)
for(let i=0;i<count*3;i++){
  positions[i]=(Math.random()-0.5)*10
  colors[i]=Math.random()
}
particlesGeometry.setAttribute("position",
  new THREE.BufferAttribute(positions,3)
)
particlesGeometry.setAttribute("color",
new THREE.BufferAttribute(colors,3)
)
const particlesMaterial=new THREE.PointsMaterial();
particlesMaterial.size=0.2;
particlesMaterial.sizeAttenuation=true
particlesMaterial.color=new THREE.Color('#ff88cc')
particlesMaterial.transparent=true
particlesMaterial.alphaMap=textures
particlesMaterial.blending=THREE.AdditiveBlending
particlesMaterial.vertexColors=true
particlesMaterial.depthWrite=false;
const particles=new THREE.Points(particlesGeometry,particlesMaterial)
scene.add(particles)

粒子动画

.

needsUpdate

: Boolean

该标志位指明当前 attribute 已经被修改过,且需要再次送入 GPU 处理。当开发者改变了该队列的值,则标志位需要设置为 true。

const tick = () => {
  const elapsedTime = clock.getElapsedTime();

  for(let i=0;i<count;i++){
    const x=particlesGeometry.attributes.position.array[i*3]
    particlesGeometry.attributes.position.array[i*3+1]=Math.sin(elapsedTime+x)
  }
  

  
  particlesGeometry.attributes.position.needsUpdate=true
  // Update controls
  controls.update();

  // Render
  renderer.render(scene, camera);

  // Call tick again on the next frame
  window.requestAnimationFrame(tick);
};

今日完整代码

import "./style.css";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import * as dat from "dat.gui";
import ky from "kyouka";

/**
 * Base
 */
// Debug
const gui = new dat.GUI();

// Canvas
const canvas = document.querySelector("canvas.webgl");

// Scene
const scene = new THREE.Scene();

/**
 * Textures
 */
const textureLoader=new THREE.TextureLoader();
const textures=textureLoader.load('textures/particles/2.png')
const count=5000
// const particlesGeometry=new THREE.SphereBufferGeometry(1,32,32);
const particlesGeometry=new THREE.BufferGeometry();
const positions=new Float32Array(count*3)
const colors=new Float32Array(count*3)
for(let i=0;i<count*3;i++){
  positions[i]=(Math.random()-0.5)*10
  colors[i]=Math.random()
}
particlesGeometry.setAttribute("position",
  new THREE.BufferAttribute(positions,3)
)
particlesGeometry.setAttribute("color",
new THREE.BufferAttribute(colors,3)
)
const particlesMaterial=new THREE.PointsMaterial();
particlesMaterial.size=0.2;
particlesMaterial.sizeAttenuation=true
particlesMaterial.color=new THREE.Color('#ff88cc')
particlesMaterial.transparent=true
particlesMaterial.alphaMap=textures
particlesMaterial.blending=THREE.AdditiveBlending
particlesMaterial.vertexColors=true
particlesMaterial.depthWrite=false;
const particles=new THREE.Points(particlesGeometry,particlesMaterial)
scene.add(particles)

/**
 * Sizes
 */
const sizes = {
  width: window.innerWidth,
  height: window.innerHeight,
};

window.addEventListener("resize", () => {
  // Update sizes
  sizes.width = window.innerWidth;
  sizes.height = window.innerHeight;


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

  // Update renderer
  renderer.setSize(sizes.width, sizes.height);
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});

/**
 * Camera
 */
// Base camera
const camera = new THREE.PerspectiveCamera(
  75,
  sizes.width / sizes.height,
  0.1,
  100
);
camera.position.z = 3;
scene.add(camera);

// Controls
const controls = new OrbitControls(camera, canvas);
controls.enableDamping = true;

/**
 * Renderer
 */
const renderer = new THREE.WebGLRenderer({
  canvas: canvas,
});
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

/**
 * Animate
 */
const clock = new THREE.Clock();

const tick = () => {
  const elapsedTime = clock.getElapsedTime();

  for(let i=0;i<count;i++){
    const x=particlesGeometry.attributes.position.array[i*3]
    particlesGeometry.attributes.position.array[i*3+1]=Math.sin(elapsedTime+x)
  }
  

  
  particlesGeometry.attributes.position.needsUpdate=true
  // Update controls
  controls.update();

  // Render
  renderer.render(scene, camera);

  // Call tick again on the next frame
  window.requestAnimationFrame(tick);
};

tick();



版权声明:本文为qq_33839972原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。