CubeSampler from Cubebuffer

Hello Optix People,
at the moment i am trying to use 6 textures as a cubemap.

From the sutil a copied the PPMLoader and called function like this:

cubeMapBuffer = loadPPMCubeBuffer(context_, { dir + "xPos.ppm", dir + "xNeg.ppm", dir + "yPos.ppm", dir + "yNeg.ppm", dir + "zPos.ppm", dir + "zNeg.ppm"});

If i try to use these textures in a TextureSampler like this

cubeSampler = context_->createTextureSampler();

and in the shader:

#include <optix.h>
#include <optix_world.h>
#include "prd.h"

rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
rtDeclareVariable(optix::Ray, ray, rtCurrentRay,);
rtTextureSampler<float4, 3> envmap;

RT_PROGRAM void envmap_miss()
  float3 rayD = ray.direction;
  prd_radiance.result = make_float3(tex3D(envmap, rayD.x, rayD.y, rayD.z) );

i only get black values. The loading of the images is functioning (no errors and there are values in the buffer).
What am i doing wrong?

[using optix 5.0.1 & cuda 9.1 (must use it) & visual studio 15.0 (must use it)]

tex3D is a legacy function for OptiX which works only with real 3D texture samplers. But loadPPMCubeBuffer() is uploading a buffer with the RT_BUFFER_CUBEMAP flag which makes this texture sampler a cubemap.

I recommend to not use any of the legacy tex1D, tex2D, and tex3D functions which work with texture samplers directly anymore. They pre-date cubemap support in OptiX. There is none provided for cubemaps by OptiX anyway (resp. the parser doesn’t understand other CUDA texture functions), so the following lookup mechanism is the only way.

Instead always use bindless texture IDs and the texture lookup functions rtTex*(id, x, …) defined inside the OptiX header optix_device.h. They wrap all texture lookup functions supported by CUDA.

You need something like this in your code to make that work:
Don’t bind the texture sampler to an “envmap” variable like in your code above, but do this instead:


Also note that you should set all other texture sampler parameters! For example the default wrap modes won’t work nicely for cubemaps. You would need to set them like this

cubeSampler->setWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
cubeSampler->setWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);

because cubemaps must not filter outside their faces or you get seams between the cube faces on your skybox.

Then your miss program would look like this:

rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
rtDeclareVariable(int, envmapID, , ); // Bindless texture ID.

RT_PROGRAM void miss()
  prd_radiance.result = optix::make_float3(optix::rtTexCubemap<float4>(envmapID, ray.direction.x, ray.direction.y, ray.direction.z));

For some more elaborate code which can load any texture file format supported by the image library DevIL, please work through the OptiX introduction tutorial examples. Link in this sticky post:

optixIntro_07 adds texture support and provides some simple classes and functions which load images by using DevIL and converts them to CUDA compatible formats automatically.
That also supports loading and creating cubemaps, most often found in DirectX *.dds files.
Follow the code path inside the Texture::createSampler() with “isCubemap”.
Texture::getId() will return the bindless texture ID when the sampler had been created.

As a bonus, the bindless texture ID method also allows to check if a texture is available on device side at runtime by comparing the bindless texture ID with RT_TEXTURE_ID_NULL.
Using texture samplers directly does not allow that! They must always be initialized when accessed anywhere on device side or the OptiX validation would fail.

Thank you, it works now. I also replaced the PPMLoader with a PNG loader now :)