Просмотр исходного кода

Add default prim for spotlight
Add cookie for spotlight

ShiroSmith 7 лет назад
Родитель
Сommit
1f2c1ddc53
3 измененных файлов с 99 добавлено и 19 удалено
  1. 14 8
      h3d/pass/SpotShadowMap.hx
  2. 65 6
      h3d/scene/pbr/SpotLight.hx
  3. 20 5
      h3d/shader/pbr/Light.hx

+ 14 - 8
h3d/pass/SpotShadowMap.hx

@@ -12,6 +12,7 @@ class SpotShadowMap extends Shadows {
 		super(light);
 		lightCamera = new h3d.Camera();
 		lightCamera.screenRatio = 1.0;
+		lightCamera.zNear = 3.0;
 		shader = sshader = new h3d.shader.SpotShadow();
 		border = new Border(size, size);
 		customDepth = h3d.Engine.getCurrent().driver.hasFeature(AllocDepthBuffer);
@@ -99,6 +100,7 @@ class SpotShadowMap extends Shadows {
 				if( staticTexture == null || staticTexture.isDisposed() )
 					staticTexture = h3d.mat.Texture.fromColor(0xFFFFFF);
 				if( mode == Static ) {
+					updateCamera();
 					syncShader(staticTexture);
 					return passes;
 				}
@@ -114,14 +116,7 @@ class SpotShadowMap extends Shadows {
 		texture.depthBuffer = depth;
 
 		if( mode != Mixed || ctx.computingStatic ) {
-			var absPos = light.getAbsPos();
-			var spotLight = cast(light, h3d.scene.pbr.SpotLight);
-			var ldir = absPos.front();
-			lightCamera.pos.set(absPos.tx, absPos.ty, absPos.tz);
-			lightCamera.target.set(absPos.tx + ldir.x, absPos.ty + ldir.y, absPos.tz + ldir.z);
-			lightCamera.fovY = spotLight.angle * 2.0;
-			lightCamera.zFar = spotLight.maxRange;
-			lightCamera.update();
+			updateCamera();
 		}
 
 		ctx.engine.pushTarget(texture);
@@ -147,6 +142,17 @@ class SpotShadowMap extends Shadows {
 		return passes;
 	}
 
+	function updateCamera(){
+		var absPos = light.getAbsPos();
+		var spotLight = cast(light, h3d.scene.pbr.SpotLight);
+		var ldir = absPos.front();
+		lightCamera.pos.set(absPos.tx, absPos.ty, absPos.tz);
+		lightCamera.target.set(absPos.tx + ldir.x, absPos.ty + ldir.y, absPos.tz + ldir.z);
+		lightCamera.fovY = spotLight.angle;
+		lightCamera.zFar = spotLight.maxRange;
+		lightCamera.update();
+	}
+
 	override function computeStatic( passes : h3d.pass.Object ) {
 		if( mode != Static && mode != Mixed )
 			return;

+ 65 - 6
h3d/scene/pbr/SpotLight.hx

@@ -6,16 +6,19 @@ class SpotLight extends Light {
 
 	public var range : Float;
 	public var maxRange(get,set) : Float;
-	public var angle : Float;
+	public var angle(default,set) : Float;
 	public var fallOff : Float;
-
+	public var cookie : h3d.mat.Texture;
+	var lightProj : h3d.Camera;
 
 	public function new(?parent) {
 		pbr = new h3d.shader.pbr.Light.SpotLight();
 		shadows = new h3d.pass.SpotShadowMap(this);
 		super(pbr,parent);
 		range = 10;
-		primitive = h3d.prim.Sphere.defaultUnitSphere();
+		generatePrim();
+		lightProj = new h3d.Camera();
+		lightProj.screenRatio = 1.0;
 	}
 
 	function get_maxRange() {
@@ -23,10 +26,57 @@ class SpotLight extends Light {
 	}
 
 	function set_maxRange(v:Float) {
-		setScale(v);
+		scaleX = v;
+		lightProj.zFar = v;
 		return cullingDistance = v;
 	}
 
+	function set_angle(v:Float) {
+		scaleY = hxd.Math.tan(hxd.Math.degToRad(v/2.0)) * maxRange;
+		scaleZ = scaleY;
+		lightProj.fovY = v;
+		return angle = v;
+	}
+
+	function generatePrim(){
+		var points = new Array<h3d.col.Point>();
+
+		// Left
+		points.push(new h3d.col.Point(0,0,0));
+		points.push(new h3d.col.Point(1,-1,-1));
+		points.push(new h3d.col.Point(1,-1,1));
+		// Right
+		points.push(new h3d.col.Point(0,0,0));
+		points.push(new h3d.col.Point(1,1,1));
+		points.push(new h3d.col.Point(1,1,-1));
+		// Up
+		points.push(new h3d.col.Point(0,0,0));
+		points.push(new h3d.col.Point(1,-1,1));
+		points.push(new h3d.col.Point(1,1,1));
+		// Down
+		points.push(new h3d.col.Point(0,0,0));
+		points.push(new h3d.col.Point(1,1,-1));
+		points.push(new h3d.col.Point(1,-1,-1));
+		// Front
+		points.push(new h3d.col.Point(1,-1,-1));
+		points.push(new h3d.col.Point(1,1,-1));
+		points.push(new h3d.col.Point(1,1,1));
+		points.push(new h3d.col.Point(1,1,1));
+		points.push(new h3d.col.Point(1,-1,1));
+		points.push(new h3d.col.Point(1,-1,-1));
+
+		var prim = new h3d.prim.Polygon(points);
+		prim.addNormals();
+		primitive = prim;
+	}
+
+	function generateLightProj(){
+		lightProj.pos.set(absPos.tx, absPos.ty, absPos.tz);
+		var ldir = absPos.front();
+		lightProj.target.set(absPos.tx + ldir.x, absPos.ty + ldir.y, absPos.tz + ldir.z);
+		lightProj.update();
+	}
+
 	override function getShadowDirection() : h3d.Vector {
 		return absPos.front();
 	}
@@ -43,10 +93,19 @@ class SpotLight extends Light {
 		pbr.lightColor.scale3(power * power);
 		pbr.lightPos.set(absPos.tx, absPos.ty, absPos.tz);
 		pbr.spotDir.load(absPos.front());
-		pbr.angle = hxd.Math.cos(hxd.Math.degToRad(angle));
-		pbr.fallOff = hxd.Math.cos(hxd.Math.degToRad(hxd.Math.min(angle, fallOff)));
+		pbr.angle = hxd.Math.cos(hxd.Math.degToRad(angle/2.0));
+		pbr.fallOff = hxd.Math.cos(hxd.Math.degToRad(hxd.Math.min(angle/2.0, fallOff)));
 		pbr.range = hxd.Math.min(range, maxRange);
 		pbr.invLightRange4 = 1 / (maxRange * maxRange * maxRange * maxRange);
+
+		if(cookie != null){
+			pbr.useCookie = true;
+			pbr.cookieTex = cookie;
+			generateLightProj();
+			pbr.lightProj.load(lightProj.m);
+		}else{
+			pbr.useCookie = false;
+		}
 	}
 
 	override function emit(ctx:RenderContext) {

+ 20 - 5
h3d/shader/pbr/Light.hx

@@ -24,14 +24,14 @@ class SpotLight extends Light {
 		@param var fallOff : Float;
 		@param var invLightRange4 : Float; // 1 / range^4
 		@param var range : Float;
+		@param var lightProj : Mat4;
+
+		@const var useCookie : Bool;
+		@param var cookieTex : Sampler2D;
 
 		function fragment() {
 			pbrLightDirection = normalize(lightPos - transformedPosition);
 
-			var theta = dot(pbrLightDirection, -spotDir);
-			var epsilon = fallOff - angle;
-			var intensity = clamp((theta - angle) / epsilon, 0.0, 1.0);
-
 			var delta = lightPos - transformedPosition;
 			/*
 				UE4 [Karis12] "Real Shading in Unreal Engine 4"
@@ -46,7 +46,22 @@ class SpotLight extends Light {
 			falloff *= falloff;
 			falloff *= 1 / (dist + 1);
 
-			pbrLightColor = lightColor * intensity * falloff;
+			pbrLightColor = lightColor * falloff;
+
+			if(useCookie){
+				var posLightSpace = vec4(transformedPosition, 1.0) * lightProj;
+				var posUV = screenToUv(posLightSpace.xy/posLightSpace.w);
+				if(posUV.x > 1 || posUV.x < 0 || posUV.y > 1 || posUV.y < 0)
+					discard;
+				var cookie = cookieTex.get(posUV).rgba;
+				pbrLightColor *= cookie.rgb * cookie.a;
+			}
+			else{
+				var theta = dot(pbrLightDirection, -spotDir);
+				var epsilon = fallOff - angle;
+				var intensity = clamp((theta - angle) / epsilon, 0.0, 1.0);
+				pbrLightColor *= intensity;
+			}
 		}
 	}
 }