Model.hx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. package hrt.prefab;
  2. class Model extends Object3D {
  3. @:s public var animation : Null<String>;
  4. @:s var lockAnimation : Bool = false;
  5. @:s var retargetAnim : Bool = false;
  6. @:s var retargetIgnore : String;
  7. public function new(parent, shared: ContextShared) {
  8. super(parent, shared);
  9. }
  10. override function save() : Dynamic {
  11. if( retargetIgnore == "" ) retargetIgnore = null;
  12. return super.save();
  13. }
  14. override function makeObject(parent3d:h3d.scene.Object):h3d.scene.Object {
  15. if( source == null)
  16. return super.makeObject(parent3d);
  17. #if editor
  18. try {
  19. #end
  20. var obj = shared.loadModel(source);
  21. if(obj.defaultTransform != null && children.length > 0) {
  22. obj.name = "root";
  23. var root = new h3d.scene.Object();
  24. root.addChild(obj);
  25. obj = root;
  26. }
  27. #if editor
  28. for(m in obj.getMeshes())
  29. if( !Std.isOfType(m,h3d.scene.Skin) )
  30. m.cullingCollider = new h3d.col.ObjectCollider(m, m.primitive.getBounds().toSphere());
  31. #end
  32. if( retargetAnim ) applyRetarget(obj);
  33. obj.name = name;
  34. parent3d.addChild(obj);
  35. if( animation != null )
  36. obj.playAnimation(shared.loadAnimation(animation));
  37. return obj;
  38. #if editor
  39. } catch( e : Dynamic ) {
  40. e.message = "Could not load model " + source + ": " + e.message;
  41. shared.onError(e);
  42. }
  43. #end
  44. return new h3d.scene.Object(parent3d);
  45. }
  46. function applyRetarget( obj : h3d.scene.Object ) {
  47. if( !retargetAnim )
  48. return;
  49. var ignorePrefix = [], ignoreNames = new Map();
  50. if( retargetIgnore != null ) {
  51. for( i in retargetIgnore.split(",") ) {
  52. if( i.charCodeAt(i.length-1) == "*".code )
  53. ignorePrefix.push(i.substr(0,-1));
  54. else
  55. ignoreNames.set(i, true);
  56. }
  57. }
  58. for( o in obj.getMeshes() ) {
  59. var sk = Std.downcast(o, h3d.scene.Skin);
  60. if( sk == null ) continue;
  61. for( j in sk.getSkinData().allJoints ) {
  62. var ignored = ignoreNames.get(j.name);
  63. if( ignored ) continue;
  64. for( i in ignorePrefix )
  65. if( StringTools.startsWith(j.name,i) ) {
  66. ignored = true;
  67. break;
  68. }
  69. if( !ignored )
  70. j.retargetAnim = true;
  71. }
  72. }
  73. }
  74. #if editor
  75. override function updateInstance(?propName : String ) {
  76. super.updateInstance(propName);
  77. polys3D = null;
  78. boundingSphere = null;
  79. }
  80. override function onEditorTreeChanged(child:Prefab):hrt.prefab.Prefab.TreeChangedResult {
  81. // Correctly handle changes in hierachy in case the model has a default transform
  82. if (Std.downcast(child, Object3D) != null) {
  83. return Rebuild;
  84. }
  85. return super.onEditorTreeChanged(child);
  86. }
  87. var polys3D = null;
  88. var boundingSphere = null;
  89. override function localRayIntersection(ray : h3d.col.Ray ) : Float {
  90. // can happen if the mesh is inside an emitter
  91. if (local3d == null)
  92. return -1.;
  93. if( polys3D == null ) {
  94. polys3D = [];
  95. var bounds = local3d.getBounds();
  96. bounds.transform(local3d.getAbsPos().getInverse());
  97. boundingSphere = bounds.toSphere();
  98. for( m in getObjects(h3d.scene.Mesh) ) {
  99. var p = cast(m.primitive, h3d.prim.HMDModel);
  100. var col = cast(cast(p.getCollider(), h3d.col.Collider.OptimizedCollider).b, h3d.col.PolygonBuffer);
  101. polys3D.push({ col : col, mat : m.getRelPos(local3d).getInverse() });
  102. }
  103. }
  104. if( boundingSphere == null || boundingSphere.rayIntersection(ray,false) < 0 )
  105. return -1.;
  106. var minD = -1.;
  107. for( p in polys3D ) {
  108. var ray2 = ray.clone();
  109. ray2.transform(p.mat);
  110. var d = p.col.rayIntersection(ray2, true);
  111. if( d > 0 && (d < minD || minD == -1) )
  112. minD = d;
  113. }
  114. return minD;
  115. }
  116. override function edit( ctx : hide.prefab.EditContext ) {
  117. super.edit(ctx);
  118. var props = ctx.properties.add(new hide.Element('
  119. <div class="group" name="Animation">
  120. <dl>
  121. <dt>Model</dt><dd><input type="model" field="source"/></dd>
  122. <dt/><dd><input type="button" value="Change All" id="changeAll"/></dd>
  123. <dt>Animation</dt><dd><input id="anim" value="--- Choose ---"></dd>
  124. <dt title="Don\'t save animation changes">Lock</dt><dd><input type="checkbox" field="lockAnimation"></dd>
  125. <dt>Retarget</dt><dd><input type="checkbox" field="retargetAnim"></dd>
  126. <dt>Retarget Ignore</dt><dd><input type="text" field="retargetIgnore"></dd>
  127. </dl>
  128. </div>
  129. '),this, function(pname) {
  130. if( pname == "retargetIgnore" && ctx.properties.isTempChange ) return;
  131. if (pname == "source")
  132. ctx.scene.editor.queueRebuild(this);
  133. ctx.onChange(this, pname);
  134. });
  135. var changeAllbtn = props.find("#changeAll");
  136. changeAllbtn.on("click",function() hide.Ide.inst.chooseFile(["fbx", "l3d"] , function (path) {
  137. ctx.scene.editor.changeAllModels(this, path);
  138. }));
  139. var anims = try ctx.scene.listAnims(source) catch(e: Dynamic) [];
  140. var elts: Array<hide.comp.Dropdown.Choice> = [];
  141. for( a in anims )
  142. elts.push({id : ctx.ide.makeRelative(a), ico : null, text : ctx.scene.animationName(a), classes : ["compact"]});
  143. var select = new hide.comp.Select(null, props.find("#anim"), elts);
  144. select.value = animation;
  145. select.onChange = function(newAnim : String) {
  146. var v = newAnim;
  147. var prev = animation;
  148. var obj = local3d;
  149. ctx.scene.setCurrent();
  150. if( v == "" ) {
  151. animation = null;
  152. obj.stopAnimation();
  153. } else {
  154. obj.playAnimation(shared.loadAnimation(v)).loop = true;
  155. if( lockAnimation ) return;
  156. animation = v;
  157. }
  158. var newValue = animation;
  159. ctx.properties.undo.change(Custom(function(undo) {
  160. var obj = local3d;
  161. animation = undo ? prev : newValue;
  162. if( animation == null ) {
  163. obj.stopAnimation();
  164. } else {
  165. obj.playAnimation(shared.loadAnimation(animation)).loop = true;
  166. }
  167. select.value = animation;
  168. }));
  169. };
  170. }
  171. override function getHideProps() : hide.prefab.HideProps {
  172. return {
  173. icon : "cube", name : "Model", fileSource : ["fbx","hmd"],
  174. allowChildren : function(t) return Prefab.isOfType(t,Object3D) || Prefab.isOfType(t,Material) || Prefab.isOfType(t,Shader) || Prefab.isOfType(t, hrt.prefab.fx.AnimEvent),
  175. onResourceRenamed : function(f) animation = f(animation),
  176. };
  177. }
  178. #end
  179. static var _ = Prefab.register("model", Model);
  180. }