From 840330064c9b5895851ceddc7d52cc3701f44e4b Mon Sep 17 00:00:00 2001 From: Ben Heasly <benjamin.heasly@gmail.com> Date: Thu, 9 Feb 2017 09:22:01 -0500 Subject: [PATCH] write and render factoid scene files --- .../Mitsuba/rtbRenderMitsubaFactoids.m | 76 +++++++++++ .../Mitsuba/rtbWriteMitsubaFactoidScene.m | 128 ++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 BatchRenderer/Renderers/Mitsuba/rtbRenderMitsubaFactoids.m create mode 100644 BatchRenderer/Renderers/Mitsuba/rtbWriteMitsubaFactoidScene.m diff --git a/BatchRenderer/Renderers/Mitsuba/rtbRenderMitsubaFactoids.m b/BatchRenderer/Renderers/Mitsuba/rtbRenderMitsubaFactoids.m new file mode 100644 index 0000000..283a1af --- /dev/null +++ b/BatchRenderer/Renderers/Mitsuba/rtbRenderMitsubaFactoids.m @@ -0,0 +1,76 @@ +function [factoids, exrOutput] = rtbRenderMitsubaFactoids(sceneFile, varargin) +% Obtain ground truth "factoids" about a Mitsuba scene. +% +% [factoids, exrOutput] = rtbRenderMitsubaFactoids(sceneFile) invokes +% Mitsuba to obtain ground truth scene "factoids". Returns a struct array +% of ground truth images, with one field per ground truth factoid. +% +% The given sceneFile must specify a "multichannel" integrator with one or +% more nested "field" integrators. You can create such scenes with +% rtbWriteMitsubaFactoidScene(). +% +% rtbRenderMitsubaFactoids( ... 'mitsuba', mitsuba) specify a struct of +% info about the installed Mitsuba renderer. For some factoids, this must +% be a version of Mistuba compiled for RGB rendering, not spectral +% rendering. The default is taken from getpref('Mitsuba'). +% +% rtbRenderMitsubaFactoids(... 'hints', hints) +% Specify a struct of RenderToolbox options. If hints is omitted, values +% are taken from rtbDefaultHints(). +% +%%% RenderToolbox4 Copyright (c) 2012-2017 The RenderToolbox Team. +%%% About Us://github.com/RenderToolbox/RenderToolbox4/wiki/About-Us +%%% RenderToolbox4 is released under the MIT License. See LICENSE file. + +parser = inputParser(); +parser.addRequired('sceneFile', @ischar); +parser.addParameter('mitsuba', [], @(m) isempty(m) || isstruct(m)); +parser.addParameter('hints', rtbDefaultHints(), @isstruct); +parser.parse(sceneFile, varargin{:}); +sceneFile = parser.Results.sceneFile; +mitsuba = parser.Results.mitsuba; +hints = rtbDefaultHints(parser.Results.hints); + +if isempty(mitsuba) + % modify default mitsuba config to look for rgb + mitsuba = getpref('Mitsuba'); + mitsuba.dockerImage = 'ninjaben/mitsuba-rgb'; + mitsuba.kubernetesPodSelector = 'app=mitsuba-spectral'; + if ismac() + mitsuba.app = '/Applications/Mitsuba-RGB.app'; + else + mitsuba.executable = 'mitusba-rgb'; + end +end + + +%% Render the factoid scene.renderer = RtbMitsubaRenderer(hints); +renderer = RtbMitsubaRenderer(hints); +renderer.mitsuba = mitsuba; + +[~, ~, exrOutput] = renderer.renderToExr(sceneFile); +[sliceInfo, data] = ReadMultichannelEXR(exrOutput); + + +%% Group data slices by factoid name. +factoids = struct(); +factoidSize = size(data); +for ii = 1:numel(sliceInfo) + % factoid channels have names like albedo.R, albedo.G, albedo.B + split = find(sliceInfo(ii).name == '.'); + factoidName = sliceInfo(ii).name(1:split-1); + channelName = sliceInfo(ii).name(split+1:end); + + % initialize factoid output with data array and channel names + if ~isfield(factoids, factoidName) + factoids.(factoidName).data = ... + zeros(factoidSize(1), factoidSize(2), 0); + factoids.(factoidName).channels = {}; + end + + % insert data and channel name into output for this factoid + slice = data(:,:,ii); + factoids.(factoidName).data(:,:,end+1) = slice; + factoids.(factoidName).channels{end+1} = channelName; +end + diff --git a/BatchRenderer/Renderers/Mitsuba/rtbWriteMitsubaFactoidScene.m b/BatchRenderer/Renderers/Mitsuba/rtbWriteMitsubaFactoidScene.m new file mode 100644 index 0000000..aee2c71 --- /dev/null +++ b/BatchRenderer/Renderers/Mitsuba/rtbWriteMitsubaFactoidScene.m @@ -0,0 +1,128 @@ +function factoidFile = rtbWriteMitsubaFactoidScene(originalFile, varargin) +% Convert the given scene to get factoids instead of ray tracing. +% +% factoidFile = rtbWriteMitsubaFactoidScene(originalFile) copies and +% modifies the given originalFile so that it will produce Mitsuba ground +% truth "factoids" instead of ray tracing data. Returns a new Mitsuba +% scene file based on the given originalFile. +% +% The returned sceneFile woill specify a "multichannel" integrator with one +% or more nested "field" integrators. You can pass this file to +% rtbRenderMitsubaFactoids() to obtain the factoid data. +% +% rtbWriteMitsubaFactoidScene( ... 'factoids', factoids) specify a cell +% array of ground truth factoid names to be obtained. The default includes +% all available factoids: +% - 'position' - absolute position of the object under each pixel +% - 'relPosition' - camera-relative position of the object under each pixel +% - 'distance' - distance to camera of the object under each pixel +% - 'geoNormal' - surface normal at the surface under each pixel +% - 'shNormal' - surface normal at the surface under each pixel, interpolated for shading +% - 'uv' - texture mapping UV coordinates at the surface under each pixel +% - 'albedo' - diffuse reflectance of the object under each pixel +% - 'shapeIndex' - integer identifier for the object under each pixel +% - 'primIndex' - integer identifier for the triangle or other primitive under each pixel +% +% rtbWriteMitsubaFactoidScene( ... 'factoidFormat', factoidFormat) specify +% a mitsuba pixel format to use for formatting the output, like 'rgb' or +% 'spectrum'. The default is 'rgb'. +% +% rtbWriteMitsubaFactoidScene( ... 'singleSampling', singleSampling) +% whether or not to do a simplified rendering with one sample per pixel and +% a narrow "box" reconstruction filder. This is useful for labeling +% factoids like shapeIndex, where it doesn't make sense to average across +% multiple ray samples. The default is true, do a simplified rendering. +% +%%% RenderToolbox4 Copyright (c) 2012-2017 The RenderToolbox Team. +%%% About Us://github.com/RenderToolbox/RenderToolbox4/wiki/About-Us +%%% RenderToolbox4 is released under the MIT License. See LICENSE file. + +parser = inputParser(); +parser.addRequired('originalFile', @ischar); +parser.addParameter('factoidFile', '', @ischar); +parser.addParameter('factoids', ... + {'position', 'relPosition', 'distance', 'geoNormal', 'shNormal', ... + 'uv', 'albedo', 'shapeIndex', 'primIndex'}, ... + @iscellstr); +parser.addParameter('factoidFormat', 'rgb', @ischar); +parser.addParameter('singleSampling', true, @islogical); +parser.parse(originalFile, varargin{:}); +originalFile = parser.Results.originalFile; +factoidFile = parser.Results.factoidFile; +factoids = parser.Results.factoids; +factoidFormat = parser.Results.factoidFormat; +singleSampling = parser.Results.singleSampling; + +% default output like the input +if isempty(factoidFile) + [factoidPath, factoidBase] = fileparts(originalFile); + factoidFile = fullfile(factoidPath, [factoidBase '-factoids.xml']); +end + + +%% Read the in the scene xml document. +sceneDocument = xml2struct(originalFile); + + +%% Replace the integrator for multiple "fields". + +% "multichannel" integrator to hold several "fields" +integrator.Attributes.id = 'integrator'; +integrator.Attributes.type = 'multichannel'; +sceneDocument.scene.integrator = integrator; + +% nested "field" for each factoid +nFactoids = numel(factoids); +fieldIntegrators = cell(1, nFactoids); +for ff = 1:nFactoids + factoidName = factoids{ff}; + + fieldIntegrator = struct(); + fieldIntegrator.Attributes.name = factoidName; + fieldIntegrator.Attributes.type = 'field'; + fieldIntegrator.string.Attributes.name = 'field'; + fieldIntegrator.string.Attributes.value = factoidName; + + fieldIntegrators{ff} = fieldIntegrator; +end +sceneDocument.scene.integrator.integrator = fieldIntegrators; + + +%% Replace the film for exr and factoid formats. +sceneDocument.scene.sensor.film.Attributes.type = 'hdrfilm'; +filmStrings = cell(1, 4); +filmStrings{1}.Attributes.name = 'componentFormat'; +filmStrings{1}.Attributes.value = 'float16'; +filmStrings{2}.Attributes.name = 'fileFormat'; +filmStrings{2}.Attributes.value = 'openexr'; + +[formatCell{1:nFactoids}] = deal(factoidFormat); +formatList = sprintf('%s, ', formatCell{:}); +filmStrings{3}.Attributes.name = 'pixelFormat'; +filmStrings{3}.Attributes.value = formatList(1:end-2); + +nameList = sprintf('%s, ', factoids{:}); +filmStrings{4}.Attributes.name = 'channelNames'; +filmStrings{4}.Attributes.value = nameList(1:end-2); + +sceneDocument.scene.sensor.film.string = filmStrings; + + +%% Replace the filter and sampler for simplified rendering? +if singleSampling + sampler.Attributes.id = 'sampler'; + sampler.Attributes.type = 'ldsampler'; + sampler.integer.Attributes.name = 'sampleCount'; + sampler.integer.Attributes.value = 1; + sceneDocument.scene.sensor.sampler = sampler; + + rfilter.Attributes.id = 'rfilter'; + rfilter.Attributes.type = 'box'; + rfilter.float.Attributes.name = 'radius'; + rfilter.float.Attributes.value= 0.5; + sceneDocument.scene.sensor.film.rfilter = rfilter; +end + + +%% Write back the scene document. +struct2xml(sceneDocument, factoidFile); -- GitLab