Browse Source

Add cullingCollider

ShiroSmith 6 năm trước cách đây
mục cha
commit
d45aeeaea2

+ 2 - 1
h3d/Camera.hx

@@ -41,7 +41,7 @@ class Camera {
 
 	public var follow : { pos : h3d.scene.Object, target : h3d.scene.Object };
 
-	public var frustum(default, null) = new h3d.col.Frustum();
+	public var frustum(default, null) : h3d.col.Frustum;
 
 	var minv : Matrix;
 	var miview : Matrix;
@@ -60,6 +60,7 @@ class Camera {
 		m = new Matrix();
 		mcam = new Matrix();
 		mproj = new Matrix();
+		frustum = new h3d.col.Frustum();
 		update();
 	}
 

+ 8 - 14
h3d/col/Bounds.hx

@@ -18,20 +18,14 @@ class Bounds implements Collider {
 		empty();
 	}
 
-	public function inFrustum( mvp : Matrix ) {
-		if( testPlane(Plane.frustumLeft(mvp)) < 0 )
-			return false;
-		if( testPlane(Plane.frustumRight(mvp)) < 0 )
-			return false;
-		if( testPlane(Plane.frustumBottom(mvp)) < 0 )
-			return false;
-		if( testPlane(Plane.frustumTop(mvp)) < 0 )
-			return false;
-		if( testPlane(Plane.frustumNear(mvp)) < 0 )
-			return false;
-		if( testPlane(Plane.frustumFar(mvp)) < 0 )
-			return false;
-		return true;
+	public inline function inFrustum( f : Frustum ) {
+		return f.hasBounds(this);
+	}
+
+	public inline function inSphere( s : Sphere ) {
+		var c = new Point(s.x,s.y,s.z);
+		var p = new Point(Math.max(xMin, Math.min(s.x, xMax)), Math.max(yMin, Math.min(s.y, yMax)), Math.max(zMin, Math.min(s.z, zMax)));
+		return c.distanceSq(p) < s.r*s.r;
 	}
 
 	inline function testPlane( p : Plane ) {

+ 15 - 6
h3d/col/Collider.hx

@@ -7,8 +7,8 @@ interface Collider extends hxd.impl.Serializable.StructSerializable {
 	**/
 	public function rayIntersection( r : Ray, bestMatch : Bool ) : Float;
 	public function contains( p : Point ) : Bool;
-	public function inFrustum( mvp : h3d.Matrix ) : Bool;
-
+	public function inFrustum( f : Frustum ) : Bool;
+	public function inSphere( s : Sphere ) : Bool;
 }
 
 
@@ -32,10 +32,13 @@ class OptimizedCollider implements hxd.impl.Serializable implements Collider {
 		return a.contains(p) && b.contains(p);
 	}
 
-	public function inFrustum( mvp : h3d.Matrix ) {
-		return a.inFrustum(mvp) && b.inFrustum(mvp);
+	public function inFrustum( f : Frustum ) {
+		return a.inFrustum(f) && b.inFrustum(f);
 	}
 
+	public function inSphere( s : Sphere ) {
+		return a.inSphere(s) && b.inSphere(s);
+	}
 
 	#if (hxbit && !macro)
 	function customSerialize(ctx:hxbit.Serializer) {
@@ -73,13 +76,19 @@ class GroupCollider implements Collider {
 		return false;
 	}
 
-	public function inFrustum( mvp : h3d.Matrix ) {
+	public function inFrustum( f : Frustum ) {
 		for( c in colliders )
-			if( c.inFrustum(mvp) )
+			if( c.inFrustum(f) )
 				return true;
 		return false;
 	}
 
+	public function inSphere( s : Sphere ) {
+		for( c in colliders )
+			if( c.inSphere(s) )
+				return true;
+		return false;
+	}
 
 	#if (hxbit && !macro && heaps_enable_serialize)
 

+ 12 - 0
h3d/col/Frustum.hx

@@ -76,6 +76,18 @@ class Frustum {
 		pfar.normalize();
 	}
 
+	public function hasPoint( p : Point ) {
+		if( pleft.distance(p) < 0 ) return false;
+		if( pright.distance(p) < 0 ) return false;
+		if( ptop.distance(p) < 0 ) return false;
+		if( pbottom.distance(p) < 0 ) return false;
+		if( checkNearFar ) {
+			if( pnear.distance(p) < 0 ) return false;
+			if( pfar.distance(p) < 0 ) return false;
+		}
+		return true;
+	}
+
 	public function hasSphere( s : Sphere ) {
 		var p = s.getCenter();
 		if( pleft.distance(p) < -s.r ) return false;

+ 6 - 1
h3d/col/ObjectCollider.hx

@@ -33,7 +33,12 @@ class ObjectCollider implements Collider implements hxd.impl.Serializable {
 		return b;
 	}
 
-	public function inFrustum( mvp : h3d.Matrix ) {
+	public function inFrustum( f : Frustum ) {
+		throw "Not implemented";
+		return false;
+	}
+
+	public function inSphere( s : Sphere ) {
 		throw "Not implemented";
 		return false;
 	}

+ 2 - 14
h3d/col/Point.hx

@@ -19,20 +19,8 @@ class Point {
 		z *= v;
 	}
 
-	public function inFrustum( mvp : Matrix ) {
-		if( !Plane.frustumLeft(mvp).side(this) )
-			return false;
-		if( !Plane.frustumRight(mvp).side(this) )
-			return false;
-		if( !Plane.frustumBottom(mvp).side(this) )
-			return false;
-		if( !Plane.frustumTop(mvp).side(this) )
-			return false;
-		if( !Plane.frustumNear(mvp).side(this) )
-			return false;
-		if( !Plane.frustumFar(mvp).side(this) )
-			return false;
-		return true;
+	public inline function inFrustum( f : Frustum ) {
+		return f.hasPoint(this);
 	}
 
 	public inline function set(x, y, z) {

+ 12 - 2
h3d/col/Polygon.hx

@@ -99,7 +99,12 @@ class TriPlane implements Collider {
 		return nx * p.x + ny * p.y + nz * p.z - d >= 0;
 	}
 
-	public function inFrustum( m : h3d.Matrix ) {
+	public function inFrustum( f : Frustum ) {
+		throw "Not implemented";
+		return false;
+	}
+
+	public function inSphere( s : Sphere ) {
 		throw "Not implemented";
 		return false;
 	}
@@ -233,7 +238,12 @@ class Polygon implements Collider {
 		return best;
 	}
 
-	public function inFrustum( m : h3d.Matrix ) {
+	public function inFrustum( f : Frustum ) {
+		throw "Not implemented";
+		return false;
+	}
+
+	public function inSphere( s : Sphere ) {
 		throw "Not implemented";
 		return false;
 	}

+ 6 - 1
h3d/col/PolygonBuffer.hx

@@ -41,7 +41,12 @@ class PolygonBuffer implements Collider {
 		return true;
 	}
 
-	public function inFrustum( m : h3d.Matrix ) {
+	public function inFrustum( f : Frustum ) {
+		throw "Not implemented";
+		return false;
+	}
+
+	public function inSphere( s : Sphere ) {
 		throw "Not implemented";
 		return false;
 	}

+ 5 - 0
h3d/col/SkinCollider.hx

@@ -26,6 +26,11 @@ class SkinCollider implements hxd.impl.Serializable implements Collider {
 		return transform.inFrustum(p);
 	}
 
+	public function inSphere( s : Sphere ) {
+		throw "Not implemented";
+		return false;
+	}
+
 	public function rayIntersection(r, bestMatch) {
 		applyTransform();
 		return transform.rayIntersection(r, bestMatch);

+ 6 - 27
h3d/col/Sphere.hx

@@ -43,33 +43,12 @@ class Sphere implements Collider {
 		return 1 - t;
 	}
 
-	public function inFrustum( mvp : Matrix ) {
-		var p = getCenter();
-		var pl = Plane.frustumLeft(mvp);
-		pl.normalize();
-		if( pl.distance(p) < -r )
-			return false;
-		var pl = Plane.frustumRight(mvp);
-		pl.normalize();
-		if( pl.distance(p) < -r )
-			return false;
-		var pl = Plane.frustumBottom(mvp);
-		pl.normalize();
-		if( pl.distance(p) < -r )
-			return false;
-		var pl = Plane.frustumTop(mvp);
-		pl.normalize();
-		if( pl.distance(p) < -r )
-			return false;
-		var pl = Plane.frustumNear(mvp);
-		pl.normalize();
-		if( pl.distance(p) < -r )
-			return false;
-		var pl = Plane.frustumNear(mvp);
-		pl.normalize();
-		if( pl.distance(p) < -r )
-			return false;
-		return true;
+	public inline function inFrustum( f : Frustum ) {
+		return f.hasSphere(this);
+	}
+
+	public inline function inSphere( s : Sphere ) {
+		return new Point(x,y,z).distanceSq(new Point(s.x,s.y,s.z)) < (s.r + r)*(s.r + r);
 	}
 
 	public function toString() {

+ 6 - 4
h3d/pass/PointShadowMap.hx

@@ -114,6 +114,11 @@ class PointShadowMap extends Shadows {
 		if( !filterPasses(passes) )
 			return;
 
+		var pointLight = cast(light, h3d.scene.pbr.PointLight);
+		var absPos = light.getAbsPos();
+		var sp = new h3d.col.Sphere(absPos.tx, absPos.ty, absPos.tz, pointLight.range);
+		passes.filter(function(p) return p.obj.cullingCollider == null || p.obj.cullingCollider.inSphere(sp));
+
 		var texture = ctx.textures.allocTarget("pointShadowMap", size, size, false, format, true);
 		if(depth == null || depth.width != size || depth.height != size || depth.isDisposed() ) {
 			if( depth != null ) depth.dispose();
@@ -126,8 +131,6 @@ class PointShadowMap extends Shadows {
 		if( mode == Mixed && !ctx.computingStatic && validBakedTexture)
 			merge = ctx.textures.allocTarget("mergedPointShadowMap", size, size, false, format, true);
 
-		var pointLight = cast(light, h3d.scene.pbr.PointLight);
-		var absPos = light.getAbsPos();
 		lightCamera.pos.set(absPos.tx, absPos.ty, absPos.tz);
 		lightCamera.zFar = pointLight.range;
 		lightCamera.zNear = pointLight.zNear;
@@ -139,8 +142,7 @@ class PointShadowMap extends Shadows {
 			ctx.engine.pushTarget(texture, i);
 			ctx.engine.clear(0xFFFFFF, 1);
 			var save = passes.save();
-			var bit = 1 << i;
-			passes.filter(function(p) return p.obj.cullingBits & bit == 0);
+			passes.filter(function(p) return p.obj.cullingCollider == null || p.obj.cullingCollider.inFrustum(lightCamera.frustum));
 			super.draw(passes);
 			passes.load(save);
 			ctx.engine.popTarget();

+ 7 - 6
h3d/scene/LightSystem.hx

@@ -16,13 +16,9 @@ class LightSystem {
 	public function initGlobals( globals : hxsl.Globals ) {
 	}
 
-	public function initLights( ctx : h3d.scene.RenderContext ) @:privateAccess {
-		lightCount = 0;
-		this.ctx = ctx;
-
+	function cullLights() @:privateAccess  {
 		// remove lights which cullingDistance is outside of frustum
 		var l = ctx.lights, prev : h3d.scene.Light = null;
-		var frustum = new h3d.col.Frustum(ctx.camera.m);
 		var s = new h3d.col.Sphere();
 		while( l != null ) {
 			s.x = l.absPos._41;
@@ -30,7 +26,7 @@ class LightSystem {
 			s.z = l.absPos._43;
 			s.r = l.cullingDistance;
 
-			if( l.cullingDistance > 0 && !ctx.computingStatic && !frustum.hasSphere(s) ) {
+			if( l.cullingDistance > 0 && !ctx.computingStatic && !ctx.camera.frustum.hasSphere(s) ) {
 				if( prev == null )
 					ctx.lights = l.next;
 				else
@@ -44,7 +40,12 @@ class LightSystem {
 			prev = l;
 			l = l.next;
 		}
+	}
 
+	public function initLights( ctx : h3d.scene.RenderContext ) @:privateAccess {
+		lightCount = 0;
+		this.ctx = ctx;
+		cullLights();
 		if( shadowLight == null || !shadowLight.allocated) {
 			var l = ctx.lights;
 			while( l != null ) {

+ 3 - 9
h3d/scene/Object.hx

@@ -13,8 +13,6 @@ package h3d.scene;
 	public var FIgnoreBounds = 0x200;
 	public var FIgnoreCollide = 0x400;
 	public var FIgnoreParentTransform = 0x800;
-	public var FCullingPlansBits = 0x1000;
-	public var FCullingPlansBitsLast = 0x20000;
 	public inline function new(value) {
 		this = value;
 	}
@@ -113,11 +111,6 @@ class Object implements hxd.impl.Serializable {
 	**/
 	public var culled(get, set) : Bool;
 
-	/**
-		Six additional bits that are used for point lights culling. Tells in which planes the object should be culled
-	**/
-	public var cullingBits(get,set) : Int;
-
 	/**
 		When an object is not visible or culled, its animation does not get synchronized unless you set alwaysSync=true
 	**/
@@ -154,6 +147,9 @@ class Object implements hxd.impl.Serializable {
 	**/
 	public var lightCameraCenter(get, set) : Bool;
 
+
+	public var cullingCollider : h3d.col.Collider;
+
 	var absPos : h3d.Matrix;
 	var invPos : h3d.Matrix;
 	var qRot : h3d.Quat;
@@ -188,7 +184,6 @@ class Object implements hxd.impl.Serializable {
 	inline function get_ignoreCollide() return flags.has(FIgnoreCollide);
 	inline function get_allowSerialize() return !flags.has(FNoSerialize);
 	inline function get_ignoreParentTransform() return flags.has(FIgnoreParentTransform);
-	inline function get_cullingBits() return (flags.toInt() >> 12) & 63;
 	inline function set_posChanged(b) return flags.set(FPosChanged, b || follow != null);
 	inline function set_culled(b) return flags.set(FCulled, b);
 	inline function set_visible(b) return flags.set(FVisible,b);
@@ -201,7 +196,6 @@ class Object implements hxd.impl.Serializable {
 	inline function set_ignoreCollide(b) return flags.set(FIgnoreCollide, b);
 	inline function set_allowSerialize(b) return !flags.set(FNoSerialize, !b);
 	inline function set_ignoreParentTransform(b) return flags.set(FIgnoreParentTransform, b);
-	inline function set_cullingBits(b) { flags = new ObjectFlags((flags.toInt() & ~0x3F000) | (b << 12)); return b; }
 
 	/**
 		Create an animation instance bound to the object, set it as currentAnimation and play it.

+ 0 - 10
h3d/scene/pbr/LightSystem.hx

@@ -13,20 +13,10 @@ class LightSystem extends h3d.scene.LightSystem {
 		return shaders;
 	}
 
-	/**
-		This can be overriden in order to mark meshes as culled=true so their shadows
-		doesn't get drawn for this specific light.
-	**/
-	public function cullObjectsForLight( light : Light ) {
-	}
 
 	public function drawLight( light : Light, passes : h3d.pass.PassList ) {
 		light.shadows.setContext(ctx);
-		cullObjectsForLight(light);
-		passes.filter(function(p) return !p.obj.culled);
 		light.shadows.draw(passes);
-		for( p in passes.getFiltered() )
-			p.obj.culled = false;
 		passes.reset();
 	}
 

+ 2 - 3
h3d/scene/pbr/PointLight.hx

@@ -52,9 +52,9 @@ class PointLight extends Light {
 		pbr.pointSize = size;
 	}
 
+	var s = new h3d.col.Sphere();
 	override function emit(ctx:RenderContext) {
-
-		if( ctx.computingStatic ){
+		if( ctx.computingStatic ) {
 			super.emit(ctx);
 			return;
 		}
@@ -62,7 +62,6 @@ class PointLight extends Light {
 		if( ctx.pbrLightPass == null )
 			throw "Rendering a pbr light require a PBR compatible scene renderer";
 
-		var s = new h3d.col.Sphere();
 		s.x = absPos._41;
 		s.y = absPos._42;
 		s.z = absPos._43;

+ 12 - 0
h3d/scene/pbr/SpotLight.hx

@@ -120,10 +120,22 @@ class SpotLight extends Light {
 		}
 	}
 
+	var s = new h3d.col.Sphere();
+	var d = new h3d.Vector();
 	override function emit(ctx:RenderContext) {
 		if( ctx.pbrLightPass == null )
 			throw "Rendering a pbr light require a PBR compatible scene renderer";
 
+		d.load(absPos.front());
+		d.scale3(maxRange / 2.0);
+		s.x = absPos.tx + d.x;
+		s.y = absPos.ty + d.y;
+		s.z = absPos.tz + d.z;
+		s.r = maxRange / 2.0;
+
+		if( !ctx.camera.frustum.hasSphere(s) )
+			return;
+
 		super.emit(ctx);
 		ctx.emitPass(ctx.pbrLightPass, this);
 	}