2017-06-14 6 views
0

J'essaie de combiner la polyvalence de Open Asset Import Library (lire dans une variété de types de fichiers 3D) avec NVIDIA Optix ray tracing pour rendre Les modèles. Jusqu'à présent, il fonctionne à chaque fois que le modèle que je suis est composé d'un seul maillage. Lorsque j'essaie de rendre un fichier avec plus d'un maillage, je n'obtiens que des résultats partiels. Je ne peux pas préciser où est le problème, à la recherche d'un aperçu. Code pertinent ici:Ray Tracing à l'aide de Nvidia Optix avec Open Asset Import Library (assimp) - rendu de plusieurs maillages

Chargement d'un fichier en utilisant l'importateur de assimp et de créer les tampons Optix:

int loadAsset(const char* path) 
{ 
Assimp::Importer importer; 

scene = importer.ReadFile(
    path, 
    aiProcess_Triangulate 
    //| aiProcess_JoinIdenticalVertices 
    | aiProcess_SortByPType 
    | aiProcess_ValidateDataStructure 
    | aiProcess_SplitLargeMeshes 
    | aiProcess_FixInfacingNormals 
    ); 

if (scene) { 
    getBoundingBox(&scene_min, &scene_max); 
    scene_center.x = (scene_min.x + scene_max.x)/2.0f; 
    scene_center.y = (scene_min.y + scene_max.y)/2.0f; 
    scene_center.z = (scene_min.z + scene_max.z)/2.0f; 

    float3 optixMin = { scene_min.x, scene_min.y, scene_min.z }; 
    float3 optixMax = { scene_max.x, scene_max.y, scene_max.z }; 
    aabb.set(optixMin, optixMax); 

    unsigned int numVerts = 0; 
    unsigned int numFaces = 0; 

    if (scene->mNumMeshes > 0) {  
     printf("Number of meshes: %d\n", scene->mNumMeshes); 

     // get the running total number of vertices & faces for all meshes 
     for (unsigned int i = 0; i < scene->mNumMeshes; i++) { 
      numVerts += scene->mMeshes[i]->mNumVertices; 
      numFaces += scene->mMeshes[i]->mNumFaces; 
     } 
     printf("Found %d Vertices and %d Faces\n", numVerts, numFaces); 

     // set up buffers 
     optix::Buffer vertices = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, numVerts); 
     optix::Buffer normals = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, numVerts); 
     optix::Buffer faces = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT3, numFaces); 
     optix::Buffer materials = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT, numVerts); 

     // unused buffer 
     Buffer tbuffer = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT2, 0); 

     // create material 
     std::string defaultPtxPath = "C:\\ProgramData\\NVIDIA Corporation\\OptiX SDK 4.1.0\\SDK\\build\\lib\\ptx\\"; 
     Program phong_ch = context->createProgramFromPTXFile(defaultPtxPath + "optixPrimitiveIndexOffsets_generated_phong.cu.ptx", "closest_hit_radiance"); 
     Program phong_ah = context->createProgramFromPTXFile(defaultPtxPath + "optixPrimitiveIndexOffsets_generated_phong.cu.ptx", "any_hit_shadow"); 

     Material matl = context->createMaterial(); 
     matl->setClosestHitProgram(0, phong_ch); 
     matl->setAnyHitProgram(1, phong_ah); 
     matl["Kd"]->setFloat(0.7f, 0.7f, 0.7f); 
     matl["Ka"]->setFloat(1.0f, 1.0f, 1.0f); 
     matl["Kr"]->setFloat(0.0f, 0.0f, 0.0f); 
     matl["phong_exp"]->setFloat(1.0f); 

     std::string triangle_mesh_ptx_path(ptxPath("triangle_mesh.cu")); 
     Program meshIntersectProgram = context->createProgramFromPTXFile(triangle_mesh_ptx_path, "mesh_intersect"); 
     Program meshBboxProgram = context->createProgramFromPTXFile(triangle_mesh_ptx_path, "mesh_bounds"); 

     optix::float3 *vertexMap = reinterpret_cast<optix::float3*>(vertices->map()); 
     optix::float3 *normalMap = reinterpret_cast<optix::float3*>(normals->map()); 
     optix::uint3 *faceMap = reinterpret_cast<optix::uint3*>(faces->map()); 
     unsigned int *materialsMap = static_cast<unsigned int*>(materials->map()); 

     context["vertex_buffer"]->setBuffer(vertices); 
     context["normal_buffer"]->setBuffer(normals); 
     context["index_buffer"]->setBuffer(faces); 
     context["texcoord_buffer"]->setBuffer(tbuffer); 
     context["material_buffer"]->setBuffer(materials); 


     Group group = createSingleGeometryGroup(meshIntersectProgram, meshBboxProgram, vertexMap, 
      normalMap, faceMap, materialsMap, matl); 

     context["top_object"]->set(group); 
     context["top_shadower"]->set(group); 

     vertices->unmap(); 
     normals->unmap(); 
     faces->unmap(); 
     materials->unmap(); 
    } 

    return 0; 
} 
return 1; 
} 

Et la fonction correspondante pour créer les géométries et le remplissage des tampons:

Group createSingleGeometryGroup(Program meshIntersectProgram, Program meshBboxProgram, optix::float3 *vertexMap, 
optix::float3 *normalMap, optix::uint3 *faceMap, unsigned int *materialsMap, Material matl) { 

Group group = context->createGroup(); 
optix::Acceleration accel = context->createAcceleration("Trbvh"); 
group->setAcceleration(accel); 
std::vector<GeometryInstance> gis; 
unsigned int vertexOffset = 0u; 
unsigned int faceOffset = 0u; 

for (unsigned int m = 0; m < scene->mNumMeshes; m++) { 
    aiMesh *mesh = scene->mMeshes[m]; 
    if (!mesh->HasPositions()) { 
     throw std::runtime_error("Mesh contains zero vertex positions"); 
    } 
    if (!mesh->HasNormals()) { 
     throw std::runtime_error("Mesh contains zero vertex normals"); 
    } 

    printf("Mesh #%d\n\tNumVertices: %d\n\tNumFaces: %d\n", m, mesh->mNumVertices, mesh->mNumFaces); 

    // add points   
    for (unsigned int i = 0u; i < mesh->mNumVertices; i++) { 
     aiVector3D pos = mesh->mVertices[i]; 
     aiVector3D norm = mesh->mNormals[i]; 

     vertexMap[i + vertexOffset] = optix::make_float3(pos.x, pos.y, pos.z) + aabb.center(); 
     normalMap[i + vertexOffset] = optix::normalize(optix::make_float3(norm.x, norm.y, norm.z)); 
     materialsMap[i + vertexOffset] = 0u; 

    } 

    // add faces 
    for (unsigned int i = 0u; i < mesh->mNumFaces; i++) { 
     aiFace face = mesh->mFaces[i]; 

     // add triangles 
     if (face.mNumIndices == 3) { 
      faceMap[i + faceOffset] = optix::make_uint3(face.mIndices[0], face.mIndices[1], face.mIndices[2]); 
     } 
     else { 
      printf("face indices != 3\n"); 
      faceMap[i + faceOffset] = optix::make_uint3(-1); 
     } 
    } 

    // create geometry 
    optix::Geometry geometry = context->createGeometry(); 
    geometry->setPrimitiveCount(mesh->mNumFaces); 
    geometry->setIntersectionProgram(meshIntersectProgram); 
    geometry->setBoundingBoxProgram(meshBboxProgram); 
    geometry->setPrimitiveIndexOffset(faceOffset); 

    optix::GeometryInstance gi = context->createGeometryInstance(geometry, &matl, &matl + 1); 
    gis.push_back(gi); 

    vertexOffset += mesh->mNumVertices; 
    faceOffset += mesh->mNumFaces; 

} 

printf("VertexOffset: %d\nFaceOffset: %d\n", vertexOffset, faceOffset); 

// add all geometry instances to a geometry group 
GeometryGroup gg = context->createGeometryGroup(); 
gg->setChildCount(static_cast<unsigned int>(gis.size())); 
for (unsigned i = 0u; i < gis.size(); i++) { 
    gg->setChild(i, gis[i]); 
} 
Acceleration a = context->createAcceleration("Trbvh"); 
gg->setAcceleration(a); 

group->setChildCount(1); 
group->setChild(0, gg); 

return group; 
} 

exécution ci-dessus code sur un exemple de fichier de assimp (en utilisant le fichier dwarf.x, le fichier contient 2 mailles) donne ce résultat: enter image description here

Vous pouvez voir sur Une partie du deuxième maillage (le corps du nain) est rendue. J'ai essayé de rendre chaque mesh séparément, un à la fois, et ils le rendent en entier. Mais quand je les rassemble, je comprends.

Je pense la question est soit à la création de la géométrie, peut-être que j'ai ces lignes mal:

geometry->setPrimitiveCount(mesh->mNumFaces); 
geometry->setPrimitiveIndexOffset(faceOffset); 

ou les drapeaux post-traitement de assimp

scene = importer.ReadFile(
    path, 
    aiProcess_Triangulate 
    //| aiProcess_JoinIdenticalVertices 
    | aiProcess_SortByPType 
    | aiProcess_ValidateDataStructure 
    | aiProcess_SplitLargeMeshes 
    | aiProcess_FixInfacingNormals 
    ); 

(note ci-dessus, je devais commenter JoinIdenticalVertices parce qu'il m'a donné un résultat horriblement mauvais montré ci-dessous): enter image description here

Quelqu'un at-il pu combiner avec succès nvidia optix avec la bibliothèque d'importation de ressources ouverte pour le rendu de fichiers avec plusieurs maillages?

Répondre

0

J'ai trouvé une solution, mais je ne sais pas comment optimale. Chaque maillage possède sa propre géométrie, mais au lieu de créer des tampons de vertex, d'index et normal partagés entre toutes les géométries, je crée des tampons séparés pour chaque géométrie.

Puis, au lieu de

context["vertex_buffer"]->setBuffer(vertices); 
context["normal_buffer"]->setBuffer(normals); 
context["index_buffer"]->setBuffer(faces); 
context["texcoord_buffer"]->setBuffer(tbuffer); 
context["material_buffer"]->setBuffer(materials); 

J'utilise

geometry["vertex_buffer"]->setBuffer(vertices); 
geometry["normal_buffer"]->setBuffer(normals); 
geometry["index_buffer"]->setBuffer(faces); 
geometry["texcoord_buffer"]->setBuffer(tbuffer); 
geometry["material_buffer"]->setBuffer(materials); 

Le résultat: enter image description here