~popey/+junk/usd

« back to all changes in this revision

Viewing changes to USD/third_party/maya/lib/usdMaya/MayaNurbsSurfaceWriter.cpp

  • Committer: Alan Pope
  • Date: 2016-09-29 12:05:28 UTC
  • Revision ID: alan@popey.com-20160929120528-32j3uk1x0dgaorip
Initial attempt to snap

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// Copyright 2016 Pixar
 
3
//
 
4
// Licensed under the Apache License, Version 2.0 (the "Apache License")
 
5
// with the following modification; you may not use this file except in
 
6
// compliance with the Apache License and the following modification to it:
 
7
// Section 6. Trademarks. is deleted and replaced with:
 
8
//
 
9
// 6. Trademarks. This License does not grant permission to use the trade
 
10
//    names, trademarks, service marks, or product names of the Licensor
 
11
//    and its affiliates, except as required to comply with Section 4(c) of
 
12
//    the License and to reproduce the content of the NOTICE file.
 
13
//
 
14
// You may obtain a copy of the Apache License at
 
15
//
 
16
//     http://www.apache.org/licenses/LICENSE-2.0
 
17
//
 
18
// Unless required by applicable law or agreed to in writing, software
 
19
// distributed under the Apache License with the above modification is
 
20
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
21
// KIND, either express or implied. See the Apache License for the specific
 
22
// language governing permissions and limitations under the Apache License.
 
23
//
 
24
 
 
25
#include "usdMaya/MayaNurbsSurfaceWriter.h"
 
26
 
 
27
#include "pxr/usd/usdGeom/nurbsPatch.h"
 
28
#include "pxr/usd/usdGeom/nurbsCurves.h"
 
29
#include "pxr/usd/usdGeom/pointBased.h"
 
30
#include "pxr/usd/usd/stage.h"
 
31
#include "pxr/usd/usdUtils/pipeline.h"
 
32
 
 
33
#include <maya/MFnDependencyNode.h>
 
34
#include <maya/MFnNurbsSurface.h>
 
35
#include <maya/MFnNurbsCurve.h>
 
36
#include <maya/MTrimBoundaryArray.h>
 
37
#include <maya/MPointArray.h>
 
38
 
 
39
MayaNurbsSurfaceWriter::MayaNurbsSurfaceWriter(
 
40
        MDagPath & iDag, 
 
41
        UsdStageRefPtr stage, 
 
42
        const JobExportArgs & iArgs) :
 
43
    MayaTransformWriter(iDag, stage, iArgs)
 
44
{
 
45
}
 
46
 
 
47
//virtual 
 
48
UsdPrim MayaNurbsSurfaceWriter::write(const UsdTimeCode &usdTimeCode)
 
49
{
 
50
    // == Write
 
51
    UsdGeomNurbsPatch primSchema =
 
52
        UsdGeomNurbsPatch::Define(getUsdStage(), getUsdPath());
 
53
    TF_AXIOM(primSchema);
 
54
    UsdPrim prim = primSchema.GetPrim();
 
55
    TF_AXIOM(prim);
 
56
 
 
57
    // Write the attrs
 
58
    writeNurbsSurfaceAttrs(usdTimeCode, primSchema);
 
59
    return prim;
 
60
}
 
61
 
 
62
// virtual
 
63
bool MayaNurbsSurfaceWriter::writeNurbsSurfaceAttrs(
 
64
    const UsdTimeCode &usdTimeCode,
 
65
    UsdGeomNurbsPatch &primSchema)
 
66
{
 
67
    MStatus status = MS::kSuccess;
 
68
 
 
69
    // Write parent class attrs
 
70
    writeTransformAttrs(usdTimeCode, primSchema);
 
71
 
 
72
    // Return if usdTimeCode does not match if shape is animated
 
73
    if (usdTimeCode.IsDefault() == isShapeAnimated() ) {
 
74
        // skip shape as the usdTimeCode does not match if shape isAnimated value
 
75
        return true; 
 
76
    }
 
77
 
 
78
    MFnNurbsSurface nurbs( getDagPath(), &status );
 
79
    if (!status) {
 
80
        MGlobal::displayError(
 
81
            "MFnNurbsSurface() failed for MayaNurbsSurfaceWriter" );
 
82
        return false;
 
83
    }
 
84
    
 
85
    // Gather GPrim DisplayColor/DisplayOpacity
 
86
    // We use the same code used for gathering shader data on a mesh
 
87
    // but we pass 0 for the numfaces argument since there is no per face
 
88
    // shader assignment possible.
 
89
    if (getArgs().exportDisplayColor) {
 
90
        VtArray<GfVec3f> RGBData;
 
91
        TfToken RGBInterp;
 
92
        VtArray<float> AlphaData;
 
93
        TfToken AlphaInterp;
 
94
        if (PxrUsdMayaUtil::GetLinearShaderColor(nurbs, 0,
 
95
                                                &RGBData, &RGBInterp,
 
96
                                                &AlphaData, &AlphaInterp)) {
 
97
            if (RGBData.size()>0) {
 
98
                UsdGeomPrimvar dispColor = primSchema.GetDisplayColorPrimvar();
 
99
                if (RGBInterp != dispColor.GetInterpolation())
 
100
                    dispColor.SetInterpolation(RGBInterp);
 
101
                dispColor.Set(RGBData);
 
102
            }
 
103
            if (AlphaData.size() > 0 && 
 
104
                GfIsClose(AlphaData[0], 1.0, 1e-9)==false) {
 
105
                UsdGeomPrimvar dispOpacity = primSchema.GetDisplayOpacityPrimvar();
 
106
                if (AlphaInterp != dispOpacity.GetInterpolation())
 
107
                    dispOpacity.SetInterpolation(AlphaInterp);
 
108
                dispOpacity.Set(AlphaData);
 
109
            }
 
110
        }
 
111
    }
 
112
 
 
113
    unsigned int numKnotsInU = nurbs.numKnotsInU();
 
114
    unsigned int numKnotsInV = nurbs.numKnotsInV();
 
115
    if (numKnotsInU < 2 || numKnotsInV < 2) {
 
116
        MGlobal::displayError(
 
117
            "MFnNurbsSurface() has degenerate knot vectors. Skippping..." );
 
118
        return false;        
 
119
    }
 
120
 
 
121
    MDoubleArray knotsInU;
 
122
    nurbs.getKnotsInU(knotsInU);
 
123
    MDoubleArray knotsInV;
 
124
    nurbs.getKnotsInV(knotsInV);
 
125
    
 
126
    // determine range
 
127
    double startU, endU, startV, endV;
 
128
    nurbs.getKnotDomain(startU, endU, startV, endV);
 
129
 
 
130
    // Offset and scale to normalize knots from 0 to 1
 
131
    double uOffset=0.0;
 
132
    double vOffset=0.0;
 
133
    double uScale = 1.0;
 
134
    double vScale = 1.0;
 
135
 
 
136
    if (getArgs().normalizeNurbs) {
 
137
        if (endU>startU && endV>startV) {
 
138
            uOffset = startU;
 
139
            vOffset = startV;
 
140
            uScale = 1.0 / (endU - startU);
 
141
            vScale = 1.0 / (endV - startV);
 
142
            startU = 0; startV = 0;
 
143
            endU = 1; endV = 1;
 
144
        }
 
145
    }
 
146
 
 
147
    GfVec2d uRange, vRange;
 
148
    uRange[0]=startU; uRange[1]=endU;
 
149
    vRange[0]=startV; vRange[1]=endV;
 
150
    
 
151
    // pad the start and end with a knot on each side, since thats what
 
152
    // most apps, like Houdini and Renderman want these two extra knots
 
153
    VtArray<double> sampKnotsInU(numKnotsInU+2);
 
154
    VtArray<double> sampKnotsInV(numKnotsInV+2);
 
155
 
 
156
    for (unsigned int i = 0; i < numKnotsInU; i++) {
 
157
        sampKnotsInU[i+1]=(double)((knotsInU[i]-uOffset)*uScale);
 
158
    }
 
159
    
 
160
    for (unsigned int i = 0; i < numKnotsInV; i++) {
 
161
        sampKnotsInV[i+1]=(double)((knotsInV[i]-vOffset)*vScale);
 
162
    }
 
163
 
 
164
    sampKnotsInU[0] = (2.0 * sampKnotsInU[1] - sampKnotsInU[2]);
 
165
    sampKnotsInU[numKnotsInU+1] = (2.0 * sampKnotsInU[numKnotsInU] - 
 
166
                                        sampKnotsInU[numKnotsInU-1]);
 
167
    sampKnotsInV[0] = (2.0 * sampKnotsInV[1] - sampKnotsInV[2]);
 
168
    sampKnotsInV[numKnotsInV+1] = (2.0 * sampKnotsInV[numKnotsInV] - 
 
169
                                        sampKnotsInV[numKnotsInV-1]);
 
170
 
 
171
    MPointArray cvArray;
 
172
    nurbs.getCVs(cvArray, MSpace::kObject);
 
173
    unsigned int numCVs = cvArray.length();
 
174
    int numCVsInU = nurbs.numCVsInU();
 
175
    int numCVsInV = nurbs.numCVsInV();
 
176
 
 
177
    VtArray<GfVec3f> sampPos(numCVs);
 
178
    VtArray<double> sampPosWeights(numCVs);
 
179
    bool setWeights = false;
 
180
 
 
181
    // Create st vec2f vertex primvar
 
182
    // NOTE: We currently support PxUsdExportJobArgsTokens->Uniform
 
183
    // So no need to do a check in its value yet
 
184
    VtArray<GfVec2f> stValues;
 
185
    if (getArgs().exportNurbsExplicitUV) {
 
186
        stValues.resize(numCVsInU*numCVsInV);
 
187
    }
 
188
 
 
189
    // Maya stores the data where v varies the fastest (v,u order)
 
190
    // so we need to pack the data differently u,v order
 
191
    // WE DIFFER FROM ALEMBIC WRITER, WE DON'T FLIP V
 
192
    int cvIndex=0;
 
193
    for (int v = 0; v < numCVsInV; v++) {
 
194
        for (int u = 0; u < numCVsInU; u++) {
 
195
            int index = u * numCVsInV + v;
 
196
            
 
197
            // Extract CV location and weight
 
198
            sampPos[cvIndex].Set(cvArray[index].x, cvArray[index].y, cvArray[index].z);
 
199
            sampPosWeights[cvIndex] = cvArray[index].w;
 
200
            if (GfIsClose(cvArray[index].w, 1.0, 1e-9)==false) {
 
201
                setWeights = true;
 
202
            }
 
203
            
 
204
            // Compute uniform ST values if stValues can hold it
 
205
            // No need to check for nurbsTexCoordParam yet since we only
 
206
            // support uniform in the code
 
207
            if (stValues.size() > static_cast<size_t>(cvIndex)) {
 
208
                float sValue = static_cast<float>(u)/static_cast<float>(numCVsInU-1);
 
209
                float tValue = static_cast<float>(v)/static_cast<float>(numCVsInV-1);
 
210
                stValues[cvIndex] = GfVec2f(sValue, tValue);
 
211
            }
 
212
            
 
213
            cvIndex++;
 
214
        }
 
215
    }
 
216
    
 
217
    // Set Gprim Attributes
 
218
    // Compute the extent using the CVs.
 
219
    VtArray<GfVec3f> extent(2);
 
220
    UsdGeomPointBased::ComputeExtent(sampPos, &extent);
 
221
    primSchema.CreateExtentAttr().Set(extent, usdTimeCode);
 
222
 
 
223
    // Set NurbsPatch attributes
 
224
    primSchema.GetUVertexCountAttr().Set(numCVsInU);
 
225
    primSchema.GetVVertexCountAttr().Set(numCVsInV);
 
226
    primSchema.GetUOrderAttr().Set(nurbs.degreeU() + 1);
 
227
    primSchema.GetVOrderAttr().Set(nurbs.degreeV() + 1);
 
228
    primSchema.GetUKnotsAttr().Set(sampKnotsInU);
 
229
    primSchema.GetVKnotsAttr().Set(sampKnotsInV);
 
230
    primSchema.GetURangeAttr().Set(uRange);
 
231
    primSchema.GetVRangeAttr().Set(vRange);
 
232
    primSchema.GetPointsAttr().Set(sampPos, usdTimeCode);
 
233
    if (setWeights) {
 
234
        primSchema.GetPointWeightsAttr().Set(sampPosWeights);
 
235
    }
 
236
 
 
237
    // If stValues vector has vertex data, create and assign st
 
238
    if (stValues.size() == static_cast<size_t>(numCVsInU * numCVsInV)) {
 
239
        UsdGeomPrimvar uvSet = 
 
240
            primSchema.CreatePrimvar(UsdUtilsGetPrimaryUVSetName(),
 
241
            SdfValueTypeNames->Float2Array, 
 
242
            UsdGeomTokens->vertex);                                                                      
 
243
        uvSet.Set( stValues );
 
244
    }
 
245
 
 
246
    // Set Form
 
247
    switch (nurbs.formInU()) {
 
248
        case MFnNurbsSurface::kClosed:
 
249
            primSchema.GetUFormAttr().Set(UsdGeomTokens->closed);
 
250
        break;
 
251
        case MFnNurbsSurface::kPeriodic:
 
252
            primSchema.GetUFormAttr().Set(UsdGeomTokens->periodic);
 
253
        break;
 
254
        default:
 
255
            primSchema.GetUFormAttr().Set(UsdGeomTokens->open);        
 
256
    }
 
257
    switch (nurbs.formInV()) {
 
258
        case MFnNurbsSurface::kClosed:
 
259
            primSchema.GetVFormAttr().Set(UsdGeomTokens->closed);
 
260
        break;
 
261
        case MFnNurbsSurface::kPeriodic:
 
262
            primSchema.GetVFormAttr().Set(UsdGeomTokens->periodic);
 
263
        break;
 
264
        default:
 
265
            primSchema.GetVFormAttr().Set(UsdGeomTokens->open);        
 
266
    }
 
267
 
 
268
    // If not trimmed surface, you are done
 
269
    // ONLY TRIM CURVE CODE BEYOND THIS POINT
 
270
    if (!nurbs.isTrimmedSurface()) {
 
271
        return true;
 
272
    }
 
273
 
 
274
    unsigned int numRegions = nurbs.numRegions();
 
275
 
 
276
    // each boundary is a curvegroup, it can have multiple trim curve segments
 
277
 
 
278
    // A Maya's trimmed NURBS surface has multiple regions.
 
279
    // Inside a region, there are multiple boundaries.
 
280
    // There are one CCW outer boundary and optional CW inner boundaries.
 
281
    // Each boundary is a closed boundary and consists of multiple curves.
 
282
    // NOTE: Maya regions are flattened but thanks for the curve ordering
 
283
    // we can reconstruct them at read time back into Maya
 
284
    // USD has the same semantic as RenderMan.
 
285
    // RenderMan's doc says: "The curves of a loop connect
 
286
    //   in head-to-tail fashion and must be explicitly closed. "
 
287
 
 
288
    // A Maya boundary is equivalent to an USD/RenderMan loop
 
289
    VtArray<int> trimNumCurves;
 
290
    VtArray<int> trimNumPos;
 
291
    VtArray<int> trimOrder;
 
292
    VtArray<double> trimKnot;
 
293
    VtArray<GfVec2d> trimRange;
 
294
    VtArray<GfVec3d> trimPoint;
 
295
 
 
296
    int numLoops = 0;
 
297
    for (unsigned int i = 0; i < numRegions; i++)
 
298
    {
 
299
        MTrimBoundaryArray result;
 
300
 
 
301
        // if the 3rd argument is set to be true, return the 2D curve
 
302
        nurbs.getTrimBoundaries(result, i, true);
 
303
        unsigned int numBoundaries = result.length();
 
304
                
 
305
        for (unsigned int j = 0; j < numBoundaries; j++)
 
306
        {
 
307
            /*
 
308
            WE DON'T NEED THIS BUT IT'S HERE FOR POSSIBLE FUTURE USE
 
309
            switch(fn.boundaryType(i,j)) {
 
310
                case MFnNurbsSurface::kInner: break;
 
311
                case MFnNurbsSurface::kOuter: break;
 
312
                case MFnNurbsSurface::kSegment: break;
 
313
                case MFnNurbsSurface::kClosedSegment: break;
 
314
                default: break;
 
315
            }
 
316
            */
 
317
            
 
318
            MObjectArray boundary = result[j];
 
319
            unsigned int numTrimCurve = boundary.length();
 
320
            trimNumCurves.push_back(numTrimCurve);
 
321
            numLoops++;
 
322
            for (unsigned int k = 0; k < numTrimCurve; k++)
 
323
            {
 
324
                MObject curveObj = boundary[k];
 
325
                if (curveObj.hasFn(MFn::kNurbsCurve))
 
326
                {
 
327
                    MFnNurbsCurve mFnCurve(curveObj);
 
328
 
 
329
                    int numCVs = mFnCurve.numCVs();
 
330
                    trimNumPos.push_back(numCVs);
 
331
                    trimOrder.push_back(mFnCurve.degree()+1);
 
332
 
 
333
                    double start, end;
 
334
                    mFnCurve.getKnotDomain(start, end);
 
335
                    GfVec2d range;
 
336
                    range[0]=start;
 
337
                    range[1]=end;
 
338
                    trimRange.push_back(range);
 
339
 
 
340
                    MPointArray cvArray;
 
341
                    mFnCurve.getCVs(cvArray);
 
342
                    // WE DIFFER FROM ALEMBIC WRITER, WE DON'T FLIP V
 
343
                    for (int l = 0; l < numCVs; l++)
 
344
                    {
 
345
                        GfVec3d point;                        
 
346
 
 
347
                        point[0]=(double)((cvArray[l].x-uOffset)*uScale);
 
348
                        point[1]=(double)((cvArray[l].y-vOffset)*vScale);
 
349
                        point[2]=cvArray[l].w;
 
350
                        trimPoint.push_back(point);
 
351
                    }
 
352
 
 
353
                    MDoubleArray knot;
 
354
                    mFnCurve.getKnots(knot);
 
355
                    unsigned int numKnots = knot.length();
 
356
 
 
357
                    // push_back a dummy value, we will set it below
 
358
                    std::size_t totalNumKnots = trimKnot.size();
 
359
                    trimKnot.push_back(0.0);
 
360
                    for (unsigned int l = 0; l < numKnots; l++)
 
361
                    {
 
362
                        trimKnot.push_back(knot[l]);
 
363
                    }
 
364
 
 
365
                    // for a knot sequence with multiple end knots, duplicate
 
366
                    // the existing first and last knots once more.
 
367
                    // for a knot sequence with uniform end knots, create their
 
368
                    // the new knots offset at an interval equal to the existing
 
369
                    // first and last knot intervals
 
370
                    double k1 = trimKnot[totalNumKnots+1];
 
371
                    double k2 = trimKnot[totalNumKnots+2];
 
372
                    double klast_1 = trimKnot[trimKnot.size()-1];
 
373
                    double klast_2 = trimKnot[trimKnot.size()-2];
 
374
                    trimKnot[totalNumKnots] = 2.0 * k1 - k2;
 
375
                    trimKnot.push_back(2.0 * klast_1 - klast_2);
 
376
                }
 
377
            } // for k
 
378
        } // for j
 
379
    } // for i
 
380
 
 
381
    primSchema.GetTrimCurveCountsAttr().Set(trimNumCurves);    
 
382
    primSchema.GetTrimCurveOrdersAttr().Set(trimOrder);    
 
383
    primSchema.GetTrimCurveVertexCountsAttr().Set(trimNumPos);    
 
384
    primSchema.GetTrimCurveKnotsAttr().Set(trimKnot);    
 
385
    primSchema.GetTrimCurveRangesAttr().Set(trimRange);    
 
386
    primSchema.GetTrimCurvePointsAttr().Set(trimPoint);    
 
387
 
 
388
    // NO NON TRIM CODE HERE SINCE WE RETURN EARLIER IF NOT TRIMMED
 
389
    return true;
 
390
}
 
391
 
 
392
bool
 
393
MayaNurbsSurfaceWriter::exportsGprims() const
 
394
{
 
395
    return true;
 
396
}
 
397