From 2527630e50d566ebbe20851aac17397a43303b68 Mon Sep 17 00:00:00 2001 From: Brian Wandell <wandell@stanford.edu> Date: Sat, 12 Aug 2017 17:11:24 -0700 Subject: [PATCH] Quality of life routines related to cloud computing, and more generally. --- ...rMultipleObj.m => remodelerCloudExample.m} | 2 +- ...modeller.m => remodelerPBRTCloudExample.m} | 2 +- ExampleScenes/GcloudRenderer/s_cloudExample.m | 39 ++++--- Utilities/rtbCamerasInit.m | 106 ++++++++++++++++++ Utilities/rtbCamerasPlace.m | 43 +++++++ Utilities/rtbHintsInit.m | 74 ++++++++++++ 6 files changed, 247 insertions(+), 19 deletions(-) rename ExampleScenes/GcloudRenderer/{MexximpRemodellerMultipleObj.m => remodelerCloudExample.m} (95%) rename ExampleScenes/GcloudRenderer/{PBRTRemodeller.m => remodelerPBRTCloudExample.m} (98%) create mode 100644 Utilities/rtbCamerasInit.m create mode 100644 Utilities/rtbCamerasPlace.m create mode 100644 Utilities/rtbHintsInit.m diff --git a/ExampleScenes/GcloudRenderer/MexximpRemodellerMultipleObj.m b/ExampleScenes/GcloudRenderer/remodelerCloudExample.m similarity index 95% rename from ExampleScenes/GcloudRenderer/MexximpRemodellerMultipleObj.m rename to ExampleScenes/GcloudRenderer/remodelerCloudExample.m index c30ec5c..6ac4457 100644 --- a/ExampleScenes/GcloudRenderer/MexximpRemodellerMultipleObj.m +++ b/ExampleScenes/GcloudRenderer/remodelerCloudExample.m @@ -1,4 +1,4 @@ -function [ scene, mappings ] = MexximpRemodellerMultipleObj( scene, mappings, names, conditionValues, conditionNumber ) +function [ scene, mappings ] = remodelerCloudExample( scene, mappings, names, conditionValues, conditionNumber ) % Remodeler used usually in remodelPerConditionAfterFunction % % diff --git a/ExampleScenes/GcloudRenderer/PBRTRemodeller.m b/ExampleScenes/GcloudRenderer/remodelerPBRTCloudExample.m similarity index 98% rename from ExampleScenes/GcloudRenderer/PBRTRemodeller.m rename to ExampleScenes/GcloudRenderer/remodelerPBRTCloudExample.m index 349317d..cd9b0ea 100644 --- a/ExampleScenes/GcloudRenderer/PBRTRemodeller.m +++ b/ExampleScenes/GcloudRenderer/remodelerPBRTCloudExample.m @@ -1,4 +1,4 @@ -function [ nativeScene ] = PBRTRemodeller( parentScene, nativeScene, mappings, names, conditionValues, conditionNumbers ) +function [ nativeScene ] = remodelerPBRTCloudExample( parentScene, nativeScene, mappings, names, conditionValues, conditionNumbers ) % Attaches PBRT-specific constructs to the PBRT scene % % diff --git a/ExampleScenes/GcloudRenderer/s_cloudExample.m b/ExampleScenes/GcloudRenderer/s_cloudExample.m index 4ce6205..77ca474 100644 --- a/ExampleScenes/GcloudRenderer/s_cloudExample.m +++ b/ExampleScenes/GcloudRenderer/s_cloudExample.m @@ -1,4 +1,18 @@ -%% Compare lens renderings of different cars +%% Illustrates google cloud platform usage +% +% Reads in a small object (millenial falcon). +% Sets up a camera array +% Places the object with respect to the cameras +% Calls batch render on the cloud +% +% Uses - rtbCloudInit, rtbCloudUpload, rtbCloudDownload +% Uses - rtbHintsInit, rtbCamerasInit, rtbCamerasPlace +% Uses - local remodelers. More discussion here. +% +% For this to run, you must have set up a google cloud account, have appropriate +% permissions, and have kubectl installed. Instructions for this should be on +% the RenderToolbox4 web-site. Soon, we hope. Now a bunch of it is on the +% NN_Camera_Generalization web site. % % BW, Henryk Blasinski, SCIEN Stanford, 2017 @@ -19,15 +33,18 @@ gcloud = true; % you could use this: % zone = 'us-west1-b'; % and then set a 'zone' parameter below. +p.addParameter('remodelerAfter', @MexximpRemodellerMultipleObj,@(x)(isequal(class(x),'function_handle'))); +p.addParameter('remodelerConvertAfter', @PBRTRemodeller,@(x)(isequal(class(x),'function_handle'))); % Should have a validity check. Surprising that we have the tokenPath early in % the ordering within this nnHintsInit routine % Small image size for debugging. -hints = nnHintsInit('imageWidth',160,'imageHeight',120,... +hints = rtbHintsInit('imageWidth',160,'imageHeight',120,... 'recipeName','cloud-example',... 'tokenPath',tokenPath,... 'gcloud',gcloud,... - 'mexximpRemodeler', @MexximpRemodellerMultipleObj); + 'remodelerConvertAfter',@remodelerPBRTCloudExample,... + 'remodelerAfter', @remodelerCloudExample); %% Open the GCP rtbCloudInit(hints); @@ -37,7 +54,7 @@ sceneFile = which('millenium-falcon.obj'); % Camera set to be 50 meters from an object distance % This could be an array of cameras. -cameras = nnGenCameras('type',{'pinhole'},... +cameras = rtbCamerasInit('type',{'pinhole'},... 'mode',{'radiance'},... 'distance',50); @@ -60,18 +77,6 @@ rtbWriteSpectrumFile(wave,d65,fullfile(resourceFolder,'D65.spd')); %% Build the scene -% dragonFile = which('Dragon.blend'); -% dragonScene = mexximpCleanImport(dragonFile,... -% 'ignoreRootTransform',true,... -% 'flipUVs',true,... -% 'imagemagicImage','hblasins/imagemagic-docker',... -% 'toReplace',{'jpg','png','tga'},... -% 'options','-gamma 0.45',... -% 'targetFormat','exr',... -% 'makeLeftHanded',true,... -% 'flipWindingOrder',true,... -% 'workingFolder',resourceFolder); - % Import the millenial faclon, which is small mfScene = mexximpCleanImport(sceneFile,... 'ignoreRootTransform',true,... @@ -100,7 +105,7 @@ objectArrangements = {objects(1), objects(2)}; % lookAt and film distance variables. Other slots are copied from the camera % object itself. The placedCameras combine the different object arrangements % and cameras. The output is placedCameras{nCameras}(nArrangements). -placedCameras = nnPlaceCameras(cameras,objectArrangements); +placedCameras = rtbCamerasPlace(cameras,objectArrangements); %% Make values used for the Conditions file. % diff --git a/Utilities/rtbCamerasInit.m b/Utilities/rtbCamerasInit.m new file mode 100644 index 0000000..76101d8 --- /dev/null +++ b/Utilities/rtbCamerasInit.m @@ -0,0 +1,106 @@ +function [ camera ] = rtbCamerasInit( varargin ) +% Generate an array of cameras with various parameters for rendering +% +% Used in conjunction with object placement for multiple scenes. +% +% See also: s_cloudExample.m +% +% HB SCIEN STANFORD< 2017 + +%% +p = inputParser; +p.addOptional('type',{'pinhole'}); +p.addOptional('lens',{'dgauss.22deg.6.0mm'}); +p.addOptional('mode',{'radiance'}); +p.addOptional('pixelSamples',128); +p.addOptional('distance',10); +p.addOptional('orientation',0); +p.addOptional('height',-1.5); +p.addOptional('PTR',{[0,0,0]}); +p.addOptional('defocus',0); +p.addOptional('diffraction',{'false'}); +p.addOptional('chromaticAberration',{'false'}); +p.addOptional('fNumber',2.8); +p.addOptional('filmDiagonal',1/6.4*25.4); +p.addOptional('microlens',{[0,0]}); +p.addOptional('lookAtObject',1); + +p.parse(varargin{:}); +inputs = p.Results; + +%% Checks +assert(length(inputs.type)==length(inputs.lens) || length(inputs.type)==1 || length(inputs.lens)==1); +assert(length(inputs.diffraction)==length(inputs.chromaticAberration) || length(inputs.diffraction)==1 || length(inputs.chromaticAberration)==1); +assert(length(inputs.microlens)==length(inputs.lens) || length(inputs.microlens) == 1 || length(inputs.lens)==1); + +%% Loop + +cntr = 1; +for a=1:max([length(inputs.type), length(inputs.lens), length(inputs.microlens)]) +for b=1:length(inputs.pixelSamples) +for c=1:length(inputs.distance) +for d=1:length(inputs.orientation) +for e=1:length(inputs.height) +for f=1:length(inputs.PTR) +for g=1:length(inputs.defocus) +for h=1:max([length(inputs.diffraction), length(inputs.chromaticAberration)]) +for i=1:length(inputs.fNumber) +for j=1:length(inputs.filmDiagonal) +for k=1:length(inputs.mode) + for l=1:length(inputs.lookAtObject) + + if length(inputs.type) == 1 + camera(cntr).type = inputs.type{1}; + else + camera(cntr).type = inputs.type{a}; + end + if length(inputs.lens) == 1 + camera(cntr).lens = inputs.lens{1}; + else + camera(cntr).lens = inputs.lens{a}; + end + if length(inputs.microlens) == 1 + camera(cntr).microlens = inputs.microlens{1}; + else + camera(cntr).microlens = inputs.microlens{a}; + end + camera(cntr).mode = inputs.mode{k}; + camera(cntr).pixelSamples = inputs.pixelSamples(b); + camera(cntr).fNumber = inputs.fNumber(i); + camera(cntr).filmDiagonal = inputs.filmDiagonal(j); + camera(cntr).distance = inputs.distance(c); + camera(cntr).orientation = inputs.orientation(d); + camera(cntr).height = inputs.height(e); + camera(cntr).PTR = inputs.PTR{f}; + camera(cntr).defocus = inputs.defocus(g); + + if length(inputs.diffraction) == 1 + camera(cntr).diffraction = inputs.diffraction{1}; + else + camera(cntr).diffraction = inputs.diffraction{h}; + end + if length(inputs.chromaticAberration) == 1 + camera(cntr).chromaticAberration = inputs.chromaticAberration{1}; + else + camera(cntr).chromaticAberration = inputs.chromaticAberration{h}; + end + camera(cntr).lookAtObject = inputs.lookAtObject(l); + + cntr = cntr+1; + end +end +end +end +end +end +end +end +end +end +end + + + + +end + diff --git a/Utilities/rtbCamerasPlace.m b/Utilities/rtbCamerasPlace.m new file mode 100644 index 0000000..90d6012 --- /dev/null +++ b/Utilities/rtbCamerasPlace.m @@ -0,0 +1,43 @@ +function [ cameras ] = nnPlaceCameras( cameras, objects ) + +global lensDir + +nArrangements = length(objects); +cameras = repmat({cameras},[1, nArrangements]); + +for a=1:nArrangements + for i=1:length(cameras{a}) + lookAtObject = cameras{a}(i).lookAtObject; + objPosition = objects{a}(lookAtObject).position; + + cx = cameras{a}(i).distance*sind(cameras{a}(i).orientation) + objPosition(1); + cy = cameras{a}(i).distance*cosd(cameras{a}(i).orientation) + objPosition(2); + + cameras{a}(i).position = [cx, cy, cameras{a}(i).height]; + cameras{a}(i).lookAt = objPosition; + cameras{a}(i).lookAt(3) = cameras{a}(i).height; + + lensFile = fullfile(lensDir,sprintf('%s.dat',cameras{a}(i).lens)); + if strcmp(cameras{a}(i).type,'pinhole') + cameras{a}(i).filmDistance = effectiveFocalLength(lensFile); + else + cameras{a}(i).filmDistance = focusLens(lensFile,cameras{a}(i).distance); + if cameras{a}(i).defocus ~= 0 + lens = lensC('fileName',lensFile); + focalLength = lens.focalLength; + + sensorInFocus = 1/(1/(focalLength/1000) - 1/cameras{a}(i).distance); + sensorOutOfFocus = 1/(1/(focalLength/1000) + cameras{a}(i).defocus - 1/cameras{a}(i).distance); + + delta = (sensorOutOfFocus - sensorInFocus)*1000; + + cameras{a}(i).filmDistance = cameras{a}(i).filmDistance + delta; + end + end + + end +end + + +end + diff --git a/Utilities/rtbHintsInit.m b/Utilities/rtbHintsInit.m new file mode 100644 index 0000000..e855803 --- /dev/null +++ b/Utilities/rtbHintsInit.m @@ -0,0 +1,74 @@ +function hints = rtbHintsInit(varargin) +% Initialize the rendering hints with the defaults +% +% +% We should set up input parameters for this +% +% BW/HB SCIEN Stanford, 2017 + +%% +p = inputParser; + +% Some can be reset. +p.addParameter('imageWidth',640,@isnumeric); +p.addParameter('imageHeight',480,@isnumeric); +p.addParameter('recipeName',tempname,@ischar); +p.addParameter('tokenPath','',@(x)(exist(x,'file'))); +p.addParameter('remodelerAfter', @MexximpRemodellerMultipleObj,@(x)(isequal(class(x),'function_handle'))); +p.addParameter('remodelerConvertAfter', @PBRTRemodeller,@(x)(isequal(class(x),'function_handle'))); + +% The Wandell lab's resources are set up to scale reasonably on this zone, but +% not on others. You can check this from the gcloud web site that shows we are +% good to scale to 800 cores there. https://console.cloud.google.com/ +% IAM | Quotas +p.addParameter('zone','us-central1-a',@ischar); + +p.addParameter('gcloud',false,@islogical); + +% Local docker image +p.addParameter('dockerImage','',@ischar); + +p.parse(varargin{:}); + +%% +hints.imageWidth = p.Results.imageWidth; +hints.imageHeight = p.Results.imageHeight; +hints.recipeName = p.Results.recipeName; % Name of the directory output +if p.Results.gcloud + hints.renderer = 'PBRTCloud'; % We're only using PBRT right now +else + hints.renderer = 'PBRT'; % We're only using PBRT right now +end +hints.copyResources = 1; % Is this a logical?? (BW) +hints.isParallel = false; + +% Change the docker container +hints.tokenPath = p.Results.tokenPath; +hints.batchRenderStrategy = RtbAssimpStrategy(hints); + +hints.batchRenderStrategy.remodelPerConditionAfterFunction = p.Results.remodelerAfter; +hints.batchRenderStrategy.converter = RtbAssimpPBRTConverter(hints); +hints.batchRenderStrategy.converter.remodelAfterMappingsFunction = p.Results.remodelerConvertAfter; +hints.batchRenderStrategy.converter.rewriteMeshData = false; + +if p.Results.gcloud + % Google cloud run + % Odd that is has to be earlier + % hints.tokenPath = p.Results.tokenPath; + hints.batchRenderStrategy.renderer = RtbPBRTCloudRenderer(hints); + if isempty(p.Results.dockerImage) + dockerImage = 'gcr.io/primal-surfer-140120/pbrt-v2-spectral-gcloud'; + end + hints.batchRenderStrategy.renderer.pbrt.dockerImage = dockerImage; + hints.batchRenderStrategy.renderer.cloudFolder = fullfile('gs://primal-surfer-140120.appspot.com',hints.recipeName); + hints.batchRenderStrategy.renderer.zone = p.Results.zone; +else + % Local run + hints.batchRenderStrategy.renderer = RtbPBRTRenderer(hints); + if isempty(p.Results.dockerImage) + dockerImage = 'vistalab/pbrt-v2-spectral'; + end + hints.batchRenderStrategy.renderer.pbrt.dockerImage = dockerImage; +end + +end \ No newline at end of file -- GitLab