mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
even more fps boost from fixing particles rendering
This commit is contained in:
parent
d3610ed338
commit
0c003189e7
2 changed files with 400 additions and 6 deletions
|
|
@ -1,11 +1,9 @@
|
||||||
package src;
|
package src;
|
||||||
|
|
||||||
import shaders.DtsTexture;
|
import shaders.DtsTexture;
|
||||||
import h3d.parts.Particles;
|
|
||||||
import h3d.Matrix;
|
import h3d.Matrix;
|
||||||
import src.TimeState;
|
import src.TimeState;
|
||||||
import h3d.prim.UV;
|
import h3d.prim.UV;
|
||||||
import h3d.parts.Data.BlendMode;
|
|
||||||
import src.MarbleWorld;
|
import src.MarbleWorld;
|
||||||
import src.Util;
|
import src.Util;
|
||||||
import h3d.mat.Data.Wrap;
|
import h3d.mat.Data.Wrap;
|
||||||
|
|
@ -33,7 +31,7 @@ class ParticleData {
|
||||||
|
|
||||||
@:publicFields
|
@:publicFields
|
||||||
class Particle {
|
class Particle {
|
||||||
public var part:h3d.parts.Particle;
|
public var part:src.ParticlesMesh.ParticleElement;
|
||||||
|
|
||||||
var data:ParticleData;
|
var data:ParticleData;
|
||||||
var manager:ParticleManager;
|
var manager:ParticleManager;
|
||||||
|
|
@ -61,7 +59,7 @@ class Particle {
|
||||||
this.lifeTime = this.o.lifetime + this.o.lifetimeVariance * (Math.random() * 2 - 1);
|
this.lifeTime = this.o.lifetime + this.o.lifetimeVariance * (Math.random() * 2 - 1);
|
||||||
this.initialSpin = Util.lerp(this.o.spinRandomMin, this.o.spinRandomMax, Math.random());
|
this.initialSpin = Util.lerp(this.o.spinRandomMin, this.o.spinRandomMax, Math.random());
|
||||||
|
|
||||||
this.part = new h3d.parts.Particle();
|
this.part = new src.ParticlesMesh.ParticleElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(time:Float, dt:Float) {
|
public function update(time:Float, dt:Float) {
|
||||||
|
|
@ -298,7 +296,7 @@ class ParticleManager {
|
||||||
var scene:Scene;
|
var scene:Scene;
|
||||||
var currentTime:Float;
|
var currentTime:Float;
|
||||||
|
|
||||||
var particleGroups:Map<String, Particles> = [];
|
var particleGroups:Map<String, src.ParticlesMesh.ParticlesMesh> = [];
|
||||||
var particles:Array<Particle> = [];
|
var particles:Array<Particle> = [];
|
||||||
|
|
||||||
var emitters:Array<ParticleEmitter> = [];
|
var emitters:Array<ParticleEmitter> = [];
|
||||||
|
|
@ -321,7 +319,7 @@ class ParticleManager {
|
||||||
if (particleGroups.exists(particleData.identifier)) {
|
if (particleGroups.exists(particleData.identifier)) {
|
||||||
particleGroups[particleData.identifier].add(particle.part);
|
particleGroups[particleData.identifier].add(particle.part);
|
||||||
} else {
|
} else {
|
||||||
var pGroup = new Particles(particle.data.texture, this.scene);
|
var pGroup = new src.ParticlesMesh.ParticlesMesh(particle.data.texture, this.scene);
|
||||||
pGroup.hasColor = true;
|
pGroup.hasColor = true;
|
||||||
pGroup.material.setDefaultProps("ui");
|
pGroup.material.setDefaultProps("ui");
|
||||||
// var pdts = new DtsTexture(pGroup.material.texture);
|
// var pdts = new DtsTexture(pGroup.material.texture);
|
||||||
|
|
|
||||||
396
src/ParticlesMesh.hx
Normal file
396
src/ParticlesMesh.hx
Normal file
|
|
@ -0,0 +1,396 @@
|
||||||
|
package src;
|
||||||
|
|
||||||
|
private class ParticleIterator {
|
||||||
|
var p:ParticleElement;
|
||||||
|
|
||||||
|
public inline function new(p) {
|
||||||
|
this.p = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function hasNext() {
|
||||||
|
return p != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function next() {
|
||||||
|
var v = p;
|
||||||
|
p = p.next;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SortMode {
|
||||||
|
Front;
|
||||||
|
Back;
|
||||||
|
Sort;
|
||||||
|
InvSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParticleElement {
|
||||||
|
public var parts:ParticlesMesh;
|
||||||
|
|
||||||
|
public var x:Float;
|
||||||
|
public var y:Float;
|
||||||
|
public var z:Float;
|
||||||
|
|
||||||
|
public var w:Float; // used for sorting
|
||||||
|
|
||||||
|
public var r:Float;
|
||||||
|
public var g:Float;
|
||||||
|
public var b:Float;
|
||||||
|
public var a:Float;
|
||||||
|
public var alpha(get, set):Float;
|
||||||
|
|
||||||
|
public var frame:Int;
|
||||||
|
|
||||||
|
public var size:Float;
|
||||||
|
public var ratio:Float;
|
||||||
|
public var rotation:Float;
|
||||||
|
|
||||||
|
public var prev:ParticleElement;
|
||||||
|
public var next:ParticleElement;
|
||||||
|
|
||||||
|
// --- Particle emitter ---
|
||||||
|
public var time:Float;
|
||||||
|
public var lifeTimeFactor:Float;
|
||||||
|
|
||||||
|
public var dx:Float;
|
||||||
|
public var dy:Float;
|
||||||
|
public var dz:Float;
|
||||||
|
|
||||||
|
public var fx:Float;
|
||||||
|
public var fy:Float;
|
||||||
|
public var fz:Float;
|
||||||
|
|
||||||
|
public var randIndex = 0;
|
||||||
|
public var randValues:Array<Float>;
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
public function new() {
|
||||||
|
r = 1;
|
||||||
|
g = 1;
|
||||||
|
b = 1;
|
||||||
|
a = 1;
|
||||||
|
frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function get_alpha()
|
||||||
|
return a;
|
||||||
|
|
||||||
|
inline function set_alpha(v)
|
||||||
|
return a = v;
|
||||||
|
|
||||||
|
public function setColor(color:Int, alpha = 1.) {
|
||||||
|
a = alpha;
|
||||||
|
r = ((color >> 16) & 0xFF) / 255.;
|
||||||
|
g = ((color >> 8) & 0xFF) / 255.;
|
||||||
|
b = (color & 0xFF) / 255.;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove() {
|
||||||
|
if (parts != null) {
|
||||||
|
@:privateAccess parts.kill(this);
|
||||||
|
parts = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rand():Float {
|
||||||
|
if (randValues == null)
|
||||||
|
randValues = [];
|
||||||
|
if (randValues.length <= randIndex)
|
||||||
|
randValues.push(Math.random());
|
||||||
|
return randValues[randIndex++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParticlesMesh extends h3d.scene.Mesh {
|
||||||
|
var pshader:h3d.shader.ParticleShader;
|
||||||
|
|
||||||
|
public var frames:Array<h2d.Tile>;
|
||||||
|
public var count(default, null):Int = 0;
|
||||||
|
public var hasColor(default, set):Bool;
|
||||||
|
public var sortMode:SortMode;
|
||||||
|
public var globalSize:Float = 1;
|
||||||
|
|
||||||
|
var head:ParticleElement;
|
||||||
|
var tail:ParticleElement;
|
||||||
|
var pool:ParticleElement;
|
||||||
|
|
||||||
|
var tmp:h3d.Vector;
|
||||||
|
var tmpBuf:hxd.FloatBuffer;
|
||||||
|
var buffer:h3d.Buffer;
|
||||||
|
var bufferSize:Int = 0;
|
||||||
|
|
||||||
|
public function new(?texture, ?parent) {
|
||||||
|
super(null, null, parent);
|
||||||
|
material.props = material.getDefaultProps("particles3D");
|
||||||
|
sortMode = Back;
|
||||||
|
pshader = new h3d.shader.ParticleShader();
|
||||||
|
pshader.isAbsolute = true;
|
||||||
|
material.mainPass.addShader(pshader);
|
||||||
|
material.mainPass.dynamicParameters = true;
|
||||||
|
material.texture = texture;
|
||||||
|
tmp = new h3d.Vector();
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_hasColor(b) {
|
||||||
|
var c = material.mainPass.getShader(h3d.shader.VertexColorAlpha);
|
||||||
|
if (b) {
|
||||||
|
if (c == null)
|
||||||
|
material.mainPass.addShader(new h3d.shader.VertexColorAlpha());
|
||||||
|
} else {
|
||||||
|
if (c != null)
|
||||||
|
material.mainPass.removeShader(c);
|
||||||
|
}
|
||||||
|
return hasColor = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Offset all existing particles by the given values.
|
||||||
|
**/
|
||||||
|
public function offsetParticles(dx:Float, dy:Float, dz = 0.) {
|
||||||
|
var p = head;
|
||||||
|
while (p != null) {
|
||||||
|
p.x += dx;
|
||||||
|
p.y += dy;
|
||||||
|
p.z += dz;
|
||||||
|
p = p.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clear() {
|
||||||
|
while (head != null)
|
||||||
|
kill(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alloc() {
|
||||||
|
var p = emitParticle();
|
||||||
|
if (posChanged)
|
||||||
|
syncPos();
|
||||||
|
p.parts = this;
|
||||||
|
p.x = absPos.tx;
|
||||||
|
p.y = absPos.ty;
|
||||||
|
p.z = absPos.tz;
|
||||||
|
p.rotation = 0;
|
||||||
|
p.ratio = 1;
|
||||||
|
p.size = 1;
|
||||||
|
p.r = p.g = p.b = p.a = 1;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add(p) {
|
||||||
|
emitParticle(p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitParticle(?p) {
|
||||||
|
if (p == null) {
|
||||||
|
if (pool == null)
|
||||||
|
p = new ParticleElement();
|
||||||
|
else {
|
||||||
|
p = pool;
|
||||||
|
pool = p.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
switch (sortMode) {
|
||||||
|
case Front, Sort, InvSort:
|
||||||
|
if (head == null) {
|
||||||
|
p.next = null;
|
||||||
|
head = tail = p;
|
||||||
|
} else {
|
||||||
|
head.prev = p;
|
||||||
|
p.next = head;
|
||||||
|
head = p;
|
||||||
|
}
|
||||||
|
case Back:
|
||||||
|
if (head == null) {
|
||||||
|
p.next = null;
|
||||||
|
head = tail = p;
|
||||||
|
} else {
|
||||||
|
tail.next = p;
|
||||||
|
p.prev = tail;
|
||||||
|
p.next = null;
|
||||||
|
tail = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
function kill(p:ParticleElement) {
|
||||||
|
if (p.prev == null)
|
||||||
|
head = p.next
|
||||||
|
else
|
||||||
|
p.prev.next = p.next;
|
||||||
|
if (p.next == null)
|
||||||
|
tail = p.prev
|
||||||
|
else
|
||||||
|
p.next.prev = p.prev;
|
||||||
|
p.prev = null;
|
||||||
|
p.next = pool;
|
||||||
|
pool = p;
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sort(list:ParticleElement) {
|
||||||
|
return haxe.ds.ListSort.sort(list, function(p1, p2) return p1.w < p2.w ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortInv(list:ParticleElement) {
|
||||||
|
return haxe.ds.ListSort.sort(list, function(p1, p2) return p1.w < p2.w ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function getParticles() {
|
||||||
|
return new ParticleIterator(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:access(h2d.Tile)
|
||||||
|
@:noDebug
|
||||||
|
override function draw(ctx:h3d.scene.RenderContext) {
|
||||||
|
if (head == null)
|
||||||
|
return;
|
||||||
|
switch (sortMode) {
|
||||||
|
case Sort, InvSort:
|
||||||
|
var p = head;
|
||||||
|
var m = ctx.camera.m;
|
||||||
|
while (p != null) {
|
||||||
|
p.w = (p.x * m._13 + p.y * m._23 + p.z * m._33 + m._43) / (p.x * m._14 + p.y * m._24 + p.z * m._34 + m._44);
|
||||||
|
p = p.next;
|
||||||
|
}
|
||||||
|
head = sortMode == Sort ? sort(head) : sortInv(head);
|
||||||
|
tail = head.prev;
|
||||||
|
head.prev = null;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if (tmpBuf == null)
|
||||||
|
tmpBuf = new hxd.FloatBuffer();
|
||||||
|
var pos = 0;
|
||||||
|
var p = head;
|
||||||
|
var tmp = tmpBuf;
|
||||||
|
var surface = 0.;
|
||||||
|
if (frames == null || frames.length == 0) {
|
||||||
|
var t = material.texture == null ? h2d.Tile.fromColor(0xFF00FF) : h2d.Tile.fromTexture(material.texture);
|
||||||
|
frames = [t];
|
||||||
|
}
|
||||||
|
material.texture = frames[0].getTexture();
|
||||||
|
|
||||||
|
while (p != null) {
|
||||||
|
var f = frames[p.frame];
|
||||||
|
if (f == null)
|
||||||
|
f = frames[0];
|
||||||
|
var ratio = p.size * p.ratio * (f.height / f.width);
|
||||||
|
|
||||||
|
if (pos >= tmp.length) {
|
||||||
|
tmp.grow(tmp.length + 40 + (hasColor ? 16 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp[pos++] = p.x;
|
||||||
|
tmp[pos++] = p.y;
|
||||||
|
tmp[pos++] = p.z;
|
||||||
|
tmp[pos++] = p.size;
|
||||||
|
tmp[pos++] = ratio;
|
||||||
|
tmp[pos++] = p.rotation;
|
||||||
|
// delta
|
||||||
|
tmp[pos++] = -0.5;
|
||||||
|
tmp[pos++] = -0.5;
|
||||||
|
// UV
|
||||||
|
tmp[pos++] = f.u;
|
||||||
|
tmp[pos++] = f.v2;
|
||||||
|
// RBGA
|
||||||
|
if (hasColor) {
|
||||||
|
tmp[pos++] = p.r;
|
||||||
|
tmp[pos++] = p.g;
|
||||||
|
tmp[pos++] = p.b;
|
||||||
|
tmp[pos++] = p.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp[pos++] = p.x;
|
||||||
|
tmp[pos++] = p.y;
|
||||||
|
tmp[pos++] = p.z;
|
||||||
|
tmp[pos++] = p.size;
|
||||||
|
tmp[pos++] = ratio;
|
||||||
|
tmp[pos++] = p.rotation;
|
||||||
|
tmp[pos++] = -0.5;
|
||||||
|
tmp[pos++] = 0.5;
|
||||||
|
tmp[pos++] = f.u;
|
||||||
|
tmp[pos++] = f.v;
|
||||||
|
if (hasColor) {
|
||||||
|
tmp[pos++] = p.r;
|
||||||
|
tmp[pos++] = p.g;
|
||||||
|
tmp[pos++] = p.b;
|
||||||
|
tmp[pos++] = p.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp[pos++] = p.x;
|
||||||
|
tmp[pos++] = p.y;
|
||||||
|
tmp[pos++] = p.z;
|
||||||
|
tmp[pos++] = p.size;
|
||||||
|
tmp[pos++] = ratio;
|
||||||
|
tmp[pos++] = p.rotation;
|
||||||
|
tmp[pos++] = 0.5;
|
||||||
|
tmp[pos++] = -0.5;
|
||||||
|
tmp[pos++] = f.u2;
|
||||||
|
tmp[pos++] = f.v2;
|
||||||
|
if (hasColor) {
|
||||||
|
tmp[pos++] = p.r;
|
||||||
|
tmp[pos++] = p.g;
|
||||||
|
tmp[pos++] = p.b;
|
||||||
|
tmp[pos++] = p.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp[pos++] = p.x;
|
||||||
|
tmp[pos++] = p.y;
|
||||||
|
tmp[pos++] = p.z;
|
||||||
|
tmp[pos++] = p.size;
|
||||||
|
tmp[pos++] = ratio;
|
||||||
|
tmp[pos++] = p.rotation;
|
||||||
|
tmp[pos++] = 0.5;
|
||||||
|
tmp[pos++] = 0.5;
|
||||||
|
tmp[pos++] = f.u2;
|
||||||
|
tmp[pos++] = f.v;
|
||||||
|
if (hasColor) {
|
||||||
|
tmp[pos++] = p.r;
|
||||||
|
tmp[pos++] = p.g;
|
||||||
|
tmp[pos++] = p.b;
|
||||||
|
tmp[pos++] = p.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = p.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos != 0) {
|
||||||
|
var stride = 10;
|
||||||
|
if (hasColor)
|
||||||
|
stride += 4;
|
||||||
|
if (buffer == null) {
|
||||||
|
buffer = h3d.Buffer.ofSubFloats(tmp, stride, Std.int(pos / stride), [Quads, Dynamic, RawFormat]);
|
||||||
|
bufferSize = Std.int(pos / stride);
|
||||||
|
} else {
|
||||||
|
var len = Std.int(pos / stride);
|
||||||
|
if (bufferSize < len) {
|
||||||
|
buffer.dispose();
|
||||||
|
buffer = h3d.Buffer.ofSubFloats(tmp, stride, Std.int(pos / stride), [Quads, Dynamic, RawFormat]);
|
||||||
|
bufferSize = Std.int(pos / stride);
|
||||||
|
} else {
|
||||||
|
buffer.uploadVector(tmp, 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pshader.is3D)
|
||||||
|
pshader.size.set(globalSize, globalSize);
|
||||||
|
else
|
||||||
|
pshader.size.set(globalSize * ctx.engine.height / ctx.engine.width * 4, globalSize * 4);
|
||||||
|
ctx.uploadParams();
|
||||||
|
var verts = Std.int(pos / stride);
|
||||||
|
var vertsPerTri = 2;
|
||||||
|
ctx.engine.renderQuadBuffer(buffer, 0, verts >> 1); // buffer, 0, Std.int(pos / stride));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override function onRemove() {
|
||||||
|
super.onRemove();
|
||||||
|
if (buffer != null) {
|
||||||
|
buffer.dispose();
|
||||||
|
buffer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue