Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

pandatool/src/maya/mayaShaderColorDef.cxx

Go to the documentation of this file.
00001 // Filename: mayaShaderColorDef.cxx
00002 // Created by:  drose (12Apr03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "mayaShaderColorDef.h"
00020 #include "maya_funcs.h"
00021 #include "config_maya.h"
00022 #include "string_utils.h"
00023 #include "pset.h"
00024 
00025 #include "pre_maya_include.h"
00026 #include <maya/MFnDependencyNode.h>
00027 #include <maya/MPlug.h>
00028 #include <maya/MPlugArray.h>
00029 #include <maya/MObject.h>
00030 #include <maya/MStatus.h>
00031 #include "post_maya_include.h"
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: MayaShaderColorDef::Constructor
00035 //       Access: Public
00036 //  Description: 
00037 ////////////////////////////////////////////////////////////////////
00038 MayaShaderColorDef::
00039 MayaShaderColorDef() {
00040   _color_gain.set(1.0f, 1.0f, 1.0f);
00041 
00042   _has_flat_color = false;
00043   _flat_color.set(0.0, 0.0, 0.0, 0.0);
00044 
00045   _has_texture = false;
00046   _projection_type = PT_off;
00047   _map_uvs = NULL;
00048 
00049   _coverage.set(1.0, 1.0);
00050   _translate_frame.set(0.0, 0.0);
00051   _rotate_frame = 0.0;
00052 
00053   _mirror = false;
00054   _stagger = false;
00055   _wrap_u = true;
00056   _wrap_v = true;
00057 
00058   _repeat_uv.set(1.0, 1.0);
00059   _offset.set(0.0, 0.0);
00060   _rotate_uv = 0.0;
00061 
00062   _color_object = (MObject *)NULL;
00063 }
00064 
00065 ////////////////////////////////////////////////////////////////////
00066 //     Function: MayaShaderColorDef::Destructor
00067 //       Access: Public
00068 //  Description: 
00069 ////////////////////////////////////////////////////////////////////
00070 MayaShaderColorDef::
00071 ~MayaShaderColorDef() {
00072   if (_color_object != (MObject *)NULL) {
00073     delete _color_object;
00074   }
00075 }
00076 
00077 ////////////////////////////////////////////////////////////////////
00078 //     Function: MayaShaderColorDef::compute_texture_matrix
00079 //       Access: Public
00080 //  Description: Returns a texture matrix corresponding to the texture
00081 //               transforms indicated by the shader.
00082 ////////////////////////////////////////////////////////////////////
00083 LMatrix3d MayaShaderColorDef::
00084 compute_texture_matrix() const {
00085   LVector2d scale(_repeat_uv[0] / _coverage[0],
00086                   _repeat_uv[1] / _coverage[1]);
00087   LVector2d trans(_offset[0] - _translate_frame[0] / _coverage[0],
00088                   _offset[1] - _translate_frame[1] / _coverage[1]);
00089 
00090   return
00091     (LMatrix3d::translate_mat(LVector2d(-0.5, -0.5)) *
00092      LMatrix3d::rotate_mat(_rotate_frame) *
00093      LMatrix3d::translate_mat(LVector2d(0.5, 0.5))) *
00094     LMatrix3d::scale_mat(scale) *
00095     LMatrix3d::translate_mat(trans);
00096 }
00097 
00098 ////////////////////////////////////////////////////////////////////
00099 //     Function: MayaShaderColorDef::has_projection
00100 //       Access: Public
00101 //  Description: Returns true if the shader has a projection in effect.
00102 ////////////////////////////////////////////////////////////////////
00103 bool MayaShaderColorDef::
00104 has_projection() const {
00105   return (_projection_type != PT_off);
00106 }
00107 
00108 ////////////////////////////////////////////////////////////////////
00109 //     Function: MayaShaderColorDef::project_uv
00110 //       Access: Public
00111 //  Description: If the shader has a projection (has_projection()
00112 //               returns true), this computes the appropriate UV
00113 //               corresponding to the indicated 3-d point.  Seams that
00114 //               might be introduced on polygons that cross quadrants
00115 //               are closed up by ensuring the point is in the same
00116 //               quadrant as the indicated reference point.
00117 ////////////////////////////////////////////////////////////////////
00118 TexCoordd MayaShaderColorDef::
00119 project_uv(const LPoint3d &pos, const LPoint3d &centroid) const {
00120   nassertr(_map_uvs != NULL, TexCoordd::zero());
00121   return (this->*_map_uvs)(pos * _projection_matrix, centroid * _projection_matrix);
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: MayaShaderColorDef::write
00126 //       Access: Public
00127 //  Description: 
00128 ////////////////////////////////////////////////////////////////////
00129 void MayaShaderColorDef::
00130 write(ostream &out) const {
00131   if (_has_texture) {
00132     out << "    texture is " << _texture << "\n"
00133         << "    coverage is " << _coverage << "\n"
00134         << "    translate_frame is " << _translate_frame << "\n"
00135         << "    rotate_frame is " << _rotate_frame << "\n"
00136         << "    mirror is " << _mirror << "\n"
00137         << "    stagger is " << _stagger << "\n"
00138         << "    wrap_u is " << _wrap_u << "\n"
00139         << "    wrap_v is " << _wrap_v << "\n"
00140         << "    repeat_uv is " << _repeat_uv << "\n"
00141         << "    offset is " << _offset << "\n"
00142         << "    rotate_uv is " << _rotate_uv << "\n"
00143         << "    color_gain is " << _color_gain << "\n";
00144 
00145   } else if (_has_flat_color) {
00146     out << "    flat color is " << _flat_color << "\n";
00147   }
00148 }
00149 
00150 ////////////////////////////////////////////////////////////////////
00151 //     Function: MayaShaderColorDef::reset_maya_texture
00152 //       Access: Public
00153 //  Description: Changes the texture filename stored in the Maya file
00154 //               for this particular shader.
00155 ////////////////////////////////////////////////////////////////////
00156 bool MayaShaderColorDef::
00157 reset_maya_texture(const Filename &texture) {
00158   if (_color_object != (MObject *)NULL) {
00159     _has_texture = set_string_attribute(*_color_object, "fileTextureName", 
00160                                         texture);
00161     _texture = texture;
00162 
00163     if (!_has_texture) {
00164       maya_cat.error()
00165         << "Unable to reset texture filename.\n";
00166     }
00167 
00168     return _has_texture;
00169   }
00170 
00171   maya_cat.error()
00172     << "Attempt to reset texture on Maya object that has no color set.\n";
00173   return false;
00174 }
00175 
00176 ////////////////////////////////////////////////////////////////////
00177 //     Function: MayaShaderColorDef::read_surface_color
00178 //       Access: Private
00179 //  Description: Determines the surface color specified by the shader.
00180 //               This includes texturing and other advanced shader
00181 //               properties.
00182 ////////////////////////////////////////////////////////////////////
00183 void MayaShaderColorDef::
00184 read_surface_color(MObject color) {
00185   RGBColorf color_gain;
00186   if (get_vec3f_attribute(color, "colorGain", color_gain)) {
00187     _color_gain[0] *= color_gain[0];
00188     _color_gain[1] *= color_gain[1];
00189     _color_gain[2] *= color_gain[2];
00190   }
00191 
00192   if (color.hasFn(MFn::kFileTexture)) {
00193     _color_object = new MObject(color);
00194     string filename;
00195     _has_texture = get_string_attribute(color, "fileTextureName", filename);
00196     if (_has_texture) {
00197       _texture = Filename::from_os_specific(filename);
00198     }
00199 
00200     get_vec2f_attribute(color, "coverage", _coverage);
00201     get_vec2f_attribute(color, "translateFrame", _translate_frame);
00202     get_angle_attribute(color, "rotateFrame", _rotate_frame);
00203 
00204     get_bool_attribute(color, "mirror", _mirror);
00205     get_bool_attribute(color, "stagger", _stagger);
00206     get_bool_attribute(color, "wrapU", _wrap_u);
00207     get_bool_attribute(color, "wrapV", _wrap_v);
00208 
00209     get_vec2f_attribute(color, "repeatUV", _repeat_uv);
00210     get_vec2f_attribute(color, "offset", _offset);
00211     get_angle_attribute(color, "rotateUV", _rotate_uv);
00212 
00213   } else if (color.hasFn(MFn::kProjection)) {
00214     // This is a projected texture.  We will have to step one level
00215     // deeper to find the actual texture.
00216     MFnDependencyNode projection_fn(color);
00217     MPlug image_plug = projection_fn.findPlug("image");
00218     if (!image_plug.isNull()) {
00219       MPlugArray image_pa;
00220       image_plug.connectedTo(image_pa, true, false);
00221       
00222       for (size_t i = 0; i < image_pa.length(); i++) {
00223         read_surface_color(image_pa[0].node());
00224       }
00225     }
00226 
00227     if (!get_mat4d_attribute(color, "placementMatrix", _projection_matrix)) {
00228       _projection_matrix = LMatrix4d::ident_mat();
00229     }
00230 
00231     // The uAngle and vAngle might be used for certain kinds of
00232     // projections.
00233     if (!get_angle_attribute(color, "uAngle", _u_angle)) {
00234       _u_angle = 360.0;
00235     }
00236     if (!get_angle_attribute(color, "vAngle", _v_angle)) {
00237       _v_angle = 180.0;
00238     }
00239 
00240     string type;
00241     if (get_enum_attribute(color, "projType", type)) {
00242       set_projection_type(type);
00243     }
00244 
00245   } else {
00246     // This shader wasn't understood.
00247     if (maya_cat.is_debug()) {
00248       maya_cat.info()
00249         << "**Don't know how to interpret color attribute type "
00250         << color.apiTypeStr() << "\n";
00251 
00252     } else {
00253       // If we don't have a heavy verbose count, only report each type
00254       // of unsupported shader once.
00255       static pset<MFn::Type> bad_types;
00256       if (bad_types.insert(color.apiType()).second) {
00257         maya_cat.info()
00258           << "**Don't know how to interpret color attribute type "
00259           << color.apiTypeStr() << "\n";
00260       }
00261     }
00262   }
00263 }
00264 
00265 ////////////////////////////////////////////////////////////////////
00266 //     Function: MayaShaderColorDef::set_projection_type
00267 //       Access: Private
00268 //  Description: Sets up the shader to apply UV's according to the
00269 //               indicated projection type.
00270 ////////////////////////////////////////////////////////////////////
00271 void MayaShaderColorDef::
00272 set_projection_type(const string &type) {
00273   if (cmp_nocase(type, "planar") == 0) {
00274     _projection_type = PT_planar;
00275     _map_uvs = &MayaShaderColorDef::map_planar;
00276 
00277     // The Planar projection normally projects to a range (-1, 1) in
00278     // both axes.  Scale this into our UV range of (0, 1).
00279     _projection_matrix = _projection_matrix * LMatrix4d(0.5, 0.0, 0.0, 0.0,
00280                                                         0.0, 0.5, 0.0, 0.0,
00281                                                         0.0, 0.0, 1.0, 0.0,
00282                                                         0.5, 0.5, 0.0, 1.0);
00283 
00284   } else if (cmp_nocase(type, "cylindrical") == 0) {
00285     _projection_type = PT_cylindrical;
00286     _map_uvs = &MayaShaderColorDef::map_cylindrical;
00287 
00288     // The cylindrical projection is orthographic in the Y axis; scale
00289     // the range (-1, 1) in this axis into our UV range (0, 1).
00290     _projection_matrix = _projection_matrix * LMatrix4d(1.0, 0.0, 0.0, 0.0,
00291                                                         0.0, 0.5, 0.0, 0.0,
00292                                                         0.0, 0.0, 1.0, 0.0,
00293                                                         0.0, 0.5, 0.0, 1.0);
00294 
00295   } else if (cmp_nocase(type, "spherical") == 0) {
00296     _projection_type = PT_spherical;
00297     _map_uvs = &MayaShaderColorDef::map_spherical;
00298 
00299   } else {
00300     // Other projection types are currently unimplemented by the
00301     // converter.
00302     maya_cat.error()
00303       << "Don't know how to handle type " << type << " projections.\n";
00304     _projection_type = PT_off;
00305     _map_uvs = NULL;
00306   }
00307 }
00308 
00309 ////////////////////////////////////////////////////////////////////
00310 //     Function: MayaShaderColorDef::map_planar
00311 //       Access: Private
00312 //  Description: Computes a UV based on the given point in space,
00313 //               using a planar projection.
00314 ////////////////////////////////////////////////////////////////////
00315 LPoint2d MayaShaderColorDef::
00316 map_planar(const LPoint3d &pos, const LPoint3d &) const {
00317   // A planar projection is about as easy as can be.  We ignore the Z
00318   // axis, and project the point into the XY plane.  Done.
00319   return LPoint2d(pos[0], pos[1]);
00320 }
00321 
00322 ////////////////////////////////////////////////////////////////////
00323 //     Function: MayaShaderColorDef::map_spherical
00324 //       Access: Private
00325 //  Description: Computes a UV based on the given point in space,
00326 //               using a spherical projection.
00327 ////////////////////////////////////////////////////////////////////
00328 LPoint2d MayaShaderColorDef::
00329 map_spherical(const LPoint3d &pos, const LPoint3d &centroid) const {
00330   // To compute the x position on the frame, we only need to consider
00331   // the angle of the vector about the Y axis.  Project the vector
00332   // into the XZ plane to do this.
00333 
00334   LVector2d xz(pos[0], pos[2]);
00335   double xz_length = xz.length();
00336 
00337   if (xz_length < 0.01) {
00338     // If we have a point on or near either pole, we've got problems.
00339     // This point maps to the entire bottom edge of the image, so
00340     // which U value should we choose?  It does make a difference,
00341     // especially if we have a number of polygons around the south
00342     // pole that all share the common vertex.
00343 
00344     // We choose the U value based on the polygon's centroid.
00345     xz.set(centroid[0], centroid[2]);
00346   }
00347 
00348   // Now, if the polygon crosses the seam, we also have problems.
00349   // Make sure that the u value is in the same half of the texture as
00350   // the centroid's u value.
00351   double u = rad_2_deg(atan2(xz[0], xz[1])) / (2.0 * _u_angle);
00352   double c = rad_2_deg(atan2(centroid[0], centroid[2])) / (2.0 * _u_angle);
00353 
00354   if (u - c > 0.5) {
00355     u -= floor(u - c + 0.5);
00356   } else if (u - c < -0.5) {
00357     u += floor(c - u + 0.5);
00358   }
00359 
00360   // Now rotate the vector into the YZ plane, and the V value is based
00361   // on the latitude: the angle about the X axis.
00362   LVector2d yz(pos[1], xz_length);
00363   double v = rad_2_deg(atan2(yz[0], yz[1])) / (2.0 * _v_angle);
00364 
00365   LPoint2d uv(u - 0.5, v - 0.5);
00366 
00367   nassertr(fabs(u - c) <= 0.5, uv);
00368   return uv;
00369 }
00370 
00371 ////////////////////////////////////////////////////////////////////
00372 //     Function: MayaShaderColorDef::map_cylindrical
00373 //       Access: Private
00374 //  Description: Computes a UV based on the given point in space,
00375 //               using a cylindrical projection.
00376 ////////////////////////////////////////////////////////////////////
00377 LPoint2d MayaShaderColorDef::
00378 map_cylindrical(const LPoint3d &pos, const LPoint3d &centroid) const {
00379   // This is almost identical to the spherical projection, except for
00380   // the computation of V.
00381 
00382   LVector2d xz(pos[0], pos[2]);
00383   double xz_length = xz.length();
00384 
00385   if (xz_length < 0.01) {
00386     // A cylindrical mapping has the same singularity problem at the
00387     // pole as a spherical mapping does: points at the pole do not map
00388     // to a single point on the texture.  (It's technically a slightly
00389     // different problem: in a cylindrical mapping, points at the pole
00390     // do not map to any point on the texture, while in a spherical
00391     // mapping, points at the pole map to the top or bottom edge of
00392     // the texture.  But this is a technicality that doesn't really
00393     // apply to us.)  We still solve it the same way: if our point is
00394     // at or near the pole, compute the angle based on the centroid of
00395     // the polygon (which we assume is further from the pole).
00396     xz.set(centroid[0], centroid[2]);
00397   }
00398 
00399   // And cylinders do still have a seam at the back.
00400   double u = rad_2_deg(atan2(xz[0], xz[1])) / _u_angle;
00401   double c = rad_2_deg(atan2(centroid[0], centroid[2])) / _u_angle;
00402 
00403   if (u - c > 0.5) {
00404     u -= floor(u - c + 0.5);
00405   } else if (u - c < -0.5) {
00406     u += floor(c - u + 0.5);
00407   }
00408 
00409   // For a cylindrical mapping, the V value comes directly from Y.
00410   // Easy.
00411   LPoint2d uv(u - 0.5, pos[1]);
00412 
00413   nassertr(fabs(u - c) <= 0.5, uv);
00414   return uv;
00415 }

Generated on Fri May 2 03:21:19 2003 for Panda-Tool by doxygen1.3