但是硬件光追就麻烦了,首先Closet Hit Shader就是负责计算求交后着色的,所以它本质上就是硬件光追的BSDF Shader。如果场景中有很多不同BSDF的材质实例,意味着管线中要绑很多个对应的Closet Hit Shader。那么当管线求交得到最近点后,它怎么知道要放到哪个Closet Hit Shader去计算呢?以及,它怎么把自己的材质参数(例如base color、roughness等)传入对应的Shader呢?这里就要请出我们的SBT了。SBT记录了管线中所拥有的每一个物体所对应的shader项,以及它要传入的材质参数,这样管线就可以在求交得到最近点后,查阅SBT得到需要调用哪个Shader,以及Shader参数是哪些。
#include <optix_device.h>
#include "LaunchParams.h"
using namespace osc;
namespace osc {
extern "C" __constant__ LaunchParams optixLaunchParams;
extern "C" __global__ void __closesthit__radiance()
{ /*! for this simple example, this will remain empty */ }
extern "C" __global__ void __anyhit__radiance()
{ /*! for this simple example, this will remain empty */ }
extern "C" __global__ void __miss__radiance()
{ /*! for this simple example, this will remain empty */ }
extern "C" __global__ void __raygen__renderFrame()
{
if (optixLaunchParams.frameID == 0 &&
optixGetLaunchIndex().x == 0 &&
optixGetLaunchIndex().y == 0) {
// we could of course also have used optixGetLaunchDims to query
// the launch size, but accessing the optixLaunchParams here
// makes sure they're not getting optimized away (because
// otherwise they'd not get used)
printf("############################################\n");
printf("Hello world from OptiX 7 raygen program!\n(within a %ix%i-sized launch)\n",
optixLaunchParams.fbSize.x,
optixLaunchParams.fbSize.y);
printf("############################################\n");
}
const int ix = optixGetLaunchIndex().x;
const int iy = optixGetLaunchIndex().y;
const int r = (ix % 256);
const int g = (iy % 256);
const int b = ((ix+iy) % 256);
const uint32_t rgba = 0xff000000
| (r<<0) | (g<<8) | (b<<16);
const uint32_t fbIndex = ix+iy*optixLaunchParams.fbSize.x;
optixLaunchParams.colorBuffer[fbIndex] = rgba;
}
}
#include "CUDABuffer.h"
#include "LaunchParams.h"
/*! \namespace osc - Optix Siggraph Course */
namespace osc {
/*! a sample OptiX-7 renderer that demonstrates how to set up
context, module, programs, pipeline, SBT, etc, and perform a
valid launch that renders some pixel (using a simple test
pattern, in this case */
class SampleRenderer
{
// ------------------------------------------------------------------
// publicly accessible interface
// ------------------------------------------------------------------
public:
/*! constructor - performs all setup, including initializing
optix, creates module, pipeline, programs, SBT, etc. */
SampleRenderer();
/*! render one frame */
void render();
/*! resize frame buffer to given resolution */
void resize(const vec2i &newSize);
/*! download the rendered color buffer */
void downloadPixels(uint32_t h_pixels[]);
protected:
// ------------------------------------------------------------------
// internal helper functions
// ------------------------------------------------------------------
/*! helper function that initializes optix and checks for errors */
void initOptix();
/*! creates and configures a optix device context (in this simple
example, only for the primary GPU device) */
void createContext();
/*! creates the module that contains all the programs we are going
to use. in this simple example, we use a single module from a
single .cu file, using a single embedded ptx string */
void createModule();
/*! does all setup for the raygen program(s) we are going to use */
void createRaygenPrograms();
/*! does all setup for the miss program(s) we are going to use */
void createMissPrograms();
/*! does all setup for the hitgroup program(s) we are going to use */
void createHitgroupPrograms();
/*! assembles the full pipeline of all programs */
void createPipeline();
/*! constructs the shader binding table */
void buildSBT();
protected:
/*! @{ CUDA device context and stream that optix pipeline will run
on, as well as device properties for this device */
CUcontext cudaContext;
CUstream stream;
cudaDeviceProp deviceProps;
/*! @} */
//! the optix context that our pipeline will run in.
OptixDeviceContext optixContext;
/*! @{ the pipeline we're building */
OptixPipeline pipeline;
OptixPipelineCompileOptions pipelineCompileOptions = {};
OptixPipelineLinkOptions pipelineLinkOptions = {};
/*! @} */
/*! @{ the module that contains out device programs */
OptixModule module;
OptixModuleCompileOptions moduleCompileOptions = {};
/* @} */
/*! vector of all our program(group)s, and the SBT built around
them */
std::vector<OptixProgramGroup> raygenPGs;
CUDABuffer raygenRecordsBuffer;
std::vector<OptixProgramGroup> missPGs;
CUDABuffer missRecordsBuffer;
std::vector<OptixProgramGroup> hitgroupPGs;
CUDABuffer hitgroupRecordsBuffer;
OptixShaderBindingTable sbt = {};
/*! @{ our launch parameters, on the host, and the buffer to store
them on the device */
LaunchParams launchParams;
CUDABuffer launchParamsBuffer;
/*! @} */
CUDABuffer colorBuffer;
};
}
#include "SampleRenderer.h"
// this include may only appear in a single source file:
#include <optix_function_table_definition.h>
/*! \namespace osc - Optix Siggraph Course */
namespace osc {
extern "C" char embedded_ptx_code[];
/*! SBT record for a raygen program */
struct __align__( OPTIX_SBT_RECORD_ALIGNMENT ) RaygenRecord
{
__align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE];
// just a dummy value - later examples will use more interesting
// data here
void *data;
};
/*! SBT record for a miss program */
struct __align__( OPTIX_SBT_RECORD_ALIGNMENT ) MissRecord
{
__align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE];
// just a dummy value - later examples will use more interesting
// data here
void *data;
};
/*! SBT record for a hitgroup program */
struct __align__( OPTIX_SBT_RECORD_ALIGNMENT ) HitgroupRecord
{
__align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE];
// just a dummy value - later examples will use more interesting
// data here
int objectID;
};
void SampleRenderer::createRaygenPrograms()
{
// we do a single ray gen program in this example:
raygenPGs.resize(1);
OptixProgramGroupOptions pgOptions = {};
OptixProgramGroupDesc pgDesc = {};
pgDesc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN;
pgDesc.raygen.module = module;
pgDesc.raygen.entryFunctionName = "__raygen__renderFrame";
// OptixProgramGroup raypg;
char log[2048];
size_t sizeof_log = sizeof( log );
OPTIX_CHECK(optixProgramGroupCreate(optixContext,
&pgDesc,
1,
&pgOptions,
log,&sizeof_log,
&raygenPGs[0]
));
if (sizeof_log > 1) PRINT(log);
}
/*! does all setup for the miss program(s) we are going to use */
void SampleRenderer::createMissPrograms()
{
// we do a single ray gen program in this example:
missPGs.resize(1);
OptixProgramGroupOptions pgOptions = {};
OptixProgramGroupDesc pgDesc = {};
pgDesc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS;
pgDesc.miss.module = module;
pgDesc.miss.entryFunctionName = "__miss__radiance";
// OptixProgramGroup raypg;
char log[2048];
size_t sizeof_log = sizeof( log );
OPTIX_CHECK(optixProgramGroupCreate(optixContext,
&pgDesc,
1,
&pgOptions,
log,&sizeof_log,
&missPGs[0]
));
if (sizeof_log > 1) PRINT(log);
}
/*! does all setup for the hitgroup program(s) we are going to use */
void SampleRenderer::createHitgroupPrograms()
{
// for this simple example, we set up a single hit group
hitgroupPGs.resize(1);
OptixProgramGroupOptions pgOptions = {};
OptixProgramGroupDesc pgDesc = {};
pgDesc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
pgDesc.hitgroup.moduleCH = module;
pgDesc.hitgroup.entryFunctionNameCH = "__closesthit__radiance";
pgDesc.hitgroup.moduleAH = module;
pgDesc.hitgroup.entryFunctionNameAH = "__anyhit__radiance";
char log[2048];
size_t sizeof_log = sizeof( log );
OPTIX_CHECK(optixProgramGroupCreate(optixContext,
&pgDesc,
1,
&pgOptions,
log,&sizeof_log,
&hitgroupPGs[0]
));
if (sizeof_log > 1) PRINT(log);
}
void SampleRenderer::createPipeline()
{
std::vector<OptixProgramGroup> programGroups;
for (auto pg : raygenPGs)
programGroups.push_back(pg);
for (auto pg : missPGs)
programGroups.push_back(pg);
for (auto pg : hitgroupPGs)
programGroups.push_back(pg);
char log[2048];
size_t sizeof_log = sizeof( log );
OPTIX_CHECK(optixPipelineCreate(optixContext,
&pipelineCompileOptions,
&pipelineLinkOptions,
programGroups.data(),
(int)programGroups.size(),
log,&sizeof_log,
&pipeline
));
if (sizeof_log > 1) PRINT(log);
OPTIX_CHECK(optixPipelineSetStackSize
(/* [in] The pipeline to configure the stack size for */
pipeline,
/* [in] The direct stack size requirement for direct
callables invoked from IS or AH. */
2*1024,
/* [in] The direct stack size requirement for direct
callables invoked from RG, MS, or CH. */
2*1024,
/* [in] The continuation stack requirement. */
2*1024,
/* [in] The maximum depth of a traversable graph
passed to trace. */
1));
if (sizeof_log > 1) PRINT(log);
}
void SampleRenderer::render()
{
// sanity check: make sure we launch only after first resize is
// already done:
if (launchParams.fbSize.x == 0) return;
launchParamsBuffer.upload(&launchParams,1);
launchParams.frameID++;
OPTIX_CHECK(optixLaunch(/*! pipeline we're launching launch: */
pipeline,stream,
/*! parameters and SBT */
launchParamsBuffer.d_pointer(),
launchParamsBuffer.sizeInBytes,
&sbt,
/*! dimensions of the launch: */
launchParams.fbSize.x,
launchParams.fbSize.y,
1
));
// sync - make sure the frame is rendered before we download and
// display (obviously, for a high-performance application you
// want to use streams and double-buffering, but for this simple
// example, this will have to do)
CUDA_SYNC_CHECK();
}
/*! resize frame buffer to given resolution */
void SampleRenderer::resize(const vec2i &newSize)
{
// if window minimized
if (newSize.x == 0 | newSize.y == 0) return;
// resize our cuda frame buffer
colorBuffer.resize(newSize.x*newSize.y*sizeof(uint32_t));
// update the launch parameters that we'll pass to the optix
// launch:
launchParams.fbSize = newSize;
launchParams.colorBuffer = (uint32_t*)colorBuffer.d_ptr;
}
/*! download the rendered color buffer */
void SampleRenderer::downloadPixels(uint32_t h_pixels[])
{
colorBuffer.download(h_pixels,
launchParams.fbSize.x*launchParams.fbSize.y);
}
Comments | 3 条评论
博主 Scofield
大佬,我使用那段python代码进行转换,出现RuntimeWarning: line buffering (buffering=1) isn’t supported in binary mode, the default buffer size will be used这是为什么呢?求解答!
博主 pladmin
@Scofield 感觉这个是python的包或者底层的bug,俺没遇到过,可以去stackoverflow网站看看…我觉得重装下python会好一些。
博主 dingdang
可以直接用cuda内的工具bin2c 转.c
bin2c -c –padd 0 –type char –name embedded_ptx_code E:\program\devicePrograms.cu.ptx > E:\program\devicePrograms.c