Quellcode durchsuchen

started gpu particles with inspector

ncannasse vor 9 Jahren
Ursprung
Commit
dcc8bb1f68
5 geänderte Dateien mit 263 neuen und 3 gelöschten Zeilen
  1. 176 0
      h3d/parts/GpuParticles.hx
  2. 2 0
      h3d/scene/Mesh.hx
  3. 40 0
      h3d/shader/GpuParticle.hx
  4. 1 0
      hxd/inspect/PropManager.hx
  5. 44 3
      hxd/inspect/ScenePanel.hx

+ 176 - 0
h3d/parts/GpuParticles.hx

@@ -0,0 +1,176 @@
+package h3d.parts;
+import hxd.Math;
+
+enum GpuEmitMode {
+	Point;
+	Cone;
+	VolumeBounds;
+	ParentBounds;
+}
+
+enum GpuPartFlag {
+}
+
+class GpuParticles extends h3d.scene.Mesh {
+
+	var needRebuild = true;
+	var pshader : h3d.shader.GpuParticle;
+	public var emitMode(default,set):GpuEmitMode= Point;
+	public var emitDist(default, set) : Float	= 1.;
+	public var emitAngle(default,set) : Float 	= Math.PI;
+	public var seed(default, set) : Int			= Std.random(0x1000000);
+	public var nparts(default, set) : Int 		= 100;
+	public var size(default, set) : Float		= 1;
+	public var sizeIncr(default, set) : Float	= 0;
+	public var sizeRand(default, set) : Float	= 0;
+	public var life(default, set) : Float		= 1;
+	public var lifeRand(default, set) : Float	= 0;
+	public var speed(default, set) : Float		= 1;
+	public var speedRand(default, set) : Float	= 0;
+	public var speedIncr : Float				= 0;
+
+	public var rotInit(default, set) : Float	= 0;
+	public var rotSpeed(default, set) : Float	= 0;
+	public var rotSpeedRand(default, set):Float = 0;
+
+	public var fadePower : Float				= 2;
+	public var volumeBounds(default, set) : h3d.col.Bounds;
+	public var partFlags(default, set) : haxe.EnumFlags<GpuPartFlag>;
+
+	public function new( ?parent ) {
+		super(null, null, parent);
+		pshader = new h3d.shader.GpuParticle();
+		material.mainPass.addShader(pshader);
+		material.mainPass.culling = None;
+		material.mainPass.depthWrite = false;
+		material.blendMode = Alpha;
+	}
+
+	inline function set_seed(v) { needRebuild = true; return seed = v; }
+	inline function set_size(v) { needRebuild = true; return size = v; }
+	inline function set_sizeRand(v) { needRebuild = true; return sizeRand = v; }
+	inline function set_sizeIncr(v) { needRebuild = true; return sizeIncr = v; }
+	inline function set_speed(v) { needRebuild = true; return speed = v; }
+	inline function set_speedRand(v) { needRebuild = true; return speedRand = v; }
+	inline function set_life(v) { needRebuild = true; return life = v; }
+	inline function set_lifeRand(v) { needRebuild = true; return lifeRand = v; }
+	inline function set_nparts(n) { if( n > nparts ) needRebuild = true; return nparts = n; }
+	inline function set_volumeBounds(v) { needRebuild = true; return volumeBounds = v; }
+	inline function set_emitMode(v) { needRebuild = true; return emitMode = v; }
+	inline function set_emitDist(v) { needRebuild = true; return emitDist = v; }
+	inline function set_emitAngle(v) { needRebuild = true; return emitAngle = v; }
+	inline function set_partFlags(v) { needRebuild = true; return partFlags = v; }
+	inline function set_rotInit(v) { needRebuild = true; return rotInit = v; }
+	inline function set_rotSpeed(v) { needRebuild = true; return rotSpeed = v; }
+	inline function set_rotSpeedRand(v) { needRebuild = true; return rotSpeedRand = v; }
+
+	override function sync(ctx) {
+		super.sync(ctx);
+		if( !needRebuild ) return;
+		needRebuild = false;
+		if( primitive != null ) {
+			primitive.dispose();
+			primitive = null;
+		}
+		var vbuf = new hxd.FloatBuffer();
+		var uvs = [new h3d.prim.UV(0, 0), new h3d.prim.UV(1, 0), new h3d.prim.UV(0, 1), new h3d.prim.UV(1, 1)];
+		var rnd = new hxd.Rand(seed);
+		var ebounds = null;
+		for( i in 0...nparts ) {
+
+			inline function rand() return rnd.rand();
+			inline function srand() return rnd.srand();
+
+			var size = size * (1 + srand() * sizeRand), rot = srand() * Math.PI * rotInit;
+			var vsize = sizeIncr, vrot = rotSpeed * (1 + rand() * rotSpeedRand) * (srand() < 0 ? -1 : 1);
+
+
+			var life = life * (1 + srand() * lifeRand), time = rand() * life;
+
+			var p = new h3d.col.Point();
+			var v = new h3d.col.Point();
+
+			switch( emitMode ) {
+			case Point:
+
+				v.x = rand();
+				v.y = rand();
+				v.z = rand();
+				v.normalizeFast();
+
+			case Cone:
+				var theta = rand() * Math.PI * 2;
+				var phi = emitAngle * rand();
+				var r = emitDist * rand();
+				v.x = Math.sin(phi) * Math.cos(theta);
+				v.y = Math.sin(phi) * Math.sin(theta);
+				v.z = Math.cos(phi);
+				p.x = v.x * r;
+				p.y = v.y * r;
+				p.z = v.z * r;
+
+			case ParentBounds, VolumeBounds:
+
+				if( ebounds == null ) {
+					if( emitMode == ParentBounds ) {
+						ebounds = parent.getBounds();
+						ebounds.transform3x4(getInvPos());
+					} else {
+						ebounds = volumeBounds;
+						if( ebounds == null ) ebounds = h3d.col.Bounds.fromValues( -1, -1, -1, 2, 2, 2 );
+					}
+				}
+
+				p.x = rand() * ebounds.xSize + ebounds.xMin;
+				p.y = rand() * ebounds.ySize + ebounds.yMin;
+				p.z = rand() * ebounds.zSize + ebounds.zMin;
+
+				v.x = rand();
+				v.y = rand();
+				v.z = rand();
+				v.normalizeFast();
+
+
+			}
+
+
+			var speed = speed * (1 + srand() * speedRand);
+
+			v.x *= speed;
+			v.y *= speed;
+			v.z *= speed;
+
+			inline function add(v) vbuf.push(v);
+			for( u in uvs ) {
+				add(p.x);
+				add(p.y);
+				add(p.z);
+
+				add(v.x);
+				add(v.y);
+				add(v.z);
+
+				add(u.u);
+				add(u.v);
+				add(time);
+				add(life);
+
+				add(rot);
+				add(size);
+				add(vrot);
+				add(vsize);
+			}
+		}
+		primitive = new h3d.prim.RawPrimitive( { vbuf : vbuf, stride : 14, quads : true }, true);
+		primitive.buffer.flags.set(RawFormat);
+	}
+
+	override function draw( ctx : h3d.scene.RenderContext ) {
+		pshader.speedIncr = speedIncr;
+		pshader.fadePower = fadePower;
+		@:privateAccess if( primitive.buffer == null || primitive.buffer.isDisposed() ) primitive.alloc(ctx.engine);
+		@:privateAccess ctx.engine.renderQuadBuffer(primitive.buffer,0,nparts*2);
+	}
+
+
+}

+ 2 - 0
h3d/scene/Mesh.hx

@@ -14,6 +14,8 @@ class Mesh extends Object {
 
 	override function getBounds( ?b : h3d.col.Bounds, rec = false ) {
 		b = super.getBounds(b, rec);
+		if( primitive == null )
+			return b;
 		var tmp = primitive.getBounds().clone();
 		tmp.transform3x4(absPos);
 		b.add(tmp);

+ 40 - 0
h3d/shader/GpuParticle.hx

@@ -0,0 +1,40 @@
+package h3d.shader;
+
+class GpuParticle extends hxsl.Shader {
+
+	static var SRC = {
+
+		@:import h3d.shader.BaseMesh;
+
+		@input var props : {
+			var uv : Vec2;
+			var time : Float;
+			var life : Float;
+			var init : Vec2;
+			var delta : Vec2;
+		};
+
+		@param var fadePower : Float;
+		@param var speedIncr : Float;
+
+		var t : Float;
+
+		function __init__() {
+			t = (props.time + global.time) % props.life;
+			transformedPosition = input.position + input.normal * t; // already transformed
+			transformedNormal = camera.dir;
+		}
+
+		function vertex() {
+			var current = props.init + props.delta * t;
+			projectedPosition = vec4(transformedPosition, 1) * camera.viewProj;
+			var size = (props.uv - 0.5) * current.y.max(0.);
+			var rot = current.x;
+			var crot = cos(rot), srot = sin(rot);
+			projectedPosition.xy += vec2(size.x * crot - size.y * srot, size.x * srot + size.y * crot) * vec2(global.pixelSize.x / global.pixelSize.y, 1);
+			pixelColor.a = 1 - abs((t / props.life) * 2 - 1).pow(fadePower);
+		}
+
+	};
+
+}

+ 1 - 0
hxd/inspect/PropManager.hx

@@ -80,6 +80,7 @@ class PropManager extends cdb.jq.Client {
 		if( pendingMessages == null ) return;
 		var msg = pendingMessages.length == 1 ? pendingMessages[0] : cdb.jq.Message.Group(pendingMessages);
 		pendingMessages = null;
+		if( sock == null ) return;
 		var data = cdb.BinSerializer.serialize(msg);
 		sock.out.wait();
 		sock.out.writeInt32(data.length);

+ 44 - 3
hxd/inspect/ScenePanel.hx

@@ -192,6 +192,8 @@ class ScenePanel extends Panel {
 	function getObjectIcon( o : h3d.scene.Object) {
 		if( Std.is(o, h3d.scene.Skin) )
 			return "child";
+		if( Std.is(o, h3d.parts.Particles) || Std.is(o,h3d.parts.GpuParticles) )
+			return "sun-o";
 		if( Std.is(o, h3d.scene.Mesh) )
 			return "cube";
 		if( Std.is(o, h3d.scene.CustomObject) )
@@ -258,10 +260,8 @@ class ScenePanel extends Panel {
 			for( c in o )
 				syncRec(c, so);
 		} else if( so.jchild != null ) {
-			for( o in so.childs )
+			for( o in so.childs.copy() )
 				o.dispose();
-			so.jchild.remove();
-			so.jchild = null;
 			if( so.openIcon == "circle-o" ) {
 				so.openIcon = null;
 				so.icon = "circle-o";
@@ -446,6 +446,11 @@ class ScenePanel extends Panel {
 					props.push(getMaterialProps(m));
 			} else
 				props.push(getMaterialProps(o.toMesh().material));
+
+			var gp = Std.instance(o, h3d.parts.GpuParticles);
+			if( gp != null )
+				props = props.concat(getPartsProps(gp));
+
 		} else {
 			var c = Std.instance(o, h3d.scene.CustomObject);
 			if( c != null )
@@ -457,6 +462,42 @@ class ScenePanel extends Panel {
 		return props;
 	}
 
+	function getPartsProps( o : h3d.parts.GpuParticles ) {
+		var props = [];
+		props.push(PGroup("Emitter", [
+			PEnum("mode", h3d.parts.GpuParticles.GpuEmitMode, function() return o.emitMode, function(v) o.emitMode = v),
+			PInt("seed", function() return o.seed, function(v) o.seed = v),
+			PRange("count", 0, 1000, function() return o.nparts, function(v) o.nparts = Std.int(v), 1),
+			PRange("distance", 0, 10, function() return o.emitDist, function(v) o.emitDist = v),
+			PRange("angle", -Math.PI, Math.PI * 2, function() return o.emitAngle, function(v) o.emitAngle = v),
+		]));
+
+		props.push(PGroup("Life", [
+			PRange("initial", 0, 10, function() return o.life, function(v) o.life = v),
+			PRange("randomNess", 0, 1, function() return o.lifeRand, function(v) o.lifeRand = v),
+		]));
+
+		props.push(PGroup("Speed", [
+			PRange("initial", 0, 10, function() return o.speed, function(v) o.speed = v),
+			PRange("randomNess", 0, 1, function() return o.speedRand, function(v) o.speedRand = v),
+			PRange("acceleration", -1, 1, function() return o.speedIncr, function(v) o.speedIncr = v),
+		]));
+
+		props.push(PGroup("Size", [
+			PRange("initial", 0.01, 2, function() return o.size, function(v) o.size = v),
+			PRange("randomNess", 0, 1, function() return o.sizeRand, function(v) o.sizeRand = v),
+			PRange("grow", -1, 1, function() return o.sizeIncr, function(v) o.sizeIncr = v),
+		]));
+
+		props.push(PGroup("Rotation", [
+			PRange("init", 0, 1, function() return o.rotInit, function(v) o.rotInit = v),
+			PRange("speed", 0, 5, function() return o.rotSpeed, function(v) o.rotSpeed = v),
+			PRange("randomNess", 0, 1, function() return o.rotSpeedRand, function(v) o.rotSpeedRand = v),
+		]));
+
+		return props;
+	}
+
 	function getDynamicProps( v : Dynamic ) : Array<Property> {
 		if( Std.is(v,h3d.pass.ScreenFx) || Std.is(v,Group) ) {
 			var props = [];