VR Group Project 1
Ashley Triplett
Celambarasan Ramasamy
Zachariah Inks
Ennis - Brown House
We chose the Ennis-Brown house for our VR project because of its unique geometric shapes and historical media significance.
We created the interior space of the house directly from the blueprints of Frank Lloyd Wright.
The Ennis-Brown house was designed by Frank Lloyd Wright and built near Los Angeles CA in 1924.
It is built from custom concrete blocks in a style similar to Mayan temples.
Most notably it has been used for such movies as:
House on Haunted Hill
Day of the Locust
Blade Runner

Ennis-Brown House Floor plans and Elevations



Custom block use in the house

Interior shots of the house


Screen shots from the VR environment.



Additionally Celu created a custom Maya exporter and parser rather than using a .obj format
/* Maya Exporter Plugin for Custom File format .celu */
/* Date 10/25/07 */
#include <maya/MIOStream.h>
#include <maya/MSimple.h>
#include <maya/MFileIO.h>
#include <maya/MFileObject.h>
#include <maya/MObject.h>
#include <maya/MStatus.h>
#include <maya/MString.h>
#include <maya/MPxFileTranslator.h>
#include <maya/MFnMesh.h>
#include <maya/MItDag.h>
#include <maya/MGlobal.h>
#include <maya/MFloatPointArray.h>
#include <maya/MPointArray.h>
#include <maya/MDagPathArray.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MStringArray.h>
#include <maya/MFnPlugin.h>
#include <maya/MSelectionList.h>
#include <maya/MItSelectionList.h>
#include <vector>
#include <fstream>
// The plugin must export two functions namley initialize and uninitialize plugin
# define MLL_EXPORT __declspec(dllexport)
void ProcessMesh(MFnMesh& tMeshFunctionSet,MObject& tMeshMObject,std::ofstream& tOutputFileStream,unsigned int& tInstanceCountForCurrentMesh, MStatus * tErrorObject = 0)
{
char tTempString[100];
// Output the name of the Mesh
tOutputFileStream << "m," << tMeshFunctionSet.name().asChar() << ",";
// Get all the Dag Paths associated with this mesh node(and hence the number of mesh instances)
tInstanceCountForCurrentMesh=tMeshFunctionSet.parentCount();
// If instance count is zero, then return failure and quit
if(tInstanceCountForCurrentMesh==0)
{
*tErrorObject=MS::kFailure;
MGlobal::displayError("Instance Count for current mesh is zero,reading scene data failed");
}
// If instance count is greater than one get all the dag paths for the current mesh
MDagPathArray tDagPathsForTheCurrentMesh;
tMeshFunctionSet.getAllPaths(tDagPathsForTheCurrentMesh);
// For each DAG path(instance) get the vertex positions in world space
for(unsigned int i=0; i < tInstanceCountForCurrentMesh; i++)
{
// Write the instance count
sprintf_s(tTempString, "instance,%d,",(i+1));
tOutputFileStream << tTempString;
MFloatPointArray tMeshVertexPointsArray;
MFloatVectorArray tNormalArray;
MStringArray tUVSetsNameArray;
// Attach the MFnMesh function set to the DAGPath objects
MFnMesh tMeshCurrentDAGFunctionSet(tDagPathsForTheCurrentMesh[i],tErrorObject);
// Standard error checking
if(*tErrorObject != MS::kSuccess)
{
MGlobal::displayError("Error Assigning Dag Path to MeshFunctionSet in current mesh");
return;
}
// Get the vertex positions from the mesh
tMeshCurrentDAGFunctionSet.getPoints(tMeshVertexPointsArray,MSpace::kWorld);
tMeshCurrentDAGFunctionSet.getNormals(tNormalArray,MSpace::kWorld);
unsigned int tVertexCount=tMeshVertexPointsArray.length();
unsigned int tNormalCount=tNormalArray.length();
// Output the number of vertices
//cout << " Total Vertex Count " << tVertexCount << endl << endl;
//write the number of vertices to the file
sprintf_s(tTempString, "vertices,%d,",tVertexCount);
tOutputFileStream << tTempString;
// Itreate throught the array and print all the points
for(unsigned int i=0;i<tVertexCount;i++)
{
//cout << tMeshVertexPointsArray[i].x << " " << tMeshVertexPointsArray[i].y << " " << tMeshVertexPointsArray[i].z << endl;
sprintf_s(tTempString, "v,%e,%e,%e,",tMeshVertexPointsArray[i].x,tMeshVertexPointsArray[i].y,tMeshVertexPointsArray[i].z);
tOutputFileStream << tTempString;
}
//write the number of vertices to the file
sprintf_s(tTempString, "normals,%d,",tNormalCount);
tOutputFileStream << tTempString;
// Output the worldspace normals
for(unsigned int i=0;i < tNormalCount;i++)
{
//cout << tNormalArray[i].x << " " << tNormalArray[i].y << " " << tNormalArray[i].z << endl;
sprintf_s(tTempString, "n,%e,%e,%e,",tNormalArray[i].x,tNormalArray[i].y,tNormalArray[i].z);
tOutputFileStream << tTempString;
}
// Get the names of the UV sets attached to this mesh object
tMeshFunctionSet.getUVSetNames(tUVSetsNameArray);
unsigned int tNumberOfUVSets=tUVSetsNameArray.length();
// A flag to indicate later whether index into the UV array needs to be added in the face data
bool tDoesTextureCoordinateExist=true;
// Check for the case where the mesh has no UV sets attached to it
if((!tNumberOfUVSets) || (!tMeshFunctionSet.numUVs(tUVSetsNameArray[0])))
{
//cout<< "No Texture Data Available";
// No UV set is attached to this object, indicate UV set count as zero
tOutputFileStream << "uvsetcount,0,";
// Dont add index into the UV array for the polygon data
tDoesTextureCoordinateExist=false;
}
else
{
// If texture co-ordinates are available then write them to file
sprintf_s(tTempString, "uvsetcount,%d,",tNumberOfUVSets);
tOutputFileStream << tTempString;
//cout << " Number Of Texture Co-ordinate Sets : " << tNumberOfUVSets << endl;
// For each UV set display the texture co-ordinate for the individual vertices
for(unsigned int i=0;i<tNumberOfUVSets;i++)
{
// write the name of the UVSet to the file
tOutputFileStream << tUVSetsNameArray[i].asChar() << ",";
//cout << tUVSetsNameArray[i].asChar() << endl;
MFloatArray tUCoordinates,tVCoordinates;
tMeshFunctionSet.getUVs(tUCoordinates,tVCoordinates,&tUVSetsNameArray[i]);
// Get the number of texture co-ordinate values in this given set
unsigned int tTextureCoordinateValuesCount=tMeshFunctionSet.numUVs(tUVSetsNameArray[i]);
// Write the number of texture co-ordinate values in this given set to the file
sprintf_s(tTempString, "%d,",tTextureCoordinateValuesCount);
tOutputFileStream << tTempString;
// Loop through and write all the UV coordinates in the current set
for(unsigned int i=0;i<tTextureCoordinateValuesCount;i++)
{
sprintf_s(tTempString, "%e,%e,",tUCoordinates[i],tVCoordinates[i]);
tOutputFileStream << tTempString;
//cout << tUCoordinates[i] << " " << tVCoordinates[i] << endl;
}
}
}
// Get the index for each vertex
// Add a polygon itreator to the mesh object
MItMeshPolygon tCurrentMeshPolygonItreator(tMeshMObject,tErrorObject);
// Standard error checking
if(*tErrorObject != MS::kSuccess)
{
MGlobal::displayError("Error Creating Polygon Itreator for current mesh object");
return;
}
unsigned int tFaceCount=0;
// Loop through and count the number of polygons in the mesh
while(!tCurrentMeshPolygonItreator.isDone())
{
tFaceCount++;
tCurrentMeshPolygonItreator.next();
}
// Reset the face itreator to the first polygon
tCurrentMeshPolygonItreator.reset();
// Write the face count for the current mesh
sprintf_s(tTempString, "facecount,%d,",tFaceCount);
tOutputFileStream << tTempString;
// Loop until all the polygons are done
while(!tCurrentMeshPolygonItreator.isDone())
{
unsigned int tVertexCountForTheCurrentPolygon=tCurrentMeshPolygonItreator.polygonVertexCount();
// Write out the vertex count for the current polygon
sprintf_s(tTempString, "f,%d,",tVertexCountForTheCurrentPolygon);
tOutputFileStream << tTempString;
// Write out vi to indicate the start of vertex index count
tOutputFileStream << "vi,";
// Write out the index into the vertex array
for(unsigned int i=0;i<tVertexCountForTheCurrentPolygon;i++)
{
sprintf_s(tTempString, "%d,",tCurrentMeshPolygonItreator.vertexIndex(i));
tOutputFileStream << tTempString;
//cout << tCurrentMeshPolygonItreator.vertexIndex(i) << " ";
}
// Write out ni to indicate the start of vertex index count
tOutputFileStream << "ni,";
// Write out the index into the normal array
for(unsigned int i=0;i<tVertexCountForTheCurrentPolygon;i++)
{
sprintf_s(tTempString, "%d,",tCurrentMeshPolygonItreator.normalIndex(i));
tOutputFileStream << tTempString;
//cout << tCurrentMeshPolygonItreator.vertexIndex(i) << " ";
}
// Write out the index into the UV array for each vertex of this face, only if texturing info exists for this polygonal face
if(tDoesTextureCoordinateExist)
{
// For each UV set, write out the index into the corresponding UV array for each vertex of the polygonal face
for(unsigned int j=0;j<tNumberOfUVSets;j++)
{
// write out the count that identifies a UV set
sprintf_s(tTempString, "uvi,%d,",j+1);
tOutputFileStream << tTempString;
int tIndexIntoUVArray;
// Write out the index into the UV array
for(unsigned int i=0;i<tVertexCountForTheCurrentPolygon;i++)
{
// Check for error while retreiving UV index
if(tCurrentMeshPolygonItreator.getUVIndex(i,tIndexIntoUVArray,&tUVSetsNameArray[j]) != MS::kSuccess)
{
MGlobal::displayError("Error Retreiving UV index for Polygonal Face");
return;
}
sprintf_s(tTempString, "%d,",tIndexIntoUVArray);
tOutputFileStream << tTempString;
//cout << tCurrentMeshPolygonItreator.vertexIndex(i) << " ";
}
}
}
//cout << endl;
tCurrentMeshPolygonItreator.next();
}
}
// This mesh has been read sucessfully
*tErrorObject = MS::kSuccess;
}
//
MStatus ExportCommand( MString tFileName)
{
// Keeps track of the number of mesh objects and their instances
std::vector<int> tMeshAndInstanceCount;
// Take the input argument and create a .celu Data File
MString tDataFileName=tFileName+"_data.celu";
MString tHeaderFileName=tFileName+"_header.celu";
// Create a file output stream for outputting the scene data
std::ofstream tOutputDataFileStream (tDataFileName.asChar(),std::ios::out | std::ios::binary);
// Create another file output stream for outputting the scene data header file
std::ofstream tOutputHeaderFileStream (tHeaderFileName.asChar(),std::ios::out | std::ios::binary);
MStatus tErrorObject;
// Create an Dag Node Itreator and itreate through all the meshes in the scene
MItDag tItreator(MItDag::kDepthFirst,MFn::kMesh,&tErrorObject);
// Standard error checking
if(tErrorObject != MS::kSuccess)
{
MGlobal::displayError("Error Creating Dag Itreator");
tOutputDataFileStream.close();
tOutputHeaderFileStream.close();
return tErrorObject;
}
// Loop through all the meshes that are not intermediate objects
while(!tItreator.isDone())
{
// Attach the function set to the object
MFnMesh tMeshFunctionSet(tItreator.item(),&tErrorObject);
// Standard error checking
if(tErrorObject != MS::kSuccess)
{
MGlobal::displayError("Error attaching Mesh function set to DAG node");
tOutputDataFileStream.close();
tOutputHeaderFileStream.close();
return tErrorObject;
}
// We are only interested in non history Items
if(!tMeshFunctionSet.isIntermediateObject())
{
unsigned int tInstanceCountForCurrentMesh=1;
// Process this non history mesh Object
ProcessMesh(tMeshFunctionSet,tItreator.item(),tOutputDataFileStream,tInstanceCountForCurrentMesh,&tErrorObject);
// Standard Error Checking
if(tErrorObject != MS::kSuccess)
{
MGlobal::displayError("Error writing Mesh Data To File");
tOutputDataFileStream.close();
tOutputHeaderFileStream.close();
return tErrorObject;
}
// Update the instance count for the current mesh
tMeshAndInstanceCount.push_back(tInstanceCountForCurrentMesh);
}
tItreator.next();
}
char tTempString[100];
// Write out the scene data header file
sprintf_s(tTempString, "mesh,%d,",(int)tMeshAndInstanceCount.size());
tOutputHeaderFileStream << tTempString;
// Write out the number of instances of each mesh
for(unsigned int i=0;i < tMeshAndInstanceCount.size();i++)
{
sprintf_s(tTempString, "%d,",tMeshAndInstanceCount[i]);
tOutputHeaderFileStream << tTempString;
}
// Close the file after writing
tOutputDataFileStream.close();
tOutputHeaderFileStream.close();
return MS::kSuccess;
}
// CeluMayaExporter is the maya class that contains the functionality of the file exporter...it should derive from the maya's MPxFileTranslator class
class CeluMayaExporter : public MPxFileTranslator
{
public:
// Default Constructor
CeluMayaExporter():MPxFileTranslator()
{}
// Destructor
~CeluMayaExporter()
{}
// Writer method that must be overloaded to implement the export function
MStatus writer(const MFileObject &file,const MString& tOptions,FileAccessMode mode)
{
MStatus tErrorObject;
// Export selection mode not supported yet
if(mode == kExportActiveAccessMode)
{
cout << "Export selection not implemented yet..exporting the entire scene" << endl;
}
// Get the name for the new file to be created and create the file
tErrorObject=ExportCommand(file.name());
if(tErrorObject!=MS::kSuccess)
{
cout << "Error Exporting Scene";
}
return tErrorObject;
}
MStatus reader( const MFileObject& file,const MString& optionsString,FileAccessMode mode)
{
MStatus tDummyObject;
return tDummyObject;
}
// Identifies if the writer function has been exported
bool haveWriteMethod() const
{
return true;
}
// Returns the default file format extension for this translator
MString defaultExtension() const
{
return "celu";
}
// Used by maya to create a new instance of our exporter
static void *creator()
{
return new CeluMayaExporter();
}
};
// The initialize function is called initially when the plugin is loaded,the registration of the plugin takes place here
MLL_EXPORT MStatus initializePlugin(MObject tObject)
{
MStatus tErrorObject;
// Attach a plugin funtion set to the received maya object
MFnPlugin tPlugin(tObject,"Celu","1.0","Any",&tErrorObject);
// Standard error checking
if(tErrorObject != MS::kSuccess)
{
printf(" Error attaching MFnPlugin function to the MObject in the plugin initialization function ");
return tErrorObject;
}
tErrorObject=tPlugin.registerFileTranslator("Celu Exporter For Maya","none",CeluMayaExporter::creator);
// Standard error checking
if(tErrorObject != MS::kSuccess)
{
printf(" Error registering the file translator plugin in the initialization method");
return tErrorObject;
}
return tErrorObject;
}
// The second function is the uninitialize function that is called when the plugin is unloaded
MLL_EXPORT MStatus uninitializePlugin(MObject tObject)
{
MStatus tErrorObject;
// Attach a plugin funtion set to the received maya object
MFnPlugin tPlugin(tObject,"Celu","1.0","Any",&tErrorObject);
// Standard error checking
if(tErrorObject != MS::kSuccess)
{
printf(" Error attaching MFnPlugin function to the MObject in the plugin uninitialization function ");
return tErrorObject;
}
// Deregister the file translator plugin with maya
tErrorObject=tPlugin.deregisterFileTranslator("Celu Exporter For Maya");
// Standard error checking
if(tErrorObject != MS::kSuccess)
{
printf(" Error deregistering the file translator plugin in the uninitialization method");
return tErrorObject;
}
return tErrorObject;
}