joonsrenderer 1.1-java

Sign up to get free protection for your applications and to get access to all the features.
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
+ }