From 81006f1eb4653c7f4431d495ce1feab82e81f190 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 4 Mar 2003 03:45:15 +0000 Subject: [PATCH] support projected textures --- pandatool/src/maya/mayaApi.cxx | 8 ++ pandatool/src/maya/mayaShader.cxx | 103 ++++++++++++++++++- pandatool/src/maya/mayaShader.h | 17 +++ pandatool/src/maya/maya_funcs.cxx | 61 +++++++++++ pandatool/src/maya/maya_funcs.h | 7 ++ pandatool/src/mayaegg/mayaToEggConverter.cxx | 45 +++++--- pandatool/src/mayaprogs/mayaToEgg.cxx | 8 ++ pandatool/src/progbase/withOutputFile.cxx | 3 +- 8 files changed, 230 insertions(+), 22 deletions(-) diff --git a/pandatool/src/maya/mayaApi.cxx b/pandatool/src/maya/mayaApi.cxx index 5fdce8bc22..31b17c66db 100644 --- a/pandatool/src/maya/mayaApi.cxx +++ b/pandatool/src/maya/mayaApi.cxx @@ -43,6 +43,9 @@ MayaApi:: MayaApi(const string &program_name) { // Beginning with Maya4.5, the call to initialize seems to change // the current directory! Yikes! + + // Furthermore, the current directory may change during the call to + // any Maya function! Egad! Filename cwd = ExecutionEnvironment::get_cwd(); MStatus stat = MLibrary::initialize((char *)program_name.c_str()); @@ -52,6 +55,11 @@ MayaApi(const string &program_name) { maya_cat.warning() << "Unable to restore current directory to " << cwd << " after initializing Maya.\n"; + } else { + if (maya_cat.is_debug()) { + maya_cat.debug() + << "Restored current directory to " << cwd << "\n"; + } } if (!stat) { diff --git a/pandatool/src/maya/mayaShader.cxx b/pandatool/src/maya/mayaShader.cxx index bf4986cc3f..fad88f2b37 100644 --- a/pandatool/src/maya/mayaShader.cxx +++ b/pandatool/src/maya/mayaShader.cxx @@ -19,6 +19,7 @@ #include "mayaShader.h" #include "maya_funcs.h" #include "config_maya.h" +#include "string_utils.h" #include "pset.h" #include "pre_maya_include.h" @@ -43,6 +44,7 @@ MayaShader(MObject engine) { _transparency = 0.0; _has_texture = false; + _projection_type = PT_off; _coverage.set(1.0, 1.0); _translate_frame.set(0.0, 0.0); @@ -114,6 +116,38 @@ compute_texture_matrix() const { LMatrix3d::translate_mat(trans); } +//////////////////////////////////////////////////////////////////// +// Function: MayaShader::has_projection +// Access: Public +// Description: Returns true if the shader has a projection in effect. +//////////////////////////////////////////////////////////////////// +bool MayaShader:: +has_projection() const { + return (_projection_type != PT_off); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaShader::project_uv +// Access: Public +// Description: If the shader has a projection (has_projection() +// returns true), this computes the appropriate UV +// corresponding to the indicated 3-d point. +//////////////////////////////////////////////////////////////////// +TexCoordd MayaShader:: +project_uv(const LPoint3d &point) const { + switch (_projection_type) { + case PT_planar: + { + LPoint3d p2d = point * _projection_matrix; + return TexCoordd(p2d[0], p2d[1]); + //return TexCoordd((p2d[0] + 1.0) / 2.0, (p2d[1] + 1.0) / 2.0); + } + + default: + return TexCoordd(0.0, 0.0); + } +} + //////////////////////////////////////////////////////////////////// // Function: MayaShader::output // Access: Public @@ -168,7 +202,7 @@ reset_maya_texture(const Filename &texture) { //////////////////////////////////////////////////////////////////// // Function: MayaShader::read_surface_shader -// Access: Public +// Access: Private // Description: Extracts out the shading information from the Maya // surface shader. //////////////////////////////////////////////////////////////////// @@ -196,6 +230,19 @@ read_surface_shader(MObject shader) { } } + // Or maybe a connection to outColor. Not sure how this differs + // from just color, but empirically it seems that either might be + // used. + MPlug out_color_plug = shader_fn.findPlug("outColor"); + if (!out_color_plug.isNull()) { + MPlugArray color_pa; + out_color_plug.connectedTo(color_pa, true, false); + + for (size_t i = 0; i < color_pa.length(); i++) { + read_surface_color(color_pa[0].node()); + } + } + // Also try to get the ordinary color directly from the surface // shader. if (shader.hasFn(MFn::kLambert)) { @@ -218,16 +265,15 @@ read_surface_shader(MObject shader) { //////////////////////////////////////////////////////////////////// // Function: MayaShader::read_surface_color -// Access: Public +// Access: Private // Description: Determines the surface color specified by the shader. // This includes texturing and other advanced shader // properties. //////////////////////////////////////////////////////////////////// void MayaShader:: read_surface_color(MObject color) { - _color_object = new MObject(color); - if (color.hasFn(MFn::kFileTexture)) { + _color_object = new MObject(color); string filename; _has_texture = get_string_attribute(color, "fileTextureName", filename); if (_has_texture) { @@ -247,6 +293,29 @@ read_surface_color(MObject color) { get_vec2f_attribute(color, "offset", _offset); get_angle_attribute(color, "rotateUV", _rotate_uv); + } else if (color.hasFn(MFn::kProjection)) { + // This is a projected texture. We will have to step one level + // deeper to find the actual texture. + MFnDependencyNode projection_fn(color); + MPlug image_plug = projection_fn.findPlug("image"); + if (!image_plug.isNull()) { + MPlugArray image_pa; + image_plug.connectedTo(image_pa, true, false); + + for (size_t i = 0; i < image_pa.length(); i++) { + read_surface_color(image_pa[0].node()); + } + } + + if (!get_mat4d_attribute(color, "placementMatrix", _projection_matrix)) { + _projection_matrix = LMatrix4d::ident_mat(); + } + + string type; + if (get_enum_attribute(color, "projType", type)) { + set_projection_type(type); + } + } else { // This shader wasn't understood. if (maya_cat.is_debug()) { @@ -266,3 +335,29 @@ read_surface_color(MObject color) { } } } + +//////////////////////////////////////////////////////////////////// +// Function: MayaShader::set_projection_type +// Access: Private +// Description: Sets up the shader to apply UV's according to the +// indicated projection type. +//////////////////////////////////////////////////////////////////// +void MayaShader:: +set_projection_type(const string &type) { + if (cmp_nocase(type, "planar") == 0) { + _projection_type = PT_planar; + + // The Planar projection normally projects to a range (-1, 1) in + // both axes. Scale this into our UV range of (0, 1). + _projection_matrix = _projection_matrix * LMatrix4d(0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.0, 1.0); + + } else { + // Other projection types are currently unimplemented by the + // converter. + maya_cat.error() + << "Don't know how to handle type " << type << " projections.\n"; + } +} diff --git a/pandatool/src/maya/mayaShader.h b/pandatool/src/maya/mayaShader.h index 57410bd0aa..96a5cc190f 100644 --- a/pandatool/src/maya/mayaShader.h +++ b/pandatool/src/maya/mayaShader.h @@ -40,6 +40,8 @@ public: ~MayaShader(); LMatrix3d compute_texture_matrix() const; + bool has_projection() const; + TexCoordd project_uv(const LPoint3d &point) const; void output(ostream &out) const; bool reset_maya_texture(const Filename &texture); @@ -53,6 +55,20 @@ public: bool _has_texture; Filename _texture; + enum ProjectionType { + PT_off, + PT_planar, + PT_spherical, + PT_cylindrical, + PT_ball, + PT_cubic, + PT_triplanar, + PT_concentric, + PT_perspective, + }; + ProjectionType _projection_type; + LMatrix4d _projection_matrix; + LVector2f _coverage; LVector2f _translate_frame; double _rotate_frame; @@ -71,6 +87,7 @@ private: bool read_surface_shader(MObject shader); void read_surface_color(MObject color); + void set_projection_type(const string &type); }; INLINE ostream &operator << (ostream &out, const MayaShader &shader) { diff --git a/pandatool/src/maya/maya_funcs.cxx b/pandatool/src/maya/maya_funcs.cxx index a1cf5a8299..54ab073a42 100644 --- a/pandatool/src/maya/maya_funcs.cxx +++ b/pandatool/src/maya/maya_funcs.cxx @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include "post_maya_include.h" //////////////////////////////////////////////////////////////////// @@ -66,6 +68,29 @@ get_maya_plug(MObject &node, const string &attribute_name, MPlug &plug) { return true; } +//////////////////////////////////////////////////////////////////// +// Function: has_attribute +// Description: Returns true if the node has the indicated attribute, +// false otherwise. +//////////////////////////////////////////////////////////////////// +bool +has_attribute(MObject &node, const string &attribute_name) { + MStatus status; + MFnDependencyNode node_fn(node, &status); + if (!status) { + maya_cat.error() + << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n"; + return false; + } + + node_fn.attribute(attribute_name.c_str(), &status); + if (!status) { + // No such attribute. + return false; + } + return true; +} + //////////////////////////////////////////////////////////////////// // Function: get_bool_attribute // Description: Extracts the named boolean attribute from the @@ -74,6 +99,12 @@ get_maya_plug(MObject &node, const string &attribute_name, MPlug &plug) { bool get_bool_attribute(MObject &node, const string &attribute_name, bool &value) { + if (!has_attribute(node, attribute_name)) { + // For bool attributes only, we assume if the attribute is absent + // it's the same thing as being false. + return false; + } + if (!get_maya_attribute(node, attribute_name, value)) { maya_cat.error() << "Attribute " << attribute_name @@ -178,6 +209,36 @@ get_vec2d_attribute(MObject &node, const string &attribute_name, return true; } +//////////////////////////////////////////////////////////////////// +// Function: get_mat4d_attribute +// Description: Extracts the named 4x4 matrix from the MObject. +//////////////////////////////////////////////////////////////////// +bool +get_mat4d_attribute(MObject &node, const string &attribute_name, + LMatrix4d &value) { + MStatus status; + MObject matrix; + if (!get_maya_attribute(node, attribute_name, matrix)) { + return false; + } + + MFnMatrixData matrix_data(matrix, &status); + if (!status) { + maya_cat.error() + << "Attribute " << attribute_name << " is of type " + << node.apiTypeStr() << ", not a Matrix.\n"; + return false; + } + + const MMatrix &mat = matrix_data.matrix(); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + value(i, j) = mat(i, j); + } + } + return true; +} + //////////////////////////////////////////////////////////////////// // Function: get_enum_attribute // Description: Extracts the enum attribute from the MObject as a diff --git a/pandatool/src/maya/maya_funcs.h b/pandatool/src/maya/maya_funcs.h index ce430219c3..12a9014d7e 100644 --- a/pandatool/src/maya/maya_funcs.h +++ b/pandatool/src/maya/maya_funcs.h @@ -48,6 +48,9 @@ bool set_maya_attribute(MObject &node, const string &attribute_name, ValueType &value); +bool +has_attribute(MObject &node, const string &attribute_name); + bool get_bool_attribute(MObject &node, const string &attribute_name, bool &value); @@ -64,6 +67,10 @@ bool get_vec2d_attribute(MObject &node, const string &attribute_name, LVecBase2d &value); +bool +get_mat4d_attribute(MObject &node, const string &attribute_name, + LMatrix4d &value); + bool get_enum_attribute(MObject &node, const string &attribute_name, string &value); diff --git a/pandatool/src/mayaegg/mayaToEggConverter.cxx b/pandatool/src/mayaegg/mayaToEggConverter.cxx index 7cf4c2bdf2..19969dfbbd 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.cxx +++ b/pandatool/src/mayaegg/mayaToEggConverter.cxx @@ -1209,12 +1209,29 @@ make_polyset(const MDagPath &dag_path, const MFnMesh &mesh, egg_poly->set_bface_flag(double_sided); + // Determine the shader for this particular polygon. + MayaShader *shader = NULL; + int index = pi.index(); + nassertv(index >= 0 && index < (int)poly_shader_indices.length()); + int shader_index = poly_shader_indices[index]; + if (shader_index != -1) { + nassertv(shader_index >= 0 && shader_index < (int)shaders.length()); + MObject engine = shaders[shader_index]; + shader = + _shaders.find_shader_for_shading_engine(engine); + + } else if (default_shader != (MayaShader *)NULL) { + shader = default_shader; + } + + // Get the vertices for the polygon. long num_verts = pi.polygonVertexCount(); for (long i = 0; i < num_verts; i++) { EggVertex vert; MPoint p = pi.point(i, MSpace::kWorld); - vert.set_pos(LPoint3d(p[0], p[1], p[2])); + LPoint3d p3d(p[0], p[1], p[2]); + vert.set_pos(p3d); MVector n; status = pi.getNormal(i, n, MSpace::kWorld); @@ -1224,7 +1241,13 @@ make_polyset(const MDagPath &dag_path, const MFnMesh &mesh, vert.set_normal(LVector3d(n[0], n[1], n[2])); } - if (pi.hasUVs()) { + if (shader->has_projection()) { + // If the shader has a projection, use it instead of the + // polygon's built-in UV's. + vert.set_uv(shader->project_uv(p3d)); + + } else if (pi.hasUVs()) { + // Get the UV's from the polygon. float2 uvs; status = pi.getUV(i, uvs); if (!status) { @@ -1249,21 +1272,9 @@ make_polyset(const MDagPath &dag_path, const MFnMesh &mesh, egg_poly->add_vertex(vpool->create_unique_vertex(vert)); } - // Determine the shader for this particular polygon. - int index = pi.index(); - nassertv(index >= 0 && index < (int)poly_shader_indices.length()); - int shader_index = poly_shader_indices[index]; - if (shader_index != -1) { - nassertv(shader_index >= 0 && shader_index < (int)shaders.length()); - MObject engine = shaders[shader_index]; - MayaShader *shader = - _shaders.find_shader_for_shading_engine(engine); - if (shader != (MayaShader *)NULL) { - set_shader_attributes(*egg_poly, *shader); - } - - } else if (default_shader != (MayaShader *)NULL) { - set_shader_attributes(*egg_poly, *default_shader); + // Now apply the shader. + if (shader != (MayaShader *)NULL) { + set_shader_attributes(*egg_poly, *shader); } pi.next(); diff --git a/pandatool/src/mayaprogs/mayaToEgg.cxx b/pandatool/src/mayaprogs/mayaToEgg.cxx index 4e400d9133..08774d1054 100644 --- a/pandatool/src/mayaprogs/mayaToEgg.cxx +++ b/pandatool/src/mayaprogs/mayaToEgg.cxx @@ -19,6 +19,7 @@ #include "mayaToEgg.h" #include "mayaToEggConverter.h" #include "config_mayaegg.h" +#include "config_maya.h" // for maya_cat //////////////////////////////////////////////////////////////////// // Function: MayaToEgg::Constructor @@ -78,13 +79,20 @@ void MayaToEgg:: run() { // Set the verbose level by using Notify. if (_verbose >= 3) { + maya_cat->set_severity(NS_spam); mayaegg_cat->set_severity(NS_spam); } else if (_verbose >= 2) { + maya_cat->set_severity(NS_debug); mayaegg_cat->set_severity(NS_debug); } else if (_verbose >= 1) { + maya_cat->set_severity(NS_info); mayaegg_cat->set_severity(NS_info); } + // Let's open the output file before we initialize Maya, since Maya + // now has a nasty habit of changing the current directory. + get_output(); + nout << "Initializing Maya.\n"; MayaToEggConverter converter(_program_name); if (!converter.open_api()) { diff --git a/pandatool/src/progbase/withOutputFile.cxx b/pandatool/src/progbase/withOutputFile.cxx index 93589f81d2..56535d33b0 100644 --- a/pandatool/src/progbase/withOutputFile.cxx +++ b/pandatool/src/progbase/withOutputFile.cxx @@ -17,8 +17,9 @@ //////////////////////////////////////////////////////////////////// #include "withOutputFile.h" +#include "executionEnvironment.h" -#include +#include "notify.h" //////////////////////////////////////////////////////////////////// // Function: WithOutputFile::Constructor