Kaynağa Gözat

added CubeTexture sample, pointLight specular and cubemap reflection shader support

ncannasse 8 yıl önce
ebeveyn
işleme
a1648061f1

+ 15 - 4
h3d/impl/DirectXDriver.hx

@@ -249,23 +249,34 @@ class DirectXDriver extends h3d.impl.Driver {
 	}
 
 	override function allocTexture(t:h3d.mat.Texture):Texture {
+
+		var mips = 1; // todo
+
 		var rt = t.flags.has(Target);
+		var isCube = t.flags.has(Cube);
+
 		var desc = new Texture2dDesc();
 		desc.width = t.width;
 		desc.height = t.height;
 		desc.format = getTextureFormat(t);
 		desc.usage = Default;
 		desc.bind = ShaderResource;
-		if( rt ) desc.bind |= RenderTarget;
+		if( rt )
+			desc.bind |= RenderTarget;
+		if( isCube ) {
+			desc.arraySize = 6;
+			desc.misc = TextureCube;
+		}
 		var tex = Driver.createTexture2d(desc);
 
 		var vdesc = new ShaderResourceViewDesc();
 		vdesc.format = desc.format;
-		vdesc.dimension = Texture2D;
+		vdesc.dimension = isCube ? TextureCube : Texture2D;
+		vdesc.arraySize = desc.arraySize;
 		vdesc.start = 0; // top mip level
 		vdesc.count = -1; // all mip levels
 		var view = Driver.createShaderResourceView(tex, vdesc);
-		return { res : tex, view : view, rt : rt ? Driver.createRenderTargetView(tex) : null };
+		return { res : tex, view : view, rt : rt ? Driver.createRenderTargetView(tex) : null, mips : mips };
 	}
 
 	override function disposeTexture( t : h3d.mat.Texture ) {
@@ -316,7 +327,7 @@ class DirectXDriver extends h3d.impl.Driver {
 
 	override function uploadTexturePixels(t:h3d.mat.Texture, pixels:hxd.Pixels, mipLevel:Int, side:Int) {
 		pixels.convert(RGBA);
-		t.t.res.updateSubresource(mipLevel + side * 6, null, pixels.bytes, pixels.width << 2, 0);
+		t.t.res.updateSubresource(mipLevel + side * t.t.mips, null, pixels.bytes, pixels.width << 2, 0);
 	}
 
 	static inline var SCISSOR_BIT = 1 << (Pass.colorMask_offset + 4);

+ 1 - 1
h3d/impl/Driver.hx

@@ -39,7 +39,7 @@ typedef Query = { q : psgl.GL.Query, kind : QueryKind };
 #elseif hldx
 typedef IndexBuffer = { res : dx.Resource, count : Int };
 typedef VertexBuffer = { res : dx.Resource, count : Int, stride : Int };
-typedef Texture = { res : dx.Resource, view : dx.Driver.ShaderResourceView, rt : dx.Driver.RenderTargetView };
+typedef Texture = { res : dx.Resource, view : dx.Driver.ShaderResourceView, rt : dx.Driver.RenderTargetView, mips : Int };
 typedef DepthBuffer = { res : dx.Resource, view : dx.Driver.DepthStencilView };
 typedef Query = {};
 #else

+ 6 - 6
h3d/impl/GlDriver.hx

@@ -639,10 +639,10 @@ class GlDriver extends Driver {
 		}
 		t.lastFrame = frame;
 		t.flags.unset(WasCleared);
-		var bind = t.flags.has(Cubic) ? GL.TEXTURE_CUBE_MAP : GL.TEXTURE_2D;
+		var bind = t.flags.has(Cube) ? GL.TEXTURE_CUBE_MAP : GL.TEXTURE_2D;
 		gl.bindTexture(bind, tt.t);
 		var outOfMem = false;
-		if( t.flags.has(Cubic) ) {
+		if( t.flags.has(Cube) ) {
 			for( i in 0...6 ) {
 				gl.texImage2D(CUBE_FACES[i], 0, tt.internalFmt, tt.width, tt.height, 0, getChannels(tt), tt.pixelFmt, null);
 				if( gl.getError() == GL.OUT_OF_MEMORY ) {
@@ -752,7 +752,7 @@ class GlDriver extends Driver {
 		uploadTexturePixels(t, pixels, mipLevel, side);
 		pixels.dispose();
 	#else
-		if( t.format != RGBA || t.flags.has(Cubic) ) {
+		if( t.format != RGBA || t.flags.has(Cube) ) {
 			var pixels = bmp.getPixels();
 			uploadTexturePixels(t, pixels, mipLevel, side);
 			pixels.dispose();
@@ -835,7 +835,7 @@ class GlDriver extends Driver {
 	}
 
 	override function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
-		var cubic = t.flags.has(Cubic);
+		var cubic = t.flags.has(Cube);
 		var bind = cubic ? GL.TEXTURE_CUBE_MAP : GL.TEXTURE_2D;
 		var face = cubic ? CUBE_FACES[side] : GL.TEXTURE_2D;
 		gl.bindTexture(bind, t.t.t);
@@ -1022,7 +1022,7 @@ class GlDriver extends Driver {
 			tex.alloc();
 
 		if( tex.flags.has(MipMapped) && !tex.flags.has(WasCleared) ) {
-			var bind = tex.flags.has(Cubic) ? GL.TEXTURE_CUBE_MAP : GL.TEXTURE_2D;
+			var bind = tex.flags.has(Cube) ? GL.TEXTURE_CUBE_MAP : GL.TEXTURE_2D;
 			gl.bindTexture(bind, tex.t.t);
 			gl.generateMipmap(bind);
 			gl.bindTexture(bind, null);
@@ -1031,7 +1031,7 @@ class GlDriver extends Driver {
 		tex.flags.set(WasCleared); // once we draw to, do not clear again
 		tex.lastFrame = frame;
 		gl.bindFramebuffer(GL.FRAMEBUFFER, commonFB);
-		gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, tex.flags.has(Cubic) ? CUBE_FACES[face] : GL.TEXTURE_2D, tex.t.t, mipLevel);
+		gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, tex.flags.has(Cube) ? CUBE_FACES[face] : GL.TEXTURE_2D, tex.t.t, mipLevel);
 		if( tex.depthBuffer != null )
 			gl.framebufferRenderbuffer(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, @:privateAccess tex.depthBuffer.b.r);
 		else

+ 4 - 4
h3d/impl/Stage3dDriver.hx

@@ -287,7 +287,7 @@ class Stage3dDriver extends Driver {
 		t.flags.unset(WasCleared);
 		try {
 			if( t.flags.has(IsNPOT) ) {
-				if( t.flags.has(Cubic) || t.flags.has(MipMapped) )
+				if( t.flags.has(Cube) || t.flags.has(MipMapped) )
 					throw "Not power of two texture is not supported with these flags";
 				#if !flash11_8
 				throw "Support for rectangle texture requires Flash 11.8+ compilation";
@@ -295,7 +295,7 @@ class Stage3dDriver extends Driver {
 				return ctx.createRectangleTexture(t.width, t.height, fmt, t.flags.has(Target));
 				#end
 			}
-			if( t.flags.has(Cubic) )
+			if( t.flags.has(Cube) )
 				return ctx.createCubeTexture(t.width, fmt, t.flags.has(Target), getMipLevels(t));
 			return ctx.createTexture(t.width, t.height, fmt, t.flags.has(Target), getMipLevels(t));
 		} catch( e : flash.errors.Error ) {
@@ -309,7 +309,7 @@ class Stage3dDriver extends Driver {
 
 	override function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
 		if( t.t == tdisposed ) return;
-		if( t.flags.has(Cubic) ) {
+		if( t.flags.has(Cube) ) {
 			var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
 			t.uploadFromBitmapData(bmp.toNative(), side, mipLevel);
 		} else if( t.flags.has(IsNPOT) ) {
@@ -327,7 +327,7 @@ class Stage3dDriver extends Driver {
 		if( t.t == tdisposed ) return;
 		pixels.convert(BGRA);
 		var data = pixels.bytes.getData();
-		if( t.flags.has(Cubic) ) {
+		if( t.flags.has(Cube) ) {
 			var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
 			t.uploadFromByteArray(data, pixels.offset, side, mipLevel);
 		} else if( t.flags.has(IsNPOT) ) {

+ 2 - 2
h3d/mat/Data.hx

@@ -77,9 +77,9 @@ enum TextureFlags {
 	**/
 	Target;
 	/**
-		Allocate a cubic texture. Might be restricted to power of two textures only.
+		Allocate a cube texture. Might be restricted to power of two textures only.
 	**/
-	Cubic;
+	Cube;
 	/**
 		Activates Mip Mapping for this texture. Might not be available for target textures.
 	**/

+ 8 - 0
h3d/scene/PointLight.hx

@@ -14,6 +14,14 @@ class PointLight extends Light {
 		return pshader.color;
 	}
 
+	override function get_enableSpecular() {
+		return pshader.enableSpecular;
+	}
+
+	override function set_enableSpecular(b) {
+		return pshader.enableSpecular = b;
+	}
+
 	inline function get_params() {
 		return pshader.params;
 	}

+ 9 - 2
h3d/shader/CubeMap.hx

@@ -7,17 +7,24 @@ class CubeMap extends hxsl.Shader {
 		var pixelColor : Vec4;
 		var transformedNormal : Vec3;
 
+		@const var reflection : Bool;
 		@param var texture : SamplerCube;
+		@global var camera : {
+			var position : Vec3;
+		};
+		var pixelTransformedPosition : Vec3;
 
 		function fragment() {
-			pixelColor.rgb *= texture.get(transformedNormal).rgb;
+			var n = if( reflection ) reflect(-normalize(camera.position - pixelTransformedPosition), transformedNormal) else transformedNormal;
+			pixelColor.rgb *= texture.get(n).rgb;
 		}
 
 	}
 
-	public function new(texture) {
+	public function new(texture, reflection=false) {
 		super();
 		this.texture = texture;
+		this.reflection = reflection;
 	}
 
 }

+ 25 - 11
h3d/shader/PointLight.hx

@@ -4,28 +4,42 @@ class PointLight extends hxsl.Shader {
 
 	static var SRC = {
 
+		@const var enableSpecular : Bool;
+		@param var color : Vec3;
+		@param var params : Vec3; // [constant, linear, quadratic]
+		@param var lightPosition : Vec3;
+		@global var camera : {
+			var position : Vec3;
+		};
+
 		var lightColor : Vec3;
 		var lightPixelColor : Vec3;
 		var transformedPosition : Vec3;
 		var pixelTransformedPosition : Vec3;
 		var transformedNormal : Vec3;
-		@param var color : Vec3;
-		@param var params : Vec3; // [constant, linear, quadratic]
-		@param var lightPosition : Vec3;
+		var specPower : Float;
+		var specColor : Vec3;
 
-		function vertex() {
-			var dvec = lightPosition - transformedPosition;
+
+		function calcLighting( position : Vec3 ) : Vec3 {
+			var dvec = lightPosition - position;
 			var dist2 = dvec.dot(dvec);
 			var dist = dist2.sqrt();
-			// TN . DVEC is already multiplied by dist
-			lightColor.rgb += color * (transformedNormal.dot(dvec).max(0.) / vec3(dist, dist2, dist * dist2).dot(params));
+			var diff = transformedNormal.dot(dvec).max(0.);
+			var factor = 1 / vec3(dist, dist2, dist * dist2).dot(params);
+			if( !enableSpecular )
+				return color * diff * factor;
+			var r = reflect(-dvec.normalize(), transformedNormal).normalize();
+			var specValue = r.dot((camera.position - position).normalize()).max(0.);
+			return color * (diff * factor + specColor * pow(specValue, specPower));
+		}
+
+		function vertex() {
+			lightColor.rgb += calcLighting(transformedPosition);
 		}
 
 		function fragment() {
-			var dvec = lightPosition - pixelTransformedPosition;
-			var dist2 = dvec.dot(dvec);
-			var dist = dist2.sqrt();
-			lightPixelColor.rgb += color * (transformedNormal.dot(dvec).max(0.) / vec3(dist, dist2, dist * dist2).dot(params));
+			lightPixelColor.rgb += calcLighting(pixelTransformedPosition);
 		}
 
 	};

+ 42 - 0
samples/CubeTexture.hx

@@ -0,0 +1,42 @@
+class CubeTexture extends hxd.App {
+
+	override function init() {
+
+		var skyTexture = new h3d.mat.Texture(128, 128, [Cube]);
+		var bmp = hxd.Pixels.alloc(skyTexture.width, skyTexture.height, h3d.mat.Texture.nativeFormat);
+		var faceColors = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0x00FFFF, 0xFF00FF];
+		for( i in 0...6 ) {
+			bmp.clear(faceColors[i]);
+			skyTexture.uploadPixels(bmp, 0, i);
+		}
+
+		var sky = new h3d.prim.Sphere(30, 128, 128);
+		sky.addNormals();
+		var skyMesh = new h3d.scene.Mesh(sky, s3d);
+		skyMesh.material.mainPass.culling = Front;
+		skyMesh.material.mainPass.addShader(new h3d.shader.CubeMap(skyTexture));
+
+		var sp = new h3d.prim.Sphere(0.5, 64, 64);
+		sp.addNormals();
+		var m = new h3d.scene.Mesh(sp, null, s3d);
+		m.material.mainPass.enableLights = true;
+		m.material.mainPass.addShader(new h3d.shader.CubeMap(skyTexture, true));
+
+		var pt = new h3d.scene.PointLight(s3d);
+		pt.x = 2;
+		pt.y = 1;
+		pt.z = 4;
+		pt.enableSpecular = true;
+		pt.params.set(0, 1, 0);
+
+		s3d.lightSystem.ambientLight.set(0.1, 0.1, 0.1);
+
+		new h3d.scene.CameraController(5, s3d).loadFromCamera();
+
+	}
+
+	static function main() {
+		new CubeTexture();
+	}
+
+}