浏览代码

added custom material props support

ncannasse 9 年之前
父节点
当前提交
9c3521b374

+ 93 - 0
h3d/mat/DefaultMaterialProps.hx

@@ -0,0 +1,93 @@
+package h3d.mat;
+
+enum MaterialKind {
+	Opaque;
+	Alpha;
+	AlphaKill;
+	Add;
+	SoftAdd;
+}
+
+enum ShadowsMode {
+	None;
+	Active;
+	CastOnly;
+	ReceiveOnly;
+}
+
+@:structInit
+class DefaultMaterialProps {
+
+	public var kind(default,null) : MaterialKind;
+	public var shadows(default, null) : ShadowsMode;
+	public var cull(default, null) : Bool;
+
+	public function new( ?kind : MaterialKind, ?shadows : ShadowsMode, ?cull : Bool ) {
+		this.kind = kind == null ? Opaque : kind;
+		this.shadows = shadows == null ? Active : shadows;
+		this.cull = cull == null ? true : cull;
+	}
+
+	public function apply( m : Material ) {
+		var mainPass = m.mainPass;
+		switch( kind ) {
+		case Opaque, AlphaKill:
+			mainPass.setBlendMode(None);
+			mainPass.depthWrite = true;
+			mainPass.setPassName("default");
+		case Alpha:
+			mainPass.setBlendMode(Alpha);
+			mainPass.depthWrite = true;
+			mainPass.setPassName("alpha");
+		case Add:
+			mainPass.setBlendMode(Add);
+			mainPass.depthWrite = false;
+			mainPass.setPassName("additive");
+		case SoftAdd:
+			mainPass.setBlendMode(SoftAdd);
+			mainPass.depthWrite = false;
+			mainPass.setPassName("additive");
+		}
+		var tshader = mainPass.getShader(h3d.shader.Texture);
+		if( tshader != null ) {
+			tshader.killAlpha = kind == AlphaKill;
+			tshader.killAlphaThreshold = 0.5;
+		}
+		switch( shadows ) {
+		case None:
+			m.shadows = false;
+		case Active:
+			m.shadows = true;
+		case CastOnly:
+			m.castShadows = true;
+			m.receiveShadows = false;
+		case ReceiveOnly:
+			m.castShadows = false;
+			m.receiveShadows = true;
+		}
+		mainPass.culling = cull ? Back : None;
+	}
+
+	public function inspect( onChange : Void -> Void ) : Array<hxd.inspect.Property> {
+		return [
+			PEnum("kind", MaterialKind, function() return kind, function(v) { kind = v; onChange(); }),
+			PEnum("shadows", ShadowsMode, function() return shadows, function(v) { shadows = v; onChange(); }),
+			PBool("cull", function() return cull, function(v) { cull = v; onChange(); }),
+		];
+	}
+
+	public function getData() : Dynamic {
+		return { kind : kind.getName(), shadows : shadows.getName(), cull : cull };
+	}
+
+	public function loadData( o : Dynamic ) {
+		kind = MaterialKind.createByName(o.kind);
+		shadows = ShadowsMode.createByName(o.shadows);
+		cull = o.cull;
+	}
+
+	public static function particlesDefault() : MaterialProps {
+		return { kind : Alpha, shadows : None, cull : false }
+	}
+
+}

+ 9 - 0
h3d/mat/Material.hx

@@ -7,6 +7,9 @@ class Material {
 	var passes : Pass;
 	public var name : String;
 	public var mainPass(get, never) : Pass;
+
+	public var props(default,set) : MaterialProps;
+
 	public var shadows(get, set) : Bool;
 	public var castShadows(default, set) : Bool;
 	public var receiveShadows(default, set) : Bool;
@@ -16,6 +19,12 @@ class Material {
 			addPass(new Pass("default",null)).addShader(shader);
 	}
 
+	function set_props(p) {
+		this.props = p;
+		if( p != null ) p.apply(this);
+		return p;
+	}
+
 	public function addPass<T:Pass>( p : T ) : T {
 		var prev = null, cur = passes;
 		while( cur != null ) {

+ 22 - 0
h3d/mat/MaterialProps.hx

@@ -0,0 +1,22 @@
+package h3d.mat;
+
+#if !macro
+
+typedef MaterialProps = haxe.macro.MacroType<[h3d.mat.MaterialProps.Macros.getDefinition()]>;
+
+#else
+
+class Macros {
+	public static function getDefinition() {
+		// using getType() will create haxe assert
+		try {
+			if( haxe.macro.Context.resolvePath("MaterialProps.hx").indexOf("h3d.mat") < 0 )
+				return macro : std.MaterialProps;
+		} catch( e : Dynamic ) {
+		}
+		return macro : DefaultMaterialProps;
+	}
+}
+
+#end
+

+ 11 - 9
h3d/parts/GpuParticles.hx

@@ -89,7 +89,7 @@ class GpuPartGroup {
 		if( FIELDS != null )
 			return FIELDS;
 		FIELDS = Type.getInstanceFields(GpuPartGroup);
-		for( f in ["blendMode", "sortMode", "emitMode", "needRebuild", "pshader", "partIndex", "particles", "texture", "colorGradient","displayedParts"] )
+		for( f in ["material", "sortMode", "emitMode", "needRebuild", "pshader", "partIndex", "particles", "texture", "colorGradient","displayedParts"] )
 			FIELDS.remove(f);
 		for( f in FIELDS.copy() )
 			if( Reflect.isFunction(Reflect.field(inst, f)) )
@@ -111,7 +111,7 @@ class GpuPartGroup {
 
 	public var name : String;
 	public var enable = true;
-	public var blendMode : h3d.mat.BlendMode = Alpha;
+	public var material : h3d.mat.MaterialProps = h3d.mat.MaterialProps.particlesDefault();
 	public var sortMode(default, set) : GpuSortMode = None;
 
 	public var nparts(default, set) : Int 		= 100;
@@ -195,7 +195,7 @@ class GpuPartGroup {
 
 	public function save() : Dynamic {
 		var o = {
-			blendMode : blendMode.getIndex(),
+			material : material.getData(),
 			sortMode : sortMode.getIndex(),
 			emitMode : emitMode.getIndex(),
 			texture : texture == null ? null : texture.name,
@@ -219,7 +219,7 @@ class GpuPartGroup {
 	public function load( version : Int, o : Dynamic ) {
 		for( f in getFields(this) )
 			Reflect.setField(this, f, Reflect.field(o, f));
-		blendMode = h3d.mat.BlendMode.createByIndex(o.blendMode);
+		if( o.material != null ) material.loadData(o.material);
 		sortMode = GpuSortMode.createByIndex(o.sortMode);
 		emitMode = GpuEmitMode.createByIndex(o.emitMode);
 		texture = loadTexture(o.texture);
@@ -236,6 +236,7 @@ class GpuParticles extends h3d.scene.MultiMaterial {
 	var groups : Array<GpuPartGroup>;
 	var bounds : h3d.col.Bounds;
 	var primitiveBuffer : hxd.FloatBuffer;
+	var resourcePath : String;
 	public var seed(default, set) : Int	= Std.random(0x1000000);
 	public var volumeBounds(default, set) : h3d.col.Bounds;
 	public var currentTime : Float = 0.;
@@ -267,7 +268,8 @@ class GpuParticles extends h3d.scene.MultiMaterial {
 		return ({ version : VERSION, groups : [for( g in groups ) g.save()], bounds : bounds } : GpuSave);
 	}
 
-	public function load( _o : Dynamic ) {
+	public function load( _o : Dynamic, ?resourcePath : String ) {
+		this.resourcePath = resourcePath;
 		var o : GpuSave = _o;
 		if( o.version == 0 || o.version > VERSION ) throw "Unsupported version " + _o.version;
 		for( g in o.groups )
@@ -563,10 +565,10 @@ class GpuParticles extends h3d.scene.MultiMaterial {
 			var m = materials[i];
 			var g = groups[i];
 			if( m != null && g.enable && g.displayedParts != 0 ) {
-				var old = m.mainPass.name;
-				m.blendMode = g.blendMode;
-				if( old != "default" && old != "alpha" && old != "add" )
-					m.mainPass.setPassName(old);
+				if( m.props != g.material ) {
+					m.name = g.name;
+					m.props = g.material;
+				}
 				ctx.emit(m, this, i);
 			}
 		}

+ 2 - 0
hxd/inspect/Property.hx

@@ -11,6 +11,8 @@ enum Property {
 	PGroup( name : String, props : Array<Property> );
 	PTexture( name : String, get : Void -> h3d.mat.Texture, set : h3d.mat.Texture -> Void );
 	PFloats( name : String, get : Void -> Array<Float>, set : Array<Float> -> Void );
+#if castle
 	PPopup( p : Property, menu : Array<String>, click : cdb.jq.JQuery -> Int -> Void );
 	PCustom( name : String, content : Void -> cdb.jq.JQuery, ?set : Dynamic -> Void );
+#end
 }

+ 1 - 1
hxd/inspect/ScenePanel.hx

@@ -157,7 +157,7 @@ private class CustomSceneProps extends SceneProps {
 			b.click(function(_) {
 				var data = haxe.Json.stringify(parts.save(), null, "\t");
 				var path = resPath.get(parts);
-				if( path == null ) path = "particles.json";
+				if( path == null ) path = @:privateAccess (parts.resourcePath == null ? "particles.json" : parts.resourcePath);
 				inspect.saveFile(path, "json", haxe.io.Bytes.ofString(data), function(path) resPath.set(parts,path));
 			});
 

+ 24 - 13
hxd/inspect/SceneProps.hx

@@ -234,9 +234,13 @@ class SceneProps {
 	function getMaterialProps( mat : h3d.mat.Material ) {
 		var props = [];
 		props.push(PString("name", function() return mat.name == null ? "" : mat.name, function(n) mat.name = n == "" ? null : n));
-		for( pass in mat.getPasses() ) {
-			var p = getMaterialPassProps(mat, pass);
-			props.push(p);
+		if( mat.props == null ) {
+			for( pass in mat.getPasses() ) {
+				var p = getMaterialPassProps(mat, pass);
+				props.push(p);
+			}
+		} else {
+			props = props.concat(mat.props.inspect(function() mat.props.apply(mat)));
 		}
 		return PGroup("Material",props);
 	}
@@ -263,13 +267,6 @@ class SceneProps {
 		props.push(PBool("visible", function() return o.visible, function(v) o.visible = v));
 
 		if( o.isMesh() ) {
-			var multi = Std.instance(o, h3d.scene.MultiMaterial);
-			if( multi != null && multi.materials.length > 1 ) {
-				for( m in multi.materials )
-					props.push(getMaterialProps(m));
-			} else
-				props.push(getMaterialProps(o.toMesh().material));
-
 			var gp = Std.instance(o, h3d.parts.GpuParticles);
 			if( gp != null ) {
 				props.push(PFloats("volumePos", function() {
@@ -302,6 +299,13 @@ class SceneProps {
 					}
 				}));
 				props = props.concat(getPartsProps(gp));
+			} else {
+				var multi = Std.instance(o, h3d.scene.MultiMaterial);
+				if( multi != null && multi.materials.length > 1 ) {
+					for( m in multi.materials )
+						props.push(getMaterialProps(m));
+				} else
+					props.push(getMaterialProps(o.toMesh().material));
 			}
 
 		} else {
@@ -365,16 +369,23 @@ class SceneProps {
 			PRange("randomNess", 0, 1, function() return o.rotSpeedRand, function(v) o.rotSpeedRand = v),
 		]));
 
-		props.push(PGroup("Animation", [
+		var mat : h3d.mat.MaterialProps = {};
+		mat.loadData(o.material.getData());
+		var matProps = mat.inspect(function() {
+			var mat2 : h3d.mat.MaterialProps = {};
+			mat2.loadData(mat.getData());
+			o.material = mat2;
+		});
+
+		props.push(PGroup("Animation", matProps.concat([
 			PTexture("diffuseTexture", function() return o.texture, function(v) o.texture = v),
-			PEnum("blend", h3d.mat.BlendMode, function() return o.blendMode, function(v) o.blendMode = v),
 			PEnum("sort", h3d.parts.GpuParticles.GpuSortMode, function() return o.sortMode, function(v) o.sortMode = v),
 			PRange("animationRepeat", 0, 10, function() return o.animationRepeat, function(v) o.animationRepeat = v),
 			PRange("frameDivisionX", 1, 16, function() return o.frameDivisionX, function(v) o.frameDivisionX = Std.int(v), 1),
 			PRange("frameDivisionY", 1, 16, function() return o.frameDivisionY, function(v) o.frameDivisionY = Std.int(v), 1),
 			PRange("frameCount", 0, 32, function() return o.frameCount, function(v) o.frameCount = Std.int(v), 1),
 			PTexture("colorGradient", function() return o.colorGradient, function(v) o.colorGradient = v),
-		]));
+		])));
 
 		return PGroup(o.name, props);
 	}