mayaShaderColorDef.cxx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. // Filename: mayaShaderColorDef.cxx
  2. // Created by: drose (12Apr03)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
  8. //
  9. // All use of this software is subject to the terms of the Panda 3d
  10. // Software license. You should have received a copy of this license
  11. // along with this source code; you will also find a current copy of
  12. // the license at http://etc.cmu.edu/panda3d/docs/license/ .
  13. //
  14. // To contact the maintainers of this program write to
  15. // [email protected] .
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. #include "mayaShaderColorDef.h"
  19. #include "mayaShader.h"
  20. #include "maya_funcs.h"
  21. #include "config_maya.h"
  22. #include "string_utils.h"
  23. #include "pset.h"
  24. #include "pre_maya_include.h"
  25. #include <maya/MFnDependencyNode.h>
  26. #include <maya/MPlug.h>
  27. #include <maya/MPlugArray.h>
  28. #include <maya/MObject.h>
  29. #include <maya/MStatus.h>
  30. #include "post_maya_include.h"
  31. ////////////////////////////////////////////////////////////////////
  32. // Function: MayaShaderColorDef::Constructor
  33. // Access: Public
  34. // Description:
  35. ////////////////////////////////////////////////////////////////////
  36. MayaShaderColorDef::
  37. MayaShaderColorDef() {
  38. _color_gain.set(1.0f, 1.0f, 1.0f, 1.0f);
  39. _has_flat_color = false;
  40. _flat_color.set(0.0, 0.0, 0.0, 0.0);
  41. _has_texture = false;
  42. _texture_name = "";
  43. _uvset_name = "default";
  44. _projection_type = PT_off;
  45. _map_uvs = NULL;
  46. _coverage.set(1.0, 1.0);
  47. _translate_frame.set(0.0, 0.0);
  48. _rotate_frame = 0.0;
  49. _mirror = false;
  50. _stagger = false;
  51. _wrap_u = true;
  52. _wrap_v = true;
  53. _alpha_is_luminance = false;
  54. _repeat_uv.set(1.0, 1.0);
  55. _offset.set(0.0, 0.0);
  56. _rotate_uv = 0.0;
  57. _color_object = (MObject *)NULL;
  58. }
  59. ////////////////////////////////////////////////////////////////////
  60. // Function: MayaShaderColorDef::Constructor
  61. // Access: Public
  62. // Description:
  63. ////////////////////////////////////////////////////////////////////
  64. MayaShaderColorDef::
  65. MayaShaderColorDef(MayaShaderColorDef &copy) {
  66. _has_texture = copy._has_texture;
  67. _texture_filename = copy._texture_filename;
  68. _texture_name = copy._texture_name;
  69. _uvset_name = copy._uvset_name;
  70. _color_gain = copy._color_gain;
  71. _has_flat_color = copy._has_flat_color;
  72. _flat_color = copy._flat_color;
  73. _projection_type = copy._projection_type;
  74. _projection_matrix = copy._projection_matrix;
  75. _u_angle = copy._u_angle;
  76. _v_angle = copy._v_angle;
  77. _coverage = copy._coverage;
  78. _translate_frame = copy._translate_frame;
  79. _rotate_frame = copy._rotate_frame;
  80. _mirror = copy._mirror;
  81. _stagger = copy._stagger;
  82. _wrap_u = copy._wrap_u;
  83. _wrap_v = copy._wrap_v;
  84. _alpha_is_luminance = copy._alpha_is_luminance;
  85. _repeat_uv = copy._repeat_uv;
  86. _offset = copy._offset;
  87. _rotate_uv = copy._rotate_uv;
  88. _map_uvs = copy._map_uvs;
  89. _color_object = copy._color_object;
  90. }
  91. ////////////////////////////////////////////////////////////////////
  92. // Function: MayaShaderColorDef::Destructor
  93. // Access: Public
  94. // Description:
  95. ////////////////////////////////////////////////////////////////////
  96. MayaShaderColorDef::
  97. ~MayaShaderColorDef() {
  98. if (_color_object != (MObject *)NULL) {
  99. delete _color_object;
  100. }
  101. }
  102. ////////////////////////////////////////////////////////////////////
  103. // Function: MayaShaderColorDef::compute_texture_matrix
  104. // Access: Public
  105. // Description: Returns a texture matrix corresponding to the texture
  106. // transforms indicated by the shader.
  107. ////////////////////////////////////////////////////////////////////
  108. LMatrix3d MayaShaderColorDef::
  109. compute_texture_matrix() const {
  110. LVector2d scale(_repeat_uv[0] / _coverage[0],
  111. _repeat_uv[1] / _coverage[1]);
  112. LVector2d trans(_offset[0] - _translate_frame[0] / _coverage[0],
  113. _offset[1] - _translate_frame[1] / _coverage[1]);
  114. return
  115. (LMatrix3d::translate_mat(LVector2d(-0.5, -0.5)) *
  116. LMatrix3d::rotate_mat(_rotate_frame) *
  117. LMatrix3d::translate_mat(LVector2d(0.5, 0.5))) *
  118. LMatrix3d::scale_mat(scale) *
  119. LMatrix3d::translate_mat(trans);
  120. }
  121. ////////////////////////////////////////////////////////////////////
  122. // Function: MayaShaderColorDef::has_projection
  123. // Access: Public
  124. // Description: Returns true if the shader has a projection in effect.
  125. ////////////////////////////////////////////////////////////////////
  126. bool MayaShaderColorDef::
  127. has_projection() const {
  128. return (_projection_type != PT_off);
  129. }
  130. ////////////////////////////////////////////////////////////////////
  131. // Function: MayaShaderColorDef::project_uv
  132. // Access: Public
  133. // Description: If the shader has a projection (has_projection()
  134. // returns true), this computes the appropriate UV
  135. // corresponding to the indicated 3-d point. Seams that
  136. // might be introduced on polygons that cross quadrants
  137. // are closed up by ensuring the point is in the same
  138. // quadrant as the indicated reference point.
  139. ////////////////////////////////////////////////////////////////////
  140. TexCoordd MayaShaderColorDef::
  141. project_uv(const LPoint3d &pos, const LPoint3d &centroid) const {
  142. nassertr(_map_uvs != NULL, TexCoordd::zero());
  143. return (this->*_map_uvs)(pos * _projection_matrix, centroid * _projection_matrix);
  144. }
  145. ////////////////////////////////////////////////////////////////////
  146. // Function: MayaShaderColorDef::write
  147. // Access: Public
  148. // Description:
  149. ////////////////////////////////////////////////////////////////////
  150. void MayaShaderColorDef::
  151. write(ostream &out) const {
  152. if (_has_texture) {
  153. out << " texture filename is " << _texture_filename << "\n"
  154. << " texture name is " << _texture_name << "\n"
  155. << " uv_set name is " << _uvset_name << "\n"
  156. << " coverage is " << _coverage << "\n"
  157. << " translate_frame is " << _translate_frame << "\n"
  158. << " rotate_frame is " << _rotate_frame << "\n"
  159. << " mirror is " << _mirror << "\n"
  160. << " stagger is " << _stagger << "\n"
  161. << " wrap_u is " << _wrap_u << "\n"
  162. << " wrap_v is " << _wrap_v << "\n"
  163. << " repeat_uv is " << _repeat_uv << "\n"
  164. << " offset is " << _offset << "\n"
  165. << " rotate_uv is " << _rotate_uv << "\n"
  166. << " color_gain is " << _color_gain << "\n";
  167. } else if (_has_flat_color) {
  168. out << " flat color is " << _flat_color << "\n";
  169. }
  170. }
  171. ////////////////////////////////////////////////////////////////////
  172. // Function: MayaShaderColorDef::reset_maya_texture
  173. // Access: Public
  174. // Description: Changes the texture filename stored in the Maya file
  175. // for this particular shader.
  176. ////////////////////////////////////////////////////////////////////
  177. bool MayaShaderColorDef::
  178. reset_maya_texture(const Filename &texture) {
  179. if (_color_object != (MObject *)NULL) {
  180. _has_texture = set_string_attribute(*_color_object, "fileTextureName",
  181. texture.to_os_generic());
  182. _texture_filename = texture;
  183. if (!_has_texture) {
  184. maya_cat.error()
  185. << "Unable to reset texture filename.\n";
  186. }
  187. return _has_texture;
  188. }
  189. maya_cat.error()
  190. << "Attempt to reset texture on Maya object that has no color set.\n";
  191. return false;
  192. }
  193. ////////////////////////////////////////////////////////////////////
  194. // Function: MayaShaderColorDef::read_surface_color
  195. // Access: Private
  196. // Description: Determines the surface color specified by the shader.
  197. // This includes texturing and other advanced shader
  198. // properties.
  199. ////////////////////////////////////////////////////////////////////
  200. void MayaShaderColorDef::
  201. read_surface_color(MayaShader *shader, MObject color, bool trans) {
  202. RGBColorf color_gain;
  203. if (get_vec3f_attribute(color, "colorGain", color_gain)) {
  204. _color_gain[0] *= color_gain[0];
  205. _color_gain[1] *= color_gain[1];
  206. _color_gain[2] *= color_gain[2];
  207. }
  208. float alpha_gain;
  209. if (get_maya_attribute(color, "alphaGain", alpha_gain)) {
  210. _color_gain[3] *= alpha_gain;
  211. }
  212. if (color.hasFn(MFn::kFileTexture)) {
  213. _color_object = new MObject(color);
  214. string filename;
  215. _has_texture = get_string_attribute(color, "fileTextureName", filename);
  216. _has_texture = _has_texture && !filename.empty();
  217. if (_has_texture) {
  218. _texture_filename = Filename::from_os_specific(filename);
  219. if (_texture_filename.is_directory()) {
  220. maya_cat.warning()
  221. << "Shader " << shader->get_name()
  222. << " references texture filename " << filename
  223. << " which is a directory; clearing.\n";
  224. _has_texture = false;
  225. set_string_attribute(color, "fileTextureName", "");
  226. }
  227. }
  228. get_vec2f_attribute(color, "coverage", _coverage);
  229. get_vec2f_attribute(color, "translateFrame", _translate_frame);
  230. get_angle_attribute(color, "rotateFrame", _rotate_frame);
  231. get_bool_attribute(color, "alphaIsLuminance", _alpha_is_luminance);
  232. get_bool_attribute(color, "mirror", _mirror);
  233. get_bool_attribute(color, "stagger", _stagger);
  234. get_bool_attribute(color, "wrapU", _wrap_u);
  235. get_bool_attribute(color, "wrapV", _wrap_v);
  236. get_vec2f_attribute(color, "repeatUV", _repeat_uv);
  237. get_vec2f_attribute(color, "offset", _offset);
  238. get_angle_attribute(color, "rotateUV", _rotate_uv);
  239. if (!trans) {
  240. maya_cat.debug() << "pushed a file texture" << endl;
  241. shader->_color.push_back(this);
  242. }
  243. } else if (color.hasFn(MFn::kProjection)) {
  244. maya_cat.debug() << "reading a projection texture" << endl;
  245. // This is a projected texture. We will have to step one level
  246. // deeper to find the actual texture.
  247. MFnDependencyNode projection_fn(color);
  248. MPlug image_plug = projection_fn.findPlug("image");
  249. if (!image_plug.isNull()) {
  250. MPlugArray image_pa;
  251. image_plug.connectedTo(image_pa, true, false);
  252. for (size_t i = 0; i < image_pa.length(); i++) {
  253. read_surface_color(shader, image_pa[0].node());
  254. }
  255. }
  256. if (!get_mat4d_attribute(color, "placementMatrix", _projection_matrix)) {
  257. _projection_matrix = LMatrix4d::ident_mat();
  258. }
  259. // The uAngle and vAngle might be used for certain kinds of
  260. // projections.
  261. if (!get_angle_attribute(color, "uAngle", _u_angle)) {
  262. _u_angle = 360.0;
  263. }
  264. if (!get_angle_attribute(color, "vAngle", _v_angle)) {
  265. _v_angle = 180.0;
  266. }
  267. string type;
  268. if (get_enum_attribute(color, "projType", type)) {
  269. set_projection_type(type);
  270. }
  271. } else if (color.hasFn(MFn::kLayeredTexture)) {
  272. maya_cat.debug() << "Found layered texture" << endl;
  273. //list_maya_attributes(color);
  274. //shader->_multi_texture = true;
  275. //get_enum_attribute(color,"blendMode",shader->_blend_mode);
  276. //maya_cat.debug() << "blend mode :" << shader->_blend_mode << endl;
  277. get_bool_attribute(color, "alphaIsLuminance", shader->_alpha_is_luminance);
  278. // get_bool_attribute(color, "isVisible", test_b);
  279. MFnDependencyNode layered_fn(color);
  280. MPlugArray color_pa;
  281. layered_fn.getConnections(color_pa);
  282. maya_cat.debug() << "number of connections: " << color_pa.length() << endl;
  283. bool first = true;
  284. for (size_t i=0; i<color_pa.length(); ++i) {
  285. MPlug pl = color_pa[i];
  286. MPlugArray pla;
  287. pl.connectedTo(pla, true, false);
  288. for (size_t j=0; j<pla.length(); ++j) {
  289. //maya_cat.debug() << pl.name() << " is(pl) " << pl.node().apiTypeStr() << endl;
  290. //maya_cat.debug() << pla[j].name() << " is(pla) " << pla[j].node().apiTypeStr() << endl;
  291. string pla_name = pla[j].name().asChar();
  292. // sometimes, by default, maya gives a outAlpha on subsequent plugs, ignore that
  293. if (pla_name.find("outAlpha") != string::npos) {
  294. maya_cat.debug() << pl.name().asChar() << " ignoring: " << pla_name << endl;
  295. // In this case the artist is wanting to retain alpha at the result
  296. // So make sure that this alpha is not thrown out by the egg file
  297. _alpha_is_luminance = true;
  298. continue;
  299. }
  300. if (!first) {
  301. maya_cat.debug() << pl.name().asChar() << " next:connectedTo: " << pla_name << endl;
  302. MayaShaderColorDef *color_p = new MayaShaderColorDef;
  303. color_p->read_surface_color(shader, pla[j].node());
  304. color_p->_texture_name.assign(pla[j].name().asChar());
  305. size_t loc = color_p->_texture_name.find('.',0);
  306. if (loc != string::npos) {
  307. color_p->_texture_name.resize(loc);
  308. }
  309. maya_cat.debug() << "uv_name : " << color_p->_texture_name << endl;
  310. }
  311. else {
  312. maya_cat.debug() << pl.name().asChar() << " first:connectedTo: " << pla_name << endl;
  313. read_surface_color(shader, pla[j].node());
  314. _texture_name.assign(pla[j].name().asChar());
  315. size_t loc = _texture_name.find('.',0);
  316. if (loc != string::npos) {
  317. _texture_name.resize(loc);
  318. }
  319. maya_cat.debug() << "uv_name : " << _texture_name << endl;
  320. first = false;
  321. }
  322. // lets see what this is connected to!?
  323. MPlug pl_temp = pla[j];
  324. MPlugArray pla_temp;
  325. pl_temp.connectedTo(pla_temp, true, false);
  326. maya_cat.debug() << pl_temp.name().asChar() << " connectedTo:" << pla_temp.length() << " plugs\n";
  327. }
  328. /*
  329. string blah;
  330. get_enum_attribute(pl.node(),"blendMode",blah);
  331. maya_cat.info() << "rsc layer: blend mode :" << blah << endl;
  332. float alpha;
  333. get_maya_attribute(pl.node(),"alpha",alpha);
  334. maya_cat.info() << "rsc layer: alpha :" << alpha << endl;
  335. */
  336. }
  337. } else {
  338. // This shader wasn't understood.
  339. if (maya_cat.is_debug()) {
  340. maya_cat.info()
  341. << "**Don't know how to interpret color attribute type "
  342. << color.apiTypeStr() << "\n";
  343. } else {
  344. // If we don't have a heavy verbose count, only report each type
  345. // of unsupported shader once.
  346. static pset<MFn::Type> bad_types;
  347. if (bad_types.insert(color.apiType()).second) {
  348. maya_cat.info()
  349. << "**Don't know how to interpret color attribute type "
  350. << color.apiTypeStr() << "\n";
  351. }
  352. }
  353. }
  354. }
  355. ////////////////////////////////////////////////////////////////////
  356. // Function: MayaShaderColorDef::set_projection_type
  357. // Access: Private
  358. // Description: Sets up the shader to apply UV's according to the
  359. // indicated projection type.
  360. ////////////////////////////////////////////////////////////////////
  361. void MayaShaderColorDef::
  362. set_projection_type(const string &type) {
  363. if (cmp_nocase(type, "planar") == 0) {
  364. _projection_type = PT_planar;
  365. _map_uvs = &MayaShaderColorDef::map_planar;
  366. // The Planar projection normally projects to a range (-1, 1) in
  367. // both axes. Scale this into our UV range of (0, 1).
  368. _projection_matrix = _projection_matrix * LMatrix4d(0.5, 0.0, 0.0, 0.0,
  369. 0.0, 0.5, 0.0, 0.0,
  370. 0.0, 0.0, 1.0, 0.0,
  371. 0.5, 0.5, 0.0, 1.0);
  372. } else if (cmp_nocase(type, "cylindrical") == 0) {
  373. _projection_type = PT_cylindrical;
  374. _map_uvs = &MayaShaderColorDef::map_cylindrical;
  375. // The cylindrical projection is orthographic in the Y axis; scale
  376. // the range (-1, 1) in this axis into our UV range (0, 1).
  377. _projection_matrix = _projection_matrix * LMatrix4d(1.0, 0.0, 0.0, 0.0,
  378. 0.0, 0.5, 0.0, 0.0,
  379. 0.0, 0.0, 1.0, 0.0,
  380. 0.0, 0.5, 0.0, 1.0);
  381. } else if (cmp_nocase(type, "spherical") == 0) {
  382. _projection_type = PT_spherical;
  383. _map_uvs = &MayaShaderColorDef::map_spherical;
  384. } else {
  385. // Other projection types are currently unimplemented by the
  386. // converter.
  387. maya_cat.error()
  388. << "Don't know how to handle type " << type << " projections.\n";
  389. _projection_type = PT_off;
  390. _map_uvs = NULL;
  391. }
  392. }
  393. ////////////////////////////////////////////////////////////////////
  394. // Function: MayaShaderColorDef::map_planar
  395. // Access: Private
  396. // Description: Computes a UV based on the given point in space,
  397. // using a planar projection.
  398. ////////////////////////////////////////////////////////////////////
  399. LPoint2d MayaShaderColorDef::
  400. map_planar(const LPoint3d &pos, const LPoint3d &) const {
  401. // A planar projection is about as easy as can be. We ignore the Z
  402. // axis, and project the point into the XY plane. Done.
  403. return LPoint2d(pos[0], pos[1]);
  404. }
  405. ////////////////////////////////////////////////////////////////////
  406. // Function: MayaShaderColorDef::map_spherical
  407. // Access: Private
  408. // Description: Computes a UV based on the given point in space,
  409. // using a spherical projection.
  410. ////////////////////////////////////////////////////////////////////
  411. LPoint2d MayaShaderColorDef::
  412. map_spherical(const LPoint3d &pos, const LPoint3d &centroid) const {
  413. // To compute the x position on the frame, we only need to consider
  414. // the angle of the vector about the Y axis. Project the vector
  415. // into the XZ plane to do this.
  416. LVector2d xz(pos[0], pos[2]);
  417. double xz_length = xz.length();
  418. if (xz_length < 0.01) {
  419. // If we have a point on or near either pole, we've got problems.
  420. // This point maps to the entire bottom edge of the image, so
  421. // which U value should we choose? It does make a difference,
  422. // especially if we have a number of polygons around the south
  423. // pole that all share the common vertex.
  424. // We choose the U value based on the polygon's centroid.
  425. xz.set(centroid[0], centroid[2]);
  426. }
  427. // Now, if the polygon crosses the seam, we also have problems.
  428. // Make sure that the u value is in the same half of the texture as
  429. // the centroid's u value.
  430. double u = rad_2_deg(atan2(xz[0], xz[1])) / (2.0 * _u_angle);
  431. double c = rad_2_deg(atan2(centroid[0], centroid[2])) / (2.0 * _u_angle);
  432. if (u - c > 0.5) {
  433. u -= floor(u - c + 0.5);
  434. } else if (u - c < -0.5) {
  435. u += floor(c - u + 0.5);
  436. }
  437. // Now rotate the vector into the YZ plane, and the V value is based
  438. // on the latitude: the angle about the X axis.
  439. LVector2d yz(pos[1], xz_length);
  440. double v = rad_2_deg(atan2(yz[0], yz[1])) / (2.0 * _v_angle);
  441. LPoint2d uv(u - 0.5, v - 0.5);
  442. nassertr(fabs(u - c) <= 0.5, uv);
  443. return uv;
  444. }
  445. ////////////////////////////////////////////////////////////////////
  446. // Function: MayaShaderColorDef::map_cylindrical
  447. // Access: Private
  448. // Description: Computes a UV based on the given point in space,
  449. // using a cylindrical projection.
  450. ////////////////////////////////////////////////////////////////////
  451. LPoint2d MayaShaderColorDef::
  452. map_cylindrical(const LPoint3d &pos, const LPoint3d &centroid) const {
  453. // This is almost identical to the spherical projection, except for
  454. // the computation of V.
  455. LVector2d xz(pos[0], pos[2]);
  456. double xz_length = xz.length();
  457. if (xz_length < 0.01) {
  458. // A cylindrical mapping has the same singularity problem at the
  459. // pole as a spherical mapping does: points at the pole do not map
  460. // to a single point on the texture. (It's technically a slightly
  461. // different problem: in a cylindrical mapping, points at the pole
  462. // do not map to any point on the texture, while in a spherical
  463. // mapping, points at the pole map to the top or bottom edge of
  464. // the texture. But this is a technicality that doesn't really
  465. // apply to us.) We still solve it the same way: if our point is
  466. // at or near the pole, compute the angle based on the centroid of
  467. // the polygon (which we assume is further from the pole).
  468. xz.set(centroid[0], centroid[2]);
  469. }
  470. // And cylinders do still have a seam at the back.
  471. double u = rad_2_deg(atan2(xz[0], xz[1])) / _u_angle;
  472. double c = rad_2_deg(atan2(centroid[0], centroid[2])) / _u_angle;
  473. if (u - c > 0.5) {
  474. u -= floor(u - c + 0.5);
  475. } else if (u - c < -0.5) {
  476. u += floor(c - u + 0.5);
  477. }
  478. // For a cylindrical mapping, the V value comes directly from Y.
  479. // Easy.
  480. LPoint2d uv(u - 0.5, pos[1]);
  481. nassertr(fabs(u - c) <= 0.5, uv);
  482. return uv;
  483. }