optix_geometry_handler.cpp 16.6 KB
Newer Older
1
/*
2 3 4 5
 *
 * author : Arthur Dufay @ inria.fr
 * Copyright INRIA 2017
 *
6 7
 * author : Romain Pacanowski @ institutoptique . fr
 * Copyright CNRS 2020 : Added Analytical Sphere
8 9
 *
 **/
DUFAY Arthur's avatar
DUFAY Arthur committed
10

Alban Fichet's avatar
Alban Fichet committed
11
#include <mrf_optix/optix_geometry_handler.hpp>
12 13

#include <mrf_core/geometry/sphere.hpp>
Alban Fichet's avatar
Alban Fichet committed
14
#include <mrf_optix/optix_util.hpp>
15

Alban Fichet's avatar
Alban Fichet committed
16 17
#include <optixu/optixu_matrix.h>
#include <optixu/optixu_math_stream_namespace.h>
18 19 20 21 22

namespace mrf
{
namespace optix_backend
{
23 24 25
OptixGeometryHandler::OptixGeometryHandler(optix::Context &context, mrf::gui::fb::Loger const &loger)
  : _context(context)
  , _loger(loger)
26
{
27 28
  _pgram_intersection          = 0;
  _pgram_bounding_box          = 0;
29
  _pgram_attributes            = 0;
30 31
  _pgram_intersection_sphere   = 0;
  _pgram_bounding_box_sphere   = 0;
32 33 34 35
  _pgram_intersection_triangle = 0;
  _pgram_bounding_box_triangle = 0;
}

36
OptixGeometryHandler::~OptixGeometryHandler() {}
37

Romain Pacanowski's avatar
Romain Pacanowski committed
38 39 40 41 42
void OptixGeometryHandler::importMrfScene(
    mrf::rendering::Scene const &                   scene,
    mrf::optix_backend::OptixMaterialHandler const &material_handler,
    mrf::optix_backend::OptixLightHandler &         light_handler,
    std::vector<std::string> const &                cuda_compile_options)
43 44 45
{
  std::vector<std::string> cuda_compile_options_temp;

MURRAY David's avatar
MURRAY David committed
46
  _loger.info("Importing scene in OptiX");
47 48 49 50 51 52

  // Starting to create the SceneGraph
  optix::Group top_group;
  top_group = _context->createGroup();
  top_group->setAcceleration(_context->createAcceleration(SPATIAL_ACCELERATION_DATA_STRUCTURE));

53
  // Set up parallelogram programs
54
  const char *ptx     = getPtxString("parallelogram.cu", cuda_compile_options);
55 56 57
  _pgram_bounding_box = _context->createProgramFromPTXString(ptx, "bounds");
  _pgram_intersection = _context->createProgramFromPTXString(ptx, "intersect");

58 59
  //Set up sphere programs
  ptx                        = getPtxString("sphere.cu", cuda_compile_options);
60 61 62
  _pgram_bounding_box_sphere = _context->createProgramFromPTXString(ptx, "bounds");
  _pgram_intersection_sphere = _context->createProgramFromPTXString(ptx, "intersect");

63
  //Create geometry group for parallelograms and spheres
64 65 66 67
  optix::GeometryGroup geometry_group = _context->createGeometryGroup();
  geometry_group->setAcceleration(_context->createAcceleration(SPATIAL_ACCELERATION_DATA_STRUCTURE));
  top_group->addChild(geometry_group);

68 69 70 71 72 73 74 75 76
  //Set up generic triangle mesh programs
  //ptx = getPtxString("triangle_mesh.cu", cuda_compile_options_temp);
  ptx = getPtxString("triangle_attributes.cu", cuda_compile_options);

  //Create geometry group for triangle geometry (using GeometryTriangle)
  optix::GeometryGroup tri_geometry_group = _context->createGeometryGroup();
  tri_geometry_group->setAcceleration(_context->createAcceleration(SPATIAL_ACCELERATION_DATA_STRUCTURE));
  top_group->addChild(tri_geometry_group);

77

78 79 80 81
  std::vector<mrf::geom::Shape *> const &shapes        = scene.shapes();
  uint                                   mesh_num      = 0;
  uint                                   shape_num     = 0;
  int                                    num_triangles = 0;
82
  //RP: When do we need this?
Romain Pacanowski's avatar
Romain Pacanowski committed
83
  optix::Aabb aabb;
84 85

  //FOR ALL SHAPES
86 87
  for (auto shape_it = shapes.begin(); shape_it != shapes.end(); shape_it++, mesh_num++, shape_num++)
  {
Romain Pacanowski's avatar
Romain Pacanowski committed
88 89
    auto a_sphere = dynamic_cast<mrf::geom::Sphere *>(*shape_it);
    if (a_sphere)
90
    {
Romain Pacanowski's avatar
Romain Pacanowski committed
91
      _loger.debug(" Found a Sphere as Shape !!! ");
92

Romain Pacanowski's avatar
Romain Pacanowski committed
93
      auto gi = createSphere(mrfToOptix(a_sphere->position()), a_sphere->radius());
94 95
      //Save it for later when applycing Material
      unsigned int mat_index = a_sphere->materialIndex();
Romain Pacanowski's avatar
Romain Pacanowski committed
96
      _optix_analytical_shapes.push_back(std::make_pair(gi, mat_index));
97 98

      // ADD MATERIAL Dummy material for now
Romain Pacanowski's avatar
Romain Pacanowski committed
99
      gi->addMaterial(material_handler.lambert());
100 101 102 103 104 105 106

      //TODO UPDATE aabb ?

      // NOW ADD TO SCENE GRAPH
      geometry_group->addChild(gi);
    }
    else
107
    {
108 109 110
      //TODO INSTANCIATION !!
      auto mrf_mesh = dynamic_cast<mrf::geom::Mesh *>((*shape_it)->mesh().get());
      if (mrf_mesh)
111
      {
112 113 114 115 116 117
        std::string instance_name = "mesh_" + std::to_string(mesh_num) + "_instance";
        std::string file_name     = mrf_mesh->absoluteFilepath();
        if (file_name.size() > 0)
        {
          OptiXMesh optix_mesh;
          optix_mesh.context = _context;
118 119


120
          uint material_id = (*shape_it)->materialIndex();
121

122
          if (material_handler.needMeshRefine(material_id))
123
            optix_mesh.attributes = _context->createProgramFromPTXString(ptx, "triangle_attributes_refine");
124
          else
125 126 127 128 129 130 131 132 133
            optix_mesh.attributes = _context->createProgramFromPTXString(ptx, "triangle_attributes");

          //if (material_handler.needMeshRefine(material_id))
          //  optix_mesh.intersection = _context->createProgramFromPTXString(ptx, "mesh_intersect_refine");
          //else
          //  optix_mesh.intersection = _context->createProgramFromPTXString(ptx, "mesh_intersect");
          //optix_mesh.intersection = _context->createProgramFromPTXString(ptx, "mesh_intersect");
          //optix_mesh.bounds       = _context->createProgramFromPTXString(ptx, "mesh_bounds");

134

MURRAY David's avatar
MURRAY David committed
135 136
          //TODO !!!!
          //DIRECTLY USE THE CORRECT ONE HERE
137 138
          //apply a default lambert material to avoid optix error due to loadMesh with a geometry
          //that hasn't got any material or closesthit/
139 140 141 142
          //optix_mesh.material = material_handler.lambert();
          std::vector<optix::Material> optix_materials;
          optix_materials.push_back(material_handler.lambert());

143

144 145
          optix::Matrix4x4 transform = optix::Matrix4x4((*shape_it)->worldToObjectTransform().ptr());
          //transform = transform.transpose();
146 147


148
          //loadMesh(file_name, optix_mesh, transform);
149
          loadMeshFromMRF(*mrf_mesh, optix_mesh, transform, optix_materials);
150

151
          //optix_mesh.has_texcoords = mesh.has_texcoords;
152

153
          tri_geometry_group->addChild(optix_mesh.geom_instance);
154

155
          aabb.include(optix_mesh.bbox_min, optix_mesh.bbox_max);
156

157 158
          _loger.trace("Optix Renderer import mesh " + file_name + ", triangle count:", optix_mesh.num_triangles);
          num_triangles += optix_mesh.num_triangles;
159

160
          _optix_geometry_instances.push_back(std::make_pair(optix_mesh, (*shape_it)));
Romain Pacanowski's avatar
Romain Pacanowski committed
161 162 163 164
        }   // end filename of the mesh is
      }     //end it is a mesh
    }       //end of else (it is not Sphere as shape)
  }         //end for loop for all SHAPES
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

  //Create parallelogram light geometries
  auto optix_lights = light_handler.optixQuadLights();
  for (auto it = optix_lights.cbegin(); it != optix_lights.cend(); ++it)
  {
    auto gi = createParallelogram(it->corner, it->v1, it->v2);

    gi->addMaterial(material_handler.diffuseEmittance());

    geometry_group->addChild(gi);
    light_handler.addQuadLight(gi);
  }

  //Create sphere light geometries
  auto optix_sph_lights = light_handler.optixSphereLights();
  for (auto it = optix_sph_lights.cbegin(); it != optix_sph_lights.cend(); ++it)
  {
    auto gi = createSphere(it->position, it->radius);

    gi->addMaterial(material_handler.diffuseEmittance());

    geometry_group->addChild(gi);
    light_handler.addSphereLight(gi);
  }

190

191 192
  //_context["top_object"]->set(geometry_group);
  _context["top_object"]->set(top_group);
193 194 195 196 197 198 199 200



  _loger.info("Optix Renderer MRF scene imported, total triangle count:", num_triangles);
}


optix::GeometryInstance OptixGeometryHandler::createParallelogram(
201 202 203
    const optix::float3 &anchor,
    const optix::float3 &offset1,
    const optix::float3 &offset2)
DUFAY Arthur's avatar
DUFAY Arthur committed
204
{
205 206 207 208 209 210
  optix::Geometry parallelogram = _context->createGeometry();
  parallelogram->setPrimitiveCount(1u);
  parallelogram->setIntersectionProgram(_pgram_intersection);
  parallelogram->setBoundingBoxProgram(_pgram_bounding_box);

  optix::float3 normal = optix::normalize(optix::cross(offset1, offset2));
211 212
  float         d      = optix::dot(normal, anchor);
  optix::float4 plane  = make_float4(normal, d);
213 214 215 216 217 218 219 220 221 222 223 224 225 226

  optix::float3 v1 = offset1 / optix::dot(offset1, offset1);
  optix::float3 v2 = offset2 / optix::dot(offset2, offset2);

  parallelogram["plane"]->setFloat(plane);
  parallelogram["anchor"]->setFloat(anchor);
  parallelogram["v1"]->setFloat(v1);
  parallelogram["v2"]->setFloat(v2);

  optix::GeometryInstance gi = _context->createGeometryInstance();
  gi->setGeometry(parallelogram);
  return gi;
}

227
optix::GeometryInstance OptixGeometryHandler::createSphere(const optix::float3 &center, const float &radius)
228 229 230 231 232 233 234 235
{
  optix::Geometry sphere = _context->createGeometry();
  sphere->setPrimitiveCount(1u);
  sphere->setIntersectionProgram(_pgram_intersection_sphere);
  sphere->setBoundingBoxProgram(_pgram_bounding_box_sphere);

  sphere["center"]->setFloat(center);
  sphere["radius"]->setFloat(radius);
DUFAY Arthur's avatar
DUFAY Arthur committed
236

237 238 239 240 241
  optix::GeometryInstance gi = _context->createGeometryInstance();
  gi->setGeometry(sphere);
  return gi;
}

242
std::vector<std::pair<OptiXMesh, mrf::geom::Shape *>> &OptixGeometryHandler::geometryInstances()
243 244 245 246 247
{
  return _optix_geometry_instances;
}

void OptixGeometryHandler::loadMeshFromMRF(
248 249
    mrf::geom::Mesh const & mrf_mesh,
    OptiXMesh &             optix_mesh,
250 251
    const optix::Matrix4x4 &load_xform,
    std::vector<optix::Material>            optix_materials)
252 253
{
  if (!optix_mesh.context)
DUFAY Arthur's avatar
DUFAY Arthur committed
254
  {
255 256 257 258
    throw std::runtime_error("OptiXMesh: loadMesh() requires valid OptiX context");
  }

  optix::Context context = optix_mesh.context;
DUFAY Arthur's avatar
DUFAY Arthur committed
259

260
  Mesh             mesh;
261 262 263
  OptixMeshBuffers buffers;
  //MeshLoader loader(filename);
  //loader.scanMesh(mesh);
DUFAY Arthur's avatar
DUFAY Arthur committed
264

265
  mesh.num_triangles = mrf_mesh.numSubObjects();
266 267 268 269
  mesh.num_vertices  = static_cast<int>(mrf_mesh.vertices().size());
  if (mrf_mesh.normals().size() == mrf_mesh.vertices().size()) mesh.has_normals = true;
  if (mrf_mesh.uvs().size() == mrf_mesh.vertices().size()) mesh.has_texcoords = true;
  if (mrf_mesh.tangents().size() == mrf_mesh.vertices().size()) mesh.has_tangents = true;
DUFAY Arthur's avatar
DUFAY Arthur committed
270

271
  mesh.num_materials = 0;
DUFAY Arthur's avatar
DUFAY Arthur committed
272

273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
  setupMeshLoaderInputs(context, buffers, mesh);


  //loader.loadMesh(mesh, load_xform.getData());

  memcpy(mesh.positions, &mrf_mesh.vertices()[0], 3 * mrf_mesh.vertices().size() * sizeof(float));

  mesh.bbox_min[0] = mrf_mesh.bbox().getMin().x();
  mesh.bbox_min[1] = mrf_mesh.bbox().getMin().y();
  mesh.bbox_min[2] = mrf_mesh.bbox().getMin().z();

  mesh.bbox_max[0] = mrf_mesh.bbox().getMax().x();
  mesh.bbox_max[1] = mrf_mesh.bbox().getMax().y();
  mesh.bbox_max[2] = mrf_mesh.bbox().getMax().z();


289
  if (mesh.has_normals) memcpy(mesh.normals, &mrf_mesh.normals()[0], 3 * mrf_mesh.normals().size() * sizeof(float));
290 291 292 293

  if (mesh.has_texcoords)
  {
    //CANNOT COPY DIRECTLY NEED TO CONVERT FROM Vec3f to FLOAT2
294
    //memcpy(mesh.texcoords, &mrf_mesh.uvs()[0], 3 * mrf_mesh.uvs().size() * sizeof(float));
295 296
    for (uint64_t i = 0; i < mrf_mesh.uvs().size(); ++i)
    {
297
      mesh.texcoords[2 * i]     = mrf_mesh.uvs()[i].x();
298 299
      mesh.texcoords[2 * i + 1] = mrf_mesh.uvs()[i].y();
    }
DUFAY Arthur's avatar
DUFAY Arthur committed
300
  }
301 302 303 304 305 306 307 308

  if (mesh.has_tangents)
  {
    memcpy(mesh.tangents, &mrf_mesh.tangents()[0], 3 * mrf_mesh.tangents().size() * sizeof(float));
  }

  //std::copy(mrf_mesh.faces().cbegin(), mrf_mesh.faces().cend(), mesh.tri_indices);
  memcpy(mesh.tri_indices, &mrf_mesh.faces()[0], mrf_mesh.faces().size() * sizeof(unsigned int));
309
  memcpy(mesh.mat_indices, &mrf_mesh.materialPerFaces()[0], mrf_mesh.materialPerFaces().size() * sizeof(unsigned int));
310 311 312 313 314

  applyLoadXForm(mesh, load_xform.getData());

  //translateMeshToOptiX(mesh, buffers, optix_mesh);

315 316 317 318 319
  //optix::Context ctx = optix_mesh.context;
  optix_mesh.bbox_min      = mrf::optix_backend::make_float3(mesh.bbox_min);
  optix_mesh.bbox_max      = mrf::optix_backend::make_float3(mesh.bbox_max);
  optix_mesh.num_triangles = mesh.num_triangles;

320 321
  //std::vector<optix::Material> optix_materials;
  if (optix_materials.size() == 1)
322 323 324
  {
    // Rewrite all mat_indices to point to single override material
    memset(mesh.mat_indices, 0, mesh.num_triangles * sizeof(int32_t));
325
    //optix_materials.push_back(optix_mesh.material);
326
  }
327 328 329 330
  //else
  //{
  //  optix_materials.resize(nb_mat);
  //}
331

332 333 334 335 336 337

  optix::GeometryTriangles geometry = optix_mesh.context->createGeometryTriangles();
  geometry->setPrimitiveCount(mesh.num_triangles);
  geometry->setVertices(static_cast<unsigned int>(mrf_mesh.vertices().size()), buffers.positions, RT_FORMAT_FLOAT3);
  geometry->setTriangleIndices(buffers.tri_indices, RT_FORMAT_UNSIGNED_INT3);

338 339 340 341 342
  geometry["vertex_buffer"]->setBuffer(buffers.positions);
  geometry["normal_buffer"]->setBuffer(buffers.normals);
  geometry["texcoord_buffer"]->setBuffer(buffers.texcoords);
  geometry["tangent_buffer"]->setBuffer(buffers.tangents);
  geometry["index_buffer"]->setBuffer(buffers.tri_indices);
343 344 345 346

  geometry->setAttributeProgram(optix_mesh.attributes);

  //Materials: TODO: per face
MURRAY David's avatar
MURRAY David committed
347
  geometry->setMaterialCount(optix_materials.size());
348 349 350 351 352 353 354 355 356 357 358 359 360
  geometry->setMaterialIndices(buffers.mat_indices, 0, 0, RT_FORMAT_UNSIGNED_INT);


  //optix::Geometry geometry = optix_mesh.context->createGeometry();
  //geometry["vertex_buffer"]->setBuffer(buffers.positions);
  //geometry["normal_buffer"]->setBuffer(buffers.normals);
  //geometry["texcoord_buffer"]->setBuffer(buffers.texcoords);
  //geometry["tangent_buffer"]->setBuffer(buffers.tangents);
  //geometry["material_buffer"]->setBuffer(buffers.mat_indices);
  //geometry["index_buffer"]->setBuffer(buffers.tri_indices);
  //geometry->setPrimitiveCount(mesh.num_triangles);
  //geometry->setBoundingBoxProgram(optix_mesh.bounds);
  //geometry->setIntersectionProgram(optix_mesh.intersection);
361 362 363

  optix_mesh.geom_instance
      = optix_mesh.context->createGeometryInstance(geometry, optix_materials.begin(), optix_materials.end());
364 365

  //unmap(buffers, mesh);
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
  buffers.tri_indices->unmap();
  buffers.mat_indices->unmap();
  buffers.positions->unmap();
  if (mesh.has_normals) buffers.normals->unmap();
  if (mesh.has_texcoords) buffers.texcoords->unmap();
  if (mesh.has_tangents) buffers.tangents->unmap();

  mesh.tri_indices = 0;
  mesh.mat_indices = 0;
  mesh.positions   = 0;
  mesh.normals     = 0;
  mesh.texcoords   = 0;
  mesh.tangents    = 0;

  //delete[] mesh.mat_params;
  //mesh.mat_params = 0;
382 383 384 385

  optix_mesh.has_texcoords = mesh.has_texcoords;
}

386
void OptixGeometryHandler::setupMeshLoaderInputs(optix::Context context, OptixMeshBuffers &buffers, Mesh &mesh)
387 388 389
{
  buffers.tri_indices = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_INT3, mesh.num_triangles);
  buffers.mat_indices = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_INT, mesh.num_triangles);
390 391 392 393 394 395 396 397 398 399 400 401 402
  buffers.positions   = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, mesh.num_vertices);
  buffers.normals = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, mesh.has_normals ? mesh.num_vertices : 0);
  buffers.texcoords
      = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT2, mesh.has_texcoords ? mesh.num_vertices : 0);
  buffers.tangents
      = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, mesh.has_tangents ? mesh.num_vertices : 0);

  mesh.tri_indices = reinterpret_cast<int32_t *>(buffers.tri_indices->map());
  mesh.mat_indices = reinterpret_cast<int32_t *>(buffers.mat_indices->map());
  mesh.positions   = reinterpret_cast<float *>(buffers.positions->map());
  mesh.normals     = reinterpret_cast<float *>(mesh.has_normals ? buffers.normals->map() : 0);
  mesh.texcoords   = reinterpret_cast<float *>(mesh.has_texcoords ? buffers.texcoords->map() : 0);
  mesh.tangents    = reinterpret_cast<float *>(mesh.has_tangents ? buffers.tangents->map() : 0);
403 404 405 406 407

  //mesh.mat_params = new MaterialParams[mesh.num_materials];
}


408
void applyLoadXForm(mrf::optix_backend::Mesh &mesh, const float *load_xform)
409
{
410
  if (!load_xform) return;
411

412 413 414
  bool have_matrix = false;
  for (int32_t i = 0; i < 16; ++i)
    if (load_xform[i] != 0.0f) have_matrix = true;
415

416 417 418 419
  if (have_matrix)
  {
    mesh.bbox_min[0] = mesh.bbox_min[1] = mesh.bbox_min[2] = 1e16f;
    mesh.bbox_max[0] = mesh.bbox_max[1] = mesh.bbox_max[2] = -1e16f;
420

421
    optix::Matrix4x4 mat(load_xform);
422

423 424 425 426 427 428 429 430 431 432 433 434
    optix::float3 *positions = reinterpret_cast<optix::float3 *>(mesh.positions);
    for (int32_t i = 0; i < mesh.num_vertices; ++i)
    {
      const optix::float3 v = optix::make_float3(mat * optix::make_float4(positions[i], 1.0f));
      positions[i]          = v;
      mesh.bbox_min[0]      = std::min<float>(mesh.bbox_min[0], v.x);
      mesh.bbox_min[1]      = std::min<float>(mesh.bbox_min[1], v.y);
      mesh.bbox_min[2]      = std::min<float>(mesh.bbox_min[2], v.z);
      mesh.bbox_max[0]      = std::max<float>(mesh.bbox_max[0], v.x);
      mesh.bbox_max[1]      = std::max<float>(mesh.bbox_max[1], v.y);
      mesh.bbox_max[2]      = std::max<float>(mesh.bbox_max[2], v.z);
    }
435

436 437 438 439
    if (mesh.has_normals)
    {
      mat                    = mat.inverse().transpose();
      optix::float3 *normals = reinterpret_cast<optix::float3 *>(mesh.normals);
440
      for (int32_t i = 0; i < mesh.num_vertices; ++i)
441
        normals[i] = optix::make_float3(mat * optix::make_float4(normals[i], 1.0f));
442
    }
443
  }
444 445
}

446 447
}   // namespace optix_backend
}   // namespace mrf