📄 gribparser.cpp
字号:
{ fprintf(stderr, "Not enough arguments to PointsGeneralPolygons, needs at least 6, got %d\n", data.size() - 1); //data.debugPrint( cerr, 3 ); return false; } if ( data.hasOptionalArg( "P" ) ) homogeneous = false; else if ( data.hasOptionalArg( "Pw" ) ) homogeneous = true; else { fprintf(stderr, "Doesn't have points or homogeneous points - skipping\n"); //data.debugPrint( cerr, 3 ); return false; } npolys = data[1].size(); nvertices.reserve( npolys ); vertex_indices.resize( npolys ); uint sum_idx = 0; for ( ipoly = 0; ipoly < npolys; ipoly++ ) { if ( data[1].intVal( ipoly ) != 1 ) { fprintf(stderr, "I only handle polys with a single loop.\n"); //data.debugPrint( cerr, 3 ); return false; } int nvertices_temp = data[2].intVal( ipoly ); nvertices.push_back( nvertices_temp ); vertex_indices[ ipoly ].reserve( nvertices_temp ); for ( uint ivtx = sum_idx; ivtx < sum_idx + nvertices_temp; ivtx++ ) { vertex_indices[ ipoly ].push_back( data[3].intVal( ivtx ) ); } sum_idx += nvertices_temp; } // Get geometry of points const RibData& points_arg = data.findOptionalArg( homogeneous ? "Pw" : "P" ); npoints = points_arg.size(); if ( homogeneous ) npoints /= 4; else npoints /= 3; points = new double[ npoints * 4 ]; if ( homogeneous ) { for ( ipt = 0; ipt < npoints; ipt++ ) { points[ ipt*4 + 0 ] = points_arg.doubleVal( ipt*4 + 0 ); points[ ipt*4 + 1 ] = points_arg.doubleVal( ipt*4 + 1 ); points[ ipt*4 + 2 ] = points_arg.doubleVal( ipt*4 + 2 ); points[ ipt*4 + 3 ] = points_arg.doubleVal( ipt*4 + 3 ); } } else { for ( ipt = 0; ipt < npoints; ipt++ ) { points[ ipt*4 + 0 ] = points_arg.doubleVal( ipt*3 + 0 ); points[ ipt*4 + 1 ] = points_arg.doubleVal( ipt*3 + 1 ); points[ ipt*4 + 2 ] = points_arg.doubleVal( ipt*3 + 2 ); points[ ipt*4 + 3 ] = 1.0; } } // Get normals if ( data.hasOptionalArg( "N" ) ) { const RibData& normals_arg = data.findOptionalArg( "N" ); uint total_size = normals_arg.size(); nnormals = total_size / 3; // 3 components per normal normals = new double[ total_size ]; for ( uint inormal = 0; inormal < total_size; inormal++ ) { normals[ inormal ] = normals_arg.doubleVal( inormal ); } } // Get texture coordinates if ( data.hasOptionalArg( "st" ) ) { const RibData& texcoords_arg = data.findOptionalArg( "st" ); uint total_size = texcoords_arg.size(); ntexcoords = total_size / 2; // 2 components per texture coordinate texcoords = new double[ total_size ]; for ( uint ist = 0; ist < total_size; ist++ ) { texcoords[ ist ] = texcoords_arg.doubleVal( ist ); } } // Transform points double curr_transform[16]; getObjectTransform( curr_transform ); for ( ipt = 0; ipt < npoints; ipt++ ) { double *curr_pt = &points[ ipt*4 ]; matrixMultiplyPoint( curr_pt, curr_transform, curr_pt ); } // There are a couple of different ways of storing a polygonal mesh. // We've implemented a subset of Renderman's pointsGeneralPolygons command. // The basic idea is that you have an array of loops, an array of the number of vertices in each loop, // an array of those vertices, and then the data for the vertices. // The data consists of points, and then optionally normals and texture coordinates. // The index for a given vertex is the same for vertices, points, and texture coordinates, so a single vertex only has one normal // However, they compensate for that by just duplicating data, if needed. // // On to what you'll actually need to do. // // The data you'll need is stored in the following variables: // // npolys: The number of polygons // npoints: The number of points // nnormals: The number of normals // ntexcoords: The number of texture coordinates // nvertices: An array of size npolys. Tells how many vertices each polygon has. // vertex_indices: A 2d array of size [(npolys)][(nvertices[npolys])]. // This keeps track of the indices of the vertices around a polygon // For example, vertex_indices[ 5 ][ 2 ] would be the vertex 2 on polygon 5. // points: An array of doubles, 4 for each point (whether the points were specified homogeneously or not) // normals: An array of doubles, 3 for each point, if normals are provided for this polyMesh. If not, you should compute face normals. // texcoords: An array of doubles, 2 for each point. // homogeneous: A boolean, telling you whether you need to use homogeneous coordinates or not. // You might be able to get some speed out of not dividing out w, especially for large meshes. // In the sample files for the class, none of them are homogeneous, so this is only really for loading other files. // GRayTraceMaterial *material = getMaterial(); GRayTraceTriMesh *mesh = new GRayTraceTriMesh(material, npoints, npolys, nnormals, ntexcoords); // Points GRayTraceVector v; for (ipt = 0; ipt < npoints; ipt++) { v.m_vals[0] = points[ipt * 4]; v.m_vals[1] = points[ipt * 4 + 1]; v.m_vals[2] = points[ipt * 4 + 2]; mesh->SetPoint(ipt, &v); } // Normals for (ipt = 0; ipt < nnormals; ipt++) { v.m_vals[0] = normals[ipt * 3]; v.m_vals[1] = normals[ipt * 3 + 1]; v.m_vals[2] = normals[ipt * 3 + 2]; mesh->SetNormal(ipt, &v); } // Texture coords for (ipt = 0; ipt < ntexcoords; ipt++) mesh->SetTextureCoord(ipt, texcoords[ipt * 2], texcoords[ipt * 2 + 1]); // Triangles for(ipoly = 0; ipoly < npolys; ipoly++ ) { vector< uint > & idx = vertex_indices[ ipoly ]; mesh->SetTriangle(ipoly, idx[0], idx[1], idx[2]); } // Add to the scene m_pScene->AddMesh( mesh ); if(material) { GRayTraceColor* pEmissive = material->GetColor(GRayTraceMaterial::Emissive, NULL); if (!pEmissive->IsBlack() ) { for(ipoly = 0; ipoly < npolys; ipoly++) { GRayTraceTriangle* pTriangle = new GRayTraceTriangle(mesh, ipoly); m_pScene->AddObject(pTriangle); // This is a duplicate object of the one the mesh added GRayTraceAreaLight* pAreaLight = new GRayTraceAreaLight(pTriangle, pEmissive->r, pEmissive->g, pEmissive->b); m_pScene->AddLight( pAreaLight ); } } } // Clean up the allocated memory. if ( points != NULL ) delete[] points; if ( normals != NULL ) delete[] normals; if ( texcoords != NULL ) delete[] texcoords; return true;}bool RibParser::handleAreaLightSource( const RibData& data ){ // The default emissive color is white for any area light source double emissive_color[ 4 ] = { 1, 1, 1, 1 }; if ( data.size() < 3 ) { fprintf(stderr, "Bad number of arguments to AreaLightSource. Requires at least 1, has %d\n", data.size() - 1); //data.debugPrint( cerr, 3 ); return false; } else { if ( data.hasOptionalArg( "lightcolor" ) ) data.fillDoubleArrayFromOptionalArg( "lightcolor", emissive_color, 3 ); // Set the emissive color in the appropriate state block(s) int i = state.size() - 1; do { for ( uint j = 0; j < 3; j++ ) state[ i ].emissive_color[ j ] = emissive_color[ j ]; i--; } while ( state[ i ].type == StateBlock::TRANSFORMBLOCK && i > 0 ); // In project 4 we do geometry light sources. // The basic idea is just setting the emissive on the material. // We do it with the AreaLightSource command, for more compatibility with how // real-world RIBs do it. // // You'll need to replace this with your own material class. // Make a copy of the current material, replace the emissive color, and set GRayTraceMaterial* new_material = new GRayTraceMaterial(getMaterial()); new_material->SetColor( GRayTraceMaterial::Emissive, emissive_color[0], emissive_color[1], emissive_color[2] ); // Add the material to the scene, so it'll be deleted properly m_pScene->AddMaterial( new_material ); // Set the current material on the parser state setMaterial( new_material ); return true; }}void RibParser::pushState( int block_type ){ state.push_back( StateBlock( block_type, state.back() ) ); if ( block_type == StateBlock::WORLDBLOCK ) { // Move the object transform to the camera transform, and clear the object transform. double transform[16]; getObjectTransform( transform ); setCameraTransform( transform ); matrixMakeIdentity( transform ); setObjectTransform( transform ); }}void RibParser::popState( int block_type ){ if ( state.back().getType() != block_type ) fprintf(stderr, "Block error: Mismatched block types: %d terminated by %d\n", state.back().getType(), block_type); // If we're about to pop the world block, create a camera. if ( state.back().getType() == StateBlock::WORLDBLOCK ) { // These variables record the type of render requested, for easy construction of the camera. bool ray_tracing_camera = false, path_tracing_camera = false; // Will be made the default camera in the scene. GRayTraceCamera *camera = NULL; // Camera parameters: Samples per pixel, ray recursion depth, and tone mapping constant int ray_depth;// double tone_mapping_constant; double from[4] = { 0, 0, 0, 1 }; double to[4] = { 0, 0, 1, 1 }; // This 'to' point isn't what you'd expect, // but it allows us to change the handedness easily. double up[4] = { 0, 1, 0, 1 }; double transform[16]; // Camera to world transform. getCameraTransform( transform ); double inverted[16]; if ( !matrixInvert( inverted, transform ) ) { fprintf(stderr, "Transform matrix wasn't invertible. Expect weird behavior\n"); } matrixMultiplyPoint( from, inverted, from ); matrixMultiplyPoint( to, inverted, to ); matrixMultiplyPoint( up, inverted, up ); // Change up point to up vector. for ( uint i = 0; i < 4; i++ ) up[i] = up[i] - from[i]; if ( hasAttribute( "cs655Setting", "renderType" ) ) { string render_type = getAttribute( "cs655Setting", "renderType" ).stringVal( 0 ); if ( render_type == "rayTracing" ) ray_tracing_camera = true; else if ( render_type == "pathTracing" ) path_tracing_camera = true; } if ( !ray_tracing_camera && !path_tracing_camera ) { printf("No renderType attribute specified: Assuming ray tracing\n"); ray_tracing_camera = true; } // At this point it's either a ray tracing camera, or path tracing. // Get other attributes common to both cameras ray_depth = getAttribute( "cs655Setting", "rayDepth" ).intVal( 0 ); camera = m_pScene->GetCamera(); if ( ray_tracing_camera ) { } else if ( path_tracing_camera ) { // Get the tone mapping constant from the attributes. GRayTraceReal tone_mapping_constant = getAttribute( "cs655Setting", "toneMappingConstant" ).doubleVal( 0 ); m_pScene->SetToneMappingConstant( (GRayTraceReal)tone_mapping_constant ); } camera->SetRaysPerPixel( pixel_samples ); camera->SetMaxDepth( ray_depth ); camera->SetFocalDistance( focal_distance ); camera->SetLensDiameter( lens_diameter ); camera->GetLookFromPoint()->Set(from[0], from[1], from[2]); camera->GetLookAtPoint()->Set(to[0], to[1], to[2]); camera->GetViewUpVector()->Set(up[0], up[1], up[2]); camera->SetViewAngle(fov); camera->SetImageSize(image_width, image_height); //camera->setScene(scene); //scene->setDefaultCamera(camera); } // We'll crash if we remove the root block, so um.. don't. if ( state.size() == 1 ) fprintf(stderr, "Block error: Too many closing blocks, removing the file block from the stack is invalid.\n"); else state.pop_back();}void RibParser::setMaterial(GRayTraceMaterial* material){ int i = state.size() - 1; state[ i ].material = material; // Transform blocks only catch transforms, so propagate the material until you hit a different block type while ( state[ i ].type == StateBlock::TRANSFORMBLOCK && i > 0 ) { --i; state[ i ].material = material; }}GRayTraceMaterial* RibParser::getMaterial(){ if ( state.back().material == NULL ) { // If there is no current material, make and return the default material.#ifdef PARSER_DEBUG fprintf(stderr, "Material requested, but no material currently defined. Returning default material.\n");#endif GRayTraceMaterial *material = new GRayTraceMaterial(); m_pScene->AddMaterial(material); setMaterial(material); return material; } else { return state.back().material; }}void RibParser::setColor( const double* color ){ StateBlock& block = state.back(); for ( uint i = 0; i < 3; i++ ) block.color[ i ] = color[ i ];}void RibParser::getColor( double *color ){ StateBlock& block = state.back(); for ( uint i = 0; i < 3; i++ ) color[ i ] = block.color[ i ];}void RibParser::setCameraTransform( const double transform[16] ){ for ( uint i = 0; i < 16; i++ ) camera_to_world[ i ] = transform[ i ];}void RibParser::getCameraTransform( double transform[16] ){ for ( uint i = 0; i < 16; i++ ) transform[ i ] = camera_to_world[ i ];}void RibParser::setObjectTransform( const double transform[16] ){ StateBlock& block = state.back(); for ( uint i = 0; i < 16; i++ ) block.transform[ i ] = transform[ i ];}void RibParser::getObjectTransform( double transform[16] ){ StateBlock& block = state.back(); for ( uint i = 0; i < 16; i++ ) transform[ i ] = block.transform[ i ];}void RibParser::multiplyTransform( const double transform[16] ){ matrixMultiply( state.back().transform, state.back().transform, transform );}bool RibParser::hasAttribute( const string& attr_class, const string& attr_name ){ int i = state.size() - 1; bool success = false; do { state[ i ].getAttribute( attr_class, attr_name, success ); if ( success ) return true; --i; } while ( i >= 0 ); return false;}RibData& RibParser::getAttribute( const string& attr_class, const string& attr_name ){ bool success = false; int i = state.size() - 1; do { RibData& data = state[ i ].getAttribute( attr_class, attr_name, success ); if ( success ) return data; --i; } while ( i >= 0 ); success = false; return *((RibData*)NULL);}void RibParser::setAttribute( const string& attr_class, const string& attr_name, const RibData& data ){ int i = state.size() - 1; do { if ( state[ i ].type != StateBlock::TRANSFORMBLOCK ) break; // This is the one we want, don't decrement any more. i--; } while ( i > 0 ); // If we ever fail this test, we should be at the root block. // Either at the root, or the topmost non-transform, catch the attribute. // Since we look up attributes from the top of the stack, // this will properly allow shadowing of attribute values state[ i ].setAttribute( attr_class, attr_name, data );}RibData& RibParser::getObjectDefinition( unsigned int index ){ if ( object_definitions.size() <= index ) object_definitions.resize( index + 1 ); return object_definitions[ index ];}////////////////////// Utility Matrix Functions////////////////////void RibParser::matrixZero( double matrix[16] ){ for ( uint i = 0; i < 16; i++ ) matrix[ i ] = 0;}void RibParser::matrixMakeIdentity( double matrix[16] ){ matrixZero( matrix ); for ( uint i = 0; i < 4; i++ ) matrix[ i * 4 + i ] = 1;}void RibParser::matrixMultiply( double dest[16], const double left[16], const double right[16] ){ uint i; double temp[16]; matrixZero( temp ); for ( i = 0; i < 4; i++ ) for ( uint j = 0; j < 4; j++ ) for ( uint k = 0; k < 4; k++ ) temp[ i*4 + j ] += left[ k*4 + j ] * right[ i*4 + k ]; // Copy to the dest for ( i = 0; i < 16; i++ ) dest[ i ] = temp[ i ];}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -