Browse Source

Opti Hide

ShiroSmith 5 năm trước cách đây
mục cha
commit
e93d570919
2 tập tin đã thay đổi với 326 bổ sung1 xóa
  1. 323 0
      hide/Scene.hx
  2. 3 1
      hide/comp/Scene.hx

+ 323 - 0
hide/Scene.hx

@@ -0,0 +1,323 @@
+package hide;
+
+import h3d.scene.Interactive;
+import h3d.col.Sphere;
+import h3d.scene.RenderContext;
+
+class ChunkScene {
+
+	public var chunkSize : Float;
+	public var chunks : Array<Chunk> = [];
+	public var sceneKey : Float = 0;
+
+	var tmpVec = new h3d.Vector();
+
+	public function new( chunkSize ) {
+		this.chunkSize = chunkSize;
+		var global = new Chunk(new h3d.col.Point(0,0,0));
+		global.isGlobal = true;
+		chunks.push(global);
+	}
+
+	// Use a stack for an iterarive version
+	var stack : Array<h3d.scene.Object> = [];
+	inline public function getSceneKey( obj : h3d.scene.Object ) : Float {
+		var key = 0.0;
+		var curCount = 1;
+
+		stack[0] = obj;
+		while( curCount != 0 ) {
+			var obj = stack[curCount - 1];
+			stack[curCount - 1] = null;
+			curCount--;
+
+			if( !obj.visible )
+				continue;
+
+			var gizmo = Std.downcast(obj, hide.view.l3d.Gizmo);
+			if( gizmo != null ) 
+				continue;
+
+			// Ignore animated objects
+			if( obj.currentAnimation == null ) {
+				var absPos = @:privateAccess obj.absPos.getPosition(tmpVec);
+				key += absPos.x + absPos.y + absPos.z;
+				for( c in @:privateAccess obj.children ) {
+					stack[curCount] = c;
+					curCount++;
+				}
+			}
+		}
+		return key;
+	}
+
+	inline public function refreshInFrustumFlag( ctx : RenderContext ) {
+		for( c in chunks ) {
+			if( c.isGlobal ) 
+				c.inFrustum = true;
+			else
+				c.inFrustum = c.bounds.inFrustum(ctx.camera.frustum);
+		}
+	}
+
+	public function chunkifyScene( scene : h3d.scene.Scene ) {
+		for( c in chunks ) 
+			c.reset();
+		chunkifyInteractives(scene);
+		chunkifyObjects(scene, null);
+	}
+
+	public function chunkifyInteractives( scene : h3d.scene.Scene ) {
+		for( i in @:privateAccess scene.interactives ) {
+			
+			// Gizmo 
+			if(	i.priority >= 100 ) {
+				getGlobalChunk().addInteractive(i);
+			} 
+			else {
+				var oc = Std.downcast(i.shape, h3d.col.ObjectCollider);
+				if( oc != null && oc.obj != null && oc.obj.visible ) {
+					var pos = oc.obj.getAbsPos().getPosition();
+					var chunks = getChunks(new h3d.Vector(pos.x, pos.y), 0.0);
+					for( c in chunks ) 
+						c.addInteractive(i);
+				}
+			}
+		}
+	}
+	
+	inline function chunkifyObjects( obj : h3d.scene.Object, chunkOverride : Array<Chunk> ) {
+
+		// Gizmo exception
+		if( Std.downcast(obj, hide.view.l3d.Gizmo) != null ) {
+			var gc = getGlobalChunk();
+			chunkOverride = [gc];
+			gc.addObject(obj,0,0);
+			for( c in @:privateAccess obj.children )
+				chunkifyObjects(c, chunkOverride);
+			return;
+		}
+
+		if( !obj.visible ) 
+			return;
+
+		if( Std.downcast(obj, h3d.scene.Light) != null ) {
+			var gc = getGlobalChunk();
+			gc.addObject(obj,0,0);
+		}
+		else {
+			var absPos = obj.getAbsPos().getPosition(tmpVec);
+			var radius = 0.0;
+
+			// Mesh Support
+			var mesh = Std.downcast(obj, h3d.scene.Mesh);
+			if( mesh != null ) {
+				if( mesh.primitive != null ) {
+					var tmp = mesh.primitive.getBounds();
+					if( !tmp.isEmpty() ) 
+						radius = hxd.Math.max(hxd.Math.max(tmp.xSize * 0.5, tmp.ySize * 0.5), tmp.zSize * 0.5);
+				}
+			}
+			
+			if( chunkOverride == null || chunkOverride.length == 0 ) {
+				var chunks : Array<Chunk> = getChunks(absPos, radius);
+				for( c in chunks ) 
+					c.addObject(obj, radius, absPos.z);
+				if( obj.currentAnimation != null ) {
+					chunkOverride = chunks;
+				}
+			}
+			else {
+				for( c in chunkOverride ) {
+					c.addObject(obj, 0, 0);
+				}
+			}
+		}
+
+		for( c in @:privateAccess obj.children )
+			chunkifyObjects(c, chunkOverride);
+	}
+
+	inline function getGlobalChunk() : Chunk {
+		var result = null;
+		for( c in chunks ) {
+			if( c.isGlobal ) {
+				result = c;
+				break;
+			}
+		}
+		return result;
+	}
+
+	inline function getChunk( x : Int, y : Int ) {
+		var r = null;
+		for( c in chunks ) {
+			if( c.pos.x == x * chunkSize && c.pos.y == y * chunkSize) {
+				r = c;
+				break;
+			}
+		}
+		return r;
+	}
+
+	inline function getChunks( pos : h3d.Vector, radius : Float) : Array<Chunk> {
+		var result = [];
+		for( x in hxd.Math.floor(pos.x / chunkSize) ... hxd.Math.floor((pos.x + radius) / chunkSize) + 1) {
+			for( y in hxd.Math.floor(pos.y / chunkSize) ... hxd.Math.floor((pos.y + radius) / chunkSize) + 1) {
+				var c = getChunk(x,y);
+				if( c == null ) {
+					c = new Chunk(new h3d.col.Point(x * chunkSize, y * chunkSize));
+					c.updateBounds(chunkSize);
+					chunks.push(c);
+				}
+				result.push(c);
+			}
+		}
+		return result;
+	}
+}
+
+class Chunk {
+
+	public var isGlobal = false;
+	public var inFrustum = false;
+	public var bounds = new h3d.col.Bounds();
+	public var pos : h3d.col.Point;
+
+	public var objects : Array<{o : h3d.scene.Object, emitFlag : Bool}> = [];
+	public var objectCount = 0;
+
+	public var interactives : Array<h3d.scene.Interactive> = [];
+	public var interactiveCount = 0;
+
+	public function new( pos : h3d.col.Point ) {
+		this.pos = pos;
+	}
+
+	public inline function reset() {
+		objectCount = 0;
+		interactiveCount = 0;
+		bounds.zMin = 0;
+		bounds.zMax = 0;
+	}
+
+	public inline function updateBounds( chunkSize : Float ) {
+		bounds.addPoint(new h3d.col.Point(pos.x, pos.y));
+		bounds.addPoint(new h3d.col.Point(pos.x + chunkSize, pos.y));
+		bounds.addPoint(new h3d.col.Point(pos.x + chunkSize, pos.y + chunkSize));
+		bounds.addPoint(new h3d.col.Point(pos.x, pos.y + chunkSize));
+		bounds.zMin = 0;
+		bounds.zMax = 0;
+	}
+
+	public inline function addObject( obj : h3d.scene.Object, radius: Float, z : Float ) {
+		objectCount++;
+		if( objectCount > objects.length )
+			objects.resize(objectCount);
+		objects[objectCount - 1] = { o : obj, emitFlag : false };
+		bounds.zMin = hxd.Math.min(bounds.zMin, z - radius);
+		bounds.zMax = hxd.Math.max(bounds.zMax, z + radius);
+	}
+
+	public inline function addInteractive( i : Interactive ) {
+		interactiveCount++;
+		if( interactiveCount > interactives.length )
+			interactives.resize(interactiveCount);
+		interactives[interactiveCount - 1] = i;
+	}
+} 
+
+class Scene extends h3d.scene.Scene {
+
+	var cs = new ChunkScene(15.0);
+	var lastChunkifyTime = 0.0;
+	
+	public function new() {
+		super();
+	}
+	
+	override function emitRec( ctx : h3d.scene.RenderContext ) {
+
+		var needChunkify = (ctx.time - lastChunkifyTime) > 1.0;
+		if( !needChunkify ) {
+			var newKey = cs.getSceneKey(this);
+			needChunkify = newKey != cs.sceneKey;
+			cs.sceneKey = newKey;
+		}
+		if( needChunkify ) {
+			cs.chunkifyScene(this);
+			lastChunkifyTime = ctx.time;
+		}
+			
+		cs.refreshInFrustumFlag(ctx);
+		
+		for( c in cs.chunks ) {
+
+			if( !c.isGlobal && !c.inFrustum )
+				continue;
+
+			for( i in 0 ... c.objectCount ) {
+				var o = c.objects[i].o;
+
+				// Some object can be in the objectlist without being visible ( Gizmo )
+				var visible = o.visible;
+				var curParent = o.parent;
+				while( curParent != null && visible ) {
+					visible = curParent.visible && visible;
+					curParent = curParent.parent;
+				}
+				if( !visible )
+					continue;
+
+				if( c.objects[i].emitFlag )
+					continue;
+				else
+					c.objects[i].emitFlag = true;
+
+				if( o.posChanged ) {
+					if( currentAnimation != null ) currentAnimation.sync();
+					posChanged = false;
+					o.calcAbsPos();
+					for( c in o.children )
+						c.posChanged = true;
+				}
+				if( !o.culled || ctx.computingStatic )
+					o.emit(ctx);
+			}
+		}
+
+		for( c in cs.chunks ) {
+			for( i in 0 ... c.objectCount ) {
+				c.objects[i].emitFlag = false;
+			}
+		}
+	}
+
+	override function handleEvent( event : hxd.Event, last : hxd.SceneEvents.Interactive ) {
+		var	visibleInteractives : Array<h3d.scene.Interactive> = [];
+
+		var interactiveCount = 0;
+		for( c in cs.chunks ) {
+			if( !c.isGlobal && !c.inFrustum )
+				continue;
+			interactiveCount += c.interactiveCount;
+		}
+		visibleInteractives.resize(interactiveCount);
+
+		var i = 0;
+		for( c in cs.chunks ) {
+			if( !c.isGlobal && !c.inFrustum )
+				continue;
+			for( j in 0 ... c.interactiveCount ) {
+				visibleInteractives[i] = c.interactives[j];
+				i++;
+			}
+		}
+
+		var old = interactives;
+		interactives = visibleInteractives;
+		var r = super.handleEvent(event, last);
+		interactives = old;
+		return r;
+	}
+}

+ 3 - 1
hide/comp/Scene.hx

@@ -113,7 +113,9 @@ class Scene extends Component implements h3d.IDrawable {
 			engine.setCurrent();
 			window.setCurrent();
 			s2d = new h2d.Scene();
-			s3d = new h3d.scene.Scene();
+			s3d = new hide.Scene();
+			// Unoptimised version of the scene
+			//s3d = new h3d.scene.Scene();
 			sevents = new hxd.SceneEvents(window);
 			sevents.addScene(s2d);
 			sevents.addScene(s3d);