Permalink
Browse files

Add a simple example renderer "testrender" to demonstrate how to use …

…OSL shaders and closures.
  • Loading branch information...
1 parent 3e29556 commit 672cf27b9561e9057232357f189c7e7867ff0486 @fpsunflower fpsunflower committed Apr 15, 2012
Showing with 3,828 additions and 9 deletions.
  1. +10 −5 src/CMakeLists.txt
  2. +46 −0 src/shaders/metal.osl
  3. +6 −0 src/testrender/CMakeLists.txt
  4. +115 −0 src/testrender/background.h
  5. +56 −0 src/testrender/optics.h
  6. +305 −0 src/testrender/raytracer.h
  7. +102 −0 src/testrender/sampling.h
  8. +586 −0 src/testrender/shading.cpp
  9. +122 −0 src/testrender/shading.h
  10. +206 −0 src/testrender/simplerend.cpp
  11. +80 −0 src/testrender/simplerend.h
  12. +657 −0 src/testrender/testrender.cpp
  13. +29 −0 src/testrender/util.h
  14. +42 −0 testsuite/common/shaders/bumptest.osl
  15. BIN testsuite/common/textures/kitchen_probe.hdr
  16. +60 −0 testsuite/render-background/checkerboard.osl
  17. +11 −0 testsuite/render-background/envmap.osl
  18. +43 −0 testsuite/render-background/matte.osl
  19. BIN testsuite/render-background/ref/out.exr
  20. +4 −0 testsuite/render-background/run.py
  21. +42 −0 testsuite/render-background/scene.xml
  22. +20 −0 testsuite/render-background/ward.osl
  23. +10 −0 testsuite/render-bumptest/bumptest.osl
  24. +29 −0 testsuite/render-bumptest/bumptest.xml
  25. +69 −0 testsuite/render-bumptest/glass.osl
  26. +46 −0 testsuite/render-bumptest/metal.osl
  27. BIN testsuite/render-bumptest/ref/out.exr
  28. +4 −0 testsuite/render-bumptest/run.py
  29. +43 −0 testsuite/render-cornell/cornell.xml
  30. +51 −0 testsuite/render-cornell/emitter.osl
  31. +43 −0 testsuite/render-cornell/matte.osl
  32. +46 −0 testsuite/render-cornell/metal.osl
  33. BIN testsuite/render-cornell/ref/out.exr
  34. +4 −0 testsuite/render-cornell/run.py
  35. +4 −0 testsuite/render-furnace-diffuse/furnace.osl
  36. +43 −0 testsuite/render-furnace-diffuse/matte.osl
  37. BIN testsuite/render-furnace-diffuse/ref/out.exr
  38. +4 −0 testsuite/render-furnace-diffuse/run.py
  39. +15 −0 testsuite/render-furnace-diffuse/scene.xml
  40. +60 −0 testsuite/render-microfacet/checkerboard.osl
  41. +11 −0 testsuite/render-microfacet/envmap.osl
  42. +14 −0 testsuite/render-microfacet/glossy_glass.osl
  43. +43 −0 testsuite/render-microfacet/matte.osl
  44. BIN testsuite/render-microfacet/ref/out.exr
  45. +4 −0 testsuite/render-microfacet/run.py
  46. +39 −0 testsuite/render-microfacet/scene.xml
  47. +60 −0 testsuite/render-oren-nayar/checkerboard.osl
  48. +51 −0 testsuite/render-oren-nayar/emitter.osl
  49. +43 −0 testsuite/render-oren-nayar/matte.osl
  50. BIN testsuite/render-oren-nayar/ref/out.exr
  51. +10 −0 testsuite/render-oren-nayar/rough_matte.osl
  52. +4 −0 testsuite/render-oren-nayar/run.py
  53. +42 −0 testsuite/render-oren-nayar/scene.xml
  54. +60 −0 testsuite/render-veachmis/checkerboard.osl
  55. +51 −0 testsuite/render-veachmis/emitter.osl
  56. +43 −0 testsuite/render-veachmis/matte.osl
  57. +46 −0 testsuite/render-veachmis/phong.osl
  58. BIN testsuite/render-veachmis/ref/out.exr
  59. +4 −0 testsuite/render-veachmis/run.py
  60. +57 −0 testsuite/render-veachmis/veach.xml
  61. +60 −0 testsuite/render-ward/checkerboard.osl
  62. +51 −0 testsuite/render-ward/emitter.osl
  63. +43 −0 testsuite/render-ward/matte.osl
  64. BIN testsuite/render-ward/ref/out.exr
  65. +4 −0 testsuite/render-ward/run.py
  66. +45 −0 testsuite/render-ward/scene.xml
  67. +20 −0 testsuite/render-ward/ward.osl
  68. +10 −4 testsuite/runtest.py
View
@@ -73,7 +73,7 @@ endif ()
if (CMAKE_COMPILER_IS_CLANG)
# disable warning about unused command line arguments
- add_definitions ("-Qunused-arguments")
+ add_definitions ("-Qunused-arguments -Wno-unknown-pragmas")
endif ()
if (CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_GNUCC)
@@ -163,6 +163,7 @@ add_subdirectory (oslc)
add_subdirectory (shaders)
add_subdirectory (oslinfo)
add_subdirectory (testshade)
+add_subdirectory (testrender)
add_subdirectory (include)
add_subdirectory (doc)
@@ -201,9 +202,11 @@ macro ( TESTSUITE )
message (STATUS "TEST ${_testname}: ${CMAKE_BINARY_DIR}/testsuite/runtest.py ${_testdir} ${_extra_test_args}")
# Run the test unoptimized
- set (_env TESTSHADE_OPT=0 OPENIMAGEIOHOME=${OPENIMAGEIOHOME})
- add_test ( NAME ${_testname}
- COMMAND env ${_env} ${_runtest} )
+ if (NOT _testname MATCHES "^render")
+ set (_env TESTSHADE_OPT=0 OPENIMAGEIOHOME=${OPENIMAGEIOHOME})
+ add_test ( NAME ${_testname}
+ COMMAND env ${_env} ${_runtest} )
+ endif ()
# Run the same test again with aggressive -O2 runtime
# optimization, triggered by setting TESTSHADE_OPT env variable
set (_env TESTSHADE_OPT=2 OPENIMAGEIOHOME=${OPENIMAGEIOHOME})
@@ -229,7 +232,9 @@ TESTSUITE ( arithmetic array array-derivs array-range
noise-perlin noise-uperlin
pnoise pnoise-cell pnoise-gabor pnoise-perlin pnoise-uperlin
oslc-err-noreturn oslc-err-paramdefault
- raytype shortcircuit spline splineinverse string
+ raytype render-background render-bumptest render-cornell render-furnace-diffuse
+ render-microfacet render-oren-nayar render-veachmis render-ward
+ shortcircuit spline splineinverse string
struct struct-array struct-array-mixture
struct-err struct-layers struct-with-array
struct-within-struct ternary
View
@@ -0,0 +1,46 @@
+/////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of Sony Pictures Imageworks nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/////////////////////////////////////////////////////////////////////////////
+
+
+surface
+metal
+ [[ string description = "Lambertian diffuse material" ]]
+(
+ float Ks = 1
+ [[ string description = "Specular scaling",
+ float UImin = 0, float UIsoftmax = 1 ]],
+ float eta = 10
+ [[ string description = "Metal's index of refraction (controls fresnel effect)",
+ float UImin = 1, float UIsoftmax = 100 ]],
+ color Cs = 1
+ [[ string description = "Base color",
+ float UImin = 0, float UImax = 1 ]]
+ )
+{
+ Ci = Ks * Cs * reflection (N, eta);
+}
@@ -0,0 +1,6 @@
+# The 'testrender' executable
+FILE(GLOB testrender_src *.cpp)
+ADD_EXECUTABLE ( testrender ${testrender_src} )
+LINK_ILMBASE ( testrender )
+TARGET_LINK_LIBRARIES ( testrender oslexec oslcomp oslquery ${OPENIMAGEIO_LIBRARY} ${Boost_LIBRARIES} ${CMAKE_DL_LIBS})
+INSTALL ( TARGETS testrender RUNTIME DESTINATION bin )
View
@@ -0,0 +1,115 @@
+#pragma once
+
+#include "dual_vec.h"
+#include "oslconfig.h"
+#include <algorithm> // upper_bound
+
+OSL_NAMESPACE_ENTER
+
+struct Background {
+ Background() : values(0), rows(0), cols(0) {}
+ ~Background() {
+ delete [] values;
+ delete [] rows;
+ delete [] cols;
+ }
+
+ template <typename F, typename T>
+ void prepare(int resolution, F cb, T* data) {
+ res = resolution;
+ if (res < 32) res = 32; // validate
+ invres = 1.0f / res;
+ jacobian = invres * invres * float(4 * M_PI);
+ values = new Vec3[res * res];
+ rows = new float[res];
+ cols = new float[res * res];
+ for (int y = 0, i = 0; y < res; y++) {
+ for (int x = 0; x < res; x++, i++) {
+ values[i] = cb(map(x + 0.5f, y + 0.5f), data);
+ cols[i] = (values[i].x + values[i].y + values[i].z) + ((x > 0) ? cols[i - 1] : 0.0f);
+ }
+ rows[y] = cols[i - 1] + ((y > 0) ? rows[y - 1] : 0.0f);
+ // normalize the pdf for this scanline (if it was non-zero)
+ if (cols[i - 1] > 0)
+ for (int x = 0; x < res; x++)
+ cols[i - res + x] /= cols[i - 1];
+ }
+ // normalize the pdf across all scanlines
+ for (int y = 0; y < res; y++)
+ rows[y] /= rows[res - 1];
+
+#if 0 // DEBUG: visualize importance table
+ using namespace OIIO;
+ ImageOutput* out = ImageOutput::create("bg.exr");
+ ImageSpec spec(res, res, 3, TypeDesc::TypeFloat);
+ if (out && out->open("bg.exr", spec))
+ out->write_image(TypeDesc::TypeFloat, &values[0]);
+ delete out;
+#endif
+ }
+
+ Vec3 eval(const Vec3& dir, float& pdf) const {
+ // map from sphere to unit-square
+ float u = atan2f(dir.y, dir.x) * float(M_1_PI * 0.5f);
+ if (u < 0) u++;
+ float v = (1 - dir.z) * 0.5f;
+ // retrieve nearest neighbor
+ int x = (int) (u * res); if (x < 0) x = 0; else if (x >= res) x = res - 1;
+ int y = (int) (v * res); if (y < 0) y = 0; else if (y >= res) y = res - 1;
+ int i = y * res + x;
+ float row_pdf = rows[y] - (y > 0 ? rows[y - 1] : 0.0f);
+ float col_pdf = cols[i] - (x > 0 ? cols[i - 1] : 0.0f);
+ pdf = (row_pdf * col_pdf) / jacobian;
+ return values[i];
+ }
+
+ Vec3 sample(float rx, float ry, Dual2<Vec3>& dir, float& invpdf) const {
+ float row_pdf, col_pdf;
+ unsigned x, y;
+ ry = sample_cdf(rows, res, ry, &y, &row_pdf);
+ rx = sample_cdf(cols + y * res, res, rx, &x, &col_pdf);
+ dir = map(x + rx, y + ry);
+ invpdf = jacobian / (row_pdf * col_pdf);
+ return values[y * res + x];
+ }
+
+private:
+ Dual2<Vec3> map(float x, float y) const {
+ // pixel coordinates of entry (x,y)
+ Dual2<float> u = Dual2<float>(x, 1, 0) * invres;
+ Dual2<float> v = Dual2<float>(y, 0, 1) * invres;
+ Dual2<float> theta = u * float(2 * M_PI);
+ Dual2<float> cos_phi = 1.0f - 2.0f * v;
+ Dual2<float> sin_phi = sqrt(1.0f - cos_phi * cos_phi);
+ return make_Vec3(sin_phi * cos(theta),
+ sin_phi * sin(theta),
+ cos_phi);
+ }
+
+ static float sample_cdf(const float* data, unsigned int n, float x, unsigned int *idx, float* pdf) {
+ DASSERT(x >= 0);
+ DASSERT(x < 1);
+ *idx = std::upper_bound(data, data + n, x) - data;
+ DASSERT(*idx < n);
+ DASSERT(x < data[*idx]);
+ float scaled_sample;
+ if (*idx == 0) {
+ *pdf = data[0];
+ scaled_sample = x / data[0];
+ } else {
+ DASSERT(x >= data[*idx - 1]);
+ *pdf = data[*idx] - data[*idx - 1];
+ scaled_sample = (x - data[*idx - 1]) / (data[*idx] - data[*idx - 1]);
+ }
+ return scaled_sample;
+ }
+
+ Vec3* values; // actual map
+ float* rows; // probability of choosing a given row 'y'
+ float* cols; // probability of choosing a given column 'x', given that we've chosen row 'y'
+ int res; // resolution in pixels of the precomputed table
+ float invres; // 1 / resolution
+ float jacobian;
+};
+
+OSL_NAMESPACE_EXIT
View
@@ -0,0 +1,56 @@
+#pragma once
+
+#include "oslconfig.h"
+
+
+OSL_NAMESPACE_ENTER
+
+inline float fresnel_dielectric(float cosi, float eta) {
+ // special case: ignore fresnel
+ if (eta == 0)
+ return 1;
+
+ // compute fresnel reflectance without explicitly computing the refracted direction
+ if (cosi < 0.0f) eta = 1.0f / eta;
+ float c = fabsf(cosi);
+ float g = eta * eta - 1 + c * c;
+ if (g > 0) {
+ g = sqrtf(g);
+ float A = (g - c) / (g + c);
+ float B = (c * (g + c) - 1) / (c * (g - c) + 1);
+ return 0.5f * A * A * (1 + B * B);
+ }
+ return 1.0f; // TIR (no refracted component)
+}
+
+inline float fresnel_refraction(const Dual2<Vec3>& I, const Vec3& N, float eta, Dual2<Vec3>& T) {
+ // compute refracted direction and fresnel term
+ // return value will be 0 if TIR occurs
+ // NOTE: I is the incoming ray direction (points toward the surface, normalized)
+ // N is the surface normal (points toward the incoming ray origin, normalized)
+ // T is the outgoing refracted direction (points away from the surface)
+ Dual2<float> cosi = -dot(I, N);
+ // check which side of the surface we are on
+ Vec3 Nn; float neta;
+ if (cosi.val() > 0) {
+ // we are on the outside of the surface, going in
+ neta = 1 / eta;
+ Nn = N;
+ } else {
+ // we are inside the surface,
+ cosi = -cosi;
+ neta = eta;
+ Nn = -N;
+ }
+ Dual2<float> arg = 1.0f - (neta * neta * (1.0f - cosi * cosi));
+ if (arg.val() >= 0) {
+ Dual2<float> dnp = sqrt(arg);
+ Dual2<float> nK = (neta * cosi) - dnp;
+ T = I * neta + Nn * nK;
+ return 1 - fresnel_dielectric(cosi.val(), eta);
+ }
+ T = make_Vec3(0, 0, 0);
+ return 0;
+}
+
+OSL_NAMESPACE_EXIT
Oops, something went wrong.

0 comments on commit 672cf27

Please sign in to comment.