AN INTRODUCTION TO NVIDIA OPTIX Ankit Patel, Detlef Roettger, - - PowerPoint PPT Presentation

an introduction to nvidia optix
SMART_READER_LITE
LIVE PREVIEW

AN INTRODUCTION TO NVIDIA OPTIX Ankit Patel, Detlef Roettger, - - PowerPoint PPT Presentation

GTC 2018 San Jose, S8518 Tutorial AN INTRODUCTION TO NVIDIA OPTIX Ankit Patel, Detlef Roettger, 2018-03-26 OptiX Overview Programming with OptiX AGENDA New Example Applications Motion Blur DL Denoiser 2 volume scattering and dispersion


slide-1
SLIDE 1

Ankit Patel, Detlef Roettger, 2018-03-26

AN INTRODUCTION TO NVIDIA OPTIX

GTC 2018 San Jose, S8518 Tutorial

slide-2
SLIDE 2

2

AGENDA

OptiX Overview Programming with OptiX New Example Applications Motion Blur DL Denoiser

slide-3
SLIDE 3

3

OptiX

High-level GPU accelerated ray-casting API C-API to setup scene and data Multiple program domains and per ray payload under developer's control Flexible single ray programming model Supports multi-GPU and NVLINK Develop "to the algorithm" https://developer.nvidia.com/optix

NVIDIA GPU Ray Casting API

volume scattering and dispersion hair intersection and shading

slide-4
SLIDE 4

4

Programming with OptiX

Windows, Linux, Mac OS NVIDIA GPU (Kepler, Maxwell, Pascal, Volta) Display Driver supporting CUDA 9.0 OptiX SDK CUDA Toolkit Host compiler supported by the CUDA Toolkit

Prerequisites

slide-5
SLIDE 5

5

OptiX Program Domains

Developer controls the algorithm via CUDA C++ programs

RayGeneration

Intersection BoundingBox ClosestHit Miss AnyHit

Exception

* per entry point * per geometric primitive type * per ray type

slide-6
SLIDE 6

6

Acceleration Structures

Bounding Volume Hierarchy (BVH)

slide-7
SLIDE 7

7

OptiX Scene Hierarchy

OptiX C-API to create and connect scene data

GeometryGroup GeometryInstance Geometry Material Acceleration ClosestHit AnyHit BoundingBox Intersection

slide-8
SLIDE 8

8

OptiX Scene Hierarchy

Instancing Sub-Trees

GeometryGroup GeometryInstance Geometry Material Acceleration Transform Transform Group ... Acceleration

slide-9
SLIDE 9

9

slide-10
SLIDE 10

10

OptiX Scene Hierarchy

Acceleration Structure Sharing

GeometryGroup GeometryInstance Geometry Material A Acceleration Transform Transform Group GeometryGroup GeometryInstance Material B Acceleration

slide-11
SLIDE 11

11

slide-12
SLIDE 12

12

OptiX Introduction Example Programs

slide-13
SLIDE 13

13

  • ptixIntro_01
slide-14
SLIDE 14

14

  • ptix::Context::create()

RayGeneration setEntryPointCount(num_entry_points) setRayTypeCount(num_ray_types) setStackSize(bytes) createBuffer(type, format, width, height) createProgramFromPTXFile(filename, program_name) launch(entry_point, width, height) buffer->map(level, flags) buffer->unmap() context["variable_name"]->set(buffer); setDevices(begin, end); setRayGenerationProgram(index, program)

slide-15
SLIDE 15

15

rtBuffer<float4, 2> sysOutputBuffer; // RGBA32F rtDeclareVariable(uint2, theLaunchIndex, rtLaunchIndex, ); rtDeclareVariable(float3, sysColorBackground, , ); RT_PROGRAM void raygeneration() { sysOutputBuffer[theLaunchIndex] = make_float4(sysColorBackground, 1.0f); }

RayGeneration Program

slide-16
SLIDE 16

16

rtBuffer<float4, 2> sysOutputBuffer; // RGBA32F rtDeclareVariable(uint2, theLaunchIndex, rtLaunchIndex, ); RT_PROGRAM void exception() { rtPrintExceptionDetails(); sysOutputBuffer[theLaunchIndex] = make_float4(1000000.0f, 0.0f, 1000000.0f, 1.0f); }

Exception Program

slide-17
SLIDE 17

17

  • ptixIntro_02
slide-18
SLIDE 18

18

sysCameraW sysCameraU sysCameraV sysCameraPosition

rtLaunchIndex [0, 0]

Pinhole Camera

rtLaunchDim

slide-19
SLIDE 19

19

Tracing Rays

Group context["sysTopObject"]->set(group);

rtTrace(sysTopObject, ray, prd);

  • ptix::Ray ray = optix::make_Ray(origin, direction, raytype, t_min, t_max);

rtDeclareVariable(rtObject, sysTopObject, , ); PerRayData prd;

slide-20
SLIDE 20

20

Variable Semantics

Access per ray data in other program domains

rtTrace(sysTopObject, ray, time, prd);

rtDeclareVariable(optix::Ray, theRay, rtCurrentRay, ); rtDeclareVariable(PerRayData, thePrd, rtPayload, ); rtDeclareVariable(float, theTime, rtCurrentTime, );

rtCurrentRay rtCurrentTime rtPayload

rtDeclareVariable(float, theDistance, rtIntersectionDistance, );

slide-21
SLIDE 21

21

  • ptixIntro_03
slide-22
SLIDE 22

22

RT_PROGRAM void boundingbox_triangle_indexed(int primitiveIndex, float result[6]) { // uint3 indices = ... ; // vertex indices of the triangle at primitiveIndex // float3 v0, v1, v2 = ... ; // vertex positions const float area = optix::length(optix::cross(v1 - v0, v2 - v0));

  • ptix::Aabb* aabb = (optix::Aabb*) result;

if (0.0f < area && !isinf(area)) { aabb->m_min = fminf(fminf(v0, v1), v2); aabb->m_max = fmaxf(fmaxf(v0, v1), v2); } else { aabb->invalidate(); } }

BoundingBox Program

slide-23
SLIDE 23

23

rtDeclareVariable(optix::Ray, theRay, rtCurrentRay, ); rtDeclareVariable(float3, varNormal, attribute NORMAL, ); RT_PROGRAM void intersection_triangle_indexed(int primitiveIndex) { // uint3 indices = ... ; // vertex indices of the triangle at primitiveIndex // float3 v0, v1, v2 = ... ; // vertex positions float3 n; float t, beta, gamma; if (intersect_triangle(theRay, v0, v1, v2, n, t, beta, gamma)) { if (rtPotentialIntersection(t)) { // float3 n0, n1, n2 = ... ; // vertex normals const float alpha = 1.0f – beta – gamma; varNormal = n0 * alpha + n1 * beta + n2 * gamma; // interpolate shading normal rtReportIntersection(0); } } }

Intersection Program

slide-24
SLIDE 24

24

rtDeclareVariable(PerRayData, thePrd, rtPayload, ); rtDeclareVariable(optix::float3, varNormal, attribute NORMAL, ); RT_PROGRAM void closesthit() { const float3 normal = optix::normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, varNormal)); thePrd.radiance = normal * 0.5f + 0.5f; }

ClosestHit Program

slide-25
SLIDE 25

25

  • ptixIntro_04
slide-26
SLIDE 26

26

Integrator

Unidirectional Path Tracer Throughput

slide-27
SLIDE 27

27

  • ptixIntro_05
slide-28
SLIDE 28

28

radiance ray shadow ray

AnyHit RayGeneration

RT_PROGRAM void anyhit_shadow() { thePrdShadow.visible = false; rtTerminateRay(); }

slide-29
SLIDE 29

29

Next Event Estimation

1spp 1spp 16spp 64spp 256spp 16spp 64spp 256spp

slide-30
SLIDE 30

30

  • ptixIntro_06
slide-31
SLIDE 31

31

Adding more BSDF and Light Types

How much code do you really need?

closest_hit sample BSDF eval BSDF sample light direct lighting? calc state calc radiance closest_hit sample BSDF eval BSDF sample light direct lighting? calc state calc radiance closest_hit sample BSDF eval BSDF sample light direct lighting? calc state calc radiance ...

slide-32
SLIDE 32

32

Buffers of Bindless Callable Program IDs

Implement fixed-function elements as bindless callable programs

closest_hit sample BSDF eval BSDF sample light direct lighting?

light_constant light_env

diffuse_reflection specular_reflection specular_reflection_transmission

calc state calc radiance

light_area

diffuse_reflection (specular_reflection) (specular_reflection_transmission)

... ... ...

sysSampleLight sysSampleBSDF sysEvalBSDF

slide-33
SLIDE 33

33

Lens Shaders

Pinhole Fisheye Spherical

slide-34
SLIDE 34

34

Bindless Callable Program

Declaration of Buffer of IDs and Example

rtBuffer< rtCallableProgramId<return_typename(typename arg0, …, typename argN)> > name; RT_CALLABLE_PROGRAM void lens_shader_pinhole(const float2 pixel, const float2 screen, const float2 sample, float3& origin, float3& direction) { const float2 fragment = pixel + sample; const float2 ndc = (fragment / screen) * 2.0f - 1.0f;

  • rigin = sysCameraPosition;

direction = optix::normalize(sysCameraU * ndc.x + sysCameraV * ndc.y + sysCameraW); }

sysCameraW sysCameraU sysCameraV sysCameraPosition

rtLaunchIndex [0, 0]

rtLaunchDim
slide-35
SLIDE 35

35

Variable Scopes

Organize your parameters

Program Type Search Order ClosestHit AnyHit Program GeometryInstance Material Context BoundingBox Intersection Program GeometryInstance Geometry Context Raygeneration Exception Miss Bindless Callable Program Program Context Visit Program Node

slide-36
SLIDE 36

36

  • ptixIntro_07
slide-37
SLIDE 37

37

slide-38
SLIDE 38

38

Cutout Opacity

Or how to use AnyHit programs

Raygeneration

RT_PROGRAM void anyhit_cutout() { if (getOpacity() < threshold) rtIgnoreIntersection(); } RT_PROGRAM void anyhit_shadow_cutout() { if (getOpacity() < threshold) { rtIgnoreIntersection(); } else { thePrdShadow.visible = false; rtTerminateRay(); } }

slide-39
SLIDE 39

39

WrapMode FilteringMode IndexingMode MaxAnisotropy

Buffer

MipLevelClamp MipLevelBias ReadMode getId() 1D 2D 3D

rtTex*<typename>(id, u, v, …)

MipLevelCount CUBEMAP

TextureSampler

slide-40
SLIDE 40

40

  • ptixIntro_08
slide-41
SLIDE 41

41

rtTransformSetMotionKeys(), rtTransformSetMotionRange(), rtTransformSetMotionBorderMode()

Motion Blur

New functions for the Transform node

Motion in Transform nodes

Two motion key types: A linearly interpolated 3x4 matrix or 16 elements from a Scale- Rotation-Translation (SRT) transformation

slide-42
SLIDE 42

42

rtGeometrySetMotionSteps(), rtGeometrySetMotionRange(), rtGeometrySetMotionBorderMode()

Motion Blur

New functions for the Geometry node

Motion in Geometry Nodes (Morphing)

RT_PROGRAM void boundingbox_motionblur(int prim_index, int motion_index, float result[6]);

New BoundingBox program function signature

slide-43
SLIDE 43

43

Rolling shutters

slide-44
SLIDE 44

44

  • ptixIntro_09
slide-45
SLIDE 45

45

Post-Processing Pipeline

beauty albedo normal tonemapped denoised

Render Tonemap Denoise

slide-46
SLIDE 46

46

PostprocessingStage tonemapper = context->createBuiltinPostProcessingStage("TonemapperSimple"); tonemapper->declareVariable("input_buffer")->set(bufferOutput); // from the renderer tonemapper->declareVariable("output_buffer")->set(bufferTonemapped); tonemapper->declareVariable("exposure")->setFloat(1.0f); tonemapper->declareVariable("gamma")->setFloat(2.2f); PostprocessingStage denoiser = context->createBuiltinPostProcessingStage("DLDenoiser"); denoiser->declareVariable("input_buffer")->set(bufferTonemapped); denoiser->declareVariable("input_albedo_buffer")->set(bufferAlbedo); // optional denoiser->declareVariable("input_normal_buffer")->set(bufferNormal); // optional denoiser->declareVariable("output_buffer")->set(bufferDenoised); CommandList commandList = context->createCommandList(); commandList->appendLaunch(0, w, h); // Launch raygeneration at entry point 0 => Render commandList->appendPostprocessingStage(tonemapper, w, h); commandList->appendPostprocessingStage(denoiser, w, h); commandList->finalize(); commandList->execute(); // Result in bufferDenoised.

Post-Processing Setup

slide-47
SLIDE 47

47

closest_hit ray_gen lens shader integrator

  • utput

any_hit cutout opacity? sample BSDF eval BSDF sample light direct lighting? bounding_box intersection

light_constant

light_env

diffuse_reflection specular_reflection

pinhole fisheye sphere

miss_null miss_constant miss_env

* rectangles are fixed-function code * round rectangles are bindless callable programs

specular_reflection_transmission

calc state calc state calc radiance

light_area

diffuse_reflection (specular_reflection)

(specular_reflection_transmission)

slide-48
SLIDE 48

48

Takeaway

OptiX is a high-level GPU ray casting SDK with a flexible programming model which allows to concentrate on the algorithm during developement State-of-the-art acceleration structures and core features get added or improved with each new version An easily extendable architecture for a global illumination path tracer using OptiX features available in version 5.0.1 has been presented The nine OptiX examples accompanying this tutorial are going to be available on github

slide-49
SLIDE 49

CE8105: Ray Tracing with the NVIDIA OptiX SDK Monday, Mar 26, 4:00 - 5:00pm, LL Pod A S8519: New Features in OptiX Tuesday, Mar 27, 3:30 - 4:20pm, Room 230B

slide-50
SLIDE 50

50

BACKUP SLIDES

slide-51
SLIDE 51

51

m_context = optix::Context::create(); m_context->setEntryPointCount(1); m_context->setRayTypeCount(0); m_context->setStackSize(m_stackSize); m_bufferOutput = m_context->createBuffer(RT_BUFFER_OUTPUT, RT_FORMAT_FLOAT4, m_width, m_height); m_context["sysOutputBuffer"]->set(m_bufferOutput);

  • ptix::Program prgRaygen = m_context->createProgramFromPTXFile(

ptxPath("raygeneration.cu"), "raygeneration"); m_context->setRayGenerationProgram(0, prgRaygen); // per entry point

  • ptix::Program prgException = m_context->createProgramFromPTXFile(

ptxPath("exception.cu"), "exception"); m_context->setExceptionProgram(0, prgException); // per entry point m_context["sysColorBackground"]->setFloat(0.0f, 1.0f, 0.0f); // green m_context->launch(0, m_width, m_height); // ==> uint2 rtLaunchDim const void* data = m_bufferOutput->map(0, RT_BUFFER_MAP_READ); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, (GLsizei) m_width, (GLsizei) m_height, 0, GL_RGBA, GL_FLOAT, data); m_bufferOutput->unmap();

slide-52
SLIDE 52

52

rtBuffer<float4, 2> sysOutputBuffer; // RGBA32F rtDeclareVariable(rtObject, sysTopObject, , ); RT_PROGRAM void raygeneration() { PerRayData prd; prd.radiance = make_float3(0.0f); ... // Camera implementations calculate origin and direction here.

  • ptix::Ray ray = optix::make_Ray(origin, direction, 0, 0.0f, RT_DEFAULT_MAX);

rtTrace(sysTopObject, ray, prd);

sysOutputBuffer[theLaunchIndex] = make_float4(prd.radiance, 1.0f); }

rtTrace

slide-53
SLIDE 53

53

rtDeclareVariable(optix::Ray, theRay, rtCurrentRay, ); rtDeclareVariable(PerRayData, thePrd, rtPayload, ); rtDeclareVariable(float3, sysColorBottom, , ); rtDeclareVariable(float3, sysColorTop, , ); RT_PROGRAM void miss_gradient() { const float t = theRay.direction.y * 0.5f + 0.5f; thePrd.radiance = optix::lerp(sysColorBottom, sysColorTop, t); }

Miss Program

slide-54
SLIDE 54

54

rtDeclareVariable(float3, varGeoNormal, attribute GEO_NORMAL, ); rtDeclareVariable(float3, varNormal, attribute NORMAL, ); rtDeclareVariable(optix::Ray, theRay, rtCurrentRay, ); rtDeclareVariable(PerRayData, thePrd, rtPayload, ); RT_PROGRAM void closesthit() { float3 geoNormal = optix::normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, varGeoNormal)); float3 normal = optix::normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, varNormal)); thePrd.pos = theRay.origin + theRay.direction * theIntersectionDistance; thePrd.flags |= (0.0f <= optix::dot(thePrd.wo, geoNormal)) ? FLAG_FRONTFACE : 0; if ((thePrd.flags & FLAG_FRONTFACE) == 0) { geoNormal = -geoNormal; normal = -normal; } // Lambert sampling implementation: thePrd.radiance = make_float3(0.0f); // No emission, no direct lighting. unitSquareToCosineHemisphere(rng2(thePrd.seed), normal, thePrd.wi, thePrd.pdf); if (thePrd.pdf <= 0.0f || optix::dot(thePrd.wi, geoNormal) <= 0.0f) { thePrd.flags |= FLAG_TERMINATE; return; } MaterialParameter parameters = sysMaterialParameters[parMaterialIndex]; thePrd.f_over_pdf = parameters.albedo * (M_1_PIf * optix::dot(thePrd.wi, normal) / thePrd.pdf); }

slide-55
SLIDE 55

55

rtDeclareVariable(PerRayData_shadow, thePrdShadow, rtPayload, ); RT_PROGRAM void anyhit_shadow() { thePrdShadow.visible = false; rtTerminateRay(); }

slide-56
SLIDE 56

56

RT_FUNCTION void integrator(PerRayData& prd, float3& radiance) { radiance = make_float3(0.0f); float3 throughput = make_float3(1.0f); int depth = 0; // Primary ray is path segment 0. while (depth < sysPathLength) { prd.wo = -prd.wi; prd.flags = 0;

  • ptix::Ray ray = optix::make_Ray(prd.pos, prd.wi, 0, sysSceneEpsilon, RT_DEFAULT_MAX);

rtTrace(sysTopObject, ray, prd); radiance += throughput * prd.radiance; if ((prd.flags & FLAG_TERMINATE) || prd.pdf <= 0.0f || isNull(prd.f_over_pdf)) { break; } throughput *= prd.f_over_pdf; // == f * (fabsf(optix::dot(wi, normal)) / pdf); ++depth; } }

slide-57
SLIDE 57

57

#include <optix.h> #include <optixu/optixu_math_namespace.h> #include "material_parameter.h" #include "per_ray_data.h" RT_CALLABLE_PROGRAM void sample_bsdf_specular_reflection(MaterialParameter const& parameters, State const& state, PerRayData& prd) { prd.wi = optix::reflect(-prd.wo, state.normal); if (optix::dot(prd.wi, state.geoNormal) <= 0.0f) { prd.flags |= FLAG_TERMINATE; return; } prd.f_over_pdf = parameters.albedo; prd.pdf = 1.0f; } RT_CALLABLE_PROGRAM float4 eval_bsdf_specular_reflection(MaterialParameter const& parameters, State const& state, PerRayData const& prd, float3 const& wiL) { return make_float4(0.0f); }

slide-58
SLIDE 58

58

rtDeclareVariable(PerRayData_shadow, thePrdShadow, rtPayload, ); rtBuffer<MaterialParameter> sysMaterialParameters; rtDeclareVariable(int, parMaterialIndex, , ); rtDeclareVariable(optix::float3, varTexCoord, attribute TEXCOORD, ); RT_PROGRAM void anyhit_shadow_cutout() { float opacity = 1.0f; const int id = sysMaterialParameters[parMaterialIndex].cutoutID; // bindless texture ID if (id != RT_TEXTURE_ID_NULL) {

  • pacity = intensity(make_float3(optix::rtTex2D<float4>(id, varTexCoord.x, varTexCoord.y)));

} // Stochastic coutout opacity, think Monte Carlo! if (opacity < 1.0f && opacity <= rng(thePrdShadow.seed)) { rtIgnoreIntersection(); } else { thePrdShadow.visible = false; rtTerminateRay(); } }

slide-59
SLIDE 59

59

  • ptix::Buffer buffer = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_BYTE4, w, h);

buffer->setMipLevelCount(1); void *dst = buffer->map(0, RT_BUFFER_MAP_WRITE_DISCARD); memcpy(dst, texels, w * h * getElementSize(RT_FORMAT_UNSIGNED_BYTE4)); buffer->unmap(0);

  • ptix::TextureSampler sampler = context->createTextureSampler();

sampler->setWrapMode(0, RT_WRAP_REPEAT); sampler->setWrapMode(1, RT_WRAP_REPEAT); sampler->setWrapMode(2, RT_WRAP_REPEAT); sampler->setFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE); sampler->setIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES; sampler->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT); sampler->setMaxAnisotropy(1.0f); sampler->setBuffer(buffer);

TextureSampler

slide-60
SLIDE 60