Hello,
this seems to be an old topic, and I have found several search results for this, but none really helped. I'm trying to sample a shader from within ObjectData::GetVirtualObjects()
.
It works fine with shaders that are calculated in UV space (e.g. Bitmap Shader, and most of the "Surface" shaders, like Galaxy, Planet, Tiles, Sunburst, etc...), but it does not seem to work with shaders that need a VolumeData (e.g. Surface/Earth, Wood, Marble, etc...). The Noise shader works, regardless of what space I set it to, but as the result does not change when I set it to "World" or "UV", I suspect it's only calculating in UV space.
I tried making up a mock VolumeData
, but it does not work yet. What am I missing? Is this the preferred way of doing it anyway?
Here is the code:
// Prepare InitRenderStruct
InitRenderStruct irs;
irs.doc = doc;
irs.document_colorprofile = DOCUMENT_COLORPROFILE_SRGB;
irs.flags = INITRENDERFLAG::TEXTURES;
irs.time = doc->GetTime();
// Inititalize shader
if (shader->InitRender(irs) != INITRENDERRESULT::OK)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Could not initialize shader!"_s);
const Float gridWidthI = Inverse((Float)gridWidth);
const Float gridHeightI = Inverse((Float)gridHeight);
// Create an array with as many ChannelDatas as we have threads available
maxon::BaseArray<ChannelData> channelData;
channelData.Resize(GeGetCurrentThreadCount(), maxon::COLLECTION_RESIZE_FLAGS::FIT_TO_SIZE) iferr_return;
const Float time = doc->GetTime().Get();
// Prepare ChannelDatas, and VolumeDatas for each thread
auto shaderInit = [&channelData, &generationParameters, &time] (maxon::ParallelFor::BreakContext& context) -> maxon::Result<void>
{
const Int threadIndex = context.GetLocalThreadIndex();
// Create mock ChannelData
ChannelData &channelDataRef = channelData[threadIndex];
channelDataRef.n = Vector(0.0, 1.0, 0.0);
channelDataRef.d = Vector(0.001);
channelDataRef.t = time;
channelDataRef.texflag = 0;
channelDataRef.off = 0.0;
channelDataRef.scale = 0.01;
// Create mock VolumeData
VolumeData *volumeData = VolumeData::Alloc();
if (!volumeData)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Could not allocate VolumeData for shader sampling!"_s);
channelDataRef.vd = volumeData;
TexData *texData = TexData::Alloc();
if (!texData)
return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION, "Could not allocate TexData for shader sampling!"_s);
texData->m = generationParameters.parentGeneratorMg;
texData->im = generationParameters.parentGeneratorMgI;
texData->Init();
volumeData->tex = texData;
volumeData->orign = channelDataRef.n;
volumeData->bumpn = channelDataRef.n;
volumeData->dispn = channelDataRef.n;
volumeData->n = channelDataRef.n;
volumeData->time = time;
volumeData->delta = channelDataRef.d;
return maxon::OK;
};
// Sample the shader
auto shaderWorker = [&gridRef, &shader, &channelData, &generationParameters, &thread, gridWidth, gridWidthI, gridHeightI] (Int y, maxon::ParallelFor::BreakContext& context) -> maxon::Result<void>
{
const Int threadIndex = context.GetLocalThreadIndex();
ChannelData &sampleCd = channelData[threadIndex];
for (Int x = 0; x < gridWidth; ++x)
{
sampleCd.p = Vector((Float)x * gridWidthI, (Float)y * gridHeightI, 0.0);
if (sampleCd.vd)
sampleCd.vd->p = Vector(x, y, 0.0);
Vector sampledColor = shader->Sample(&sampleCd).GetAverage();
/*
do something with sampledColor...
*/
}
return maxon::OK;
};
// Free the allocated structures
auto shaderFinalize = [&channelData] (maxon::ParallelFor::BreakContext& context)
{
for (maxon::BaseArray<ChannelData>::Iterator cdIt = channelData.Begin(); cdIt != channelData.End(); ++cdIt)
{
ChannelData &cd = *cdIt;
// TexData::Free(cd.vd->tex):
VolumeData::Free(cd.vd);
}
};
maxon::ParallelFor::Dynamic<maxon::ParallelFor::BreakContext>(0, gridHeight, shaderInit, shaderWorker, shaderFinalize) iferr_return;
shader->FreeRender();
Thanks for any help!
Cheers,
Frank
P.S.: By the way, using this on an "Effects -> Spectral" shader crashes Cinema.