Przeglądaj źródła

Major Emitter optimizations (#225)

This PR speeds-up particles update (EmitterObject.setTime) by a factor of 2.
Data structures had to be completely refactored to avoid scattering data in tiny objects as much as possible.
Extra optimizations have been made on HL using @:struct for even more locality, but gains can be seen even on JS, due to having fewer objects overall in ParticleInstance.
trethaller 2 lat temu
rodzic
commit
aa79039cf9

+ 2 - 2
hide/view/FXEditor.hx

@@ -996,10 +996,10 @@ class FXEditor extends FileView {
 			updateExpanded();
 		});
 		var dopesheet = trackEl.find(".dopesheet");
-		var evaluator = new hrt.prefab.fx.Evaluator(new hxd.Rand(0));
+		var evaluator = new hrt.prefab.fx.Evaluator();
 
 		function getKeyColor(key) {
-			return evaluator.getVector(Curve.getColorValue(curves), key.time);
+			return evaluator.getVector(Curve.getColorValue(curves), key.time, new h3d.Vector());
 		}
 
 		function dragKey(from: hide.comp.CurveEditor, prevTime: Float, newTime: Float) {

+ 1 - 1
hrt/prefab/DynamicShader.hx

@@ -71,7 +71,7 @@ class DynamicShader extends Shader {
 		if(StringTools.endsWith(path, ".hx")) path = path.substr(0, -3);
 		var cpath = path.split("/").join(".");
 		var cl = cast Type.resolveClass(cpath);
-		if( cl == null && !opt ) throw "Missing shader class"+cpath;
+		if( cl == null && !opt ) throw "Missing shader class "+cpath;
 		return cl;
 	}
 

+ 4 - 3
hrt/prefab/fx/BaseFX.hx

@@ -46,6 +46,7 @@ class ShaderAnimation extends Evaluator {
 
 class ShaderDynAnimation extends ShaderAnimation {
 
+	static var tmpVec = new h3d.Vector();
 	override function setTime(time: Float) {
 		var shader : hxsl.DynamicShader = cast shader;
 		for(param in params) {
@@ -61,8 +62,8 @@ class ShaderDynAnimation extends ShaderAnimation {
 					var val = getFloat(param.value, time) >= 0.5;
 					shader.setParamValue(v, val);
 				case TVec(_, VFloat):
-					var val = getVector(param.value, time);
-					shader.setParamValue(v, val);
+					getVector(param.value, time, tmpVec);
+					shader.setParamValue(v, tmpVec);
 				default:
 			}
 		}
@@ -174,7 +175,7 @@ class BaseFX extends hrt.prefab.Library {
 
 		for(shCtx in ctx.shared.getContexts(elt)) {
 			if(shCtx.custom == null) continue;
-			var anim = Std.isOfType(shCtx.custom,hxsl.DynamicShader) ? new ShaderDynAnimation(new hxd.Rand(0)) : new ShaderAnimation(new hxd.Rand(0));
+			var anim = Std.isOfType(shCtx.custom,hxsl.DynamicShader) ? new ShaderDynAnimation() : new ShaderAnimation();
 			anim.shader = shCtx.custom;
 			anim.params = makeShaderParams(ctx, shader);
 			anims.push(anim);

Plik diff jest za duży
+ 349 - 356
hrt/prefab/fx/Emitter.hx


+ 28 - 61
hrt/prefab/fx/Evaluator.hx

@@ -1,39 +1,20 @@
 package hrt.prefab.fx;
 
-class VecPool {
-	var vecPool : Array<h3d.Vector> = null;
-	var vecPoolSize = 0;
-
-	public function new() { }
+class Evaluator {
+	var randValues : Array<Float>;
+	var stride : Int;
 
-	public function begin() {
-		if(vecPool == null)
-			vecPool = [];
-		vecPoolSize = 0;
+	public function new(?randValues: Array<Float>, stride: Int=0) {
+		this.randValues = randValues;
+		this.stride = stride;
 	}
 
-	public function get() {
-		var vec = null;
-		if(vecPoolSize < vecPool.length)
-			vec = vecPool[vecPoolSize++];
-		else {
-			vec = new h3d.Vector();
-			vecPool.push(vec);
-		}
-		return vec;
+	inline function getRandom(pidx: Int, ridx: Int) {
+		var i = pidx * stride + ridx;
+		return randValues[i];
 	}
-}
 
-class Evaluator {
-	var randValues : Array<Float> = [];
-	var random: hxd.Rand;
-	public var vecPool : VecPool;
-
-	public function new(random: hxd.Rand) {
-		this.random = random;
-	}
-
-	public function getFloat(val: Value, time: Float) : Float {
+	public function getFloat(pidx: Int=0, val: Value, time: Float) : Float {
 		if(val == null)
 			return 0.0;
 		switch(val) {
@@ -42,24 +23,16 @@ class Evaluator {
 			case VConst(v): return v;
 			case VCurve(c): return c.getVal(time);
 			case VCurveScale(c, scale): return c.getVal(time) * scale;
-			case VRandom(idx, scale):
-				var len = randValues.length;
-				while(idx >= len) {
-					randValues.push(random.srand());
-					++len;
-				}
-				return randValues[idx] * getFloat(scale, time);
-			case VRandomScale(idx, scale):
-				var len = randValues.length;
-				while(idx >= len) {
-					randValues.push(random.srand());
-					++len;
-				}
-				return randValues[idx] * scale;
+			case VRandom(ridx, scale):
+				return getRandom(pidx, ridx) * getFloat(pidx, scale, time);
+			case VRandomScale(ridx, scale):
+				return getRandom(pidx, ridx) * scale;
+			case VAddRandCurve(cst, ridx, rscale, c):
+				return (cst + getRandom(pidx, ridx) * rscale) * c.getVal(time);
 			case VMult(a, b):
-				return getFloat(a, time) * getFloat(b, time);
+				return getFloat(pidx, a, time) * getFloat(pidx, b, time);
 			case VAdd(a, b):
-				return getFloat(a, time) + getFloat(b, time);
+				return getFloat(pidx, a, time) + getFloat(pidx, b, time);
 			default: 0.0;
 		}
 		return 0.0;
@@ -74,30 +47,24 @@ class Evaluator {
 			case VAdd(a, b):
 				return getSum(a, time) + getSum(b, time);
 			case VMult(a, b):
-				throw "Not implemented";
-				return 0.0;
-			default: 0.0;
+			default: throw "Not implemented";
 		}
 		return 0.0;
 	}
 
-	public function getVector(v: Value, time: Float, ?vec: h3d.Vector) : h3d.Vector {
-		if(vec == null)
-			vec = vecPool != null ? vecPool.get() : new h3d.Vector();
+	public function getVector(pidx: Int=0, v: Value, time: Float, vec: h3d.Vector) {
 		switch(v) {
 			case VMult(a, b):
-				var av = getVector(a, time);
-				var bv = getVector(b, time);
-				vec.set(av.x * bv.x, av.y * bv.y, av.z * bv.z, av.w * bv.w);
+				throw "need optimization";
 			case VVector(x, y, z, null):
-				vec.set(getFloat(x, time), getFloat(y, time), getFloat(z, time), 1.0);
+				vec.set(getFloat(pidx, x, time), getFloat(pidx, y, time), getFloat(pidx, z, time), 1.0);
 			case VVector(x, y, z, w):
-				vec.set(getFloat(x, time), getFloat(y, time), getFloat(z, time), getFloat(w, time));
+				vec.set(getFloat(pidx, x, time), getFloat(pidx, y, time), getFloat(pidx, z, time), getFloat(pidx, w, time));
 			case VHsl(h, s, l, a):
-				var hval = getFloat(h, time);
-				var sval = getFloat(s, time);
-				var lval = getFloat(l, time);
-				var aval = getFloat(a, time);
+				var hval = getFloat(pidx, h, time);
+				var sval = getFloat(pidx, s, time);
+				var lval = getFloat(pidx, l, time);
+				var aval = getFloat(pidx, a, time);
 				vec.makeColor(hval, sval, lval);
 				vec.a = aval;
 			case VZero:
@@ -105,7 +72,7 @@ class Evaluator {
 			case VOne:
 				vec.set(1,1,1,1);
 			default:
-				var f = getFloat(v, time);
+				var f = getFloat(pidx, v, time);
 				vec.set(f, f, f, 1.0);
 		}
 		return vec;

+ 1 - 6
hrt/prefab/fx/FX.hx

@@ -27,7 +27,6 @@ class FXAnimation extends h3d.scene.Object {
 	public var shaderAnims : Array<ShaderAnimation> = [];
 	public var constraints : Array<hrt.prefab.l3d.Constraint>;
 
-	public var vecPool = new Evaluator.VecPool();
 	var evaluator : Evaluator;
 	var parentFX : FXAnimation;
 	var random : hxd.Rand;
@@ -39,8 +38,7 @@ class FXAnimation extends h3d.scene.Object {
 		super(parent);
 		randSeed = #if editor 0 #else Std.random(0xFFFFFF) #end;
 		random = new hxd.Rand(randSeed);
-		evaluator = new Evaluator(random);
-		evaluator.vecPool = vecPool;
+		evaluator = new Evaluator();
 		name = "FXAnimation";
 		inheritCulled = true;
 	}
@@ -54,8 +52,6 @@ class FXAnimation extends h3d.scene.Object {
 		events = initEvents(root, ctx);
 		var root = def.getFXRoot(ctx, def);
 		initConstraints(ctx, root != null ? root : def);
-		for(s in shaderAnims)
-			s.vecPool = vecPool;
 	}
 
 	override function onRemove() {
@@ -146,7 +142,6 @@ class FXAnimation extends h3d.scene.Object {
 	public function setTime( time : Float, fullSync=true ) {
 		this.localTime = time;
 		if(fullSync) {
-			vecPool.begin();
 			if(objAnims != null) {
 				for(anim in objAnims) {
 					if(anim.scale != null || anim.rotation != null || anim.position != null) {

+ 11 - 10
hrt/prefab/fx/FX2D.hx

@@ -28,7 +28,7 @@ class FX2DAnimation extends h2d.Object {
 	public function new(?parent) {
 		super(parent);
 		random = new hxd.Rand(Std.random(0xFFFFFF));
-		evaluator = new Evaluator(random);
+		evaluator = new Evaluator();
 		name = "FX2DAnimation";
 		setTime(0);
 	}
@@ -75,26 +75,27 @@ class FX2DAnimation extends h2d.Object {
 	}
 
 
+	static var tmpPt = new h3d.Vector();
 	public function setTime( time : Float ) {
 
 		this.localTime = time;
 
 		for(anim in objects) {
 			if(anim.scale != null) {
-				var scale = evaluator.getVector(anim.scale, time);
-				anim.obj2d.scaleX = scale.x;
-				anim.obj2d.scaleY = scale.y;
+				evaluator.getVector(anim.scale, time, tmpPt);
+				anim.obj2d.scaleX = tmpPt.x;
+				anim.obj2d.scaleY = tmpPt.y;
 			}
 
 			if(anim.rotation != null) {
-				var rotation = evaluator.getVector(anim.rotation, time);
-				anim.obj2d.rotation = rotation.x * (Math.PI / 180.0);
+				var rotation = evaluator.getFloat(anim.rotation, time);
+				anim.obj2d.rotation = rotation * (Math.PI / 180.0);
 			}
 
 			if(anim.position != null) {
-				var pos = evaluator.getVector(anim.position, time);
-				anim.obj2d.x = anim.elt2d.x + pos.x;
-				anim.obj2d.y = anim.elt2d.y + pos.y;
+				evaluator.getVector(anim.position, time, tmpPt);
+				anim.obj2d.x = anim.elt2d.x + tmpPt.x;
+				anim.obj2d.y = anim.elt2d.y + tmpPt.y;
 			}
 
 			if(anim.visibility != null)
@@ -107,7 +108,7 @@ class FX2DAnimation extends h2d.Object {
 					default:
 						var drawable = Std.downcast(anim.obj2d, h2d.Drawable);
 						if (drawable != null)
-							drawable.color = evaluator.getVector(anim.color, time);
+							evaluator.getVector(anim.color, time, drawable.color);
 				}
 			}
 

+ 1 - 0
hrt/prefab/fx/Value.hx

@@ -8,6 +8,7 @@ enum Value {
 	VCurveScale(c: Curve, scale: Float);
 	VRandom(idx: Int, scale: Value);
 	VRandomScale(idx: Int, scale: Float);
+	VAddRandCurve(cst: Float, ridx: Int, rscale: Float, c: Curve);
 	VAdd(a: Value, b: Value);
 	VMult(a: Value, b: Value);
 	VVector(x: Value, y: Value, z: Value, ?w: Value);

+ 1 - 1
hrt/prefab/l2d/Particle2D.hx

@@ -27,7 +27,7 @@ class Particles extends h2d.Particles {
 		super(parent);
 		randomSeed = Std.random(0xFFFFFF);
 		random = new hxd.Rand(randomSeed);
-		evaluator = new Evaluator(random);
+		evaluator = new Evaluator();
 	}
 
 	function tick( dt : Float, full=true) {

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików