渲染 Filter Implementation
Based on maxon::FilterContextInterface , maxon::FilterImageInterface and maxon::FilterInterface one can implement custom render filters.
A filter context is the central class to create queues, images and filters. A real-world implementation would initialize a library or a framework such as CUDA or OpenCL.
// This example shows the declaration of a FilterContext implementation.// This example shows a simple implementation of FilterContextInterface.
// Create the filter of type 'filterType'. // In a real world example the context would create some internal object and provide the FilterRef with the object, for instance. maxon::FilterRef filter = maxon::FilterClasses::Get (filterType. Get ()).Create() iferr_return ; return filter; } maxon::Result<maxon::FilterImageRef> FilterContextImpl::CreateImage( const maxon::DataDictionary& imageDesc) { iferr_scope ;
// Create an image using the imageDesc DataDictionary maxon::FilterImageRef image = maxon::FilterImageClasses::EXAMPLEIMAGE().Create() iferr_return ;
// Get Image parameters... const maxon::UInt32 width = imageDesc.Get(maxon::FilterImageDescriptionParameters::WIDTH) iferr_return ; const maxon::UInt32 height = imageDesc.Get(maxon::FilterImageDescriptionParameters::HEIGHT) iferr_return ;
// ... and do sanity checking! CheckState (width > 0 && height > 0, "Invalid Image Size!" _s);
// Get the actual implementation of our FilterImage FilterImageImpl* imageImpl = FilterImageImpl::GetOrNull(image); CheckState (imageImpl); imageImpl->Init(width, height) iferr_return ; return image; } maxon::Result<maxon::FilterCommandQueueRef> FilterContextImpl::CreateCommandQueue() { // A command queue is optional and not needed in this case. return maxon::FunctionNotImplementedError( MAXON_SOURCE_LOCATION , "No command queue support" _s); } maxon::Result<void> FilterContextImpl::ExecuteCommandQueue(maxon::FilterCommandQueueRef commandQueue) { // A command queue is optional and not supported in this case. return maxon::FunctionNotImplementedError( MAXON_SOURCE_LOCATION , "No command queue support" _s); }
// register implementation MAXON_COMPONENT_CLASS_REGISTER (FilterContextImpl, maxon::FilterContextClasses::EXAMPLECONTEXT);
A filter image stores the given image data. Internally it might represent a data structure related to the underlying library or framework.
// This example shows the declaration of a FilterImage implementation. namespace FilterImageClasses { MAXON_DECLARATION (maxon::FilterImageClasses::EntryType, EXAMPLEIMAGE, "net.maxonexample.render_filter.image.example" ); } // FilterImageClasses// This example shows a simple implementation of FilterImageInterface wrapping around a maxon::BaseArray. class FilterImageImpl : public maxon::Component <FilterImageImpl, maxon::FilterImageInterface> { MAXON_COMPONENT (); public : MAXON_METHOD maxon::Result<void> WriteToBuffer( maxon::BaseArray<maxon::Vector4d32> & buffer); MAXON_METHOD maxon::Result<void> ReadFromCPUMemory( const maxon::BaseArray<maxon::Vector4d32> & data); MAXON_METHOD maxon::Result<void> WriteToFile( const maxon::Url & url); maxon::Result<void> Init( const maxon::UInt32 width, const maxon::UInt32 height); const maxon::BaseArray<maxon::Vector4d32> & GetImageData() const ; maxon::BaseArray<maxon::Vector4d32> & GetImageData(); private : // Here, the FilterImage just holds a BaseArray of Vector Data to represent and image. maxon::BaseArray<maxon::Vector4d32> _imgData; }; maxon::Result<void> FilterImageImpl::WriteToBuffer( maxon::BaseArray<maxon::Vector4d32> & buffer) { return buffer. CopyFrom (_imgData); } maxon::Result<void> FilterImageImpl::ReadFromCPUMemory( const maxon::BaseArray<maxon::Vector4d32> & data) { return _imgData.CopyFrom(data); } maxon::Result<void> FilterImageImpl::WriteToFile( const maxon::Url & url) { return maxon::FunctionNotImplementedError( MAXON_SOURCE_LOCATION , "Function not implemented" _s); } maxon::Result<void> FilterImageImpl::Init( const maxon::UInt32 width, const maxon::UInt32 height) { return _imgData.Resize(width * height); } const maxon::BaseArray<maxon::Vector4d32> & FilterImageImpl::GetImageData() const { return _imgData; } maxon::BaseArray<maxon::Vector4d32> & FilterImageImpl::GetImageData() { return _imgData; }
// register implementation MAXON_COMPONENT_CLASS_REGISTER (FilterImageImpl, maxon::FilterImageClasses::EXAMPLEIMAGE);
The actual filter is based on maxon::FilterInterface . It can store various parameters and operates on the given data set.
// This example shows the declaration of a Filter implementation. namespace FilterClasses { MAXON_DECLARATION (FilterClasses::EntryType, EXAMPLEINVERT, "net.maxonexample.render_filter.filter.example.invert" ); MAXON_DECLARATION (FilterClasses::EntryType, EXAMPLEPOWER, "net.maxonexample.render_filter.filter.example.power" ); } // FilterClasses// This example shows two simple implementations of FilterInterface. Both share functionality using a ComponentRoot.
//------------------------------------------------------------------------------------- // A custom ComponentRoot that provides a base implementation for all our filters //------------------------------------------------------------------------------------- class FilterComponentRoot : public maxon::ComponentRoot { public : // shared implementation of Execute() maxon::Result<void> Execute( const maxon::FilterImageRef& input, maxon::FilterImageRef output); protected : virtual maxon::Result<void> ExecuteImpl( const maxon::BaseArray<maxon::Vector4d32> & inputData, maxon::BaseArray<maxon::Vector4d32> & outputData) = 0; }; maxon::Result<void> FilterComponentRoot::Execute( const maxon::FilterImageRef& input, maxon::FilterImageRef output) { iferr_scope ;
// Get the actual implementation of our FilterImage FilterImageImpl* inputImpl = FilterImageImpl::GetOrNull(input); FilterImageImpl* outputImpl = FilterImageImpl::GetOrNull(output); CheckState (inputImpl && outputImpl); const maxon::BaseArray<maxon::Vector4d32> & inputData = inputImpl->GetImageData(); maxon::BaseArray<maxon::Vector4d32> & outputData = outputImpl->GetImageData(); CheckState (inputData. GetCount () == outputData. GetCount (), "Input and Output image sizes do not match!" _s); ExecuteImpl(inputData, outputData) iferr_return ; return maxon::OK ; }
//------------------------------------------------------------------------------------- // Filter Examples // Represents a filter that can be executed or attached to a filter command queue. // Use the Set() function to apply settings. //------------------------------------------------------------------------------------- class InvertFilterImpl : public maxon::ComponentWithBase <InvertFilterImpl, FilterComponentRoot, maxon::FilterInterface> { MAXON_COMPONENT (); public : MAXON_METHOD maxon::Result<void> Set( const maxon::InternedId & parameter, const maxon::Data & data); MAXON_METHOD maxon::Result<void> SetProgressMonitor( const maxon::FilterProgressMonitorFunction progressMonitor, void * userPtr); private : virtual maxon::Result<void> ExecuteImpl( const maxon::BaseArray<maxon::Vector4d32> & inputData, maxon::BaseArray<maxon::Vector4d32> & outputData) override ; maxon::Bool _everyPixel = true ; }; class PowerFilterImpl : public maxon::ComponentWithBase <PowerFilterImpl, FilterComponentRoot, maxon::FilterInterface> { MAXON_COMPONENT (); public : MAXON_METHOD maxon::Result<void> Set( const maxon::InternedId & parameter, const maxon::Data & data); MAXON_METHOD maxon::Result<void> SetProgressMonitor( const maxon::FilterProgressMonitorFunction progressMonitor, void * userPtr); private : virtual maxon::Result<void> ExecuteImpl( const maxon::BaseArray<maxon::Vector4d32> & inputData, maxon::BaseArray<maxon::Vector4d32> & outputData) override ; maxon::Float32 _exponent = 1.0f; }; maxon::Result<void> InvertFilterImpl::Set( const maxon::InternedId & parameter, const maxon::Data & data) { // Switch on the parameter ID switch ( ID_SWITCH (parameter)) { case ID_CASE (maxonexample::FilterExampleParameter::EVERYPIXEL): { _everyPixel = data. GetOrNull < maxon::Bool >(); break ; } } return maxon::OK ; } maxon::Result<void> InvertFilterImpl::SetProgressMonitor( const maxon::FilterProgressMonitorFunction progressMonitor, void * userPtr) { iferr_scope ; return maxon::OK ; } maxon::Result<void> InvertFilterImpl::ExecuteImpl( const maxon::BaseArray<maxon::Vector4d32> & inputData, maxon::BaseArray<maxon::Vector4d32> & outputData) { for ( maxon::UInt32 i = 0; i < outputData. GetCount (); ++i) { const maxon::Bool skip = _everyPixel == false && i % 2 == 0; outputData[i] = skip ? inputData[i] : maxon::Vector4d32 (1.0f) - inputData[i]; } return maxon::OK ; } maxon::Result<void> PowerFilterImpl::Set( const maxon::InternedId & parameter, const maxon::Data & data) { // Switch on the parameter ID switch ( ID_SWITCH (parameter)) { case ID_CASE (maxonexample::FilterExampleParameter::EXPONENT): { _exponent = data. GetOrNull < maxon::Float32 >(); break ; } } return maxon::OK ; } maxon::Result<void> PowerFilterImpl::SetProgressMonitor( const maxon::FilterProgressMonitorFunction progressMonitor, void * userPtr) { iferr_scope ; return maxon::OK ; } maxon::Result<void> PowerFilterImpl::ExecuteImpl( const maxon::BaseArray<maxon::Vector4d32> & inputData, maxon::BaseArray<maxon::Vector4d32> & outputData) { for ( maxon::UInt32 i = 0; i < outputData. GetCount (); ++i) { const maxon::Vector4d32 & input = inputData[i]; maxon::Vector4d32 & output = outputData[i]; for ( maxon::UInt32 c = 0; c < 4; ++c) { output[c] = maxon::Pow (input[c], _exponent); } } return maxon::OK ; }
// register implementations MAXON_COMPONENT_CLASS_REGISTER (InvertFilterImpl, maxon::FilterClasses::EXAMPLEINVERT); MAXON_COMPONENT_CLASS_REGISTER (PowerFilterImpl, maxon::FilterClasses::EXAMPLEPOWER);
Custom filter can be used as presented:
// Create example context maxon::FilterContextRef filterContext = maxon::FilterContextClasses::EXAMPLECONTEXT().Create() iferr_return ; filterContext.Init() iferr_return ;// Create filter maxon::FilterRef filterInvert = filterContext.CreateFilter(maxon::FilterClasses::EXAMPLEINVERT.GetId()) iferr_return ; filterInvert.Set(maxonexample::FilterExampleParameter::EVERYPIXEL, maxon::Data ( false )) iferr_return ; maxon::FilterRef filterPower = filterContext.CreateFilter(maxon::FilterClasses::EXAMPLEPOWER.GetId()) iferr_return ; filterPower.Set(maxonexample::FilterExampleParameter::EXPONENT, maxon::Data (0.42f)) iferr_return ;
// Create images maxon::DataDictionary imgDesc; imgDesc.Set(maxon::FilterImageDescriptionParameters::WIDTH, static_cast< maxon::UInt32 > (width)) iferr_return ; imgDesc.Set(maxon::FilterImageDescriptionParameters::HEIGHT, static_cast< maxon::UInt32 > (height)) iferr_return ; maxon::FilterImageRef input = filterContext.CreateImage(imgDesc) iferr_return ; maxon::FilterImageRef output = filterContext.CreateImage(imgDesc) iferr_return ;
// Load image data input.ReadFromCPUMemory(bufferColor) iferr_return ;
// Execute the filters filterInvert.Execute(input, output) iferr_return ; filterPower.Execute(output, input) iferr_return ;
// Get result image input.WriteToBuffer(bufferFiltered) iferr_return ;