2
0
Эх сурвалжийг харах

MeshSpray : reduce lags + better preview brush

Tom Spira 5 жил өмнө
parent
commit
79827321cb

+ 6 - 4
hide/comp/SceneEditor.hx

@@ -1073,11 +1073,12 @@ class SceneEditor {
 		scene.init(ctx.local3d);
 	}
 
-	public function addObject(elts : Array<PrefabElement>) {
+	public function addObject(elts : Array<PrefabElement>, selectObj : Bool = true, doRefresh : Bool = true) {
 		for (e in elts) {
 			makeInstance(e);
 		}
-		refresh(Partial, () -> selectObjects(elts));
+		if (doRefresh)
+			refresh(Partial, if (selectObj) () -> selectObjects(elts) else null);
 		undo.change(Custom(function(undo) {
 			var fullRefresh = false;
 			if(undo) {
@@ -1620,7 +1621,7 @@ class SceneEditor {
 			obj3d.updateInstance(ctx);
 	}
 
-	public function deleteElements(elts : Array<PrefabElement>, ?then: Void->Void) {
+	public function deleteElements(elts : Array<PrefabElement>, ?then: Void->Void, doRefresh : Bool = true) {
 		var fullRefresh = false;
 		var undoes = [];
 		for(elt in elts) {
@@ -1638,7 +1639,8 @@ class SceneEditor {
 			refresh(fullRefresh ? Full : Partial, then);
 		}
 
-		refreshFunc(then != null ? then : deselect);
+		if (doRefresh)
+			refreshFunc(then != null ? then : deselect);
 
 		undo.change(Custom(function(undo) {
 			if(!undo && !fullRefresh)

+ 130 - 31
hrt/prefab/l3d/MeshSpray.hx

@@ -23,7 +23,7 @@ class MeshSpray extends Object3D {
 
 	var sprayEnable : Bool = false;
 	var interactive : h2d.Interactive;
-	var gBrush : h3d.scene.Graphics;
+	var gBrush : h3d.scene.Mesh;
 
 	var timerCicle : haxe.Timer;
 
@@ -83,6 +83,7 @@ class MeshSpray extends Object3D {
 		return childParts[childParts.length - 1].split(".")[0];
 	}
 
+	var wasEdited = false;
 	override function edit( ectx : EditContext ) {
 		sceneEditor = ectx.scene.editor;
 
@@ -100,18 +101,22 @@ class MeshSpray extends Object3D {
 		interactive.onPush = function(e) {
 			e.propagate = false;
 			sprayEnable = true;
-
+			var worldPos = getMousePicker(s2d.mouseX, s2d.mouseY);
+			addMeshesAround(ctx, worldPos);
 		};
 
 		interactive.onRelease = function(e) {
 			e.propagate = false;
 			sprayEnable = false;
+			if (wasEdited)
+				sceneEditor.refresh(Partial, () -> { });
+			wasEdited = false;
 		};
 
 		interactive.onMove = function(e) {
-			var worldPos = screenToWorld(s2d.mouseX, s2d.mouseY);
+			var worldPos = getMousePicker(s2d.mouseX, s2d.mouseY);
 
-			drawCircle(ctx, worldPos.x, worldPos.y, getZ(worldPos.x, worldPos.y), radius, 2, 16711680);
+			drawCircle(ctx, worldPos.x, worldPos.y, worldPos.z, radius, 5, 16711680);
 
 			if( K.isDown( K.MOUSE_LEFT) ) {
 				e.propagate = false;
@@ -205,7 +210,7 @@ class MeshSpray extends Object3D {
 			timerCicle = new haxe.Timer(100);
 			timerCicle.run = function() {
 				timerCicle.stop();
-				if (gBrush != null) gBrush.remove();
+				gBrush.visible = false;
 			};
 		}
 	}
@@ -219,6 +224,7 @@ class MeshSpray extends Object3D {
 		meshes.remove(path);
 	}
 
+	var localMat = new h3d.Matrix();
 	function addMeshesAround(ctx : Context, point : h3d.col.Point) {
 		if (meshes.length == 0) {
 			throw "There is no meshes";
@@ -293,7 +299,6 @@ class MeshSpray extends Object3D {
 				model.source = meshes[meshId];
 				model.name = extractMeshName(model.source);
 
-				var localMat = new h3d.Matrix();
 				localMat.initRotationZ(rotationZ);
 
 				var randScaleOffset = random.rand() * scaleOffset;
@@ -317,8 +322,11 @@ class MeshSpray extends Object3D {
 				currentPivots.push(new h2d.col.Point(model.x, model.y));
 			}
 
-			sceneEditor.addObject(models);
-			sceneEditor.selectObjects([this]);
+			if (models.length > 0) {
+				wasEdited = true;
+				sceneEditor.addObject(models, false, false);
+			}
+
 		}
 	}
 
@@ -338,44 +346,133 @@ class MeshSpray extends Object3D {
 				childToRemove.push(child);
 			}
 		}
-		sceneEditor.deleteElements(childToRemove);
-		sceneEditor.selectObjects([this]);
+		if (childToRemove.length > 0) {
+			wasEdited = true;
+			sceneEditor.deleteElements(childToRemove, () -> { }, false);
+			sceneEditor.selectObjects([this]);
+		}
 	}
 
 	public function drawCircle(ctx : Context, originX : Float, originY : Float, originZ : Float, radius: Float, thickness: Float, color) {
-		if (gBrush != null) gBrush.remove();
-		gBrush = new h3d.scene.Graphics(ctx.local3d);
-		gBrush.material.props = h3d.mat.MaterialSetup.current.getDefaults("fx");
-		gBrush.material.mainPass.setPassName("overlay");
-		gBrush.material.shadows = false;
-		gBrush.setPosition(originX, originY, originZ + 0.15);
-		gBrush.lineStyle(thickness, color, 1.0);
-		gBrush.moveTo(radius, 0, 0);
-		var nsegments = 32;
-		for(i in 0...nsegments) {
-			var theta = Math.PI * 2 * (i+1)/nsegments;
-			gBrush.lineTo(Math.cos(theta) * radius, Math.sin(theta) * radius, 0);
+		if (gBrush == null || gBrush.scaleX != radius) {
+			if (gBrush != null) gBrush.remove();
+			gBrush = new h3d.scene.Mesh(makePrimCircle(32, 0.98), ctx.local3d);
+			gBrush.scaleX = gBrush.scaleY = radius;
+			gBrush.material.mainPass.setPassName("overlay");
+			gBrush.material.shadows = false;
+			gBrush.material.color = h3d.Vector.fromColor(color);
+			gBrush.material.color.w = 0.2;
+			gBrush.material.blendMode = AlphaAdd;
+		}
+		gBrush.visible = true;
+		gBrush.x = originX;
+		gBrush.y = originY;
+		gBrush.z = originZ+0.1;
+	}
+
+	function makePrimCircle(segments: Int, inner : Float = 0, rings : Int = 0) {
+		var points = [];
+		var uvs = [];
+		var indices = [];
+		++segments;
+		var anglerad = hxd.Math.degToRad(360);
+		for(i in 0...segments) {
+			var t = i / (segments - 1);
+			var a = hxd.Math.lerp(-anglerad/2, anglerad/2, t);
+			var ct = hxd.Math.cos(a);
+			var st = hxd.Math.sin(a);
+			for(r in 0...(rings + 2)) {
+				var v = r / (rings + 1);
+				var r = hxd.Math.lerp(inner, 1.0, v);
+				points.push(new h2d.col.Point(ct * r, st * r));
+				uvs.push(new h2d.col.Point(t, v));
+			}
+		}
+		for(i in 0...segments-1) {
+			for(r in 0...(rings + 1)) {
+				var idx = r + i * (rings + 2);
+				var nxt = r + (i + 1) * (rings + 2);
+				indices.push(idx);
+				indices.push(idx + 1);
+				indices.push(nxt);
+				indices.push(nxt);
+				indices.push(idx + 1);
+				indices.push(nxt + 1);
+			}
 		}
 
-		gBrush.lineStyle();
+		var verts = [for(p in points) new h3d.col.Point(p.x, p.y, 0.)];
+		var idx = new hxd.IndexBuffer();
+		for(i in indices)
+			idx.push(i);
+		var primitive = new h3d.prim.Polygon(verts, idx);
+		primitive.normals = [for(p in points) new h3d.col.Point(0, 0, 1.)];
+		primitive.tangents = [for(p in points) new h3d.col.Point(0., 1., 0.)];
+		primitive.uvs = [for(uv in uvs) new h3d.prim.UV(uv.x, uv.y)];
+		primitive.colors = [for(p in points) new h3d.col.Point(1,1,1)];
+		primitive.incref();
+		return primitive;
 	}
 
+	var terrainPrefab : hrt.prefab.terrain.Terrain = null;
+	
 	// GET Z with TERRAIN
-
 	public function getZ( x : Float, y : Float ) {
 		var z = this.z;
 
-		@:privateAccess var terrain = sceneEditor.sceneData.find(p -> Std.downcast(p, hrt.prefab.terrain.Terrain));
+		if (terrainPrefab == null)
+			@:privateAccess terrainPrefab = sceneEditor.sceneData.find(p -> Std.downcast(p, hrt.prefab.terrain.Terrain));
 
-		if(terrain != null){
+		if(terrainPrefab != null){
 			var pos = new h3d.Vector(x, y, 0);
 			pos.transform3x4(this.getTransform());
-			z = terrain.terrain.getHeight(pos.x, pos.y);
+			z = terrainPrefab.terrain.getHeight(pos.x, pos.y);
 		}
 
 		return z;
 	}
 
+	public function  getMousePicker( ?x, ?y ) {
+		var camera = sceneEditor.scene.s3d.camera;
+		var ray = camera.rayFromScreen(x, y);
+		var planePt = ray.intersect(h3d.col.Plane.Z());
+		var offset = ray.getDir();
+
+		// Find rough intersection point in the camera forward direction to get first collision point
+		final maxZBounds = 25;
+		offset.scale(maxZBounds);
+		var pt = planePt.clone();
+		pt.load(pt.sub(offset));
+
+		var step = ray.getDir();
+		step.scale(0.25);
+
+		while(pt.z > -maxZBounds) {
+			var z = getZ(pt.x, pt.y);
+			if(pt.z < z)
+				break;
+			pt.load(pt.add(step));
+		}
+
+		// Bissect search for exact intersection point
+		for(_ in 0...50) {
+			var z = getZ(pt.x, pt.y);
+			var delta = z - pt.z;
+			if(hxd.Math.abs(delta) < 0.05)
+				return pt;
+
+			if(delta < 0)
+				pt.load(pt.add(step));
+			else
+				pt.load(pt.sub(step));
+
+			step.scale(0.5);
+		}
+
+		return planePt;
+	}
+	
+
 	public function screenToWorld(sx: Float, sy: Float) {
 		var camera = sceneEditor.scene.s3d.camera;
 		var ray = camera.rayFromScreen(sx, sy);
@@ -387,15 +484,17 @@ class MeshSpray extends Object3D {
 	}
 
 	function projectToGround( ray: h3d.col.Ray ) {
-		var minDist = -1.;
-		@:privateAccess var terrainPrefab = sceneEditor.sceneData.find(p -> Std.downcast(p, hrt.prefab.terrain.Terrain));
+		var dist = 0.0;
+		if (terrainPrefab == null)
+			@:privateAccess terrainPrefab = sceneEditor.sceneData.find(p -> Std.downcast(p, hrt.prefab.terrain.Terrain));
+		
 		if (terrainPrefab != null) {
 			var normal = terrainPrefab.terrain.getAbsPos().up();
 			var plane = h3d.col.Plane.fromNormalPoint(normal.toPoint(), new h3d.col.Point(terrainPrefab.terrain.getAbsPos().tx, terrainPrefab.terrain.getAbsPos().ty, terrainPrefab.terrain.getAbsPos().tz));
 			var pt = ray.intersect(plane);
-			if(pt != null) { minDist = pt.sub(ray.getPos()).length();}
+			if(pt != null) { dist = pt.sub(ray.getPos()).length();}
 		}
-		return minDist;
+		return dist;
 	}
 
 	#end