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,28 @@
|
|
|
1
|
+
package org.sunflow.core.filter;
|
|
2
|
+
|
|
3
|
+
import org.sunflow.core.Filter;
|
|
4
|
+
|
|
5
|
+
public class MitchellFilter implements Filter {
|
|
6
|
+
|
|
7
|
+
@Override
|
|
8
|
+
public float getSize() {
|
|
9
|
+
return 4.0f;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@Override
|
|
13
|
+
public float get(float x, float y) {
|
|
14
|
+
return mitchell(x) * mitchell(y);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private float mitchell(float x) {
|
|
18
|
+
final float B = 1 / 3.0f;
|
|
19
|
+
final float C = 1 / 3.0f;
|
|
20
|
+
final float SIXTH = 1 / 6.0f;
|
|
21
|
+
x = Math.abs(x);
|
|
22
|
+
float x2 = x * x;
|
|
23
|
+
if (x > 1.0f) {
|
|
24
|
+
return ((-B - 6 * C) * x * x2 + (6 * B + 30 * C) * x2 + (-12 * B - 48 * C) * x + (8 * B + 24 * C)) * SIXTH;
|
|
25
|
+
}
|
|
26
|
+
return ((12 - 9 * B - 6 * C) * x * x2 + (-18 + 12 * B + 6 * C) * x2 + (6 - 2 * B)) * SIXTH;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
package org.sunflow.core.filter;
|
|
2
|
+
|
|
3
|
+
import org.sunflow.core.Filter;
|
|
4
|
+
|
|
5
|
+
public class SincFilter implements Filter {
|
|
6
|
+
|
|
7
|
+
@Override
|
|
8
|
+
public float getSize() {
|
|
9
|
+
return 4.0f;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@Override
|
|
13
|
+
public float get(float x, float y) {
|
|
14
|
+
return sinc1d(x) * sinc1d(y);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private float sinc1d(float x) {
|
|
18
|
+
x = Math.abs(x);
|
|
19
|
+
if (x < 0.0001f) {
|
|
20
|
+
return 1.0f;
|
|
21
|
+
}
|
|
22
|
+
x *= Math.PI;
|
|
23
|
+
return (float) Math.sin(x) / x;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package org.sunflow.core.filter;
|
|
2
|
+
|
|
3
|
+
import org.sunflow.core.Filter;
|
|
4
|
+
|
|
5
|
+
public class TriangleFilter implements Filter {
|
|
6
|
+
|
|
7
|
+
@Override
|
|
8
|
+
public float getSize() {
|
|
9
|
+
return 2.0f;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@Override
|
|
13
|
+
public float get(float x, float y) {
|
|
14
|
+
return (1.0f - Math.abs(x)) * (1.0f - Math.abs(y));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
package org.sunflow.core.gi;
|
|
2
|
+
|
|
3
|
+
import org.sunflow.core.GIEngine;
|
|
4
|
+
import org.sunflow.core.Options;
|
|
5
|
+
import org.sunflow.core.Ray;
|
|
6
|
+
import org.sunflow.core.Scene;
|
|
7
|
+
import org.sunflow.core.ShadingState;
|
|
8
|
+
import org.sunflow.image.Color;
|
|
9
|
+
import org.sunflow.math.OrthoNormalBasis;
|
|
10
|
+
import org.sunflow.math.Vector3;
|
|
11
|
+
|
|
12
|
+
public class AmbientOcclusionGIEngine implements GIEngine {
|
|
13
|
+
|
|
14
|
+
private Color bright;
|
|
15
|
+
private Color dark;
|
|
16
|
+
private int samples;
|
|
17
|
+
private float maxDist;
|
|
18
|
+
|
|
19
|
+
@Override
|
|
20
|
+
public Color getGlobalRadiance(ShadingState state) {
|
|
21
|
+
return Color.BLACK;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Override
|
|
25
|
+
public boolean init(Options options, Scene scene) {
|
|
26
|
+
bright = options.getColor("gi.ambocc.bright", Color.WHITE);
|
|
27
|
+
dark = options.getColor("gi.ambocc.dark", Color.BLACK);
|
|
28
|
+
samples = options.getInt("gi.ambocc.samples", 32);
|
|
29
|
+
maxDist = options.getFloat("gi.ambocc.maxdist", 0);
|
|
30
|
+
maxDist = (maxDist <= 0) ? Float.POSITIVE_INFINITY : maxDist;
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@Override
|
|
35
|
+
public Color getIrradiance(ShadingState state, Color diffuseReflectance) {
|
|
36
|
+
OrthoNormalBasis onb = state.getBasis();
|
|
37
|
+
Vector3 w = new Vector3();
|
|
38
|
+
Color result = Color.black();
|
|
39
|
+
for (int i = 0; i < samples; i++) {
|
|
40
|
+
float xi = (float) state.getRandom(i, 0, samples);
|
|
41
|
+
float xj = (float) state.getRandom(i, 1, samples);
|
|
42
|
+
float phi = (float) (2 * Math.PI * xi);
|
|
43
|
+
float cosPhi = (float) Math.cos(phi);
|
|
44
|
+
float sinPhi = (float) Math.sin(phi);
|
|
45
|
+
float sinTheta = (float) Math.sqrt(xj);
|
|
46
|
+
float cosTheta = (float) Math.sqrt(1.0f - xj);
|
|
47
|
+
w.x = cosPhi * sinTheta;
|
|
48
|
+
w.y = sinPhi * sinTheta;
|
|
49
|
+
w.z = cosTheta;
|
|
50
|
+
onb.transform(w);
|
|
51
|
+
Ray r = new Ray(state.getPoint(), w);
|
|
52
|
+
r.setMax(maxDist);
|
|
53
|
+
result.add(Color.blend(bright, dark, state.traceShadow(r)));
|
|
54
|
+
}
|
|
55
|
+
return result.mul((float) Math.PI / samples);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
package org.sunflow.core.gi;
|
|
2
|
+
|
|
3
|
+
import org.sunflow.core.GIEngine;
|
|
4
|
+
import org.sunflow.core.Options;
|
|
5
|
+
import org.sunflow.core.Scene;
|
|
6
|
+
import org.sunflow.core.ShadingState;
|
|
7
|
+
import org.sunflow.image.Color;
|
|
8
|
+
import org.sunflow.math.Vector3;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* This is a quick way to get a bit of ambient lighting into your scene with
|
|
12
|
+
* hardly any overhead. It's based on the formula found here:
|
|
13
|
+
*
|
|
14
|
+
* @link http://www.cs.utah.edu/~shirley/papers/rtrt/node7.html#SECTION00031100000000000000
|
|
15
|
+
*/
|
|
16
|
+
public class FakeGIEngine implements GIEngine {
|
|
17
|
+
|
|
18
|
+
private Vector3 up;
|
|
19
|
+
private Color sky;
|
|
20
|
+
private Color ground;
|
|
21
|
+
|
|
22
|
+
@Override
|
|
23
|
+
public Color getIrradiance(ShadingState state, Color diffuseReflectance) {
|
|
24
|
+
float cosTheta = Vector3.dot(up, state.getNormal());
|
|
25
|
+
float sin2 = (1 - cosTheta * cosTheta);
|
|
26
|
+
float sine = sin2 > 0 ? (float) Math.sqrt(sin2) * 0.5f : 0;
|
|
27
|
+
if (cosTheta > 0) {
|
|
28
|
+
return Color.blend(sky, ground, sine);
|
|
29
|
+
} else {
|
|
30
|
+
return Color.blend(ground, sky, sine);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@Override
|
|
35
|
+
public Color getGlobalRadiance(ShadingState state) {
|
|
36
|
+
return Color.BLACK;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Override
|
|
40
|
+
public boolean init(Options options, Scene scene) {
|
|
41
|
+
up = options.getVector("gi.fake.up", new Vector3(0, 1, 0)).normalize();
|
|
42
|
+
sky = options.getColor("gi.fake.sky", Color.WHITE).copy();
|
|
43
|
+
ground = options.getColor("gi.fake.ground", Color.BLACK).copy();
|
|
44
|
+
sky.mul((float) Math.PI);
|
|
45
|
+
ground.mul((float) Math.PI);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
package org.sunflow.core.gi;
|
|
2
|
+
|
|
3
|
+
import java.util.ArrayList;
|
|
4
|
+
|
|
5
|
+
import org.sunflow.core.GIEngine;
|
|
6
|
+
import org.sunflow.core.Options;
|
|
7
|
+
import org.sunflow.core.PhotonStore;
|
|
8
|
+
import org.sunflow.core.Ray;
|
|
9
|
+
import org.sunflow.core.Scene;
|
|
10
|
+
import org.sunflow.core.ShadingState;
|
|
11
|
+
import org.sunflow.image.Color;
|
|
12
|
+
import org.sunflow.math.BoundingBox;
|
|
13
|
+
import org.sunflow.math.OrthoNormalBasis;
|
|
14
|
+
import org.sunflow.math.Point3;
|
|
15
|
+
import org.sunflow.math.Vector3;
|
|
16
|
+
import org.sunflow.system.UI;
|
|
17
|
+
import org.sunflow.system.UI.Module;
|
|
18
|
+
|
|
19
|
+
public class InstantGI implements GIEngine {
|
|
20
|
+
|
|
21
|
+
private int numPhotons;
|
|
22
|
+
private int numSets;
|
|
23
|
+
private float c;
|
|
24
|
+
private int numBias;
|
|
25
|
+
private PointLight[][] virtualLights;
|
|
26
|
+
|
|
27
|
+
@Override
|
|
28
|
+
public Color getGlobalRadiance(ShadingState state) {
|
|
29
|
+
Point3 p = state.getPoint();
|
|
30
|
+
Vector3 n = state.getNormal();
|
|
31
|
+
int set = (int) (state.getRandom(0, 1, 1) * numSets);
|
|
32
|
+
float maxAvgPow = 0;
|
|
33
|
+
float minDist = 1;
|
|
34
|
+
Color pow = null;
|
|
35
|
+
for (PointLight vpl : virtualLights[set]) {
|
|
36
|
+
maxAvgPow = Math.max(maxAvgPow, vpl.power.getAverage());
|
|
37
|
+
if (Vector3.dot(n, vpl.n) > 0.9f) {
|
|
38
|
+
float d = vpl.p.distanceToSquared(p);
|
|
39
|
+
if (d < minDist) {
|
|
40
|
+
pow = vpl.power;
|
|
41
|
+
minDist = d;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return pow == null ? Color.BLACK : pow.copy().mul(1.0f / maxAvgPow);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Override
|
|
49
|
+
public boolean init(Options options, Scene scene) {
|
|
50
|
+
numPhotons = options.getInt("gi.igi.samples", 64);
|
|
51
|
+
numSets = options.getInt("gi.igi.sets", 1);
|
|
52
|
+
c = options.getFloat("gi.igi.c", 0.00003f);
|
|
53
|
+
numBias = options.getInt("gi.igi.bias_samples", 0);
|
|
54
|
+
virtualLights = null;
|
|
55
|
+
if (numSets < 1) {
|
|
56
|
+
numSets = 1;
|
|
57
|
+
}
|
|
58
|
+
UI.printInfo(Module.LIGHT, "Instant Global Illumination settings:");
|
|
59
|
+
UI.printInfo(Module.LIGHT, " * Samples: %d", numPhotons);
|
|
60
|
+
UI.printInfo(Module.LIGHT, " * Sets: %d", numSets);
|
|
61
|
+
UI.printInfo(Module.LIGHT, " * Bias bound: %f", c);
|
|
62
|
+
UI.printInfo(Module.LIGHT, " * Bias rays: %d", numBias);
|
|
63
|
+
virtualLights = new PointLight[numSets][];
|
|
64
|
+
if (numPhotons > 0) {
|
|
65
|
+
for (int i = 0, seed = 0; i < virtualLights.length; i++, seed += numPhotons) {
|
|
66
|
+
PointLightStore map = new PointLightStore();
|
|
67
|
+
if (!scene.calculatePhotons(map, "virtual", seed, options)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
virtualLights[i] = map.virtualLights.toArray(new PointLight[map.virtualLights.size()]);
|
|
71
|
+
UI.printInfo(Module.LIGHT, "Stored %d virtual point lights for set %d of %d", virtualLights[i].length, i + 1, numSets);
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
// create an empty array
|
|
75
|
+
for (int i = 0; i < virtualLights.length; i++) {
|
|
76
|
+
virtualLights[i] = new PointLight[0];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@Override
|
|
83
|
+
public Color getIrradiance(ShadingState state, Color diffuseReflectance) {
|
|
84
|
+
float b = (float) Math.PI * c / diffuseReflectance.getMax();
|
|
85
|
+
Color irr = Color.black();
|
|
86
|
+
Point3 p = state.getPoint();
|
|
87
|
+
Vector3 n = state.getNormal();
|
|
88
|
+
int set = (int) (state.getRandom(0, 1, 1) * numSets);
|
|
89
|
+
for (PointLight vpl : virtualLights[set]) {
|
|
90
|
+
Ray r = new Ray(p, vpl.p);
|
|
91
|
+
float dotNlD = -(r.dx * vpl.n.x + r.dy * vpl.n.y + r.dz * vpl.n.z);
|
|
92
|
+
float dotND = r.dx * n.x + r.dy * n.y + r.dz * n.z;
|
|
93
|
+
if (dotNlD > 0 && dotND > 0) {
|
|
94
|
+
float r2 = r.getMax() * r.getMax();
|
|
95
|
+
Color opacity = state.traceShadow(r);
|
|
96
|
+
Color power = Color.blend(vpl.power, Color.BLACK, opacity);
|
|
97
|
+
float g = (dotND * dotNlD) / r2;
|
|
98
|
+
irr.madd(0.25f * Math.min(g, b), power);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// bias compensation
|
|
102
|
+
int nb = (state.getDiffuseDepth() == 0 || numBias <= 0) ? numBias : 1;
|
|
103
|
+
if (nb <= 0) {
|
|
104
|
+
return irr;
|
|
105
|
+
}
|
|
106
|
+
OrthoNormalBasis onb = state.getBasis();
|
|
107
|
+
Vector3 w = new Vector3();
|
|
108
|
+
float scale = (float) Math.PI / nb;
|
|
109
|
+
for (int i = 0; i < nb; i++) {
|
|
110
|
+
float xi = (float) state.getRandom(i, 0, nb);
|
|
111
|
+
float xj = (float) state.getRandom(i, 1, nb);
|
|
112
|
+
float phi = (float) (xi * 2 * Math.PI);
|
|
113
|
+
float cosPhi = (float) Math.cos(phi);
|
|
114
|
+
float sinPhi = (float) Math.sin(phi);
|
|
115
|
+
float sinTheta = (float) Math.sqrt(xj);
|
|
116
|
+
float cosTheta = (float) Math.sqrt(1.0f - xj);
|
|
117
|
+
w.x = cosPhi * sinTheta;
|
|
118
|
+
w.y = sinPhi * sinTheta;
|
|
119
|
+
w.z = cosTheta;
|
|
120
|
+
onb.transform(w);
|
|
121
|
+
Ray r = new Ray(state.getPoint(), w);
|
|
122
|
+
r.setMax((float) Math.sqrt(cosTheta / b));
|
|
123
|
+
ShadingState temp = state.traceFinalGather(r, i);
|
|
124
|
+
if (temp != null) {
|
|
125
|
+
temp.getInstance().prepareShadingState(temp);
|
|
126
|
+
if (temp.getShader() != null) {
|
|
127
|
+
float dist = temp.getRay().getMax();
|
|
128
|
+
float r2 = dist * dist;
|
|
129
|
+
float cosThetaY = -Vector3.dot(w, temp.getNormal());
|
|
130
|
+
if (cosThetaY > 0) {
|
|
131
|
+
float g = (cosTheta * cosThetaY) / r2;
|
|
132
|
+
// was this path accounted for yet?
|
|
133
|
+
if (g > b) {
|
|
134
|
+
irr.madd(scale * (g - b) / g, temp.getShader().getRadiance(temp));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return irr;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private static class PointLight {
|
|
144
|
+
|
|
145
|
+
Point3 p;
|
|
146
|
+
Vector3 n;
|
|
147
|
+
Color power;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private class PointLightStore implements PhotonStore {
|
|
151
|
+
|
|
152
|
+
ArrayList<PointLight> virtualLights = new ArrayList<>();
|
|
153
|
+
|
|
154
|
+
@Override
|
|
155
|
+
public int numEmit() {
|
|
156
|
+
return numPhotons;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@Override
|
|
160
|
+
public void prepare(Options options, BoundingBox sceneBounds) {
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@Override
|
|
164
|
+
public void store(ShadingState state, Vector3 dir, Color power, Color diffuse) {
|
|
165
|
+
state.faceforward();
|
|
166
|
+
PointLight vpl = new PointLight();
|
|
167
|
+
vpl.p = state.getPoint();
|
|
168
|
+
vpl.n = state.getNormal();
|
|
169
|
+
vpl.power = power;
|
|
170
|
+
synchronized (this) {
|
|
171
|
+
virtualLights.add(vpl);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@Override
|
|
176
|
+
public void init() {
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@Override
|
|
180
|
+
public boolean allowDiffuseBounced() {
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@Override
|
|
185
|
+
public boolean allowReflectionBounced() {
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@Override
|
|
190
|
+
public boolean allowRefractionBounced() {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
package org.sunflow.core.gi;
|
|
2
|
+
|
|
3
|
+
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
4
|
+
|
|
5
|
+
import org.sunflow.PluginRegistry;
|
|
6
|
+
import org.sunflow.core.GIEngine;
|
|
7
|
+
import org.sunflow.core.GlobalPhotonMapInterface;
|
|
8
|
+
import org.sunflow.core.Options;
|
|
9
|
+
import org.sunflow.core.Ray;
|
|
10
|
+
import org.sunflow.core.Scene;
|
|
11
|
+
import org.sunflow.core.ShadingState;
|
|
12
|
+
import org.sunflow.image.Color;
|
|
13
|
+
import org.sunflow.math.MathUtils;
|
|
14
|
+
import org.sunflow.math.OrthoNormalBasis;
|
|
15
|
+
import org.sunflow.math.Point3;
|
|
16
|
+
import org.sunflow.math.Vector3;
|
|
17
|
+
import org.sunflow.system.UI;
|
|
18
|
+
import org.sunflow.system.UI.Module;
|
|
19
|
+
|
|
20
|
+
public class IrradianceCacheGIEngine implements GIEngine {
|
|
21
|
+
|
|
22
|
+
private int samples;
|
|
23
|
+
private float tolerance;
|
|
24
|
+
private float invTolerance;
|
|
25
|
+
private float minSpacing;
|
|
26
|
+
private float maxSpacing;
|
|
27
|
+
private Node root;
|
|
28
|
+
private ReentrantReadWriteLock rwl;
|
|
29
|
+
private GlobalPhotonMapInterface globalPhotonMap;
|
|
30
|
+
|
|
31
|
+
@Override
|
|
32
|
+
public boolean init(Options options, Scene scene) {
|
|
33
|
+
// get settings
|
|
34
|
+
samples = options.getInt("gi.irr-cache.samples", 256);
|
|
35
|
+
tolerance = options.getFloat("gi.irr-cache.tolerance", 0.05f);
|
|
36
|
+
invTolerance = 1.0f / tolerance;
|
|
37
|
+
minSpacing = options.getFloat("gi.irr-cache.min_spacing", 0.05f);
|
|
38
|
+
maxSpacing = options.getFloat("gi.irr-cache.max_spacing", 5.00f);
|
|
39
|
+
root = null;
|
|
40
|
+
rwl = new ReentrantReadWriteLock();
|
|
41
|
+
globalPhotonMap = PluginRegistry.GLOBAL_PHOTON_MAP_PLUGINS.createObject(options.getString("gi.irr-cache.gmap", null));
|
|
42
|
+
// check settings
|
|
43
|
+
samples = Math.max(0, samples);
|
|
44
|
+
minSpacing = Math.max(0.001f, minSpacing);
|
|
45
|
+
maxSpacing = Math.max(0.001f, maxSpacing);
|
|
46
|
+
// display settings
|
|
47
|
+
UI.printInfo(Module.LIGHT, "Irradiance cache settings:");
|
|
48
|
+
UI.printInfo(Module.LIGHT, " * Samples: %d", samples);
|
|
49
|
+
if (tolerance <= 0) {
|
|
50
|
+
UI.printInfo(Module.LIGHT, " * Tolerance: off");
|
|
51
|
+
} else {
|
|
52
|
+
UI.printInfo(Module.LIGHT, " * Tolerance: %.3f", tolerance);
|
|
53
|
+
}
|
|
54
|
+
UI.printInfo(Module.LIGHT, " * Spacing: %.3f to %.3f", minSpacing, maxSpacing);
|
|
55
|
+
// prepare root node
|
|
56
|
+
Vector3 ext = scene.getBounds().getExtents();
|
|
57
|
+
root = new Node(scene.getBounds().getCenter(), 1.0001f * MathUtils.max(ext.x, ext.y, ext.z));
|
|
58
|
+
// init global photon map
|
|
59
|
+
return (globalPhotonMap != null) ? scene.calculatePhotons(globalPhotonMap, "global", 0, options) : true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@Override
|
|
63
|
+
public Color getGlobalRadiance(ShadingState state) {
|
|
64
|
+
if (globalPhotonMap == null) {
|
|
65
|
+
if (state.getShader() != null) {
|
|
66
|
+
return state.getShader().getRadiance(state);
|
|
67
|
+
} else {
|
|
68
|
+
return Color.BLACK;
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
return globalPhotonMap.getRadiance(state.getPoint(), state.getNormal());
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@Override
|
|
76
|
+
public Color getIrradiance(ShadingState state, Color diffuseReflectance) {
|
|
77
|
+
if (samples <= 0) {
|
|
78
|
+
return Color.BLACK;
|
|
79
|
+
}
|
|
80
|
+
if (state.getDiffuseDepth() > 0) {
|
|
81
|
+
// do simple path tracing for additional bounces (single ray)
|
|
82
|
+
float xi = (float) state.getRandom(0, 0, 1);
|
|
83
|
+
float xj = (float) state.getRandom(0, 1, 1);
|
|
84
|
+
float phi = (float) (xi * 2 * Math.PI);
|
|
85
|
+
float cosPhi = (float) Math.cos(phi);
|
|
86
|
+
float sinPhi = (float) Math.sin(phi);
|
|
87
|
+
float sinTheta = (float) Math.sqrt(xj);
|
|
88
|
+
float cosTheta = (float) Math.sqrt(1.0f - xj);
|
|
89
|
+
Vector3 w = new Vector3();
|
|
90
|
+
w.x = cosPhi * sinTheta;
|
|
91
|
+
w.y = sinPhi * sinTheta;
|
|
92
|
+
w.z = cosTheta;
|
|
93
|
+
OrthoNormalBasis onb = state.getBasis();
|
|
94
|
+
onb.transform(w);
|
|
95
|
+
Ray r = new Ray(state.getPoint(), w);
|
|
96
|
+
ShadingState temp = state.traceFinalGather(r, 0);
|
|
97
|
+
return temp != null ? getGlobalRadiance(temp).copy().mul((float) Math.PI) : Color.BLACK;
|
|
98
|
+
}
|
|
99
|
+
rwl.readLock().lock();
|
|
100
|
+
Color irr;
|
|
101
|
+
try {
|
|
102
|
+
irr = getIrradiance(state.getPoint(), state.getNormal());
|
|
103
|
+
} finally {
|
|
104
|
+
rwl.readLock().unlock();
|
|
105
|
+
}
|
|
106
|
+
if (irr == null) {
|
|
107
|
+
// compute new sample
|
|
108
|
+
irr = Color.black();
|
|
109
|
+
OrthoNormalBasis onb = state.getBasis();
|
|
110
|
+
float invR = 0;
|
|
111
|
+
float minR = Float.POSITIVE_INFINITY;
|
|
112
|
+
Vector3 w = new Vector3();
|
|
113
|
+
for (int i = 0; i < samples; i++) {
|
|
114
|
+
float xi = (float) state.getRandom(i, 0, samples);
|
|
115
|
+
float xj = (float) state.getRandom(i, 1, samples);
|
|
116
|
+
float phi = (float) (xi * 2 * Math.PI);
|
|
117
|
+
float cosPhi = (float) Math.cos(phi);
|
|
118
|
+
float sinPhi = (float) Math.sin(phi);
|
|
119
|
+
float sinTheta = (float) Math.sqrt(xj);
|
|
120
|
+
float cosTheta = (float) Math.sqrt(1.0f - xj);
|
|
121
|
+
w.x = cosPhi * sinTheta;
|
|
122
|
+
w.y = sinPhi * sinTheta;
|
|
123
|
+
w.z = cosTheta;
|
|
124
|
+
onb.transform(w);
|
|
125
|
+
Ray r = new Ray(state.getPoint(), w);
|
|
126
|
+
ShadingState temp = state.traceFinalGather(r, i);
|
|
127
|
+
if (temp != null) {
|
|
128
|
+
minR = Math.min(r.getMax(), minR);
|
|
129
|
+
invR += 1.0f / r.getMax();
|
|
130
|
+
temp.getInstance().prepareShadingState(temp);
|
|
131
|
+
irr.add(getGlobalRadiance(temp));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
irr.mul((float) Math.PI / samples);
|
|
135
|
+
invR = samples / invR;
|
|
136
|
+
rwl.writeLock().lock();
|
|
137
|
+
try {
|
|
138
|
+
insert(state.getPoint(), state.getNormal(), invR, irr);
|
|
139
|
+
} finally {
|
|
140
|
+
rwl.writeLock().unlock();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return irr;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private void insert(Point3 p, Vector3 n, float r0, Color irr) {
|
|
147
|
+
if (tolerance <= 0) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
Node node = root;
|
|
151
|
+
r0 = MathUtils.clamp(r0 * tolerance, minSpacing, maxSpacing) * invTolerance;
|
|
152
|
+
if (root.isInside(p)) {
|
|
153
|
+
while (node.sideLength >= (4.0 * r0 * tolerance)) {
|
|
154
|
+
int k = 0;
|
|
155
|
+
k |= (p.x > node.center.x) ? 1 : 0;
|
|
156
|
+
k |= (p.y > node.center.y) ? 2 : 0;
|
|
157
|
+
k |= (p.z > node.center.z) ? 4 : 0;
|
|
158
|
+
if (node.children[k] == null) {
|
|
159
|
+
Point3 c = new Point3(node.center);
|
|
160
|
+
c.x += ((k & 1) == 0) ? -node.quadSideLength : node.quadSideLength;
|
|
161
|
+
c.y += ((k & 2) == 0) ? -node.quadSideLength : node.quadSideLength;
|
|
162
|
+
c.z += ((k & 4) == 0) ? -node.quadSideLength : node.quadSideLength;
|
|
163
|
+
node.children[k] = new Node(c, node.halfSideLength);
|
|
164
|
+
}
|
|
165
|
+
node = node.children[k];
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
Sample s = new Sample(p, n, r0, irr);
|
|
169
|
+
s.next = node.first;
|
|
170
|
+
node.first = s;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private Color getIrradiance(Point3 p, Vector3 n) {
|
|
174
|
+
if (tolerance <= 0) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
Sample x = new Sample(p, n);
|
|
178
|
+
float w = root.find(x);
|
|
179
|
+
return (x.irr == null) ? null : x.irr.mul(1.0f / w);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private final class Node {
|
|
183
|
+
|
|
184
|
+
Node[] children;
|
|
185
|
+
Sample first;
|
|
186
|
+
Point3 center;
|
|
187
|
+
float sideLength;
|
|
188
|
+
float halfSideLength;
|
|
189
|
+
float quadSideLength;
|
|
190
|
+
|
|
191
|
+
Node(Point3 center, float sideLength) {
|
|
192
|
+
children = new Node[8];
|
|
193
|
+
for (int i = 0; i < 8; i++) {
|
|
194
|
+
children[i] = null;
|
|
195
|
+
}
|
|
196
|
+
this.center = new Point3(center);
|
|
197
|
+
this.sideLength = sideLength;
|
|
198
|
+
halfSideLength = 0.5f * sideLength;
|
|
199
|
+
quadSideLength = 0.5f * halfSideLength;
|
|
200
|
+
first = null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
final boolean isInside(Point3 p) {
|
|
204
|
+
return (Math.abs(p.x - center.x) < halfSideLength) && (Math.abs(p.y - center.y) < halfSideLength) && (Math.abs(p.z - center.z) < halfSideLength);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
final float find(Sample x) {
|
|
208
|
+
float weight = 0;
|
|
209
|
+
for (Sample s = first; s != null; s = s.next) {
|
|
210
|
+
float c2 = 1.0f - (x.nix * s.nix + x.niy * s.niy + x.niz * s.niz);
|
|
211
|
+
float d2 = (x.pix - s.pix) * (x.pix - s.pix) + (x.piy - s.piy) * (x.piy - s.piy) + (x.piz - s.piz) * (x.piz - s.piz);
|
|
212
|
+
if (c2 > tolerance * tolerance || d2 > maxSpacing * maxSpacing) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
float invWi = (float) (Math.sqrt(d2) * s.invR0 + Math.sqrt(Math.max(c2, 0)));
|
|
216
|
+
if (invWi < tolerance || d2 < minSpacing * minSpacing) {
|
|
217
|
+
float wi = Math.min(1e10f, 1.0f / invWi);
|
|
218
|
+
if (x.irr != null) {
|
|
219
|
+
x.irr.madd(wi, s.irr);
|
|
220
|
+
} else {
|
|
221
|
+
x.irr = s.irr.copy().mul(wi);
|
|
222
|
+
}
|
|
223
|
+
weight += wi;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
for (int i = 0; i < 8; i++) {
|
|
227
|
+
if ((children[i] != null) && (Math.abs(children[i].center.x - x.pix) <= halfSideLength) && (Math.abs(children[i].center.y - x.piy) <= halfSideLength) && (Math.abs(children[i].center.z - x.piz) <= halfSideLength)) {
|
|
228
|
+
weight += children[i].find(x);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return weight;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private static final class Sample {
|
|
236
|
+
|
|
237
|
+
float pix, piy, piz;
|
|
238
|
+
float nix, niy, niz;
|
|
239
|
+
float invR0;
|
|
240
|
+
Color irr;
|
|
241
|
+
Sample next;
|
|
242
|
+
|
|
243
|
+
Sample(Point3 p, Vector3 n) {
|
|
244
|
+
pix = p.x;
|
|
245
|
+
piy = p.y;
|
|
246
|
+
piz = p.z;
|
|
247
|
+
Vector3 ni = new Vector3(n).normalize();
|
|
248
|
+
nix = ni.x;
|
|
249
|
+
niy = ni.y;
|
|
250
|
+
niz = ni.z;
|
|
251
|
+
irr = null;
|
|
252
|
+
next = null;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
Sample(Point3 p, Vector3 n, float r0, Color irr) {
|
|
256
|
+
pix = p.x;
|
|
257
|
+
piy = p.y;
|
|
258
|
+
piz = p.z;
|
|
259
|
+
Vector3 ni = new Vector3(n).normalize();
|
|
260
|
+
nix = ni.x;
|
|
261
|
+
niy = ni.y;
|
|
262
|
+
niz = ni.z;
|
|
263
|
+
invR0 = 1.0f / r0;
|
|
264
|
+
this.irr = irr;
|
|
265
|
+
next = null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|