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.
- checksums.yaml +7 -0
- data/.gitignore +53 -0
- data/.mvn/extensions.xml +8 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +6 -0
- data/LICENSE +674 -0
- data/README.md +2 -0
- data/Rakefile +43 -0
- data/docs/.gitignore +6 -0
- data/docs/_config.yml +20 -0
- data/docs/_includes/footer.html +38 -0
- data/docs/_includes/head.html +15 -0
- data/docs/_includes/header.html +27 -0
- data/docs/_includes/icon-github.html +1 -0
- data/docs/_includes/icon-github.svg +1 -0
- data/docs/_includes/icon-twitter.html +1 -0
- data/docs/_includes/icon-twitter.svg +1 -0
- data/docs/_layouts/default.html +20 -0
- data/docs/_layouts/page.html +14 -0
- data/docs/_layouts/post.html +15 -0
- data/docs/_posts/2017-01-08-animated_ray_tracing.md +72 -0
- data/docs/_posts/2017-01-08-welcome.md +78 -0
- data/docs/_sass/_base.scss +206 -0
- data/docs/_sass/_layout.scss +242 -0
- data/docs/_sass/_syntax-highlighting.scss +71 -0
- data/docs/about.md +12 -0
- data/docs/assets/Animation.ogv +0 -0
- data/docs/assets/Animation.png +0 -0
- data/docs/assets/basic.png +0 -0
- data/docs/assets/basic_traced.png +0 -0
- data/docs/css/main.scss +38 -0
- data/docs/favicon.ico +0 -0
- data/docs/feed.xml +30 -0
- data/docs/index.html +38 -0
- data/joonsrenderer.gemspec +23 -0
- data/lib/joonsrenderer.rb +12 -0
- data/lib/joonsrenderer/version.rb +3 -0
- data/pom.rb +75 -0
- data/pom.xml +163 -0
- data/src/main/java/SunflowGUI.java +1354 -0
- data/src/main/java/joons/JRFiller.java +79 -0
- data/src/main/java/joons/JRImagePanel.java +141 -0
- data/src/main/java/joons/JRRecorder.java +183 -0
- data/src/main/java/joons/JRStatics.java +199 -0
- data/src/main/java/joons/JoonsRenderer.java +837 -0
- data/src/main/java/org/sunflow/AsciiFileSunflowAPI.java +98 -0
- data/src/main/java/org/sunflow/Benchmark.java +313 -0
- data/src/main/java/org/sunflow/BinaryFileSunflowAPI.java +228 -0
- data/src/main/java/org/sunflow/FileSunflowAPI.java +354 -0
- data/src/main/java/org/sunflow/PluginRegistry.java +322 -0
- data/src/main/java/org/sunflow/RealtimeBenchmark.java +125 -0
- data/src/main/java/org/sunflow/RenderObjectMap.java +344 -0
- data/src/main/java/org/sunflow/SunflowAPI.java +762 -0
- data/src/main/java/org/sunflow/SunflowAPIInterface.java +277 -0
- data/src/main/java/org/sunflow/core/AccelerationStructure.java +20 -0
- data/src/main/java/org/sunflow/core/AccelerationStructureFactory.java +36 -0
- data/src/main/java/org/sunflow/core/BucketOrder.java +21 -0
- data/src/main/java/org/sunflow/core/Camera.java +125 -0
- data/src/main/java/org/sunflow/core/CameraLens.java +29 -0
- data/src/main/java/org/sunflow/core/CausticPhotonMapInterface.java +15 -0
- data/src/main/java/org/sunflow/core/Display.java +78 -0
- data/src/main/java/org/sunflow/core/Filter.java +27 -0
- data/src/main/java/org/sunflow/core/GIEngine.java +42 -0
- data/src/main/java/org/sunflow/core/Geometry.java +157 -0
- data/src/main/java/org/sunflow/core/GlobalPhotonMapInterface.java +21 -0
- data/src/main/java/org/sunflow/core/ImageSampler.java +26 -0
- data/src/main/java/org/sunflow/core/Instance.java +224 -0
- data/src/main/java/org/sunflow/core/InstanceList.java +83 -0
- data/src/main/java/org/sunflow/core/IntersectionState.java +120 -0
- data/src/main/java/org/sunflow/core/LightSample.java +104 -0
- data/src/main/java/org/sunflow/core/LightServer.java +382 -0
- data/src/main/java/org/sunflow/core/LightSource.java +67 -0
- data/src/main/java/org/sunflow/core/Modifier.java +16 -0
- data/src/main/java/org/sunflow/core/Options.java +20 -0
- data/src/main/java/org/sunflow/core/ParameterList.java +758 -0
- data/src/main/java/org/sunflow/core/PhotonStore.java +62 -0
- data/src/main/java/org/sunflow/core/PrimitiveList.java +70 -0
- data/src/main/java/org/sunflow/core/Ray.java +219 -0
- data/src/main/java/org/sunflow/core/RenderObject.java +25 -0
- data/src/main/java/org/sunflow/core/Scene.java +377 -0
- data/src/main/java/org/sunflow/core/SceneParser.java +58 -0
- data/src/main/java/org/sunflow/core/Shader.java +30 -0
- data/src/main/java/org/sunflow/core/ShadingCache.java +84 -0
- data/src/main/java/org/sunflow/core/ShadingState.java +939 -0
- data/src/main/java/org/sunflow/core/Statistics.java +85 -0
- data/src/main/java/org/sunflow/core/Tesselatable.java +36 -0
- data/src/main/java/org/sunflow/core/Texture.java +128 -0
- data/src/main/java/org/sunflow/core/TextureCache.java +48 -0
- data/src/main/java/org/sunflow/core/accel/BoundingIntervalHierarchy.java +652 -0
- data/src/main/java/org/sunflow/core/accel/KDTree.java +833 -0
- data/src/main/java/org/sunflow/core/accel/NullAccelerator.java +30 -0
- data/src/main/java/org/sunflow/core/accel/UniformGrid.java +329 -0
- data/src/main/java/org/sunflow/core/bucket/BucketOrderFactory.java +26 -0
- data/src/main/java/org/sunflow/core/bucket/ColumnBucketOrder.java +21 -0
- data/src/main/java/org/sunflow/core/bucket/DiagonalBucketOrder.java +28 -0
- data/src/main/java/org/sunflow/core/bucket/HilbertBucketOrder.java +65 -0
- data/src/main/java/org/sunflow/core/bucket/InvertedBucketOrder.java +28 -0
- data/src/main/java/org/sunflow/core/bucket/RandomBucketOrder.java +49 -0
- data/src/main/java/org/sunflow/core/bucket/RowBucketOrder.java +21 -0
- data/src/main/java/org/sunflow/core/bucket/SpiralBucketOrder.java +43 -0
- data/src/main/java/org/sunflow/core/camera/FisheyeLens.java +25 -0
- data/src/main/java/org/sunflow/core/camera/PinholeLens.java +43 -0
- data/src/main/java/org/sunflow/core/camera/SphericalLens.java +22 -0
- data/src/main/java/org/sunflow/core/camera/ThinLens.java +107 -0
- data/src/main/java/org/sunflow/core/display/FastDisplay.java +119 -0
- data/src/main/java/org/sunflow/core/display/FileDisplay.java +83 -0
- data/src/main/java/org/sunflow/core/display/FrameDisplay.java +97 -0
- data/src/main/java/org/sunflow/core/display/ImgPipeDisplay.java +109 -0
- data/src/main/java/org/sunflow/core/filter/BlackmanHarrisFilter.java +28 -0
- data/src/main/java/org/sunflow/core/filter/BoxFilter.java +16 -0
- data/src/main/java/org/sunflow/core/filter/CatmullRomFilter.java +29 -0
- data/src/main/java/org/sunflow/core/filter/CubicBSpline.java +32 -0
- data/src/main/java/org/sunflow/core/filter/GaussianFilter.java +24 -0
- data/src/main/java/org/sunflow/core/filter/LanczosFilter.java +30 -0
- data/src/main/java/org/sunflow/core/filter/MitchellFilter.java +28 -0
- data/src/main/java/org/sunflow/core/filter/SincFilter.java +25 -0
- data/src/main/java/org/sunflow/core/filter/TriangleFilter.java +16 -0
- data/src/main/java/org/sunflow/core/gi/AmbientOcclusionGIEngine.java +57 -0
- data/src/main/java/org/sunflow/core/gi/FakeGIEngine.java +48 -0
- data/src/main/java/org/sunflow/core/gi/InstantGI.java +194 -0
- data/src/main/java/org/sunflow/core/gi/IrradianceCacheGIEngine.java +268 -0
- data/src/main/java/org/sunflow/core/gi/PathTracingGIEngine.java +65 -0
- data/src/main/java/org/sunflow/core/light/DirectionalSpotlight.java +103 -0
- data/src/main/java/org/sunflow/core/light/ImageBasedLight.java +303 -0
- data/src/main/java/org/sunflow/core/light/PointLight.java +72 -0
- data/src/main/java/org/sunflow/core/light/SphereLight.java +166 -0
- data/src/main/java/org/sunflow/core/light/SunSkyLight.java +362 -0
- data/src/main/java/org/sunflow/core/light/TriangleMeshLight.java +296 -0
- data/src/main/java/org/sunflow/core/modifiers/BumpMappingModifier.java +37 -0
- data/src/main/java/org/sunflow/core/modifiers/NormalMapModifier.java +34 -0
- data/src/main/java/org/sunflow/core/modifiers/PerlinModifier.java +80 -0
- data/src/main/java/org/sunflow/core/parser/Keyword.java +39 -0
- data/src/main/java/org/sunflow/core/parser/RA2Parser.java +107 -0
- data/src/main/java/org/sunflow/core/parser/RA3Parser.java +68 -0
- data/src/main/java/org/sunflow/core/parser/SCAbstractParser.java +299 -0
- data/src/main/java/org/sunflow/core/parser/SCAsciiParser.java +251 -0
- data/src/main/java/org/sunflow/core/parser/SCBinaryParser.java +156 -0
- data/src/main/java/org/sunflow/core/parser/SCParser.java +1403 -0
- data/src/main/java/org/sunflow/core/parser/ShaveRibParser.java +174 -0
- data/src/main/java/org/sunflow/core/parser/TriParser.java +79 -0
- data/src/main/java/org/sunflow/core/photonmap/CausticPhotonMap.java +429 -0
- data/src/main/java/org/sunflow/core/photonmap/GlobalPhotonMap.java +530 -0
- data/src/main/java/org/sunflow/core/photonmap/GridPhotonMap.java +308 -0
- data/src/main/java/org/sunflow/core/primitive/Background.java +55 -0
- data/src/main/java/org/sunflow/core/primitive/BanchoffSurface.java +100 -0
- data/src/main/java/org/sunflow/core/primitive/Box.java +210 -0
- data/src/main/java/org/sunflow/core/primitive/CornellBox.java +476 -0
- data/src/main/java/org/sunflow/core/primitive/CubeGrid.java +318 -0
- data/src/main/java/org/sunflow/core/primitive/Cylinder.java +104 -0
- data/src/main/java/org/sunflow/core/primitive/Hair.java +275 -0
- data/src/main/java/org/sunflow/core/primitive/JuliaFractal.java +266 -0
- data/src/main/java/org/sunflow/core/primitive/ParticleSurface.java +114 -0
- data/src/main/java/org/sunflow/core/primitive/Plane.java +163 -0
- data/src/main/java/org/sunflow/core/primitive/QuadMesh.java +413 -0
- data/src/main/java/org/sunflow/core/primitive/Sphere.java +101 -0
- data/src/main/java/org/sunflow/core/primitive/SphereFlake.java +234 -0
- data/src/main/java/org/sunflow/core/primitive/Torus.java +145 -0
- data/src/main/java/org/sunflow/core/primitive/TriangleMesh.java +849 -0
- data/src/main/java/org/sunflow/core/renderer/BucketRenderer.java +491 -0
- data/src/main/java/org/sunflow/core/renderer/MultipassRenderer.java +237 -0
- data/src/main/java/org/sunflow/core/renderer/ProgressiveRenderer.java +171 -0
- data/src/main/java/org/sunflow/core/renderer/SimpleRenderer.java +106 -0
- data/src/main/java/org/sunflow/core/shader/AmbientOcclusionShader.java +53 -0
- data/src/main/java/org/sunflow/core/shader/AnisotropicWardShader.java +216 -0
- data/src/main/java/org/sunflow/core/shader/ConstantShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/DiffuseShader.java +65 -0
- data/src/main/java/org/sunflow/core/shader/GlassShader.java +147 -0
- data/src/main/java/org/sunflow/core/shader/IDShader.java +27 -0
- data/src/main/java/org/sunflow/core/shader/MirrorShader.java +68 -0
- data/src/main/java/org/sunflow/core/shader/NormalShader.java +32 -0
- data/src/main/java/org/sunflow/core/shader/PhongShader.java +89 -0
- data/src/main/java/org/sunflow/core/shader/PrimIDShader.java +30 -0
- data/src/main/java/org/sunflow/core/shader/QuickGrayShader.java +63 -0
- data/src/main/java/org/sunflow/core/shader/ShinyDiffuseShader.java +98 -0
- data/src/main/java/org/sunflow/core/shader/SimpleShader.java +24 -0
- data/src/main/java/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/TexturedDiffuseShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/TexturedPhongShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/TexturedShinyDiffuseShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/TexturedWardShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/UVShader.java +27 -0
- data/src/main/java/org/sunflow/core/shader/UberShader.java +149 -0
- data/src/main/java/org/sunflow/core/shader/ViewCausticsShader.java +33 -0
- data/src/main/java/org/sunflow/core/shader/ViewGlobalPhotonsShader.java +25 -0
- data/src/main/java/org/sunflow/core/shader/ViewIrradianceShader.java +25 -0
- data/src/main/java/org/sunflow/core/shader/WireframeShader.java +83 -0
- data/src/main/java/org/sunflow/core/tesselatable/BezierMesh.java +254 -0
- data/src/main/java/org/sunflow/core/tesselatable/FileMesh.java +251 -0
- data/src/main/java/org/sunflow/core/tesselatable/Gumbo.java +1147 -0
- data/src/main/java/org/sunflow/core/tesselatable/Teapot.java +237 -0
- data/src/main/java/org/sunflow/image/Bitmap.java +15 -0
- data/src/main/java/org/sunflow/image/BitmapReader.java +39 -0
- data/src/main/java/org/sunflow/image/BitmapWriter.java +79 -0
- data/src/main/java/org/sunflow/image/BlackbodySpectrum.java +16 -0
- data/src/main/java/org/sunflow/image/ChromaticitySpectrum.java +55 -0
- data/src/main/java/org/sunflow/image/Color.java +374 -0
- data/src/main/java/org/sunflow/image/ColorEncoder.java +94 -0
- data/src/main/java/org/sunflow/image/ColorFactory.java +122 -0
- data/src/main/java/org/sunflow/image/ConstantSpectralCurve.java +21 -0
- data/src/main/java/org/sunflow/image/IrregularSpectralCurve.java +57 -0
- data/src/main/java/org/sunflow/image/RGBSpace.java +207 -0
- data/src/main/java/org/sunflow/image/RegularSpectralCurve.java +30 -0
- data/src/main/java/org/sunflow/image/SpectralCurve.java +118 -0
- data/src/main/java/org/sunflow/image/XYZColor.java +50 -0
- data/src/main/java/org/sunflow/image/formats/BitmapBlack.java +27 -0
- data/src/main/java/org/sunflow/image/formats/BitmapG8.java +36 -0
- data/src/main/java/org/sunflow/image/formats/BitmapGA8.java +30 -0
- data/src/main/java/org/sunflow/image/formats/BitmapRGB8.java +40 -0
- data/src/main/java/org/sunflow/image/formats/BitmapRGBA8.java +40 -0
- data/src/main/java/org/sunflow/image/formats/BitmapRGBE.java +60 -0
- data/src/main/java/org/sunflow/image/formats/BitmapXYZ.java +38 -0
- data/src/main/java/org/sunflow/image/formats/GenericBitmap.java +73 -0
- data/src/main/java/org/sunflow/image/readers/BMPBitmapReader.java +39 -0
- data/src/main/java/org/sunflow/image/readers/HDRBitmapReader.java +155 -0
- data/src/main/java/org/sunflow/image/readers/IGIBitmapReader.java +104 -0
- data/src/main/java/org/sunflow/image/readers/JPGBitmapReader.java +39 -0
- data/src/main/java/org/sunflow/image/readers/PNGBitmapReader.java +40 -0
- data/src/main/java/org/sunflow/image/readers/TGABitmapReader.java +141 -0
- data/src/main/java/org/sunflow/image/writers/EXRBitmapWriter.java +395 -0
- data/src/main/java/org/sunflow/image/writers/HDRBitmapWriter.java +54 -0
- data/src/main/java/org/sunflow/image/writers/IGIBitmapWriter.java +75 -0
- data/src/main/java/org/sunflow/image/writers/PNGBitmapWriter.java +39 -0
- data/src/main/java/org/sunflow/image/writers/TGABitmapWriter.java +63 -0
- data/src/main/java/org/sunflow/math/BoundingBox.java +340 -0
- data/src/main/java/org/sunflow/math/MathUtils.java +159 -0
- data/src/main/java/org/sunflow/math/Matrix4.java +573 -0
- data/src/main/java/org/sunflow/math/MovingMatrix4.java +119 -0
- data/src/main/java/org/sunflow/math/OrthoNormalBasis.java +110 -0
- data/src/main/java/org/sunflow/math/PerlinScalar.java +331 -0
- data/src/main/java/org/sunflow/math/PerlinVector.java +132 -0
- data/src/main/java/org/sunflow/math/Point2.java +36 -0
- data/src/main/java/org/sunflow/math/Point3.java +133 -0
- data/src/main/java/org/sunflow/math/QMC.java +209 -0
- data/src/main/java/org/sunflow/math/Solvers.java +142 -0
- data/src/main/java/org/sunflow/math/Vector3.java +197 -0
- data/src/main/java/org/sunflow/system/BenchmarkFramework.java +73 -0
- data/src/main/java/org/sunflow/system/BenchmarkTest.java +17 -0
- data/src/main/java/org/sunflow/system/ByteUtil.java +119 -0
- data/src/main/java/org/sunflow/system/FileUtils.java +27 -0
- data/src/main/java/org/sunflow/system/ImagePanel.java +282 -0
- data/src/main/java/org/sunflow/system/Memory.java +18 -0
- data/src/main/java/org/sunflow/system/Parser.java +162 -0
- data/src/main/java/org/sunflow/system/Plugins.java +142 -0
- data/src/main/java/org/sunflow/system/RenderGlobalsPanel.java +209 -0
- data/src/main/java/org/sunflow/system/SearchPath.java +67 -0
- data/src/main/java/org/sunflow/system/Timer.java +53 -0
- data/src/main/java/org/sunflow/system/UI.java +112 -0
- data/src/main/java/org/sunflow/system/UserInterface.java +46 -0
- data/src/main/java/org/sunflow/system/ui/ConsoleInterface.java +48 -0
- data/src/main/java/org/sunflow/system/ui/SilentInterface.java +28 -0
- data/src/main/java/org/sunflow/util/FastHashMap.java +220 -0
- data/src/main/java/org/sunflow/util/FloatArray.java +77 -0
- data/src/main/java/org/sunflow/util/IntArray.java +77 -0
- data/src/test/java/a_maintest.java +129 -0
- 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
|
+
}
|