Skip to content

Commit

Permalink
Adding min/max size on gpuemitter. rework infinite mode so lifetime s…
Browse files Browse the repository at this point in the history
…till increase. Adding LocalRotation simulation shader. WIP on mesh spawn.
  • Loading branch information
clementlandrin committed Nov 15, 2024
1 parent 47e670a commit 6bfecef
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 31 deletions.
12 changes: 7 additions & 5 deletions hrt/prefab/fx/gpuemitter/BaseSimulation.hx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package hrt.prefab.fx.gpuemitter;
class BaseSimulation extends ComputeUtils {
static var SRC = {
@param var batchBuffer : RWPartialBuffer<{
modelView : Mat4,
modelView : Mat4,
}>;
@param var particleBuffer : RWPartialBuffer<{
speed : Vec3,
Expand All @@ -12,14 +12,15 @@ class BaseSimulation extends ComputeUtils {
random : Float,
}>;

@const var INFINITE : Bool = false;
@const var FACE_CAM : Bool = false;
@const var CAMERA_BOUNDS : Bool = false;

@param var dtParam : Float;
@param var cameraUp : Vec3;
@param var boundsPos : Vec3;
@param var boundsSize : Vec3;
@param var minSize : Float;
@param var maxSize : Float;

var dt : Float;
var speed : Vec3;
Expand All @@ -29,12 +30,14 @@ class BaseSimulation extends ComputeUtils {
var instanceID : Int;
var prevModelView : Mat4;
var prevSpeed : Vec3;
var relativeTransform : Mat4;
function __init__() {
dt = dtParam;
speed = particleBuffer[computeVar.globalInvocation.x].speed;
lifeTime = particleBuffer[computeVar.globalInvocation.x].lifeTime;
prevModelView = batchBuffer[computeVar.globalInvocation.x].modelView;
particleRandom = particleBuffer[computeVar.globalInvocation.x].random;
relativeTransform = scaleMatrix(vec3(particleRandom * (maxSize - minSize) + minSize));
}

function main() {
Expand All @@ -48,10 +51,9 @@ class BaseSimulation extends ComputeUtils {
var newPos = prevPos + speed * dt;
if ( CAMERA_BOUNDS )
newPos = ((newPos - boundsPos) % boundsSize) + boundsPos;
modelView = align * translationMatrix(newPos);
modelView = relativeTransform * align * translationMatrix(newPos);
var idx = computeVar.globalInvocation.x;
if ( !INFINITE )
particleBuffer[idx].lifeTime = lifeTime - dt;
particleBuffer[idx].lifeTime = lifeTime - dt;
particleBuffer[idx].speed = speed;
batchBuffer[idx].modelView = modelView;
}
Expand Down
6 changes: 4 additions & 2 deletions hrt/prefab/fx/gpuemitter/BaseSpawn.hx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class BaseSpawn extends ComputeUtils {
}>;
@param var atomic : RWBuffer<Int>;

@const var FORCED : Bool = false;
@const var INFINITE : Bool = false;
@const var SPEED_NORMAL : Bool;
@param var minLifeTime : Float;
@param var maxLifeTime : Float;
Expand All @@ -36,9 +38,9 @@ class BaseSpawn extends ComputeUtils {

function main() {
var idx = computeVar.globalInvocation.x;
if ( particleBuffer[idx].lifeTime < 0.0 ) {
if ( FORCED || (!INFINITE && particleBuffer[idx].lifeTime < 0.0) ) {
var c = atomicAdd(atomic, 0, 1);
if ( c < rate ) {
if ( FORCED || (!INFINITE && c < rate) ) {
batchBuffer[idx].modelView = modelView;
var s = vec3(0.0, 0.0, 1.0);
if ( SPEED_NORMAL )
Expand Down
22 changes: 20 additions & 2 deletions hrt/prefab/fx/gpuemitter/ComputeUtils.hx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ComputeUtils extends hxsl.Shader {
@global var camera : {
var position : Vec3;
}

function random(pos : Vec2) : Float {
return fract(sin(dot(pos, vec2(12.9898,78.233)))*43758.5453123);
}
Expand Down Expand Up @@ -51,7 +51,7 @@ class ComputeUtils extends hxsl.Shader {
var sTheta = sin(theta);
return vec3(radius * sTheta * cos(phi), radius * sTheta * sin(phi), radius * cos(theta));
}

function cartesianToSpherical(pos : Vec3) : Vec3 {
var radius = length(pos);
var dir = pos / radius;
Expand Down Expand Up @@ -91,6 +91,24 @@ class ComputeUtils extends hxsl.Shader {
return matrix;
}

function rotateMatrixX(angle : Float) : Mat4 {
return mat4(
vec4(1.0, 0.0, 0.0, 0.0),
vec4(0.0, cos(angle), -sin(angle), 0.0),
vec4(0.0, sin(angle), cos(angle), 0.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
}

function rotateMatrixY(angle : Float) : Mat4 {
return mat4(
vec4(cos(angle), 0.0, -sin(angle), 0.0),
vec4(0.0, 1.0, 0.0, 0.0),
vec4(sin(angle), 0.0, cos(angle), 0.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
}

function rotateMatrixZ(angle : Float) : Mat4 {
return mat4(
vec4(cos(angle), -sin(angle), 0.0, 0.0),
Expand Down
27 changes: 18 additions & 9 deletions hrt/prefab/fx/gpuemitter/GPUEmitter.hx
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ typedef Data = {
var infinite : Bool;
var maxLifeTime : Float;
var minLifeTime : Float;
var gravity : Float;
var radius : Float;
var maxSize : Float;
var minSize : Float;
var startSpeed : Float;
var trs : h3d.Matrix;
var mode : Mode;
Expand Down Expand Up @@ -75,6 +75,7 @@ class GPUEmitterObject extends h3d.scene.MeshBatch {
var particleShader : ParticleShader;

var rateAccumulation : Float = 0.0;
var firstDispatch : Bool = true;

public function new(data, primitive, materials, ?parent) {
super(primitive, null, parent);
Expand Down Expand Up @@ -138,8 +139,8 @@ class GPUEmitterObject extends h3d.scene.MeshBatch {
floats[i * stride + 4] = 1.0 / l; // lifeRatio
floats[i * stride + 5] = hxd.Math.random(); // random
// padding
floats[i * stride + 6] = 0.0;
floats[i * stride + 7] = 0.0;
// floats[i * stride + 6] = 0.0;
// floats[i * stride + 7] = 0.0;
}
particleBuffer.buffer = alloc.ofFloats(floats, particleBufferFormat, UniformReadWrite);
particleBuffer.atomic = alloc.allocBuffer( 1, hxd.BufferFormat.VEC4_DATA, UniformReadWrite );
Expand Down Expand Up @@ -224,6 +225,8 @@ class GPUEmitterObject extends h3d.scene.MeshBatch {
baseSpawn.minLifeTime = data.minLifeTime;
baseSpawn.maxStartSpeed = data.maxStartSpeed;
baseSpawn.minStartSpeed = data.minStartSpeed;
baseSpawn.FORCED = data.infinite && firstDispatch;
baseSpawn.INFINITE = data.infinite;
if ( data.rate > 0 ) {
var r = data.rate * ctx.elapsedTime;
baseSpawn.rate = Math.floor(r);
Expand All @@ -245,8 +248,9 @@ class GPUEmitterObject extends h3d.scene.MeshBatch {
}

var baseSimulation = simulationPass.getShader(BaseSimulation);
baseSimulation.INFINITE = data.infinite;
baseSimulation.dtParam = ctx.elapsedTime;
baseSimulation.maxSize = data.maxSize;
baseSimulation.minSize = data.minSize;
switch ( data.align ) {
case FaceCam:
baseSimulation.FACE_CAM = true;
Expand Down Expand Up @@ -347,6 +351,7 @@ class GPUEmitterObject extends h3d.scene.MeshBatch {
p = p.next;
particleBuffer = particleBuffer.next;
}
firstDispatch = false;
}

override function emit(ctx : h3d.scene.RenderContext) {
Expand Down Expand Up @@ -387,8 +392,8 @@ class GPUEmitter extends Object3D {
@:s var maxLifeTime : Float = 1.0;
@:s var minStartSpeed : Float = 0.5;
@:s var maxStartSpeed : Float = 1.0;
@:s var gravity : Float = 1.0;
@:s var radius : Float = 1.0;
@:s var minSize : Float = 0.5;
@:s var maxSize : Float = 1.5;
@:s var startSpeed : Float = 1.0;
@:s var infinite : Bool = false;
@:s var mode : Mode = World;
Expand All @@ -401,8 +406,10 @@ class GPUEmitter extends Object3D {
}

override function makeChild(c : hrt.prefab.Prefab) {
#if !editor
if ( Std.isOfType(c, hrt.prefab.Object3D) )
return;
#end
super.makeChild(c);
}

Expand Down Expand Up @@ -431,8 +438,8 @@ class GPUEmitter extends Object3D {
maxCount : maxCount,
minLifeTime : minLifeTime,
maxLifeTime : maxLifeTime,
gravity : gravity,
radius : radius,
minSize : minSize,
maxSize : maxSize,
startSpeed : startSpeed,
trs : trs,
infinite : infinite,
Expand Down Expand Up @@ -508,6 +515,8 @@ class GPUEmitter extends Object3D {
<dt>Max count</dt><dd><input type="range" step="1" min="1" max="8192" field="maxCount"/></dd>
<dt>Min life time</dt><dd><input type="range" min="0.1" max="10" field="minLifeTime"/></dd>
<dt>Max life time</dt><dd><input type="range" min="0.1" max="10" field="maxLifeTime"/></dd>
<dt>Min size</dt><dd><input type="range" min="0.1" max="10" field="minSize"/></dd>
<dt>Max size</dt><dd><input type="range" min="0.1" max="10" field="maxSize"/></dd>
<dt>Infinite</dt><dd><input type="checkbox" field="infinite"/></dd>
<dt>Mode</dt>
<dd>
Expand Down
52 changes: 52 additions & 0 deletions hrt/prefab/fx/gpuemitter/LocalRotation.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package hrt.prefab.fx.gpuemitter;

class LocalRotationShader extends ComputeUtils {

static var SRC = {
@param var speedRotation : Float;

var relativeTransform : Mat4;
var dt : Float;
var lifeTime : Float;
var particleRandom : Float;
function main() {
var r = 2.0 * random3d(vec2(particleRandom)) - 1.0;
relativeTransform = rotateMatrixX(speedRotation * lifeTime * r.x) *
rotateMatrixY(speedRotation * lifeTime * r.y) *
rotateMatrixZ(speedRotation * lifeTime * r.z) *
relativeTransform;
}
}
}

class LocalRotation extends SimulationShader {

@:s var speedRotation : Float = 1.0;

override function makeShader() {
return new LocalRotationShader();
}

override function updateInstance(?propName) {
super.updateInstance(propName);

var sh = cast(shader, LocalRotationShader);
sh.speedRotation = speedRotation * 2.0 * Math.PI;
}

#if editor
override function edit( ctx : hide.prefab.EditContext ) {
ctx.properties.add(new hide.Element('
<div class="group" name="Simulation">
<dl>
<dt>Rotation speed</dt><dd><input type="range" min="0" max="1" field="speedRotation"/></dd>
</dl>
</div>
'), this, function(pname) {
ctx.onChange(this, pname);
});
}
#end

static var _ = Prefab.register("localRotation", LocalRotation);
}
57 changes: 44 additions & 13 deletions hrt/prefab/fx/gpuemitter/MeshSpawn.hx
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,29 @@ class MeshSpawnShader extends ComputeUtils {

vertexCount = hxd.Math.imin(128, originalBuffer.vertices);
vertexCount = originalBuffer.vertices;

var skip = Math.floor(originalBuffer.vertices / vertexCount);

var alloc = hxd.impl.Allocator.get();
vbuf = alloc.allocBuffer(vertexCount, hxd.BufferFormat.make([
{ name : "position", type : DVec3 },
{ name : "normal", type : DVec3 },
]), UniformReadWrite);
var fmt = if ( Std.isOfType(m, h3d.scene.Skin) ) {
hxd.BufferFormat.make([
{ name : "position", type : DVec3 },
{ name : "padding", type : DFloat },
{ name : "normal", type : DVec3 },
{ name : "padding2", type : DFloat },
{ name : "weights", type : DVec3 },
{ name : "indexes", type : DBytes4 },
]);
} else {
hxd.BufferFormat.make([
{ name : "position", type : DVec3 },
{ name : "normal", type : DVec3 },
]);
}
vbuf = alloc.allocBuffer(vertexCount, fmt, UniformReadWrite);

var floatBuffer = alloc.allocFloats(vertexCount * vbuf.format.stride);
var buffers = cast(mesh.primitive, h3d.prim.HMDModel).getDataBuffers(vbuf.format);
var buffers = cast(mesh.primitive, h3d.prim.HMDModel).getDataBuffers(vbuf.format, [for ( i in 0...5) new h3d.Vector4()]);
for ( i in 0...vertexCount ) {
for ( j in 0...vbuf.format.stride ) {
floatBuffer[i * vbuf.format.stride + j] = buffers.vertexes.get(i * skip * vbuf.format.stride + j);
Expand All @@ -38,27 +51,45 @@ class MeshSpawnShader extends ComputeUtils {
parentInvert.invert();
parentInvert.multiply3x4inline(mesh.getAbsPos(), parentInvert);
emitter.setTransform(parentInvert);

var skinShader = mesh.material.mainPass.getShader(h3d.shader.SkinBase);
bonesMatrixes = skinShader.bonesMatrixes;
MaxBones = skinShader.MaxBones;
}

static var SRC = {
@const var MaxBones : Int;

@param var vertexCount : Int;
@param var vbuf : RWPartialBuffer<{ position : Vec3,
@param var vbuf : RWPartialBuffer<{
position : Vec3,
padding : Float,
normal : Vec3,
// weights : Vec3,
// indexes : Bytes4
padding2 : Float,
weights : Vec3,
indexes : Bytes4
}>;
// @param var bonesMatrixes : Array<Mat3x4,MaxBones>;
@param var modelTransform : Mat4;
@param var bonesMatrixes : Array<Mat3x4,MaxBones>;

var emitNormal : Vec3;
var lifeTime : Float;
var relativeTransform : Mat4;
var relativePosition : Vec3;
function main() {
var idx = computeVar.globalInvocation.x;
var vertexId = idx % vertexCount;
emitNormal = vbuf[vertexId].normal;
relativePosition = vbuf[vertexId].position;
var vertexData = vbuf[vertexId];
emitNormal = vertexData.normal;
var relativePosition = vertexData.position;

relativePosition =
(relativePosition * bonesMatrixes[int(vertexData.indexes.x)]) * vertexData.weights.x +
(relativePosition * bonesMatrixes[int(vertexData.indexes.y)]) * vertexData.weights.y +
(relativePosition * bonesMatrixes[int(vertexData.indexes.z)]) * vertexData.weights.z;
// transformedNormal =
// (vertexData.normal * mat3(bonesMatrixes[int(vertexData.indexes.x)])) * vertexData.weights.x +
// (vertexData.normal * mat3(bonesMatrixes[int(vertexData.indexes.y)])) * vertexData.weights.y +
// (vertexData.normal * mat3(bonesMatrixes[int(vertexData.indexes.z)])) * vertexData.weights.z;

relativeTransform = translationMatrix(relativePosition);
}
}
Expand Down

0 comments on commit 6bfecef

Please sign in to comment.