Skip to content

Commit

Permalink
support horizon and vertical billboard in shader
Browse files Browse the repository at this point in the history
  • Loading branch information
Alchemist0823 committed Sep 21, 2023
1 parent 25d5cb1 commit e53fcb0
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Change Log

## version 0.10.8
- Support horizontal and vertical billboard in shader

## version 0.10.6
- fix render setting reference bug
- fix shaders can not loaded in some loader because of shader chunk reference
Expand Down
99 changes: 99 additions & 0 deletions examples/billboardDemo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {
BatchedParticleRenderer,
ConstantColor,
PointEmitter,
IntervalValue,
ConstantValue,
ParticleSystem,
SizeOverLife,
PiecewiseBezier,
Bezier,
RenderMode,
RandomQuatGenerator,
AxisAngleGenerator,
Rotation3DOverLife,
RotationOverLife,
SpeedOverLife,
EulerGenerator,
} from './js/three.quarks.esm.js';
import {
MeshBasicMaterial,
NormalBlending,
AdditiveBlending,
TextureLoader,
Vector4,
Vector3,
PlaneGeometry,
DoubleSide,
} from './js/three.module.js';
import {Demo} from './demo.js';

export class BillboardDemo extends Demo {
name = 'Horizon & Vertical BillboardDemo';

initScene() {
super.initScene();

this.batchRenderer = new BatchedParticleRenderer();
this.scene.add(this.batchRenderer);

const texture = new TextureLoader().load('textures/logo_texture.png');
const config = {
duration: 5,
looping: true,
//instancingGeometry: new PlaneGeometry(1, 1),//.rotateX((-90 / 180) * Math.PI),
startLife: new IntervalValue(4, 5),
startSpeed: new ConstantValue(2),
startSize: new IntervalValue(0.4, 0.5),
//startRotation: new EulerGenerator(new ConstantValue(0), new ConstantValue(0), new ConstantValue(0)),
startColor: new ConstantColor(new Vector4(1, 1, 1, 1)),
worldSpace: false,

maxParticle: 100,
emissionOverTime: new ConstantValue(0),
emissionBursts: [
{
time: 0,
count: 100,
cycle: 1,
interval: 0.01,
probability: 1,
},
],

shape: new PointEmitter(),
material: new MeshBasicMaterial({
blending: NormalBlending,
transparent: true,
map: texture,
//side: DoubleSide,
}),
startTileIndex: new ConstantValue(0),
uTileCount: 1,
vTileCount: 1,
renderOrder: 2,
renderMode: RenderMode.VerticalBillBoard,
};

// Create particle system based on your configuration
let billboard1 = new ParticleSystem(config);
billboard1.addBehavior(new SpeedOverLife(new PiecewiseBezier([[new Bezier(1, 0.75, 0.5, 0), 0]])));
billboard1.emitter.name = 'billboard';
billboard1.emitter.position.x = 5;

config.renderMode = RenderMode.HorizontalBillBoard;
let billboard2 = new ParticleSystem(config);
billboard2.addBehavior(new SpeedOverLife(new PiecewiseBezier([[new Bezier(1, 0.75, 0.5, 0), 0]])));
billboard2.emitter.name = 'billboard';
billboard2.emitter.position.x = -5;

this.batchRenderer.addSystem(billboard1);
this.batchRenderer.addSystem(billboard2);

this.scene.add(billboard1.emitter);
this.scene.add(billboard2.emitter);
this.scene.add(this.batchRenderer);

return this.scene;
}
}
3 changes: 2 additions & 1 deletion examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
import {SequencerDemo} from "./sequencerDemo.js";
import {MeshMaterialDemo} from "./meshMaterialDemo.js";
import {AlphaTestDemo} from "./alphaTestDemo.js";
import {BillboardDemo} from "./billboardDemo.js";

const WEBGL = {
isWebGLAvailable: function () {
Expand Down Expand Up @@ -142,7 +143,7 @@
let scene;
let demo;

let demos = [MuzzleFlashDemo, TornadoDemo, TrailDemo, SequencerDemo, MeshMaterialDemo, TurbulenceDemo, AlphaTestDemo, CustomPluginDemo];
let demos = [MuzzleFlashDemo, TornadoDemo, TrailDemo, SequencerDemo, MeshMaterialDemo, TurbulenceDemo, AlphaTestDemo, CustomPluginDemo, BillboardDemo];
let demoIndex = 0;

function init() {
Expand Down
Binary file added examples/textures/particle_default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "three.quarks",
"version": "0.10.7",
"version": "0.10.8",
"description": "A General-Purpose Particle System for three.js",
"type": "module",
"types": "./dist/types/index.d.ts",
Expand Down
2 changes: 2 additions & 0 deletions src/BatchedRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export class BatchedRenderer extends Object3D {
break;
case RenderMode.Mesh:
case RenderMode.BillBoard:
case RenderMode.VerticalBillBoard:
case RenderMode.HorizontalBillBoard:
case RenderMode.StretchedBillBoard:
batch = new SpriteBatch(settings);
break;
Expand Down
12 changes: 11 additions & 1 deletion src/ParticleSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,8 @@ export class ParticleSystem {
this.startRotation = new AxisAngleGenerator(new Vector3(0, 1, 0), new ConstantValue(0));
break;
case RenderMode.BillBoard:
case RenderMode.VerticalBillBoard:
case RenderMode.HorizontalBillBoard:
case RenderMode.StretchedBillBoard:
this.rendererEmitterSettings = {};
if (this.rendererSettings.renderMode === RenderMode.Mesh) {
Expand Down Expand Up @@ -572,6 +574,8 @@ export class ParticleSystem {
if (
this.rendererSettings.renderMode === RenderMode.Mesh ||
this.rendererSettings.renderMode === RenderMode.BillBoard ||
this.rendererSettings.renderMode === RenderMode.VerticalBillBoard ||
this.rendererSettings.renderMode === RenderMode.HorizontalBillBoard ||
this.rendererSettings.renderMode === RenderMode.StretchedBillBoard
) {
const sprite = particle as SpriteParticle;
Expand Down Expand Up @@ -612,7 +616,8 @@ export class ParticleSystem {
}
if (this.worldSpace) {
particle.position.applyMatrix4(matrix);
particle.startSize = (particle.startSize * (Math.abs(scale.x) + Math.abs(scale.y) + Math.abs(scale.z))) / 3;
particle.startSize =
(particle.startSize * (Math.abs(scale.x) + Math.abs(scale.y) + Math.abs(scale.z))) / 3;
particle.size = particle.startSize;
particle.velocity.multiply(scale).applyMatrix3(this.normalMatrix);
if (particle.rotation && particle.rotation instanceof Quaternion) {
Expand Down Expand Up @@ -685,10 +690,15 @@ export class ParticleSystem {
if (this.looping && this.prewarm && !this.prewarmed) {
this.prewarmed = true;
for (let i = 0; i < this.duration * PREWARM_FPS; i++) {
// stack overflow?
this.update(1.0 / PREWARM_FPS);
}
}

if (delta > 0.1) {
delta = 0.1;
}

if (this.neededToUpdateRender) {
if (this._renderer) this._renderer.updateSystem(this);
this.neededToUpdateRender = false;
Expand Down
28 changes: 21 additions & 7 deletions src/SpriteBatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export class SpriteBatch extends VFXBatch {
this.geometry.setAttribute('rotation', this.rotationBuffer);
} else if (
this.settings.renderMode === RenderMode.BillBoard ||
this.settings.renderMode === RenderMode.HorizontalBillBoard ||
this.settings.renderMode === RenderMode.VerticalBillBoard ||
this.settings.renderMode === RenderMode.StretchedBillBoard
) {
this.rotationBuffer = new InstancedBufferAttribute(new Float32Array(this.maxParticles), 1);
Expand Down Expand Up @@ -186,7 +188,12 @@ export class SpriteBatch extends VFXBatch {
defines['USE_COLOR_ALPHA'] = '';

let needLights = false;
if (this.settings.renderMode === RenderMode.BillBoard || this.settings.renderMode === RenderMode.Mesh) {
if (
this.settings.renderMode === RenderMode.BillBoard ||
this.settings.renderMode === RenderMode.VerticalBillBoard ||
this.settings.renderMode === RenderMode.HorizontalBillBoard ||
this.settings.renderMode === RenderMode.Mesh
) {
let vertexShader;
let fragmentShader;
if (this.settings.renderMode === RenderMode.Mesh) {
Expand All @@ -206,6 +213,11 @@ export class SpriteBatch extends VFXBatch {
vertexShader = particle_vert;
fragmentShader = particle_frag;
}
if (this.settings.renderMode === RenderMode.VerticalBillBoard) {
defines['VERTICAL'] = '';
} else if (this.settings.renderMode === RenderMode.HorizontalBillBoard) {
defines['HORIZONTAL'] = '';
}
this.material = new ShaderMaterial({
uniforms: uniforms,
defines: defines,
Expand Down Expand Up @@ -236,11 +248,6 @@ export class SpriteBatch extends VFXBatch {
}
}

/*
clone() {
let system = this.system.clone();
return system.emitter as any;
}*/
vector_: Vector3 = new Vector3();
vector2_: Vector3 = new Vector3();
vector3_: Vector3 = new Vector3();
Expand Down Expand Up @@ -291,6 +298,8 @@ export class SpriteBatch extends VFXBatch {
this.rotationBuffer.setXYZW(index, q.x, q.y, q.z, q.w);
} else if (
this.settings.renderMode === RenderMode.StretchedBillBoard ||
this.settings.renderMode === RenderMode.VerticalBillBoard ||
this.settings.renderMode === RenderMode.HorizontalBillBoard ||
this.settings.renderMode === RenderMode.BillBoard
) {
this.rotationBuffer.setX(index, particle.rotation as number);
Expand All @@ -316,7 +325,10 @@ export class SpriteBatch extends VFXBatch {
if (particle.parentMatrix) {
this.sizeBuffer.setX(index, particle.size);
} else {
this.sizeBuffer.setX(index, (particle.size * (Math.abs(scale.x) + Math.abs(scale.y) + Math.abs(scale.z))) / 3);
this.sizeBuffer.setX(
index,
(particle.size * (Math.abs(scale.x) + Math.abs(scale.y) + Math.abs(scale.z))) / 3
);
}
}
this.uvTileBuffer.setX(index, particle.uvTile);
Expand Down Expand Up @@ -364,6 +376,8 @@ export class SpriteBatch extends VFXBatch {
this.rotationBuffer.needsUpdate = true;
} else if (
this.settings.renderMode === RenderMode.StretchedBillBoard ||
this.settings.renderMode === RenderMode.HorizontalBillBoard ||
this.settings.renderMode === RenderMode.VerticalBillBoard ||
this.settings.renderMode === RenderMode.BillBoard
) {
this.rotationBuffer.updateRange.count = index;
Expand Down
2 changes: 2 additions & 0 deletions src/VFXBatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export enum RenderMode {
StretchedBillBoard = 1,
Mesh = 2,
Trail = 3,
HorizontalBillBoard = 4,
VerticalBillBoard = 5,
}

export abstract class VFXBatch extends Mesh {
Expand Down
16 changes: 8 additions & 8 deletions src/shaders/local_particle_physics_vert.glsl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,25 @@ uniform vec2 tileCount;
void main() {
${uv_vertex_tile}
float x2 = rotation.x + rotation.x, y2 = rotation.y + rotation.y, z2 = rotation.z + rotation.z;
float xx = rotation.x * x2, xy = rotation.x * y2, xz = rotation.x * z2;
float yy = rotation.y * y2, yz = rotation.y * z2, zz = rotation.z * z2;
float wx = rotation.w * x2, wy = rotation.w * y2, wz = rotation.w * z2;
float sx = size, sy = size, sz = size;
mat4 particleMatrix = mat4(( 1.0 - ( yy + zz ) ) * sx, ( xy + wz ) * sx, ( xz - wy ) * sx, 0.0, // 1. column
( xy - wz ) * sy, ( 1.0 - ( xx + zz ) ) * sy, ( yz + wx ) * sy, 0.0, // 2. column
( xz + wy ) * sz, ( yz - wx ) * sz, ( 1.0 - ( xx + yy ) ) * sz, 0.0, // 3. column
offset.x, offset.y, offset.z, 1.0);
#include <color_vertex>
#include <morphcolor_vertex>
#include <beginnormal_vertex>
#include <morphnormal_vertex>
#include <skinbase_vertex>
#include <skinnormal_vertex>
// replace defaultnormal_vertex
vec3 transformedNormal = objectNormal;
mat3 m = mat3( particleMatrix );
Expand All @@ -64,16 +64,16 @@ void main() {
transformedTangent = - transformedTangent;
#endif
#endif
#include <normal_vertex>
#include <begin_vertex>
#include <morphtarget_vertex>
#include <skinning_vertex>
#include <displacementmap_vertex>
// replace include <project_vertex>
vec4 mvPosition = vec4( transformed, 1.0 );
mvPosition = modelViewMatrix * (particleMatrix * mvPosition);
vec4 mvPosition = vec4( transformed, 1.0 );
mvPosition = modelViewMatrix * (particleMatrix * mvPosition);
gl_Position = projectionMatrix * mvPosition;
#include <logdepthbuf_vertex>
Expand Down
16 changes: 13 additions & 3 deletions src/shaders/particle_vert.glsl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,25 @@ void main() {
${uv_vertex_tile}
vec4 mvPosition = modelViewMatrix * vec4( offset, 1.0 );
vec2 alignedPosition = ( position.xy ) * size;
vec2 rotatedPosition;
rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;
rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;
#ifdef HORIZONTAL
vec4 mvPosition = modelMatrix * vec4( offset, 1.0 );
mvPosition.x += rotatedPosition.x;
mvPosition.z -= rotatedPosition.y;
mvPosition = viewMatrix * mvPosition;
#elif defined(VERTICAL)
vec4 mvPosition = modelMatrix * vec4( offset, 1.0 );
mvPosition.y += rotatedPosition.y;
mvPosition = viewMatrix * mvPosition;
mvPosition.x += rotatedPosition.x;
#else
vec4 mvPosition = modelViewMatrix * vec4( offset, 1.0 );
mvPosition.xy += rotatedPosition;
#endif
vColor = color;
Expand Down

0 comments on commit e53fcb0

Please sign in to comment.