joonsrenderer 1.1-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +53 -0
  3. data/.mvn/extensions.xml +8 -0
  4. data/CHANGELOG.md +2 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE +674 -0
  7. data/README.md +2 -0
  8. data/Rakefile +43 -0
  9. data/docs/.gitignore +6 -0
  10. data/docs/_config.yml +20 -0
  11. data/docs/_includes/footer.html +38 -0
  12. data/docs/_includes/head.html +15 -0
  13. data/docs/_includes/header.html +27 -0
  14. data/docs/_includes/icon-github.html +1 -0
  15. data/docs/_includes/icon-github.svg +1 -0
  16. data/docs/_includes/icon-twitter.html +1 -0
  17. data/docs/_includes/icon-twitter.svg +1 -0
  18. data/docs/_layouts/default.html +20 -0
  19. data/docs/_layouts/page.html +14 -0
  20. data/docs/_layouts/post.html +15 -0
  21. data/docs/_posts/2017-01-08-animated_ray_tracing.md +72 -0
  22. data/docs/_posts/2017-01-08-welcome.md +78 -0
  23. data/docs/_sass/_base.scss +206 -0
  24. data/docs/_sass/_layout.scss +242 -0
  25. data/docs/_sass/_syntax-highlighting.scss +71 -0
  26. data/docs/about.md +12 -0
  27. data/docs/assets/Animation.ogv +0 -0
  28. data/docs/assets/Animation.png +0 -0
  29. data/docs/assets/basic.png +0 -0
  30. data/docs/assets/basic_traced.png +0 -0
  31. data/docs/css/main.scss +38 -0
  32. data/docs/favicon.ico +0 -0
  33. data/docs/feed.xml +30 -0
  34. data/docs/index.html +38 -0
  35. data/joonsrenderer.gemspec +23 -0
  36. data/lib/joonsrenderer.rb +12 -0
  37. data/lib/joonsrenderer/version.rb +3 -0
  38. data/pom.rb +75 -0
  39. data/pom.xml +163 -0
  40. data/src/main/java/SunflowGUI.java +1354 -0
  41. data/src/main/java/joons/JRFiller.java +79 -0
  42. data/src/main/java/joons/JRImagePanel.java +141 -0
  43. data/src/main/java/joons/JRRecorder.java +183 -0
  44. data/src/main/java/joons/JRStatics.java +199 -0
  45. data/src/main/java/joons/JoonsRenderer.java +837 -0
  46. data/src/main/java/org/sunflow/AsciiFileSunflowAPI.java +98 -0
  47. data/src/main/java/org/sunflow/Benchmark.java +313 -0
  48. data/src/main/java/org/sunflow/BinaryFileSunflowAPI.java +228 -0
  49. data/src/main/java/org/sunflow/FileSunflowAPI.java +354 -0
  50. data/src/main/java/org/sunflow/PluginRegistry.java +322 -0
  51. data/src/main/java/org/sunflow/RealtimeBenchmark.java +125 -0
  52. data/src/main/java/org/sunflow/RenderObjectMap.java +344 -0
  53. data/src/main/java/org/sunflow/SunflowAPI.java +762 -0
  54. data/src/main/java/org/sunflow/SunflowAPIInterface.java +277 -0
  55. data/src/main/java/org/sunflow/core/AccelerationStructure.java +20 -0
  56. data/src/main/java/org/sunflow/core/AccelerationStructureFactory.java +36 -0
  57. data/src/main/java/org/sunflow/core/BucketOrder.java +21 -0
  58. data/src/main/java/org/sunflow/core/Camera.java +125 -0
  59. data/src/main/java/org/sunflow/core/CameraLens.java +29 -0
  60. data/src/main/java/org/sunflow/core/CausticPhotonMapInterface.java +15 -0
  61. data/src/main/java/org/sunflow/core/Display.java +78 -0
  62. data/src/main/java/org/sunflow/core/Filter.java +27 -0
  63. data/src/main/java/org/sunflow/core/GIEngine.java +42 -0
  64. data/src/main/java/org/sunflow/core/Geometry.java +157 -0
  65. data/src/main/java/org/sunflow/core/GlobalPhotonMapInterface.java +21 -0
  66. data/src/main/java/org/sunflow/core/ImageSampler.java +26 -0
  67. data/src/main/java/org/sunflow/core/Instance.java +224 -0
  68. data/src/main/java/org/sunflow/core/InstanceList.java +83 -0
  69. data/src/main/java/org/sunflow/core/IntersectionState.java +120 -0
  70. data/src/main/java/org/sunflow/core/LightSample.java +104 -0
  71. data/src/main/java/org/sunflow/core/LightServer.java +382 -0
  72. data/src/main/java/org/sunflow/core/LightSource.java +67 -0
  73. data/src/main/java/org/sunflow/core/Modifier.java +16 -0
  74. data/src/main/java/org/sunflow/core/Options.java +20 -0
  75. data/src/main/java/org/sunflow/core/ParameterList.java +758 -0
  76. data/src/main/java/org/sunflow/core/PhotonStore.java +62 -0
  77. data/src/main/java/org/sunflow/core/PrimitiveList.java +70 -0
  78. data/src/main/java/org/sunflow/core/Ray.java +219 -0
  79. data/src/main/java/org/sunflow/core/RenderObject.java +25 -0
  80. data/src/main/java/org/sunflow/core/Scene.java +377 -0
  81. data/src/main/java/org/sunflow/core/SceneParser.java +58 -0
  82. data/src/main/java/org/sunflow/core/Shader.java +30 -0
  83. data/src/main/java/org/sunflow/core/ShadingCache.java +84 -0
  84. data/src/main/java/org/sunflow/core/ShadingState.java +939 -0
  85. data/src/main/java/org/sunflow/core/Statistics.java +85 -0
  86. data/src/main/java/org/sunflow/core/Tesselatable.java +36 -0
  87. data/src/main/java/org/sunflow/core/Texture.java +128 -0
  88. data/src/main/java/org/sunflow/core/TextureCache.java +48 -0
  89. data/src/main/java/org/sunflow/core/accel/BoundingIntervalHierarchy.java +652 -0
  90. data/src/main/java/org/sunflow/core/accel/KDTree.java +833 -0
  91. data/src/main/java/org/sunflow/core/accel/NullAccelerator.java +30 -0
  92. data/src/main/java/org/sunflow/core/accel/UniformGrid.java +329 -0
  93. data/src/main/java/org/sunflow/core/bucket/BucketOrderFactory.java +26 -0
  94. data/src/main/java/org/sunflow/core/bucket/ColumnBucketOrder.java +21 -0
  95. data/src/main/java/org/sunflow/core/bucket/DiagonalBucketOrder.java +28 -0
  96. data/src/main/java/org/sunflow/core/bucket/HilbertBucketOrder.java +65 -0
  97. data/src/main/java/org/sunflow/core/bucket/InvertedBucketOrder.java +28 -0
  98. data/src/main/java/org/sunflow/core/bucket/RandomBucketOrder.java +49 -0
  99. data/src/main/java/org/sunflow/core/bucket/RowBucketOrder.java +21 -0
  100. data/src/main/java/org/sunflow/core/bucket/SpiralBucketOrder.java +43 -0
  101. data/src/main/java/org/sunflow/core/camera/FisheyeLens.java +25 -0
  102. data/src/main/java/org/sunflow/core/camera/PinholeLens.java +43 -0
  103. data/src/main/java/org/sunflow/core/camera/SphericalLens.java +22 -0
  104. data/src/main/java/org/sunflow/core/camera/ThinLens.java +107 -0
  105. data/src/main/java/org/sunflow/core/display/FastDisplay.java +119 -0
  106. data/src/main/java/org/sunflow/core/display/FileDisplay.java +83 -0
  107. data/src/main/java/org/sunflow/core/display/FrameDisplay.java +97 -0
  108. data/src/main/java/org/sunflow/core/display/ImgPipeDisplay.java +109 -0
  109. data/src/main/java/org/sunflow/core/filter/BlackmanHarrisFilter.java +28 -0
  110. data/src/main/java/org/sunflow/core/filter/BoxFilter.java +16 -0
  111. data/src/main/java/org/sunflow/core/filter/CatmullRomFilter.java +29 -0
  112. data/src/main/java/org/sunflow/core/filter/CubicBSpline.java +32 -0
  113. data/src/main/java/org/sunflow/core/filter/GaussianFilter.java +24 -0
  114. data/src/main/java/org/sunflow/core/filter/LanczosFilter.java +30 -0
  115. data/src/main/java/org/sunflow/core/filter/MitchellFilter.java +28 -0
  116. data/src/main/java/org/sunflow/core/filter/SincFilter.java +25 -0
  117. data/src/main/java/org/sunflow/core/filter/TriangleFilter.java +16 -0
  118. data/src/main/java/org/sunflow/core/gi/AmbientOcclusionGIEngine.java +57 -0
  119. data/src/main/java/org/sunflow/core/gi/FakeGIEngine.java +48 -0
  120. data/src/main/java/org/sunflow/core/gi/InstantGI.java +194 -0
  121. data/src/main/java/org/sunflow/core/gi/IrradianceCacheGIEngine.java +268 -0
  122. data/src/main/java/org/sunflow/core/gi/PathTracingGIEngine.java +65 -0
  123. data/src/main/java/org/sunflow/core/light/DirectionalSpotlight.java +103 -0
  124. data/src/main/java/org/sunflow/core/light/ImageBasedLight.java +303 -0
  125. data/src/main/java/org/sunflow/core/light/PointLight.java +72 -0
  126. data/src/main/java/org/sunflow/core/light/SphereLight.java +166 -0
  127. data/src/main/java/org/sunflow/core/light/SunSkyLight.java +362 -0
  128. data/src/main/java/org/sunflow/core/light/TriangleMeshLight.java +296 -0
  129. data/src/main/java/org/sunflow/core/modifiers/BumpMappingModifier.java +37 -0
  130. data/src/main/java/org/sunflow/core/modifiers/NormalMapModifier.java +34 -0
  131. data/src/main/java/org/sunflow/core/modifiers/PerlinModifier.java +80 -0
  132. data/src/main/java/org/sunflow/core/parser/Keyword.java +39 -0
  133. data/src/main/java/org/sunflow/core/parser/RA2Parser.java +107 -0
  134. data/src/main/java/org/sunflow/core/parser/RA3Parser.java +68 -0
  135. data/src/main/java/org/sunflow/core/parser/SCAbstractParser.java +299 -0
  136. data/src/main/java/org/sunflow/core/parser/SCAsciiParser.java +251 -0
  137. data/src/main/java/org/sunflow/core/parser/SCBinaryParser.java +156 -0
  138. data/src/main/java/org/sunflow/core/parser/SCParser.java +1403 -0
  139. data/src/main/java/org/sunflow/core/parser/ShaveRibParser.java +174 -0
  140. data/src/main/java/org/sunflow/core/parser/TriParser.java +79 -0
  141. data/src/main/java/org/sunflow/core/photonmap/CausticPhotonMap.java +429 -0
  142. data/src/main/java/org/sunflow/core/photonmap/GlobalPhotonMap.java +530 -0
  143. data/src/main/java/org/sunflow/core/photonmap/GridPhotonMap.java +308 -0
  144. data/src/main/java/org/sunflow/core/primitive/Background.java +55 -0
  145. data/src/main/java/org/sunflow/core/primitive/BanchoffSurface.java +100 -0
  146. data/src/main/java/org/sunflow/core/primitive/Box.java +210 -0
  147. data/src/main/java/org/sunflow/core/primitive/CornellBox.java +476 -0
  148. data/src/main/java/org/sunflow/core/primitive/CubeGrid.java +318 -0
  149. data/src/main/java/org/sunflow/core/primitive/Cylinder.java +104 -0
  150. data/src/main/java/org/sunflow/core/primitive/Hair.java +275 -0
  151. data/src/main/java/org/sunflow/core/primitive/JuliaFractal.java +266 -0
  152. data/src/main/java/org/sunflow/core/primitive/ParticleSurface.java +114 -0
  153. data/src/main/java/org/sunflow/core/primitive/Plane.java +163 -0
  154. data/src/main/java/org/sunflow/core/primitive/QuadMesh.java +413 -0
  155. data/src/main/java/org/sunflow/core/primitive/Sphere.java +101 -0
  156. data/src/main/java/org/sunflow/core/primitive/SphereFlake.java +234 -0
  157. data/src/main/java/org/sunflow/core/primitive/Torus.java +145 -0
  158. data/src/main/java/org/sunflow/core/primitive/TriangleMesh.java +849 -0
  159. data/src/main/java/org/sunflow/core/renderer/BucketRenderer.java +491 -0
  160. data/src/main/java/org/sunflow/core/renderer/MultipassRenderer.java +237 -0
  161. data/src/main/java/org/sunflow/core/renderer/ProgressiveRenderer.java +171 -0
  162. data/src/main/java/org/sunflow/core/renderer/SimpleRenderer.java +106 -0
  163. data/src/main/java/org/sunflow/core/shader/AmbientOcclusionShader.java +53 -0
  164. data/src/main/java/org/sunflow/core/shader/AnisotropicWardShader.java +216 -0
  165. data/src/main/java/org/sunflow/core/shader/ConstantShader.java +31 -0
  166. data/src/main/java/org/sunflow/core/shader/DiffuseShader.java +65 -0
  167. data/src/main/java/org/sunflow/core/shader/GlassShader.java +147 -0
  168. data/src/main/java/org/sunflow/core/shader/IDShader.java +27 -0
  169. data/src/main/java/org/sunflow/core/shader/MirrorShader.java +68 -0
  170. data/src/main/java/org/sunflow/core/shader/NormalShader.java +32 -0
  171. data/src/main/java/org/sunflow/core/shader/PhongShader.java +89 -0
  172. data/src/main/java/org/sunflow/core/shader/PrimIDShader.java +30 -0
  173. data/src/main/java/org/sunflow/core/shader/QuickGrayShader.java +63 -0
  174. data/src/main/java/org/sunflow/core/shader/ShinyDiffuseShader.java +98 -0
  175. data/src/main/java/org/sunflow/core/shader/SimpleShader.java +24 -0
  176. data/src/main/java/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java +31 -0
  177. data/src/main/java/org/sunflow/core/shader/TexturedDiffuseShader.java +31 -0
  178. data/src/main/java/org/sunflow/core/shader/TexturedPhongShader.java +31 -0
  179. data/src/main/java/org/sunflow/core/shader/TexturedShinyDiffuseShader.java +31 -0
  180. data/src/main/java/org/sunflow/core/shader/TexturedWardShader.java +31 -0
  181. data/src/main/java/org/sunflow/core/shader/UVShader.java +27 -0
  182. data/src/main/java/org/sunflow/core/shader/UberShader.java +149 -0
  183. data/src/main/java/org/sunflow/core/shader/ViewCausticsShader.java +33 -0
  184. data/src/main/java/org/sunflow/core/shader/ViewGlobalPhotonsShader.java +25 -0
  185. data/src/main/java/org/sunflow/core/shader/ViewIrradianceShader.java +25 -0
  186. data/src/main/java/org/sunflow/core/shader/WireframeShader.java +83 -0
  187. data/src/main/java/org/sunflow/core/tesselatable/BezierMesh.java +254 -0
  188. data/src/main/java/org/sunflow/core/tesselatable/FileMesh.java +251 -0
  189. data/src/main/java/org/sunflow/core/tesselatable/Gumbo.java +1147 -0
  190. data/src/main/java/org/sunflow/core/tesselatable/Teapot.java +237 -0
  191. data/src/main/java/org/sunflow/image/Bitmap.java +15 -0
  192. data/src/main/java/org/sunflow/image/BitmapReader.java +39 -0
  193. data/src/main/java/org/sunflow/image/BitmapWriter.java +79 -0
  194. data/src/main/java/org/sunflow/image/BlackbodySpectrum.java +16 -0
  195. data/src/main/java/org/sunflow/image/ChromaticitySpectrum.java +55 -0
  196. data/src/main/java/org/sunflow/image/Color.java +374 -0
  197. data/src/main/java/org/sunflow/image/ColorEncoder.java +94 -0
  198. data/src/main/java/org/sunflow/image/ColorFactory.java +122 -0
  199. data/src/main/java/org/sunflow/image/ConstantSpectralCurve.java +21 -0
  200. data/src/main/java/org/sunflow/image/IrregularSpectralCurve.java +57 -0
  201. data/src/main/java/org/sunflow/image/RGBSpace.java +207 -0
  202. data/src/main/java/org/sunflow/image/RegularSpectralCurve.java +30 -0
  203. data/src/main/java/org/sunflow/image/SpectralCurve.java +118 -0
  204. data/src/main/java/org/sunflow/image/XYZColor.java +50 -0
  205. data/src/main/java/org/sunflow/image/formats/BitmapBlack.java +27 -0
  206. data/src/main/java/org/sunflow/image/formats/BitmapG8.java +36 -0
  207. data/src/main/java/org/sunflow/image/formats/BitmapGA8.java +30 -0
  208. data/src/main/java/org/sunflow/image/formats/BitmapRGB8.java +40 -0
  209. data/src/main/java/org/sunflow/image/formats/BitmapRGBA8.java +40 -0
  210. data/src/main/java/org/sunflow/image/formats/BitmapRGBE.java +60 -0
  211. data/src/main/java/org/sunflow/image/formats/BitmapXYZ.java +38 -0
  212. data/src/main/java/org/sunflow/image/formats/GenericBitmap.java +73 -0
  213. data/src/main/java/org/sunflow/image/readers/BMPBitmapReader.java +39 -0
  214. data/src/main/java/org/sunflow/image/readers/HDRBitmapReader.java +155 -0
  215. data/src/main/java/org/sunflow/image/readers/IGIBitmapReader.java +104 -0
  216. data/src/main/java/org/sunflow/image/readers/JPGBitmapReader.java +39 -0
  217. data/src/main/java/org/sunflow/image/readers/PNGBitmapReader.java +40 -0
  218. data/src/main/java/org/sunflow/image/readers/TGABitmapReader.java +141 -0
  219. data/src/main/java/org/sunflow/image/writers/EXRBitmapWriter.java +395 -0
  220. data/src/main/java/org/sunflow/image/writers/HDRBitmapWriter.java +54 -0
  221. data/src/main/java/org/sunflow/image/writers/IGIBitmapWriter.java +75 -0
  222. data/src/main/java/org/sunflow/image/writers/PNGBitmapWriter.java +39 -0
  223. data/src/main/java/org/sunflow/image/writers/TGABitmapWriter.java +63 -0
  224. data/src/main/java/org/sunflow/math/BoundingBox.java +340 -0
  225. data/src/main/java/org/sunflow/math/MathUtils.java +159 -0
  226. data/src/main/java/org/sunflow/math/Matrix4.java +573 -0
  227. data/src/main/java/org/sunflow/math/MovingMatrix4.java +119 -0
  228. data/src/main/java/org/sunflow/math/OrthoNormalBasis.java +110 -0
  229. data/src/main/java/org/sunflow/math/PerlinScalar.java +331 -0
  230. data/src/main/java/org/sunflow/math/PerlinVector.java +132 -0
  231. data/src/main/java/org/sunflow/math/Point2.java +36 -0
  232. data/src/main/java/org/sunflow/math/Point3.java +133 -0
  233. data/src/main/java/org/sunflow/math/QMC.java +209 -0
  234. data/src/main/java/org/sunflow/math/Solvers.java +142 -0
  235. data/src/main/java/org/sunflow/math/Vector3.java +197 -0
  236. data/src/main/java/org/sunflow/system/BenchmarkFramework.java +73 -0
  237. data/src/main/java/org/sunflow/system/BenchmarkTest.java +17 -0
  238. data/src/main/java/org/sunflow/system/ByteUtil.java +119 -0
  239. data/src/main/java/org/sunflow/system/FileUtils.java +27 -0
  240. data/src/main/java/org/sunflow/system/ImagePanel.java +282 -0
  241. data/src/main/java/org/sunflow/system/Memory.java +18 -0
  242. data/src/main/java/org/sunflow/system/Parser.java +162 -0
  243. data/src/main/java/org/sunflow/system/Plugins.java +142 -0
  244. data/src/main/java/org/sunflow/system/RenderGlobalsPanel.java +209 -0
  245. data/src/main/java/org/sunflow/system/SearchPath.java +67 -0
  246. data/src/main/java/org/sunflow/system/Timer.java +53 -0
  247. data/src/main/java/org/sunflow/system/UI.java +112 -0
  248. data/src/main/java/org/sunflow/system/UserInterface.java +46 -0
  249. data/src/main/java/org/sunflow/system/ui/ConsoleInterface.java +48 -0
  250. data/src/main/java/org/sunflow/system/ui/SilentInterface.java +28 -0
  251. data/src/main/java/org/sunflow/util/FastHashMap.java +220 -0
  252. data/src/main/java/org/sunflow/util/FloatArray.java +77 -0
  253. data/src/main/java/org/sunflow/util/IntArray.java +77 -0
  254. data/src/test/java/a_maintest.java +129 -0
  255. metadata +300 -0
@@ -0,0 +1,58 @@
1
+ package org.sunflow.core;
2
+
3
+ import org.sunflow.SunflowAPI;
4
+ import org.sunflow.SunflowAPIInterface;
5
+
6
+ /**
7
+ * Simple interface to allow for scene creation from arbitrary file formats.
8
+ */
9
+ public interface SceneParser {
10
+
11
+ final String ASPECT = "aspect";
12
+ final String BACKGROUND = "background";
13
+ final String CENTER = "center";
14
+ final String COLOR = "color";
15
+ final String DIFF = "diff";
16
+ final String DIFFUSE = "diffuse";
17
+ final String EMIT = "emit";
18
+ final String FACEVARYING = "facevarying";
19
+ final String FILTER = "filter";
20
+ final String FOV = "fov";
21
+ final String GI_ENGINE = "gi.engine";
22
+ final String MODIFIER = "modifier";
23
+ final String MODIFIERS = "modifiers";
24
+ final String NAME = "name";
25
+ final String NONE = "none";
26
+ final String NORMALS = "normals";
27
+ final String POINTS = "points";
28
+ final String POINT = "point";
29
+ final String POWER = "power";
30
+ final String VERTEX = "vertex";
31
+ final String RADIUS = "radius";
32
+ final String RADIANCE = "radiance";
33
+ final String REFL = "refl";
34
+ final String SAMPLES = "samples";
35
+ final String SCALE = "scale";
36
+ final String SHADER = "shader";
37
+ final String SHADERS = "shaders";
38
+ final String SMOOTH = "scale";
39
+ final String SUBDIVS = "subdivs";
40
+ final String TEXTURE = "texture";
41
+ final String TEXCOORD = "texcoord";
42
+ final String TRANSFORM = "transform";
43
+ final String TRIANGLES = "triangles";
44
+ final String TRIANGLE_MESH = "triangle_mesh";
45
+ final String TYPE = "type";
46
+ final String UVS = "uvs";
47
+
48
+ /**
49
+ * Parse the specified file to create a scene description into the provided
50
+ * {@link SunflowAPI} object.
51
+ *
52
+ * @param filename filename to parse
53
+ * @param api scene to parse the file into
54
+ * @return <code>true</code> upon success, or <code>false</code> if errors
55
+ * have occurred.
56
+ */
57
+ public boolean parse(String filename, SunflowAPIInterface api);
58
+ }
@@ -0,0 +1,30 @@
1
+ package org.sunflow.core;
2
+
3
+ import org.sunflow.image.Color;
4
+
5
+ /**
6
+ * A shader represents a particular light-surface interaction.
7
+ */
8
+ public interface Shader extends RenderObject {
9
+
10
+ /**
11
+ * Gets the radiance for a specified rendering state. When this method is
12
+ * called, you can assume that a hit has been registered in the state and
13
+ * that the hit surface information has been computed.
14
+ *
15
+ * @param state current render state
16
+ * @return color emitted or reflected by the shader
17
+ */
18
+ public Color getRadiance(ShadingState state);
19
+
20
+ /**
21
+ * Scatter a photon with the specied power. Incoming photon direction is
22
+ * specified by the ray attached to the current render state. This method
23
+ * can safely do nothing if photon scattering is not supported or relevant
24
+ * for the shader type.
25
+ *
26
+ * @param state current state
27
+ * @param power power of the incoming photon.
28
+ */
29
+ public void scatterPhoton(ShadingState state, Color power);
30
+ }
@@ -0,0 +1,84 @@
1
+ package org.sunflow.core;
2
+
3
+ import org.sunflow.image.Color;
4
+
5
+ public class ShadingCache {
6
+
7
+ private Sample first;
8
+ private int depth;
9
+ // stats
10
+ long hits;
11
+ long misses;
12
+ long sumDepth;
13
+ long numCaches;
14
+
15
+ private static class Sample {
16
+
17
+ Instance i;
18
+ Shader s;
19
+ float nx, ny, nz;
20
+ float dx, dy, dz;
21
+ Color c;
22
+ Sample next; // linked list
23
+ }
24
+
25
+ public ShadingCache() {
26
+ reset();
27
+ hits = 0;
28
+ misses = 0;
29
+ }
30
+
31
+ public void reset() {
32
+ sumDepth += depth;
33
+ if (depth > 0) {
34
+ numCaches++;
35
+ }
36
+ first = null;
37
+ depth = 0;
38
+ }
39
+
40
+ public Color lookup(ShadingState state, Shader shader) {
41
+ if (state.getNormal() == null) {
42
+ return null;
43
+ }
44
+ // search further
45
+ for (Sample s = first; s != null; s = s.next) {
46
+ if (s.i != state.getInstance()) {
47
+ continue;
48
+ }
49
+ if (s.s != shader) {
50
+ continue;
51
+ }
52
+ if (state.getRay().dot(s.dx, s.dy, s.dz) < 0.999f) {
53
+ continue;
54
+ }
55
+ if (state.getNormal().dot(s.nx, s.ny, s.nz) < 0.99f) {
56
+ continue;
57
+ }
58
+ // we have a match
59
+ hits++;
60
+ return s.c;
61
+ }
62
+ misses++;
63
+ return null;
64
+ }
65
+
66
+ public void add(ShadingState state, Shader shader, Color c) {
67
+ if (state.getNormal() == null) {
68
+ return;
69
+ }
70
+ depth++;
71
+ Sample s = new Sample();
72
+ s.i = state.getInstance();
73
+ s.s = shader;
74
+ s.c = c;
75
+ s.dx = state.getRay().dx;
76
+ s.dy = state.getRay().dy;
77
+ s.dz = state.getRay().dz;
78
+ s.nx = state.getNormal().x;
79
+ s.ny = state.getNormal().y;
80
+ s.nz = state.getNormal().z;
81
+ s.next = first;
82
+ first = s;
83
+ }
84
+ }
@@ -0,0 +1,939 @@
1
+ package org.sunflow.core;
2
+
3
+ import java.util.Iterator;
4
+
5
+ import org.sunflow.core.primitive.TriangleMesh;
6
+ import org.sunflow.image.Color;
7
+ import org.sunflow.math.Matrix4;
8
+ import org.sunflow.math.OrthoNormalBasis;
9
+ import org.sunflow.math.Point2;
10
+ import org.sunflow.math.Point3;
11
+ import org.sunflow.math.QMC;
12
+ import org.sunflow.math.Vector3;
13
+
14
+ /**
15
+ * Represents a point to be shaded and provides various options for the shading
16
+ * of this point, including spawning of new rays.
17
+ */
18
+ public final class ShadingState implements Iterable<LightSample> {
19
+
20
+ private IntersectionState istate;
21
+ private LightServer server;
22
+ private float rx, ry, time;
23
+ private Color result;
24
+ private Point3 p;
25
+ private Vector3 n;
26
+ private Point2 tex;
27
+ private Vector3 ng;
28
+ private OrthoNormalBasis basis;
29
+ private float cosND;
30
+ private float bias;
31
+ private boolean behind;
32
+ private float hitU, hitV, hitW;
33
+ private Instance instance;
34
+ private int primitiveID;
35
+ private Matrix4 o2w, w2o;
36
+ private Ray r;
37
+ private int d; // quasi monte carlo instance variables
38
+ private int i; // quasi monte carlo instance variables
39
+ private double qmcD0I;
40
+ private double qmcD1I;
41
+ private Shader shader;
42
+ private Modifier modifier;
43
+ private int diffuseDepth;
44
+ private int reflectionDepth;
45
+ private int refractionDepth;
46
+ private boolean includeLights;
47
+ private boolean includeSpecular;
48
+ private LightSample lightSample;
49
+ private PhotonStore map;
50
+
51
+ static ShadingState createPhotonState(Ray r, IntersectionState istate, int i, PhotonStore map, LightServer server) {
52
+ ShadingState s = new ShadingState(null, istate, r, i, 4);
53
+ s.server = server;
54
+ s.map = map;
55
+ return s;
56
+
57
+ }
58
+
59
+ static ShadingState createState(IntersectionState istate, float rx, float ry, float time, Ray r, int i, int d, LightServer server) {
60
+ ShadingState s = new ShadingState(null, istate, r, i, d);
61
+ s.server = server;
62
+ s.rx = rx;
63
+ s.ry = ry;
64
+ s.time = time;
65
+ return s;
66
+ }
67
+
68
+ static ShadingState createDiffuseBounceState(ShadingState previous, Ray r, int i) {
69
+ ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
70
+ s.diffuseDepth++;
71
+ return s;
72
+ }
73
+
74
+ static ShadingState createGlossyBounceState(ShadingState previous, Ray r, int i) {
75
+ ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
76
+ s.includeLights = false;
77
+ s.includeSpecular = false;
78
+ s.reflectionDepth++;
79
+ return s;
80
+ }
81
+
82
+ static ShadingState createReflectionBounceState(ShadingState previous, Ray r, int i) {
83
+ ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
84
+ s.reflectionDepth++;
85
+ return s;
86
+ }
87
+
88
+ static ShadingState createRefractionBounceState(ShadingState previous, Ray r, int i) {
89
+ ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
90
+ s.refractionDepth++;
91
+ return s;
92
+ }
93
+
94
+ static ShadingState createFinalGatherState(ShadingState state, Ray r, int i) {
95
+ ShadingState finalGatherState = new ShadingState(state, state.istate, r, i, 2);
96
+ finalGatherState.diffuseDepth++;
97
+ finalGatherState.includeLights = false;
98
+ finalGatherState.includeSpecular = false;
99
+ return finalGatherState;
100
+ }
101
+
102
+ private ShadingState(ShadingState previous, IntersectionState istate, Ray r, int i, int d) {
103
+ this.r = r;
104
+ this.istate = istate;
105
+ this.i = i;
106
+ this.d = d;
107
+ time = istate.time;
108
+ instance = istate.instance; // local copy
109
+ primitiveID = istate.id;
110
+ hitU = istate.u;
111
+ hitV = istate.v;
112
+ hitW = istate.w;
113
+ // get matrices for current time
114
+ o2w = instance.getObjectToWorld(time);
115
+ w2o = instance.getWorldToObject(time);
116
+ if (previous == null) {
117
+ diffuseDepth = 0;
118
+ reflectionDepth = 0;
119
+ refractionDepth = 0;
120
+
121
+ } else {
122
+ diffuseDepth = previous.diffuseDepth;
123
+ reflectionDepth = previous.reflectionDepth;
124
+ refractionDepth = previous.refractionDepth;
125
+ server = previous.server;
126
+ map = previous.map;
127
+ rx = previous.rx;
128
+ ry = previous.ry;
129
+ this.i += previous.i;
130
+ this.d += previous.d;
131
+ }
132
+ behind = false;
133
+ cosND = Float.NaN;
134
+ includeLights = includeSpecular = true;
135
+ qmcD0I = QMC.halton(this.d, this.i);
136
+ qmcD1I = QMC.halton(this.d + 1, this.i);
137
+ result = null;
138
+ bias = 0.001f;
139
+ }
140
+
141
+ final void setRay(Ray r) {
142
+ this.r = r;
143
+ }
144
+
145
+ /**
146
+ * Create objects needed for surface shading: point, normal, texture
147
+ * coordinates and basis.
148
+ */
149
+ public final void init() {
150
+ p = new Point3();
151
+ n = new Vector3();
152
+ tex = new Point2();
153
+ ng = new Vector3();
154
+ basis = null;
155
+ }
156
+
157
+ /**
158
+ * Run the shader at this surface point.
159
+ *
160
+ * @return shaded result
161
+ */
162
+ public final Color shade() {
163
+ return server.shadeHit(this);
164
+ }
165
+
166
+ final void correctShadingNormal() {
167
+ // correct shading normals pointing the wrong way
168
+ if (Vector3.dot(n, ng) < 0) {
169
+ n.negate();
170
+ basis.flipW();
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Flip the surface normals to ensure they are facing the current ray. This
176
+ * method also offsets the shading point away from the surface so that new
177
+ * rays will not intersect the same surface again by mistake.
178
+ */
179
+ public final void faceforward() {
180
+ // make sure we are on the right side of the material
181
+ if (r.dot(ng) < 0) {
182
+ } else {
183
+ // this ensure the ray and the geomtric normal are pointing in the
184
+ // same direction
185
+ ng.negate();
186
+ n.negate();
187
+ basis.flipW();
188
+ behind = true;
189
+ }
190
+ cosND = Math.max(-r.dot(n), 0); // can't be negative
191
+ // offset the shaded point away from the surface to prevent
192
+ // self-intersection errors
193
+ if (Math.abs(ng.x) > Math.abs(ng.y) && Math.abs(ng.x) > Math.abs(ng.z)) {
194
+ bias = Math.max(bias, 25 * Math.ulp(Math.abs(p.x)));
195
+ } else if (Math.abs(ng.y) > Math.abs(ng.z)) {
196
+ bias = Math.max(bias, 25 * Math.ulp(Math.abs(p.y)));
197
+ } else {
198
+ bias = Math.max(bias, 25 * Math.ulp(Math.abs(p.z)));
199
+ }
200
+ p.x += bias * ng.x;
201
+ p.y += bias * ng.y;
202
+ p.z += bias * ng.z;
203
+ }
204
+
205
+ /**
206
+ * Get x coordinate of the pixel being shaded.
207
+ *
208
+ * @return pixel x coordinate
209
+ */
210
+ public final float getRasterX() {
211
+ return rx;
212
+ }
213
+
214
+ /**
215
+ * Get y coordinate of the pixel being shaded.
216
+ *
217
+ * @return pixel y coordinate
218
+ */
219
+ public final float getRasterY() {
220
+ return ry;
221
+ }
222
+
223
+ /**
224
+ * Cosine between the shading normal and the ray. This is set by
225
+ * {@link #faceforward()}.
226
+ *
227
+ * @return cosine between shading normal and the ray
228
+ */
229
+ public final float getCosND() {
230
+ return cosND;
231
+ }
232
+
233
+ /**
234
+ * Returns true if the ray hit the surface from behind. This is set by
235
+ * {@link #faceforward()}.
236
+ *
237
+ * @return <code>true</code> if the surface was hit from behind.
238
+ */
239
+ public final boolean isBehind() {
240
+ return behind;
241
+ }
242
+
243
+ final IntersectionState getIntersectionState() {
244
+ return istate;
245
+ }
246
+
247
+ /**
248
+ * Get u barycentric coordinate of the intersection point.
249
+ *
250
+ * @return u barycentric coordinate
251
+ */
252
+ public final float getU() {
253
+ return hitU;
254
+ }
255
+
256
+ /**
257
+ * Get v barycentric coordinate of the intersection point.
258
+ *
259
+ * @return v barycentric coordinate
260
+ */
261
+ public final float getV() {
262
+ return hitV;
263
+ }
264
+
265
+ /**
266
+ * Get w barycentric coordinate of the intersection point.
267
+ *
268
+ * @return w barycentric coordinate
269
+ */
270
+ public final float getW() {
271
+ return hitW;
272
+ }
273
+
274
+ /**
275
+ * Get the instance which was intersected
276
+ *
277
+ * @return intersected instance object
278
+ */
279
+ public final Instance getInstance() {
280
+ return instance;
281
+ }
282
+
283
+ /**
284
+ * Get the primitive ID which was intersected
285
+ *
286
+ * @return intersected primitive ID
287
+ */
288
+ public final int getPrimitiveID() {
289
+ return primitiveID;
290
+ }
291
+
292
+ /**
293
+ * Transform the given point from object space to world space. A new
294
+ * {@link Point3} object is returned.
295
+ *
296
+ * @param p object space position to transform
297
+ * @return transformed position
298
+ */
299
+ public Point3 transformObjectToWorld(Point3 p) {
300
+ return o2w == null ? new Point3(p) : o2w.transformP(p);
301
+ }
302
+
303
+ /**
304
+ * Transform the given point from world space to object space. A new
305
+ * {@link Point3} object is returned.
306
+ *
307
+ * @param p world space position to transform
308
+ * @return transformed position
309
+ */
310
+ public Point3 transformWorldToObject(Point3 p) {
311
+ return w2o == null ? new Point3(p) : w2o.transformP(p);
312
+ }
313
+
314
+ /**
315
+ * Transform the given normal from object space to world space. A new
316
+ * {@link Vector3} object is returned.
317
+ *
318
+ * @param n object space normal to transform
319
+ * @return transformed normal
320
+ */
321
+ public Vector3 transformNormalObjectToWorld(Vector3 n) {
322
+ return o2w == null ? new Vector3(n) : w2o.transformTransposeV(n);
323
+ }
324
+
325
+ /**
326
+ * Transform the given normal from world space to object space. A new
327
+ * {@link Vector3} object is returned.
328
+ *
329
+ * @param n world space normal to transform
330
+ * @return transformed normal
331
+ */
332
+ public Vector3 transformNormalWorldToObject(Vector3 n) {
333
+ return o2w == null ? new Vector3(n) : o2w.transformTransposeV(n);
334
+ }
335
+
336
+ /**
337
+ * Transform the given vector from object space to world space. A new
338
+ * {@link Vector3} object is returned.
339
+ *
340
+ * @param v object space vector to transform
341
+ * @return transformed vector
342
+ */
343
+ public Vector3 transformVectorObjectToWorld(Vector3 v) {
344
+ return o2w == null ? new Vector3(v) : o2w.transformV(v);
345
+ }
346
+
347
+ /**
348
+ * Transform the given vector from world space to object space. A new
349
+ * {@link Vector3} object is returned.
350
+ *
351
+ * @param v world space vector to transform
352
+ * @return transformed vector
353
+ */
354
+ public Vector3 transformVectorWorldToObject(Vector3 v) {
355
+ return o2w == null ? new Vector3(v) : w2o.transformV(v);
356
+ }
357
+
358
+ final void setResult(Color c) {
359
+ result = c;
360
+ }
361
+
362
+ /**
363
+ * Get the result of shading this point
364
+ *
365
+ * @return shaded result
366
+ */
367
+ public final Color getResult() {
368
+ return result;
369
+ }
370
+
371
+ final LightServer getLightServer() {
372
+ return server;
373
+ }
374
+
375
+ /**
376
+ * Add the specified light sample to the list of lights to be used
377
+ *
378
+ * @param sample a valid light sample
379
+ */
380
+ public final void addSample(LightSample sample) {
381
+ // add to list
382
+ sample.next = lightSample;
383
+ lightSample = sample;
384
+ }
385
+
386
+ /**
387
+ * Get a QMC sample from an infinite sequence.
388
+ *
389
+ * @param j sample number (starts from 0)
390
+ * @param dim dimension to sample
391
+ * @return pseudo-random value in [0,1)
392
+ */
393
+ public final double getRandom(int j, int dim) {
394
+ switch (dim) {
395
+ case 0:
396
+ return QMC.mod1(qmcD0I + QMC.halton(0, j));
397
+ case 1:
398
+ return QMC.mod1(qmcD1I + QMC.halton(1, j));
399
+ default:
400
+ return QMC.mod1(QMC.halton(d + dim, i) + QMC.halton(dim, j));
401
+ }
402
+ }
403
+
404
+ /**
405
+ * Get a QMC sample from a finite sequence of n elements. This provides
406
+ * better stratification than the infinite version, but does not allow for
407
+ * adaptive sampling.
408
+ *
409
+ * @param j sample number (starts from 0)
410
+ * @param dim dimension to sample
411
+ * @param n number of samples
412
+ * @return pseudo-random value in [0,1)
413
+ */
414
+ public final double getRandom(int j, int dim, int n) {
415
+ switch (dim) {
416
+ case 0:
417
+ return QMC.mod1(qmcD0I + (double) j / (double) n);
418
+ case 1:
419
+ return QMC.mod1(qmcD1I + QMC.halton(0, j));
420
+ default:
421
+ return QMC.mod1(QMC.halton(d + dim, i) + QMC.halton(dim - 1, j));
422
+ }
423
+ }
424
+
425
+ /**
426
+ * Checks to see if the shader should include emitted light.
427
+ *
428
+ * @return <code>true</code> if emitted light should be included,
429
+ * <code>false</code> otherwise
430
+ */
431
+ public final boolean includeLights() {
432
+ return includeLights;
433
+ }
434
+
435
+ /**
436
+ * Checks to see if the shader should include specular terms.
437
+ *
438
+ * @return <code>true</code> if specular terms should be included,
439
+ * <code>false</code> otherwise
440
+ */
441
+ public final boolean includeSpecular() {
442
+ return includeSpecular;
443
+ }
444
+
445
+ /**
446
+ * Get the shader to be used to shade this surface.
447
+ *
448
+ * @return shader to be used
449
+ */
450
+ public final Shader getShader() {
451
+ return shader;
452
+ }
453
+
454
+ /**
455
+ * Record which shader should be executed for the intersected surface.
456
+ *
457
+ * @param shader surface shader to use to shade the current intersection
458
+ * point
459
+ */
460
+ public final void setShader(Shader shader) {
461
+ this.shader = shader;
462
+ }
463
+
464
+ final Modifier getModifier() {
465
+ return modifier;
466
+ }
467
+
468
+ /**
469
+ * Record which modifier should be applied to the intersected surface
470
+ *
471
+ * @param modifier modifier to use the change this shading state
472
+ */
473
+ public final void setModifier(Modifier modifier) {
474
+ this.modifier = modifier;
475
+ }
476
+
477
+ /**
478
+ * Get the current total tracing depth. First generation rays have a depth
479
+ * of 0.
480
+ *
481
+ * @return current tracing depth
482
+ */
483
+ public final int getDepth() {
484
+ return diffuseDepth + reflectionDepth + refractionDepth;
485
+ }
486
+
487
+ /**
488
+ * Get the current diffuse tracing depth. This is the number of diffuse
489
+ * surfaces reflected from.
490
+ *
491
+ * @return current diffuse tracing depth
492
+ */
493
+ public final int getDiffuseDepth() {
494
+ return diffuseDepth;
495
+ }
496
+
497
+ /**
498
+ * Get the current reflection tracing depth. This is the number of specular
499
+ * surfaces reflected from.
500
+ *
501
+ * @return current reflection tracing depth
502
+ */
503
+ public final int getReflectionDepth() {
504
+ return reflectionDepth;
505
+ }
506
+
507
+ /**
508
+ * Get the current refraction tracing depth. This is the number of specular
509
+ * surfaces refracted from.
510
+ *
511
+ * @return current refraction tracing depth
512
+ */
513
+ public final int getRefractionDepth() {
514
+ return refractionDepth;
515
+ }
516
+
517
+ /**
518
+ * Get hit point.
519
+ *
520
+ * @return hit point
521
+ */
522
+ public final Point3 getPoint() {
523
+ return p;
524
+ }
525
+
526
+ /**
527
+ * Get shading normal at the hit point. This may differ from the geometric
528
+ * normal
529
+ *
530
+ * @return shading normal
531
+ */
532
+ public final Vector3 getNormal() {
533
+ return n;
534
+ }
535
+
536
+ /**
537
+ * Get texture coordinates at the hit point.
538
+ *
539
+ * @return texture coordinate
540
+ */
541
+ public final Point2 getUV() {
542
+ return tex;
543
+ }
544
+
545
+ /**
546
+ * Gets the geometric normal of the current hit point.
547
+ *
548
+ * @return geometric normal of the current hit point
549
+ */
550
+ public final Vector3 getGeoNormal() {
551
+ return ng;
552
+ }
553
+
554
+ /**
555
+ * Gets the local orthonormal basis for the current hit point.
556
+ *
557
+ * @return local basis or <code>null</code> if undefined
558
+ */
559
+ public final OrthoNormalBasis getBasis() {
560
+ return basis;
561
+ }
562
+
563
+ /**
564
+ * Define the orthonormal basis for the current hit point.
565
+ *
566
+ * @param basis
567
+ */
568
+ public final void setBasis(OrthoNormalBasis basis) {
569
+ this.basis = basis;
570
+ }
571
+
572
+ /**
573
+ * Gets the ray that is associated with this state.
574
+ *
575
+ * @return ray associated with this state.
576
+ */
577
+ public final Ray getRay() {
578
+ return r;
579
+ }
580
+
581
+ /**
582
+ * Get a transformation matrix that will transform camera space points into
583
+ * world space.
584
+ *
585
+ * @return camera to world transform
586
+ */
587
+ public final Matrix4 getCameraToWorld() {
588
+ Camera c = server.getScene().getCamera();
589
+ return c != null ? c.getCameraToWorld(time) : Matrix4.IDENTITY;
590
+ }
591
+
592
+ /**
593
+ * Get a transformation matrix that will transform world space points into
594
+ * camera space.
595
+ *
596
+ * @return world to camera transform
597
+ */
598
+ public final Matrix4 getWorldToCamera() {
599
+ Camera c = server.getScene().getCamera();
600
+ return c != null ? c.getWorldToCamera(time) : Matrix4.IDENTITY;
601
+ }
602
+
603
+ /**
604
+ * Get the three triangle corners in object space if the hit object is a
605
+ * mesh, returns false otherwise.
606
+ *
607
+ * @param p array of 3 points
608
+ * @return <code>true</code> if the points were read succesfully,
609
+ * <code>false</code>otherwise
610
+ */
611
+ public final boolean getTrianglePoints(Point3[] p) {
612
+ PrimitiveList prims = instance.getGeometry().getPrimitiveList();
613
+ if (prims instanceof TriangleMesh) {
614
+ TriangleMesh m = (TriangleMesh) prims;
615
+ m.getPoint(primitiveID, 0, p[0] = new Point3());
616
+ m.getPoint(primitiveID, 1, p[1] = new Point3());
617
+ m.getPoint(primitiveID, 2, p[2] = new Point3());
618
+ return true;
619
+ }
620
+ return false;
621
+ }
622
+
623
+ /**
624
+ * Initialize the use of light samples. Prepares a list of visible lights
625
+ * from the current point.
626
+ */
627
+ public final void initLightSamples() {
628
+ server.initLightSamples(this);
629
+ }
630
+
631
+ /**
632
+ * Add caustic samples to the current light sample set. This method does
633
+ * nothing if caustics are not enabled.
634
+ */
635
+ public final void initCausticSamples() {
636
+ server.initCausticSamples(this);
637
+ }
638
+
639
+ /**
640
+ * Returns the color obtained by recursively tracing the specified ray. The
641
+ * reflection is assumed to be glossy.
642
+ *
643
+ * @param r ray to trace
644
+ * @param i instance number of this sample
645
+ * @return color observed along specified ray.
646
+ */
647
+ public final Color traceGlossy(Ray r, int i) {
648
+ return server.traceGlossy(this, r, i);
649
+ }
650
+
651
+ /**
652
+ * Returns the color obtained by recursively tracing the specified ray. The
653
+ * reflection is assumed to be specular.
654
+ *
655
+ * @param r ray to trace
656
+ * @param i instance number of this sample
657
+ * @return color observed along specified ray.
658
+ */
659
+ public final Color traceReflection(Ray r, int i) {
660
+ return server.traceReflection(this, r, i);
661
+ }
662
+
663
+ /**
664
+ * Returns the color obtained by recursively tracing the specified ray.
665
+ *
666
+ * @param r ray to trace
667
+ * @param i instance number of this sample
668
+ * @return color observed along specified ray.
669
+ */
670
+ public final Color traceRefraction(Ray r, int i) {
671
+ // this assumes the refraction ray is pointing away from the normal
672
+ r.ox -= 2 * bias * ng.x;
673
+ r.oy -= 2 * bias * ng.y;
674
+ r.oz -= 2 * bias * ng.z;
675
+ return server.traceRefraction(this, r, i);
676
+ }
677
+
678
+ /**
679
+ * Trace transparency, this is equivalent to tracing a refraction ray in the
680
+ * incoming ray direction.
681
+ *
682
+ * @return color observed behind the current shading point
683
+ */
684
+ public final Color traceTransparency() {
685
+ return traceRefraction(new Ray(p.x, p.y, p.z, r.dx, r.dy, r.dz), 0);
686
+ }
687
+
688
+ /**
689
+ * Trace a shadow ray against the scene, and computes the accumulated
690
+ * opacity along the ray.
691
+ *
692
+ * @param r ray to trace
693
+ * @return opacity along the shadow ray
694
+ */
695
+ public final Color traceShadow(Ray r) {
696
+ return server.getScene().traceShadow(r, istate);
697
+ }
698
+
699
+ /**
700
+ * Records a photon at the specified location.
701
+ *
702
+ * @param dir incoming direction of the photon
703
+ * @param power photon power
704
+ * @param diffuse diffuse reflectance at the given point
705
+ */
706
+ public final void storePhoton(Vector3 dir, Color power, Color diffuse) {
707
+ map.store(this, dir, power, diffuse);
708
+ }
709
+
710
+ /**
711
+ * Trace a new photon from the current location. This assumes that the
712
+ * photon was reflected by a specular surface.
713
+ *
714
+ * @param r ray to trace photon along
715
+ * @param power power of the new photon
716
+ */
717
+ public final void traceReflectionPhoton(Ray r, Color power) {
718
+ if (map.allowReflectionBounced()) {
719
+ server.traceReflectionPhoton(this, r, power);
720
+ }
721
+ }
722
+
723
+ /**
724
+ * Trace a new photon from the current location. This assumes that the
725
+ * photon was refracted by a specular surface.
726
+ *
727
+ * @param r ray to trace photon along
728
+ * @param power power of the new photon
729
+ */
730
+ public final void traceRefractionPhoton(Ray r, Color power) {
731
+ if (map.allowRefractionBounced()) {
732
+ // this assumes the refraction ray is pointing away from the normal
733
+ r.ox -= 0.002f * ng.x;
734
+ r.oy -= 0.002f * ng.y;
735
+ r.oz -= 0.002f * ng.z;
736
+ server.traceRefractionPhoton(this, r, power);
737
+ }
738
+ }
739
+
740
+ /**
741
+ * Trace a new photon from the current location. This assumes that the
742
+ * photon was reflected by a diffuse surface.
743
+ *
744
+ * @param r ray to trace photon along
745
+ * @param power power of the new photon
746
+ */
747
+ public final void traceDiffusePhoton(Ray r, Color power) {
748
+ if (map.allowDiffuseBounced()) {
749
+ server.traceDiffusePhoton(this, r, power);
750
+ }
751
+ }
752
+
753
+ /**
754
+ * Returns the glboal diffuse radiance estimate given by the current
755
+ * {@link GIEngine} if present.
756
+ *
757
+ * @return global diffuse radiance estimate
758
+ */
759
+ public final Color getGlobalRadiance() {
760
+ return server.getGlobalRadiance(this);
761
+ }
762
+
763
+ /**
764
+ * Gets the total irradiance reaching the current point from diffuse
765
+ * surfaces.
766
+ *
767
+ * @param diffuseReflectance diffuse reflectance at the current point, can
768
+ * be used for importance tracking
769
+ * @return indirect diffuse irradiance reaching the point
770
+ */
771
+ public final Color getIrradiance(Color diffuseReflectance) {
772
+ return server.getIrradiance(this, diffuseReflectance);
773
+ }
774
+
775
+ /**
776
+ * Trace a final gather ray and return the intersection result as a new
777
+ * render state
778
+ *
779
+ * @param r ray to shoot
780
+ * @param i instance of the ray
781
+ * @return new render state object corresponding to the intersection result
782
+ */
783
+ public final ShadingState traceFinalGather(Ray r, int i) {
784
+ return server.traceFinalGather(this, r, i);
785
+ }
786
+
787
+ /**
788
+ * Simple black and white ambient occlusion.
789
+ *
790
+ * @param samples number of sample rays
791
+ * @param maxDist maximum length of the rays
792
+ * @return occlusion color
793
+ */
794
+ public final Color occlusion(int samples, float maxDist) {
795
+ return occlusion(samples, maxDist, Color.WHITE, Color.BLACK);
796
+ }
797
+
798
+ /**
799
+ * Ambient occlusion routine, returns a value between bright and dark
800
+ * depending on the amount of geometric occlusion in the scene.
801
+ *
802
+ * @param samples number of sample rays
803
+ * @param maxDist maximum length of the rays
804
+ * @param bright color when nothing is occluded
805
+ * @param dark color when fully occluded
806
+ * @return occlusion color
807
+ */
808
+ public final Color occlusion(int samples, float maxDist, Color bright, Color dark) {
809
+ if (n == null) {
810
+ // in case we got called on a geometry without orientation
811
+ return bright;
812
+ }
813
+ // make sure we are on the right side of the material
814
+ faceforward();
815
+ OrthoNormalBasis onb = getBasis();
816
+ Vector3 w = new Vector3();
817
+ Color result = Color.black();
818
+ for (int i = 0; i < samples; i++) {
819
+ float xi = (float) getRandom(i, 0, samples);
820
+ float xj = (float) getRandom(i, 1, samples);
821
+ float phi = (float) (2 * Math.PI * xi);
822
+ float cosPhi = (float) Math.cos(phi);
823
+ float sinPhi = (float) Math.sin(phi);
824
+ float sinTheta = (float) Math.sqrt(xj);
825
+ float cosTheta = (float) Math.sqrt(1.0f - xj);
826
+ w.x = cosPhi * sinTheta;
827
+ w.y = sinPhi * sinTheta;
828
+ w.z = cosTheta;
829
+ onb.transform(w);
830
+ Ray r = new Ray(p, w);
831
+ r.setMax(maxDist);
832
+ result.add(Color.blend(bright, dark, traceShadow(r)));
833
+ }
834
+ return result.mul(1.0f / samples);
835
+ }
836
+
837
+ /**
838
+ * Computes a plain diffuse response to the current light samples and global
839
+ * illumination.
840
+ *
841
+ * @param diff diffuse color
842
+ * @return shaded result
843
+ */
844
+ public final Color diffuse(Color diff) {
845
+ // integrate a diffuse function
846
+ Color lr = Color.black();
847
+ if (diff.isBlack()) {
848
+ return lr;
849
+ }
850
+ for (LightSample sample : this) {
851
+ lr.madd(sample.dot(n), sample.getDiffuseRadiance());
852
+ }
853
+ lr.add(getIrradiance(diff));
854
+ return lr.mul(diff).mul(1.0f / (float) Math.PI);
855
+ }
856
+
857
+ /**
858
+ * Computes a phong specular response to the current light samples and
859
+ * global illumination.
860
+ *
861
+ * @param spec specular color
862
+ * @param power phong exponent
863
+ * @param numRays number of glossy rays to trace
864
+ * @return shaded color
865
+ */
866
+ public final Color specularPhong(Color spec, float power, int numRays) {
867
+ // integrate a phong specular function
868
+ Color lr = Color.black();
869
+ if (!includeSpecular || spec.isBlack()) {
870
+ return lr;
871
+ }
872
+ // reflected direction
873
+ float dn = 2 * cosND;
874
+ Vector3 refDir = new Vector3();
875
+ refDir.x = (dn * n.x) + r.dx;
876
+ refDir.y = (dn * n.y) + r.dy;
877
+ refDir.z = (dn * n.z) + r.dz;
878
+ // direct lighting
879
+ for (LightSample sample : this) {
880
+ float cosNL = sample.dot(n);
881
+ float cosLR = sample.dot(refDir);
882
+ if (cosLR > 0) {
883
+ lr.madd(cosNL * (float) Math.pow(cosLR, power), sample.getSpecularRadiance());
884
+ }
885
+ }
886
+ // indirect lighting
887
+ if (numRays > 0) {
888
+ int numSamples = getDepth() == 0 ? numRays : 1;
889
+ OrthoNormalBasis onb = OrthoNormalBasis.makeFromW(refDir);
890
+ float mul = (2.0f * (float) Math.PI / (power + 1)) / numSamples;
891
+ for (int i = 0; i < numSamples; i++) {
892
+ // specular indirect lighting
893
+ double r1 = getRandom(i, 0, numSamples);
894
+ double r2 = getRandom(i, 1, numSamples);
895
+ double u = 2 * Math.PI * r1;
896
+ double s = (float) Math.pow(r2, 1 / (power + 1));
897
+ double s1 = (float) Math.sqrt(1 - s * s);
898
+ Vector3 w = new Vector3((float) (Math.cos(u) * s1), (float) (Math.sin(u) * s1), (float) s);
899
+ w = onb.transform(w, new Vector3());
900
+ float wn = Vector3.dot(w, n);
901
+ if (wn > 0) {
902
+ lr.madd(wn * mul, traceGlossy(new Ray(p, w), i));
903
+ }
904
+ }
905
+ }
906
+ lr.mul(spec).mul((power + 2) / (2.0f * (float) Math.PI));
907
+ return lr;
908
+ }
909
+
910
+ /**
911
+ * Allows iteration over current light samples.
912
+ */
913
+ public Iterator<LightSample> iterator() {
914
+ return new LightSampleIterator(lightSample);
915
+ }
916
+
917
+ private static class LightSampleIterator implements Iterator<LightSample> {
918
+
919
+ private LightSample current;
920
+
921
+ LightSampleIterator(LightSample head) {
922
+ current = head;
923
+ }
924
+
925
+ public boolean hasNext() {
926
+ return current != null;
927
+ }
928
+
929
+ public LightSample next() {
930
+ LightSample c = current;
931
+ current = current.next;
932
+ return c;
933
+ }
934
+
935
+ public void remove() {
936
+ throw new UnsupportedOperationException();
937
+ }
938
+ }
939
+ }