Browse Source

Adding SplineMeshSpawner. some clean on Spline and SplineMesh.

clementlandrin 3 months ago
parent
commit
6277e0175c
3 changed files with 151 additions and 23 deletions
  1. 10 15
      hrt/prefab/l3d/Spline.hx
  2. 11 8
      hrt/prefab/l3d/SplineMesh.hx
  3. 130 0
      hrt/prefab/l3d/SplineMeshSpawner.hx

+ 10 - 15
hrt/prefab/l3d/Spline.hx

@@ -83,11 +83,17 @@ class SplinePoint {
 }
 }
 
 
 @:allow(hrt.prefab.l3d.SplineMesh)
 @:allow(hrt.prefab.l3d.SplineMesh)
+@:allow(hrt.prefab.l3d.SplineMeshSpawner)
 class Spline extends hrt.prefab.Object3D {
 class Spline extends hrt.prefab.Object3D {
 	static var OLD_CLASS_POINT = "splinePoint";
 	static var OLD_CLASS_POINT = "splinePoint";
 
 
 	@:c public var points: Array<SplinePoint> = []; // Local to spline
 	@:c public var points: Array<SplinePoint> = []; // Local to spline
-	@:c var samples: Array<SplinePoint> = null; // World relative
+	@:c var samples(get, default): Array<SplinePoint> = null; // World relative
+	function get_samples() {
+		if ( samples == null )
+			computeSamples();
+		return samples;
+	}
 
 
 	@:s public var loop : Bool = false;
 	@:s public var loop : Bool = false;
 	@:s public var sampleResolution: Int = 16;
 	@:s public var sampleResolution: Int = 16;
@@ -134,9 +140,6 @@ class Spline extends hrt.prefab.Object3D {
 		obj.points = [ for (p in points) p.save()];
 		obj.points = [ for (p in points) p.save()];
 		obj.shape = shape.getIndex();
 		obj.shape = shape.getIndex();
 
 
-		if (samples == null)
-			computeSamples();
-
 		obj.samples = [ for (s in samples) s.save()];
 		obj.samples = [ for (s in samples) s.save()];
 		return obj;
 		return obj;
 	}
 	}
@@ -234,15 +237,14 @@ class Spline extends hrt.prefab.Object3D {
 				h.material.mainPass.depth(false, overlayGizmos ? Always : LessEqual);
 				h.material.mainPass.depth(false, overlayGizmos ? Always : LessEqual);
 		}
 		}
 
 
-		var splineMeshes = findAll(SplineMesh, true);
-		for ( s in splineMeshes )
+		for ( s in findAll(SplineMesh, true) )
+			s.updateInstance();
+		for ( s in findAll(hrt.prefab.l3d.SplineMeshSpawner, true) )
 			s.updateInstance();
 			s.updateInstance();
 	}
 	}
 
 
 
 
 	inline public function getSplinePoint(t: Float, ?out: SplinePoint) : SplinePoint {
 	inline public function getSplinePoint(t: Float, ?out: SplinePoint) : SplinePoint {
-		if (samples == null)
-			computeSamples();
 
 
 		if (samples.length <= 1)
 		if (samples.length <= 1)
 			return null;
 			return null;
@@ -296,8 +298,6 @@ class Spline extends hrt.prefab.Object3D {
 	}
 	}
 
 
 	inline public function getPoint(t: Float, ?out: h3d.col.Point) : h3d.col.Point {
 	inline public function getPoint(t: Float, ?out: h3d.col.Point) : h3d.col.Point {
-		if (samples == null)
-			computeSamples();
 
 
 		if (samples.length <= 1)
 		if (samples.length <= 1)
 			return null;
 			return null;
@@ -346,9 +346,6 @@ class Spline extends hrt.prefab.Object3D {
 	}
 	}
 
 
 	inline public function getNearestPointProgressOnSpline(p: h3d.col.Point) : Float {
 	inline public function getNearestPointProgressOnSpline(p: h3d.col.Point) : Float {
-		if (samples == null)
-			computeSamples();
-
 		var closestSq = hxd.Math.POSITIVE_INFINITY;
 		var closestSq = hxd.Math.POSITIVE_INFINITY;
 		var closestT = 0.;
 		var closestT = 0.;
 		var c = p;
 		var c = p;
@@ -390,8 +387,6 @@ class Spline extends hrt.prefab.Object3D {
 	}
 	}
 
 
 	public function getLength() {
 	public function getLength() {
-		if (samples == null)
-			computeSamples();
 		if (samples == null || samples.length == 0)
 		if (samples == null || samples.length == 0)
 			return 0.0;
 			return 0.0;
 		return samples[samples.length - 1].length;
 		return samples[samples.length - 1].length;

+ 11 - 8
hrt/prefab/l3d/SplineMesh.hx

@@ -41,7 +41,12 @@ class SplineMesh extends hrt.prefab.Object3D {
 
 
 	static var SPLINE_FMT = hxd.BufferFormat.make([{ name : "position", type : DVec3 }, { name : "normal", type : DVec3 }, { name : "tangent", type : DVec3 }, { name : "uv", type : DVec2 }]);
 	static var SPLINE_FMT = hxd.BufferFormat.make([{ name : "position", type : DVec3 }, { name : "normal", type : DVec3 }, { name : "tangent", type : DVec3 }, { name : "uv", type : DVec2 }]);
 
 
-	var spline : Spline = null;
+	var spline(get, default) : Spline = null;
+	function get_spline() {
+		if ( spline == null )
+			spline = findParent(Spline, null, false, true);
+		return spline;
+	}
 
 
 	@:s var scaleUVy : Float = 1.0;
 	@:s var scaleUVy : Float = 1.0;
 	@:s var scaleUVx : Float = 1.0;
 	@:s var scaleUVx : Float = 1.0;
@@ -63,8 +68,6 @@ class SplineMesh extends hrt.prefab.Object3D {
 	}
 	}
 
 
 	override function makeObject(parent3d: h3d.scene.Object) : h3d.scene.Object {
 	override function makeObject(parent3d: h3d.scene.Object) : h3d.scene.Object {
-		if (spline == null)
-			spline = findParent(Spline, null, false, true);
 		return new SplineMeshObject(spline, null, parent3d);
 		return new SplineMeshObject(spline, null, parent3d);
 	}
 	}
 
 
@@ -72,8 +75,6 @@ class SplineMesh extends hrt.prefab.Object3D {
 		super.updateInstance(propName);
 		super.updateInstance(propName);
 		disposeSplineMesh();
 		disposeSplineMesh();
 
 
-		if (spline == null)
-			spline = findParent(Spline, null, false, true);
 		if ( spline == null || spline.samples == null )
 		if ( spline == null || spline.samples == null )
 			computeDefaultSplineMesh();
 			computeDefaultSplineMesh();
 		else
 		else
@@ -192,7 +193,8 @@ class SplineMesh extends hrt.prefab.Object3D {
 		var vertexData = new hxd.FloatBuffer(splineDataSize * count);
 		var vertexData = new hxd.FloatBuffer(splineDataSize * count);
 
 
 		var localPoints = getLocalPoints();
 		var localPoints = getLocalPoints();
-
+		var splineInvAbsPos = spline.getAbsPos(true).getInverse();
+		
 		var dataPos = 0;
 		var dataPos = 0;
 		for ( s in 0...count ) {
 		for ( s in 0...count ) {
 			var spacing = s * spacing - spacing * (count - 1) * 0.5;
 			var spacing = s * spacing - spacing * (count - 1) * 0.5;
@@ -202,12 +204,13 @@ class SplineMesh extends hrt.prefab.Object3D {
 				var absPos = spline.globalToLocal(samples[i].pos);
 				var absPos = spline.globalToLocal(samples[i].pos);
 				var curPos = absPos.clone();
 				var curPos = absPos.clone();
 				uv += curPos.distance(prevPos);
 				uv += curPos.distance(prevPos);
-				var tangent = samples[i].tangentOut.transformed3x3(spline.getAbsPos(true).getInverse()).normalized();
+				var tangent = samples[i].tangentOut.transformed3x3(splineInvAbsPos).normalized();
 				var q = new h3d.Quat();
 				var q = new h3d.Quat();
 				q.initDirection(tangent);
 				q.initDirection(tangent);
+				var euler = q.toEuler();
 				var trs = new h3d.Matrix();
 				var trs = new h3d.Matrix();
 				trs.initTranslation(0.0, spacing, 0.0);
 				trs.initTranslation(0.0, spacing, 0.0);
-				trs.rotate(q.toEuler().x, q.toEuler().y, q.toEuler().z);
+				trs.rotate(euler.x, euler.y, euler.z);
 				trs.translate(absPos.x, absPos.y, absPos.z);
 				trs.translate(absPos.x, absPos.y, absPos.z);
 				fillPoint(vertexData, dataPos, localPoints, trs, uv, bounds);
 				fillPoint(vertexData, dataPos, localPoints, trs, uv, bounds);
 				dataPos += vertexDataStride * vertexPerPoint;
 				dataPos += vertexDataStride * vertexPerPoint;

+ 130 - 0
hrt/prefab/l3d/SplineMeshSpawner.hx

@@ -0,0 +1,130 @@
+package hrt.prefab.l3d;
+
+class SplineMeshSpawnerObject extends h3d.scene.Object {
+	var spline : Spline;
+	var batches : Array<h3d.scene.MeshBatch> = [];
+
+	override public function new(spline : Spline, parent : h3d.scene.Object) {
+		super(parent);
+		this.spline = spline;
+	}
+
+	public function init() {
+		for ( b in batches )
+			b.remove();
+		batches = [];
+
+		var points = spline.points;
+		if ( points == null || points.length < 2 )
+			return;
+
+		var meshes = findAll(o -> Std.downcast(o, h3d.scene.Mesh));
+		for ( mesh in meshes ) {
+			var prim = Std.downcast(mesh.primitive, h3d.prim.MeshPrimitive);
+			mesh.culled = prim != null;
+			if ( prim == null )
+				continue;
+			var meshRelPos = new h3d.Matrix();
+			meshRelPos.multiply3x4inline(mesh.getAbsPos(), this.getAbsPos().getInverse());
+			var multi = Std.downcast(mesh, h3d.scene.MultiMaterial);
+			var batch = new h3d.scene.MeshBatch(prim, null, this);
+			batches.push(batch);
+			batch.materials = multi != null ? [for ( m in multi.materials ) m] : [mesh.material];
+			batch.worldPosition = new h3d.Matrix();
+			batch.begin();
+
+			var primBounds = prim.getBounds();
+			var primMin = primBounds.getMin();
+			var primMax = primBounds.getMax();
+			var primSize = primBounds.getSize();
+
+			for ( i in 0...points.length-1 ) {
+				var from = points[i];
+				var to = points[i+1];
+
+				var dist = to.pos.sub(from.pos).length();
+				var count = hxd.Math.imax(Math.floor(dist / primSize.x), 1);
+				var distPerCount = dist / count;
+
+				for ( j in 0...count ) {
+					var dir = to.pos.sub(from.pos).normalized();
+					var q = new h3d.Quat();
+					q.initDirection(dir, from.up);
+					var matRot = q.toMatrix();
+
+					batch.worldPosition.identity();
+					batch.worldPosition.load(meshRelPos);
+					var scale = distPerCount / primSize.x;
+					batch.worldPosition.translate(-primMin.x, 0.0, 0.0);
+					batch.worldPosition.scale(scale);
+					batch.worldPosition.multiply3x4inline(batch.worldPosition, matRot);
+					var start = new h3d.Vector();
+					start.lerp(from.pos, to.pos, j/count);
+					batch.worldPosition.translate(start.x, start.y, start.z);
+					batch.emitInstance();
+				}
+			}
+		}
+		
+	}
+}
+
+class SplineMeshSpawner extends hrt.prefab.Object3D {
+
+	var spline(get, default) : Spline = null;
+	function get_spline() {
+		if ( spline == null )
+			spline = findParent(Spline, null, false, true);
+		return spline;
+	}
+
+	override function makeObject(parent3d: h3d.scene.Object) : h3d.scene.Object {
+		return new SplineMeshSpawnerObject(spline, parent3d);
+	}
+
+	override function updateInstance(?propName : String ) {
+		super.updateInstance(propName);
+
+		if ( spline != null && spline.samples != null )
+			init();
+	}
+
+	override function postMakeInstance() {
+		super.postMakeInstance();
+		init();
+	}
+
+	function init() {
+		if ( local3d != null )
+			cast(local3d, SplineMeshSpawnerObject).init();
+	}
+
+	#if editor
+	override function edit( ctx : hide.prefab.EditContext ) {
+		super.edit(ctx);
+
+		var props = new hide.Element('
+			<div class="group" name="Preview">
+				<dl>
+					<dt>Points</dt><dd><input type="range" min="4" max="64" step="1" field="previewPointCount"/></dd>
+					<dt>Radius</dt><dd><input type="range" min="1" max="10" field="previewRadius"/></dd>
+				</dl>
+			</div>
+			');
+
+		props.find(".refresh").click(function(_) { ctx.onChange(this, null); });
+		ctx.properties.add(props, this, function(pname) { ctx.onChange(this, pname); });
+	}
+
+	override function getHideProps() : hide.prefab.HideProps {
+		return {
+			icon : "arrows-v",
+			name : "SplineMeshSpawner",
+			allowParent : (p) -> Std.isOfType(p, Spline) || p.parent == null,
+			onChildUpdate : (p) -> init(),
+		};
+	}
+	#end
+
+	static var _ = hrt.prefab.Prefab.register("splineMeshSpawner", SplineMeshSpawner);
+}