//- // ========================================================================== // Copyright (C) 1995 - 2005 Alias Systems Corp. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files are provided by Alias // Systems Corp. ("Alias") and/or its licensors for the exclusive use of the // Customer (as defined in the Alias Software License Agreement that // accompanies this Alias software). Such Customer has the right to use, // modify, and incorporate the Data into other products and to distribute such // products for use by end-users. // // THE DATA IS PROVIDED "AS IS". ALIAS HEREBY DISCLAIMS ALL WARRANTIES // RELATING TO THE DATA, INCLUDING, WITHOUT LIMITATION, ANY AND ALL EXPRESS OR // IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL ALIAS BE LIABLE FOR ANY DAMAGES // WHATSOEVER, WHETHER DIRECT, INDIRECT, SPECIAL, OR PUNITIVE, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, OR IN EQUITY, // ARISING OUT OF ACCESS TO, USE OF, OR RELIANCE UPON THE DATA. // ========================================================================== //+ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "blindDataMesh.h" MStatus returnStatus; #define McheckErr(stat,msg) \ if ( MS::kSuccess != stat ) { \ cerr << msg; \ return MS::kFailure; \ } MObject blindDataMesh::seed; MObject blindDataMesh::outputMesh; MTypeId blindDataMesh::id( 0x60EA ); void* blindDataMesh::creator() { return new blindDataMesh; } MStatus blindDataMesh::initialize() { MFnTypedAttribute typedAttr; MStatus returnStatus; blindDataMesh::outputMesh = typedAttr.create( "outputMesh", "out", MFnData::kMesh, &returnStatus ); McheckErr(returnStatus, "ERROR creating blindDataMesh output attribute\n"); typedAttr.setStorable(false); returnStatus = addAttribute(blindDataMesh::outputMesh); McheckErr(returnStatus, "ERROR adding outputMesh attribute\n"); MFnNumericAttribute numAttr; blindDataMesh::seed = numAttr.create( "randomSeed", "seed", MFnNumericData::kLong, 0, &returnStatus ); McheckErr(returnStatus, "ERROR creating blindDataMesh input attribute\n"); returnStatus = addAttribute(blindDataMesh::seed); McheckErr(returnStatus, "ERROR adding input attribute\n"); returnStatus = attributeAffects(blindDataMesh::seed, blindDataMesh::outputMesh); McheckErr(returnStatus, "ERROR in attributeAffects\n"); return MS::kSuccess; } MObject blindDataMesh::createMesh(long seed, MObject& outData, MStatus& stat) { MFloatPointArray vertices; MIntArray faceDegrees; MIntArray faceVertices; int i, j; srand(seed); float planeSize = 20.0f; float planeOffset = planeSize / 2.0f; float planeDim = 0.5f; int numDivisions = (int) (planeSize / planeDim); // int numVertices = (numDivisions + 1) * (numDivisions + 1); // int numEdge = (2 * numDivisions) * (numDivisions + 1); int numFaces = numDivisions * numDivisions; // Set up an array containing the vertex positions for the plane. The // vertices are placed equi-distant on the X-Z plane to form a square // grid that has a side length of "planeSize". // // The Y-coordinate of each vertex is the average of the neighbors already // calculated, if there are any, with a small random offset added. Because // of the way the vertices are calculated, the whole plane will look like // it is streaked in a diagonal direction with mountains and depressions. // for (i = 0; i < (numDivisions + 1); ++i) { for (j = 0; j < (numDivisions + 1); ++j) { float height; if (i == 0 && j == 0) { height = ((rand() % 101) / 100.0f - 0.5f); } else if (i == 0) { float previousHeight = vertices[j - 1][1]; height = previousHeight + ((rand() % 101) / 100.0f - 0.5f); } else if (j == 0) { float previousHeight = vertices[(i-1)*(numDivisions + 1)][1]; height = previousHeight + ((rand() % 101) / 100.0f - 0.5f); } else { float previousHeight = vertices[(i-1)*(numDivisions + 1) + j][1]; float previousHeight2 = vertices[i*(numDivisions + 1) + j - 1][1]; height = (previousHeight + previousHeight2) / 2.0f + ((rand() % 101) / 100.0f - 0.5f); } MFloatPoint vtx( i * planeDim - planeOffset, height, j * planeDim - planeOffset ); vertices.append(vtx); } } // Set up an array containing the number of vertices // for each of the plane's faces // for (i = 0; i < numFaces; ++i) { faceDegrees.append(4); } // Set up an array to assign the vertices for each face // for (i = 0; i < numDivisions; ++i) { for (j = 0; j < numDivisions; ++j) { faceVertices.append(i*(numDivisions+1) + j); faceVertices.append(i*(numDivisions+1) + j + 1); faceVertices.append((i+1)*(numDivisions+1) + j + 1); faceVertices.append((i+1)*(numDivisions+1) + j); } } MFnMesh meshFn; MObject newMesh = meshFn.create(vertices.length(), numFaces, vertices, faceDegrees, faceVertices, outData, &stat); return newMesh; } MStatus blindDataMesh::compute(const MPlug& plug, MDataBlock& data) { MStatus returnStatus; if (plug == outputMesh) { // Get the given random number generator seed. We need to use a // seed, because a pseudo-random number generator will always give // the same random numbers for a constant seed. This means that the // mesh will not change when it is recalculated. // MDataHandle seedHandle = data.inputValue(seed, &returnStatus); McheckErr(returnStatus,"ERROR getting random number generator seed\n"); long seed = seedHandle.asLong(); // Get the handle to the output mesh. The creation of the output mesh // is done in two steps. First, the mesh is created. That involves // calculating the position of the vertices and their connectivity. // // Second, blind data is associated to the vertices on the mesh. // For this example, three double blind data values is associated // to each vertex: "red", "green" and "blue". // MFnMeshData dataCreator; MDataHandle outputHandle = data.outputValue(outputMesh, &returnStatus); McheckErr(returnStatus, "ERROR getting polygon data handle\n"); MObject newOutputData = dataCreator.create(&returnStatus); McheckErr(returnStatus, "ERROR creating outputData"); MObject newMesh = createMesh(seed, newOutputData, returnStatus); McheckErr(returnStatus, "ERROR creating new plane"); returnStatus = setMeshBlindData(newOutputData); McheckErr(returnStatus, "ERROR setting the blind Data on the plane"); outputHandle.set(newOutputData); data.setClean( plug ); } else return MS::kUnknownParameter; return MS::kSuccess; } MStatus blindDataMesh::setMeshBlindData(MObject& mesh) { MStatus stat = MS::kSuccess; MFnMesh meshFn(mesh); // First, make sure that the blind data attribute exists, // Otherwise, create it. // int blindDataID = 60; if (!meshFn.isBlindDataTypeUsed(blindDataID, &stat)) { MStringArray longNames, shortNames, formatNames; longNames.append("red_color"); shortNames.append("red"); formatNames.append("double"); longNames.append("green"); shortNames.append("grn"); formatNames.append("double"); longNames.append("blue_color"); shortNames.append("blue"); formatNames.append("double"); stat = meshFn.createBlindDataType( blindDataID, longNames, shortNames, formatNames ); if (!stat) return stat; } else if (!stat) return stat; // Iterate through the mesh vertices and assign to each some // color value that is related to the height of the vertex // so that it goes from dark blue at the lowest point to // white at the highest.. // // Find the lowest and the highest points. // MItMeshVertex itVertex(mesh); double lowest = 1e10, highest = -1e10; for ( ; !itVertex.isDone(); itVertex.next() ) { MPoint vertexPosition = itVertex.position(); double height = vertexPosition[1]; if (height < lowest) lowest = height; if (height > highest) highest = height; } double range = highest - lowest; for ( itVertex.reset(mesh); !itVertex.isDone(); itVertex.next() ) { MPoint vertexPosition = itVertex.position(); double height = vertexPosition[1] - lowest; double red, green, blue; // Calculate the interpolated color for each vertex // using its relative height // red = 2.0 * ( height / range ) - 1.0; if (height > range/2.0) { if (red < 0.7) green = 0.7; else green = red; } else green = 0.7 * (1.0 - (((range/2.0) - height) / (range/2.0)) * (((range/2.0) - height) / (range/2.0))); if (height > range/2.0) blue = red; else blue = 1.0 - (green*green); if (red < 0.0) red = 0.0; // Set the color values in the blind data // stat = meshFn.setDoubleBlindData(itVertex.index(), MFn::kMeshVertComponent, blindDataID, "red", red); if (!stat) return stat; stat = meshFn.setDoubleBlindData(itVertex.index(), MFn::kMeshVertComponent, blindDataID, "green", green); if (!stat) return stat; stat = meshFn.setDoubleBlindData(itVertex.index(), MFn::kMeshVertComponent, blindDataID, "blue", blue); if (!stat) return stat; } return stat; }