├── janino.jar
├── sunflow.sh
├── examples
├── sky_small.hdr
├── textures
│ ├── brick_color.jpg
│ ├── brick_normal.jpg
│ ├── dirty_bump.jpg
│ ├── slime_bump.jpg
│ ├── shiphull_bump.png
│ └── reptileskin_bump.png
├── shader_examples
│ ├── AO002.sc
│ ├── Mirror001.sc
│ ├── Phong003.sc
│ ├── Glass001.sc
│ ├── Phong004.sc
│ ├── Shiny001.sc
│ ├── Glass002.sc
│ ├── AO001.sc
│ ├── Phong002.sc
│ ├── Glass003.sc
│ ├── Ward001.sc
│ ├── Phong001.sc
│ ├── Ward002.sc
│ └── include
│ │ └── example_array.geo.sc
├── sphereflake.sc
├── julia.sc
├── wireframe_demo.java
└── cornell_box_jensen.sc
├── resources
├── golden_0020.png
├── golden_0040.png
├── golden_0060.png
├── golden_0080.png
├── golden_0100.png
├── golden_0180.png
└── golden_0200.png
├── exporters
├── sketchup
│ └── Components
│ │ └── su2sf
│ │ ├── su2sf_pointlight.skp
│ │ ├── su2sf_sphericallight.skp
│ │ └── su2sf_directionnallight.skp
└── maya
│ └── sunflowExporter
│ ├── mel
│ ├── sunflowDeleteMenu.mel
│ ├── sunflowShutdown.mel
│ ├── unregisterSunflowRenderer.mel
│ ├── sunflowStartup.mel
│ ├── sunflowRender.mel
│ ├── AEsunflowSkyNodeTemplate.mel
│ ├── updateSunflowGlobalsTab.mel
│ ├── sunflowCreateMenu.mel
│ ├── AEsunflowHelperNodeTemplate.mel
│ ├── sunflowUtils.mel
│ └── registerSunflowRenderer.mel
│ ├── src
│ ├── sunflowConstants.h
│ ├── sunflowConstants.cpp
│ ├── sunflowBucketToRenderView.h
│ ├── sunflowHelperNode.h
│ ├── sunflowGlobalsNode.h
│ ├── sunflowExportCmd.h
│ ├── sunflowShaderNode.h
│ ├── sunflowBucketToRenderView.cpp
│ ├── pluginMain.cpp
│ ├── sunflowSkyNode.h
│ └── skylight.h
│ ├── sunflowExport.sln
│ └── SConstruct
├── sunflow.bat
├── .settings
├── org.eclipse.ltk.core.refactoring.prefs
└── org.eclipse.jdt.ui.prefs
├── .classpath
├── src
└── org
│ └── sunflow
│ ├── core
│ ├── filter
│ │ ├── BoxFilter.java
│ │ ├── TriangleFilter.java
│ │ ├── SincFilter.java
│ │ ├── GaussianFilter.java
│ │ ├── CatmullRomFilter.java
│ │ ├── CubicBSpline.java
│ │ ├── LanczosFilter.java
│ │ ├── BlackmanHarrisFilter.java
│ │ └── MitchellFilter.java
│ ├── CausticPhotonMapInterface.java
│ ├── Modifier.java
│ ├── bucket
│ │ ├── RowBucketOrder.java
│ │ ├── ColumnBucketOrder.java
│ │ ├── DiagonalBucketOrder.java
│ │ ├── InvertedBucketOrder.java
│ │ ├── BucketOrderFactory.java
│ │ ├── SpiralBucketOrder.java
│ │ └── RandomBucketOrder.java
│ ├── Options.java
│ ├── AccelerationStructure.java
│ ├── shader
│ │ ├── SimpleShader.java
│ │ ├── ViewGlobalPhotonsShader.java
│ │ ├── UVShader.java
│ │ ├── ViewIrradianceShader.java
│ │ ├── ConstantShader.java
│ │ ├── IDShader.java
│ │ ├── NormalShader.java
│ │ ├── PrimIDShader.java
│ │ ├── ViewCausticsShader.java
│ │ ├── TexturedPhongShader.java
│ │ ├── TexturedDiffuseShader.java
│ │ ├── TexturedWardShader.java
│ │ ├── TexturedShinyDiffuseShader.java
│ │ ├── TexturedAmbientOcclusionShader.java
│ │ ├── AmbientOcclusionShader.java
│ │ ├── DiffuseShader.java
│ │ ├── MirrorShader.java
│ │ └── QuickGrayShader.java
│ ├── SceneParser.java
│ ├── GlobalPhotonMapInterface.java
│ ├── BucketOrder.java
│ ├── camera
│ │ ├── FisheyeLens.java
│ │ ├── SphericalLens.java
│ │ └── PinholeLens.java
│ ├── accel
│ │ └── NullAccelerator.java
│ ├── Filter.java
│ ├── ImageSampler.java
│ ├── RenderObject.java
│ ├── Shader.java
│ ├── modifiers
│ │ ├── NormalMapModifier.java
│ │ ├── BumpMappingModifier.java
│ │ └── PerlinModifier.java
│ ├── AccelerationStructureFactory.java
│ ├── primitive
│ │ └── Background.java
│ ├── CameraLens.java
│ ├── Tesselatable.java
│ ├── gi
│ │ ├── FakeGIEngine.java
│ │ ├── AmbientOcclusionGIEngine.java
│ │ └── PathTracingGIEngine.java
│ ├── GIEngine.java
│ ├── TextureCache.java
│ ├── PhotonStore.java
│ ├── ShadingCache.java
│ ├── InstanceList.java
│ ├── light
│ │ └── PointLight.java
│ ├── display
│ │ └── FileDisplay.java
│ ├── parser
│ │ └── RA3Parser.java
│ ├── PrimitiveList.java
│ └── LightSource.java
│ ├── image
│ ├── Bitmap.java
│ ├── BlackbodySpectrum.java
│ ├── formats
│ │ ├── BitmapBlack.java
│ │ ├── BitmapGA8.java
│ │ ├── BitmapG8.java
│ │ ├── BitmapXYZ.java
│ │ ├── BitmapRGB8.java
│ │ ├── BitmapRGBA8.java
│ │ ├── BitmapRGBE.java
│ │ └── GenericBitmap.java
│ ├── ConstantSpectralCurve.java
│ ├── XYZColor.java
│ ├── RegularSpectralCurve.java
│ ├── writers
│ │ ├── PNGBitmapWriter.java
│ │ ├── HDRBitmapWriter.java
│ │ ├── TGABitmapWriter.java
│ │ └── IGIBitmapWriter.java
│ ├── BitmapReader.java
│ ├── readers
│ │ ├── BMPBitmapReader.java
│ │ ├── JPGBitmapReader.java
│ │ └── PNGBitmapReader.java
│ └── IrregularSpectralCurve.java
│ ├── system
│ ├── Memory.java
│ ├── BenchmarkTest.java
│ ├── ui
│ │ ├── SilentInterface.java
│ │ └── ConsoleInterface.java
│ ├── FileUtils.java
│ ├── Timer.java
│ ├── UserInterface.java
│ ├── SearchPath.java
│ └── BenchmarkFramework.java
│ ├── math
│ └── Point2.java
│ └── util
│ ├── IntArray.java
│ └── FloatArray.java
├── .project
├── LICENSE
└── .externalToolBuilders
└── Ant Build.launch
/janino.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/janino.jar
--------------------------------------------------------------------------------
/sunflow.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mem=1G
3 | java -Xmx$mem -server -jar sunflow.jar $*
4 |
--------------------------------------------------------------------------------
/examples/sky_small.hdr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/examples/sky_small.hdr
--------------------------------------------------------------------------------
/resources/golden_0020.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/resources/golden_0020.png
--------------------------------------------------------------------------------
/resources/golden_0040.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/resources/golden_0040.png
--------------------------------------------------------------------------------
/resources/golden_0060.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/resources/golden_0060.png
--------------------------------------------------------------------------------
/resources/golden_0080.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/resources/golden_0080.png
--------------------------------------------------------------------------------
/resources/golden_0100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/resources/golden_0100.png
--------------------------------------------------------------------------------
/resources/golden_0180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/resources/golden_0180.png
--------------------------------------------------------------------------------
/resources/golden_0200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/resources/golden_0200.png
--------------------------------------------------------------------------------
/examples/textures/brick_color.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/examples/textures/brick_color.jpg
--------------------------------------------------------------------------------
/examples/textures/brick_normal.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/examples/textures/brick_normal.jpg
--------------------------------------------------------------------------------
/examples/textures/dirty_bump.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/examples/textures/dirty_bump.jpg
--------------------------------------------------------------------------------
/examples/textures/slime_bump.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/examples/textures/slime_bump.jpg
--------------------------------------------------------------------------------
/examples/textures/shiphull_bump.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/examples/textures/shiphull_bump.png
--------------------------------------------------------------------------------
/examples/textures/reptileskin_bump.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/examples/textures/reptileskin_bump.png
--------------------------------------------------------------------------------
/exporters/sketchup/Components/su2sf/su2sf_pointlight.skp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/exporters/sketchup/Components/su2sf/su2sf_pointlight.skp
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/mel/sunflowDeleteMenu.mel:
--------------------------------------------------------------------------------
1 | global proc sunflowDeleteMenu(){
2 | if ( `menu -exists sunflowMainWindowMenu` ) deleteUI sunflowMainWindowMenu;
3 | }
--------------------------------------------------------------------------------
/exporters/sketchup/Components/su2sf/su2sf_sphericallight.skp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/exporters/sketchup/Components/su2sf/su2sf_sphericallight.skp
--------------------------------------------------------------------------------
/sunflow.bat:
--------------------------------------------------------------------------------
1 | @set javadir="c:\program files\java\jdk1.6.0"
2 | @set mem=1G
3 | @%javadir%\bin\java -Xmx%mem% -server -jar sunflow.jar %*
4 | @if %errorlevel% neq 0 pause
5 |
--------------------------------------------------------------------------------
/exporters/sketchup/Components/su2sf/su2sf_directionnallight.skp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpsunflower/sunflow/HEAD/exporters/sketchup/Components/su2sf/su2sf_directionnallight.skp
--------------------------------------------------------------------------------
/.settings/org.eclipse.ltk.core.refactoring.prefs:
--------------------------------------------------------------------------------
1 | #Sat Sep 23 11:47:05 CDT 2006
2 | eclipse.preferences.version=1
3 | org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
4 |
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/mel/sunflowShutdown.mel:
--------------------------------------------------------------------------------
1 | global proc sunflowShutdown(){
2 | sunflowDeleteMenu();
3 | unregisterSunflowRenderer();
4 | print("Sunflow is shutting down!\n");
5 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/mel/unregisterSunflowRenderer.mel:
--------------------------------------------------------------------------------
1 | global proc unregisterSunflowRenderer(){
2 | if ( `renderer -q -ex sunflow` ) renderer -unregisterRenderer sunflow;
3 | updateRendererUI();
4 | }
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.ui.prefs:
--------------------------------------------------------------------------------
1 | #Sat Sep 23 11:47:05 CDT 2006
2 | eclipse.preferences.version=1
3 | formatter_profile=_Sunflow Conventions
4 | formatter_settings_version=10
5 | internal.default.compliance=default
6 | org.eclipse.jdt.ui.text.custom_code_templates=
7 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/filter/BoxFilter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.filter;
2 |
3 | import org.sunflow.core.Filter;
4 |
5 | public class BoxFilter implements Filter {
6 | public float getSize() {
7 | return 1.0f;
8 | }
9 |
10 | public float get(float x, float y) {
11 | return 1.0f;
12 | }
13 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/filter/TriangleFilter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.filter;
2 |
3 | import org.sunflow.core.Filter;
4 |
5 | public class TriangleFilter implements Filter {
6 | public float getSize() {
7 | return 2;
8 | }
9 |
10 | public float get(float x, float y) {
11 | return (1.0f - Math.abs(x)) * (1.0f - Math.abs(y));
12 | }
13 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/src/sunflowConstants.h:
--------------------------------------------------------------------------------
1 | #ifndef SUNFLOW_CONSTANTS_H
2 | #define SUNFLOW_CONSTANTS_H
3 |
4 | extern const char* FILTER_NAMES[];
5 | extern const unsigned int NUM_FILTER_NAMES;
6 |
7 | extern const char* BUCKET_ORDERS[];
8 | extern const unsigned int NUM_BUCKET_ORDERS;
9 |
10 | extern const unsigned int DIR_LIGHT_RADIUS;
11 | #endif /* SUNFLOW_CONSTANTS_H */
12 |
--------------------------------------------------------------------------------
/src/org/sunflow/image/Bitmap.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image;
2 |
3 | public abstract class Bitmap {
4 | protected static final float INV255 = 1.0f / 255;
5 | protected static final float INV65535 = 1.0f / 65535;
6 |
7 | public abstract int getWidth();
8 |
9 | public abstract int getHeight();
10 |
11 | public abstract Color readColor(int x, int y);
12 |
13 | public abstract float readAlpha(int x, int y);
14 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/CausticPhotonMapInterface.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | /**
4 | * This class is a generic interface to caustic photon mapping capabilities.
5 | */
6 | public interface CausticPhotonMapInterface extends PhotonStore {
7 | /**
8 | * Retrieve caustic photons at the specified shading location and add them
9 | * as diffuse light samples.
10 | *
11 | * @param state
12 | */
13 | void getSamples(ShadingState state);
14 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/BlackbodySpectrum.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image;
2 |
3 | public class BlackbodySpectrum extends SpectralCurve {
4 | private float temp;
5 |
6 | public BlackbodySpectrum(float temp) {
7 | this.temp = temp;
8 | }
9 |
10 | @Override
11 | public float sample(float lambda) {
12 | double wavelength = lambda * 1e-9;
13 | return (float) ((3.74183e-16 * Math.pow(wavelength, -5.0)) / (Math.exp(1.4388e-2 / (wavelength * temp)) - 1.0));
14 | }
15 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/Modifier.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | /**
4 | * This represents a surface modifier. This is run on each instance prior to
5 | * shading and can modify the shading state in arbitrary ways to provide effects
6 | * such as bump mapping.
7 | */
8 | public interface Modifier extends RenderObject {
9 |
10 | /**
11 | * Modify the shading state for the point to be shaded.
12 | *
13 | * @param state shading state to modify
14 | */
15 | public void modify(ShadingState state);
16 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/filter/SincFilter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.filter;
2 |
3 | import org.sunflow.core.Filter;
4 |
5 | public class SincFilter implements Filter {
6 | public float getSize() {
7 | return 4;
8 | }
9 |
10 | public float get(float x, float y) {
11 | return sinc1d(x) * sinc1d(y);
12 | }
13 |
14 | private float sinc1d(float x) {
15 | x = Math.abs(x);
16 | if (x < 0.0001f)
17 | return 1.0f;
18 | x *= Math.PI;
19 | return (float) Math.sin(x) / x;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/org/sunflow/system/Memory.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.system;
2 |
3 | public final class Memory {
4 | public static final String sizeof(int[] array) {
5 | return bytesToString(array == null ? 0 : 4 * array.length);
6 | }
7 |
8 | public static final String bytesToString(long bytes) {
9 | if (bytes < 1024)
10 | return String.format("%db", bytes);
11 | if (bytes < 1024 * 1024)
12 | return String.format("%dKb", (bytes + 512) >>> 10);
13 | return String.format("%dMb", (bytes + 512 * 1024) >>> 20);
14 | }
15 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/filter/GaussianFilter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.filter;
2 |
3 | import org.sunflow.core.Filter;
4 |
5 | public class GaussianFilter implements Filter {
6 | private float es2;
7 |
8 | public GaussianFilter() {
9 | es2 = (float) -Math.exp(-getSize() * getSize());
10 | }
11 |
12 | public float getSize() {
13 | return 3.0f;
14 | }
15 |
16 | public float get(float x, float y) {
17 | float gx = (float) Math.exp(-x * x) + es2;
18 | float gy = (float) Math.exp(-y * y) + es2;
19 | return gx * gy;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/org/sunflow/system/BenchmarkTest.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.system;
2 |
3 | /**
4 | * This interface is used to represent a piece of code which is to be
5 | * benchmarked by repeatedly running and timing the kernel code. The begin/end
6 | * routines are called per-iteration to do any local initialization which is not
7 | * meant to be taken into acount in the timing (like preparing or destroying
8 | * data structures).
9 | */
10 | public interface BenchmarkTest {
11 |
12 | public void kernelBegin();
13 |
14 | public void kernelMain();
15 |
16 | public void kernelEnd();
17 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/mel/sunflowStartup.mel:
--------------------------------------------------------------------------------
1 | global proc sunflowStartup(){
2 | string $mel_files[] = {
3 | "sunflowUtils.mel",
4 | "createSunflowGlobalsTab.mel",
5 | "updateSunflowGlobalsTab.mel",
6 | "registerSunflowRenderer.mel",
7 | "unregisterSunflowRenderer.mel",
8 | "sunflowRender.mel",
9 | "sunflowCreateMenu.mel",
10 | "sunflowDeleteMenu.mel",
11 | "sunflowShutdown.mel"
12 | };
13 |
14 | int $i;
15 | for ( $i = 0; $i < size($mel_files); $i++) {
16 | eval( "source \""+$mel_files[$i]+"\"" );
17 | }
18 | registerSunflowRenderer();
19 | sunflowCreateMenu();
20 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/formats/BitmapBlack.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.formats;
2 |
3 | import org.sunflow.image.Bitmap;
4 | import org.sunflow.image.Color;
5 |
6 | public class BitmapBlack extends Bitmap {
7 | @Override
8 | public int getWidth() {
9 | return 1;
10 | }
11 |
12 | @Override
13 | public int getHeight() {
14 | return 1;
15 | }
16 |
17 | @Override
18 | public Color readColor(int x, int y) {
19 | return Color.BLACK;
20 | }
21 |
22 | @Override
23 | public float readAlpha(int x, int y) {
24 | return 0;
25 | }
26 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/bucket/RowBucketOrder.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.bucket;
2 |
3 | import org.sunflow.core.BucketOrder;
4 |
5 | public class RowBucketOrder implements BucketOrder {
6 | public int[] getBucketSequence(int nbw, int nbh) {
7 | int[] coords = new int[2 * nbw * nbh];
8 | for (int i = 0; i < nbw * nbh; i++) {
9 | int by = i / nbw;
10 | int bx = i % nbw;
11 | if ((by & 1) == 1)
12 | bx = nbw - 1 - bx;
13 | coords[2 * i + 0] = bx;
14 | coords[2 * i + 1] = by;
15 | }
16 | return coords;
17 | }
18 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/bucket/ColumnBucketOrder.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.bucket;
2 |
3 | import org.sunflow.core.BucketOrder;
4 |
5 | public class ColumnBucketOrder implements BucketOrder {
6 | public int[] getBucketSequence(int nbw, int nbh) {
7 | int[] coords = new int[2 * nbw * nbh];
8 | for (int i = 0; i < nbw * nbh; i++) {
9 | int bx = i / nbh;
10 | int by = i % nbh;
11 | if ((bx & 1) == 1)
12 | by = nbh - 1 - by;
13 | coords[2 * i + 0] = bx;
14 | coords[2 * i + 1] = by;
15 | }
16 | return coords;
17 | }
18 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/mel/sunflowRender.mel:
--------------------------------------------------------------------------------
1 | global proc sunflowRender(int $width, int $height, int $doShadows, int $doGlowPass, string $camera, string $option){
2 | // sunflowCheckGlobals;
3 | sunflowExportCmd($width, $height, $doShadows, $doGlowPass, $camera, $option);
4 | }
5 |
6 | global proc sunflowIPRRender(int $width, int $height, int $doShadows, int $doGlowPass, string $camera, string $option){
7 | print($width+"\n");
8 | print($height+"\n");
9 | print($doShadows+"\n");
10 | print($doGlowPass+"\n");
11 | print($camera+"\n");
12 | print($option+"\n");
13 | sunflowExportCmd($width, $height, $doShadows, $doGlowPass, $camera, $option);
14 | }
15 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/Options.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.util.FastHashMap;
5 |
6 | /**
7 | * This holds rendering objects as key, value pairs.
8 | */
9 | public final class Options extends ParameterList implements RenderObject {
10 | public boolean update(ParameterList pl, SunflowAPI api) {
11 | // take all attributes, and update them into the current set
12 | for (FastHashMap.Entry e : pl.list) {
13 | list.put(e.getKey(), e.getValue());
14 | e.getValue().check();
15 | }
16 | return true;
17 | }
18 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/AccelerationStructure.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | public interface AccelerationStructure {
4 | /**
5 | * Construct an acceleration structure for the specified primitive list.
6 | *
7 | * @param primitives
8 | */
9 | public void build(PrimitiveList primitives);
10 |
11 | /**
12 | * Intersect the specified ray with the geometry in local space. The ray
13 | * will be provided in local space.
14 | *
15 | * @param r ray in local space
16 | * @param istate state to store the intersection into
17 | */
18 | public void intersect(Ray r, IntersectionState istate);
19 | }
--------------------------------------------------------------------------------
/src/org/sunflow/system/ui/SilentInterface.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.system.ui;
2 |
3 | import org.sunflow.system.UserInterface;
4 | import org.sunflow.system.UI.Module;
5 | import org.sunflow.system.UI.PrintLevel;
6 |
7 | /**
8 | * Null implementation of a user interface. This is usefull to silence the
9 | * output.
10 | */
11 | public class SilentInterface implements UserInterface {
12 | public void print(Module m, PrintLevel level, String s) {
13 | }
14 |
15 | public void taskStart(String s, int min, int max) {
16 | }
17 |
18 | public void taskUpdate(int current) {
19 | }
20 |
21 | public void taskStop() {
22 | }
23 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/SimpleShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Shader;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.image.Color;
8 |
9 | public class SimpleShader implements Shader {
10 | public boolean update(ParameterList pl, SunflowAPI api) {
11 | return true;
12 | }
13 |
14 | public Color getRadiance(ShadingState state) {
15 | return new Color(Math.abs(state.getRay().dot(state.getNormal())));
16 | }
17 |
18 | public void scatterPhoton(ShadingState state, Color power) {
19 | }
20 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/mel/AEsunflowSkyNodeTemplate.mel:
--------------------------------------------------------------------------------
1 | global proc AEsunflowSkyNodeTemplate( string $nodeName )
2 | {
3 | editorTemplate -beginScrollLayout;
4 | editorTemplate -beginLayout "Sky Attributes" -collapse 0;
5 | editorTemplate -l "Turbidity" -addControl "Turbidity";
6 | editorTemplate -endLayout;
7 | editorTemplate -beginLayout "UI Attributes" -collapse 0;
8 | editorTemplate -l "Size" -addControl "size";
9 | editorTemplate -l "Quality" -addControl "resolution";
10 | editorTemplate -l "Exposure" -addControl "Exposure";
11 | editorTemplate -endLayout;
12 | editorTemplate -addExtraControls;
13 | editorTemplate -endScrollLayout;
14 | }
15 |
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/src/sunflowConstants.cpp:
--------------------------------------------------------------------------------
1 | #include "sunflowConstants.h"
2 |
3 | const char* FILTER_NAMES[] = {
4 | "box",
5 | "triangle",
6 | "catmull-rom",
7 | "mitchell",
8 | "lanczos",
9 | "blackman-harris",
10 | "sinc",
11 | "gaussian"
12 | };
13 |
14 | const unsigned int NUM_FILTER_NAMES = sizeof(FILTER_NAMES) / sizeof(const char*);
15 |
16 | const char* BUCKET_ORDERS[] = {
17 | "hilbert",
18 | "spiral",
19 | "column",
20 | "row",
21 | "diagonal",
22 | "random"
23 | };
24 | const unsigned int NUM_BUCKET_ORDERS = sizeof(BUCKET_ORDERS) / sizeof(const char*);
25 |
26 | const unsigned int DIR_LIGHT_RADIUS = 1000;
27 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/filter/CatmullRomFilter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.filter;
2 |
3 | import org.sunflow.core.Filter;
4 |
5 | public class CatmullRomFilter implements Filter {
6 | public float getSize() {
7 | return 4.0f;
8 | }
9 |
10 | public float get(float x, float y) {
11 | return catrom1d(x) * catrom1d(y);
12 | }
13 |
14 | private float catrom1d(float x) {
15 | x = Math.abs(x);
16 | float x2 = x * x;
17 | float x3 = x * x2;
18 | if (x >= 2)
19 | return 0;
20 | if (x < 1)
21 | return 3 * x3 - 5 * x2 + 2;
22 | return -x3 + 5 * x2 - 8 * x + 4;
23 | }
24 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/ViewGlobalPhotonsShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Shader;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.image.Color;
8 |
9 | public class ViewGlobalPhotonsShader implements Shader {
10 | public boolean update(ParameterList pl, SunflowAPI api) {
11 | return true;
12 | }
13 |
14 | public Color getRadiance(ShadingState state) {
15 | state.faceforward();
16 | return state.getGlobalRadiance();
17 | }
18 |
19 | public void scatterPhoton(ShadingState state, Color power) {
20 | }
21 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/ConstantSpectralCurve.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image;
2 |
3 | /**
4 | * Very simple class equivalent to a constant spectral curve. Note that this is
5 | * most likely physically impossible for amplitudes > 0, however this class can
6 | * be handy since in practice spectral curves end up being integrated against
7 | * the finite width color matching functions.
8 | */
9 | public class ConstantSpectralCurve extends SpectralCurve {
10 | private final float amp;
11 |
12 | public ConstantSpectralCurve(float amp) {
13 | this.amp = amp;
14 | }
15 |
16 | @Override
17 | public float sample(float lambda) {
18 | return amp;
19 | }
20 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/UVShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Shader;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.image.Color;
8 |
9 | public class UVShader implements Shader {
10 | public boolean update(ParameterList pl, SunflowAPI api) {
11 | return true;
12 | }
13 |
14 | public Color getRadiance(ShadingState state) {
15 | if (state.getUV() == null)
16 | return Color.BLACK;
17 | return new Color(state.getUV().x, state.getUV().y, 0);
18 | }
19 |
20 | public void scatterPhoton(ShadingState state, Color power) {
21 | }
22 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/SceneParser.java:
--------------------------------------------------------------------------------
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 | * Parse the specified file to create a scene description into the provided
12 | * {@link SunflowAPI} object.
13 | *
14 | * @param filename filename to parse
15 | * @param api scene to parse the file into
16 | * @return true upon sucess, or false if
17 | * errors have occured.
18 | */
19 | public boolean parse(String filename, SunflowAPIInterface api);
20 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/ViewIrradianceShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Shader;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.image.Color;
8 |
9 | public class ViewIrradianceShader implements Shader {
10 | public boolean update(ParameterList pl, SunflowAPI api) {
11 | return true;
12 | }
13 |
14 | public Color getRadiance(ShadingState state) {
15 | state.faceforward();
16 | return new Color().set(state.getIrradiance(Color.WHITE)).mul(1.0f / (float) Math.PI);
17 | }
18 |
19 | public void scatterPhoton(ShadingState state, Color power) {
20 | }
21 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/filter/CubicBSpline.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.filter;
2 |
3 | import org.sunflow.core.Filter;
4 |
5 | public class CubicBSpline implements Filter {
6 | public float get(float x, float y) {
7 | return B3(x) * B3(y);
8 | }
9 |
10 | public float getSize() {
11 | return 4;
12 | }
13 |
14 | private float B3(float t) {
15 | t = Math.abs(t);
16 | if (t <= 1)
17 | return b1(1 - t);
18 | return b0(2 - t);
19 | }
20 |
21 | private float b0(float t) {
22 | return t * t * t * (1.0f / 6);
23 | }
24 |
25 | private float b1(float t) {
26 | return (1.0f / 6) * (-3 * t * t * t + 3 * t * t + 3 * t + 1);
27 | }
28 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/mel/updateSunflowGlobalsTab.mel:
--------------------------------------------------------------------------------
1 | //==================================================================
2 | // Sunflow Renderer Tab
3 | //==================================================================
4 |
5 | // Description:
6 | // Update procedure that is called whenever renderer is changed or
7 | // different layer is selected.
8 | // Must update any controls whose state may have changed
9 | // through another instance of the tab.
10 | //
11 | global proc updateSunflowGlobalsTab()
12 | {
13 | //updateSunflowSamplingFrameUI();
14 | updateSunflowPhotonFrameUI();
15 | updateSunflowGIFrameUI();
16 | updateSunflowEnvironmentFrameUI();
17 | updateSunflowOverrideFrameUI();
18 | updateSunflowSystemFrameUI();
19 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/filter/LanczosFilter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.filter;
2 |
3 | import org.sunflow.core.Filter;
4 |
5 | public class LanczosFilter implements Filter {
6 | public float getSize() {
7 | return 4.0f;
8 | }
9 |
10 | public float get(float x, float y) {
11 | return sinc1d(x * 0.5f) * sinc1d(y * 0.5f);
12 | }
13 |
14 | private float sinc1d(float x) {
15 | x = Math.abs(x);
16 | if (x < 1e-5f)
17 | return 1;
18 | if (x > 1.0f)
19 | return 0;
20 | x *= Math.PI;
21 | float sinc = (float) Math.sin(3 * x) / (3 * x);
22 | float lanczos = (float) Math.sin(x) / x;
23 | return sinc * lanczos;
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/formats/BitmapGA8.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.formats;
2 |
3 | import org.sunflow.image.Bitmap;
4 | import org.sunflow.image.Color;
5 |
6 | public class BitmapGA8 extends Bitmap {
7 | private int w, h;
8 | private byte[] data;
9 |
10 | @Override
11 | public int getWidth() {
12 | return w;
13 | }
14 |
15 | @Override
16 | public int getHeight() {
17 | return h;
18 | }
19 |
20 | @Override
21 | public Color readColor(int x, int y) {
22 | return new Color((data[2 * (x + y * w) + 0] & 0xFF) * INV255);
23 | }
24 |
25 | @Override
26 | public float readAlpha(int x, int y) {
27 | return (data[2 * (x + y * w) + 1] & 0xFF) * INV255;
28 | }
29 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/GlobalPhotonMapInterface.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import org.sunflow.image.Color;
4 | import org.sunflow.math.Point3;
5 | import org.sunflow.math.Vector3;
6 |
7 | /**
8 | * Represents a global photon map. This is a structure which can return a rough
9 | * approximation of the diffuse radiance at a given surface point.
10 | */
11 | public interface GlobalPhotonMapInterface extends PhotonStore {
12 |
13 | /**
14 | * Lookup the global diffuse radiance at the specified surface point.
15 | *
16 | * @param p surface position
17 | * @param n surface normal
18 | * @return an approximation of global diffuse radiance at this point
19 | */
20 | public Color getRadiance(Point3 p, Vector3 n);
21 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/ConstantShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Shader;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.image.Color;
8 |
9 | public class ConstantShader implements Shader {
10 | private Color c;
11 |
12 | public ConstantShader() {
13 | c = Color.WHITE;
14 | }
15 |
16 | public boolean update(ParameterList pl, SunflowAPI api) {
17 | c = pl.getColor("color", c);
18 | return true;
19 | }
20 |
21 | public Color getRadiance(ShadingState state) {
22 | return c;
23 | }
24 |
25 | public void scatterPhoton(ShadingState state, Color power) {
26 | }
27 | }
--------------------------------------------------------------------------------
/src/org/sunflow/math/Point2.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.math;
2 |
3 | public final class Point2 {
4 | public float x, y;
5 |
6 | public Point2() {
7 | }
8 |
9 | public Point2(float x, float y) {
10 | this.x = x;
11 | this.y = y;
12 | }
13 |
14 | public Point2(Point2 p) {
15 | x = p.x;
16 | y = p.y;
17 | }
18 |
19 | public final Point2 set(float x, float y) {
20 | this.x = x;
21 | this.y = y;
22 | return this;
23 | }
24 |
25 | public final Point2 set(Point2 p) {
26 | x = p.x;
27 | y = p.y;
28 | return this;
29 | }
30 |
31 | @Override
32 | public final String toString() {
33 | return String.format("(%.2f, %.2f)", x, y);
34 | }
35 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/IDShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Shader;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.image.Color;
8 | import org.sunflow.math.Vector3;
9 |
10 | public class IDShader implements Shader {
11 | public boolean update(ParameterList pl, SunflowAPI api) {
12 | return true;
13 | }
14 |
15 | public Color getRadiance(ShadingState state) {
16 | Vector3 n = state.getNormal();
17 | float f = n == null ? 1.0f : Math.abs(state.getRay().dot(n));
18 | return new Color(state.getInstance().hashCode()).mul(f);
19 | }
20 |
21 | public void scatterPhoton(ShadingState state, Color power) {
22 | }
23 | }
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | sunflow
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.ui.externaltools.ExternalToolBuilder
15 | full,incremental,
16 |
17 |
18 | LaunchConfigHandle
19 | <project>/.externalToolBuilders/Ant Build.launch
20 |
21 |
22 |
23 |
24 |
25 | org.eclipse.jdt.core.javanature
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/BucketOrder.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | /**
4 | * Creates an array of coordinates that iterate over the tiled screen. Classes
5 | * which implement this interface are responsible for guarenteeing the entire
6 | * screen is tiled. No attempt is made to check for duplicates or incomplete
7 | * coverage.
8 | */
9 | public interface BucketOrder {
10 | /**
11 | * Computes the order in which each coordinate on the screen should be
12 | * visited.
13 | *
14 | * @param nbw number of buckets in the X direction
15 | * @param nbh number of buckets in the Y direction
16 | * @return array of coordinates with interleaved X, Y of the positions of
17 | * buckets to be rendered.
18 | */
19 | int[] getBucketSequence(int nbw, int nbh);
20 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/filter/BlackmanHarrisFilter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.filter;
2 |
3 | import org.sunflow.core.Filter;
4 |
5 | public class BlackmanHarrisFilter implements Filter {
6 | public float getSize() {
7 | return 4;
8 | }
9 |
10 | public float get(float x, float y) {
11 | return bh1d(x * 0.5f) * bh1d(y * 0.5f);
12 | }
13 |
14 | private float bh1d(float x) {
15 | if (x < -1.0f || x > 1.0f)
16 | return 0.0f;
17 | x = (x + 1) * 0.5f;
18 | final double A0 = 0.35875;
19 | final double A1 = -0.48829;
20 | final double A2 = 0.14128;
21 | final double A3 = -0.01168;
22 | return (float) (A0 + A1 * Math.cos(2 * Math.PI * x) + A2 * Math.cos(4 * Math.PI * x) + A3 * Math.cos(6 * Math.PI * x));
23 | }
24 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/camera/FisheyeLens.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.camera;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.CameraLens;
5 | import org.sunflow.core.ParameterList;
6 | import org.sunflow.core.Ray;
7 |
8 | public class FisheyeLens implements CameraLens {
9 | public boolean update(ParameterList pl, SunflowAPI api) {
10 | return true;
11 | }
12 |
13 | public Ray getRay(float x, float y, int imageWidth, int imageHeight, double lensX, double lensY, double time) {
14 | float cx = 2.0f * x / imageWidth - 1.0f;
15 | float cy = 2.0f * y / imageHeight - 1.0f;
16 | float r2 = cx * cx + cy * cy;
17 | if (r2 > 1)
18 | return null; // outside the fisheye
19 | return new Ray(0, 0, 0, cx, cy, (float) -Math.sqrt(1 - r2));
20 | }
21 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/accel/NullAccelerator.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.accel;
2 |
3 | import org.sunflow.core.AccelerationStructure;
4 | import org.sunflow.core.IntersectionState;
5 | import org.sunflow.core.PrimitiveList;
6 | import org.sunflow.core.Ray;
7 |
8 | public class NullAccelerator implements AccelerationStructure {
9 | private PrimitiveList primitives;
10 | private int n;
11 |
12 | public NullAccelerator() {
13 | primitives = null;
14 | n = 0;
15 | }
16 |
17 | public void build(PrimitiveList primitives) {
18 | this.primitives = primitives;
19 | n = primitives.getNumPrimitives();
20 | }
21 |
22 | public void intersect(Ray r, IntersectionState state) {
23 | for (int i = 0; i < n; i++)
24 | primitives.intersectPrimitive(r, i, state);
25 | }
26 | }
--------------------------------------------------------------------------------
/examples/shader_examples/AO002.sc:
--------------------------------------------------------------------------------
1 | shader {
2 | name "boxes"
3 | type amb-occ2
4 | bright 0 0 1
5 | dark 0 0.6 0
6 | samples 32
7 | dist 2
8 | }
9 |
10 | shader {
11 | name "ground"
12 | type amb-occ2
13 | bright 1 0 1
14 | dark 0 0 0
15 | samples 32
16 | dist 2
17 | }
18 |
19 | shader {
20 | name "left_sphere"
21 | type amb-occ2
22 | bright 0 1 1
23 | dark 0 0 0
24 | samples 32
25 | dist 2
26 | }
27 |
28 | shader {
29 | name "top_sphere"
30 | type amb-occ2
31 | bright 0 0 0
32 | dark 1 1 1
33 | samples 32
34 | dist 2
35 | }
36 |
37 | shader {
38 | name "right_sphere"
39 | type amb-occ2
40 | bright 0 0.3 0
41 | dark 0.4 0 0
42 | samples 32
43 | dist 2
44 | }
45 |
46 | include "include/example_scene.geo.sc"
47 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/filter/MitchellFilter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.filter;
2 |
3 | import org.sunflow.core.Filter;
4 |
5 | public class MitchellFilter implements Filter {
6 | public float getSize() {
7 | return 4.0f;
8 | }
9 |
10 | public float get(float x, float y) {
11 | return mitchell(x) * mitchell(y);
12 | }
13 |
14 | private float mitchell(float x) {
15 | final float B = 1 / 3.0f;
16 | final float C = 1 / 3.0f;
17 | final float SIXTH = 1 / 6.0f;
18 | x = Math.abs(x);
19 | float x2 = x * x;
20 | if (x > 1.0f)
21 | return ((-B - 6 * C) * x * x2 + (6 * B + 30 * C) * x2 + (-12 * B - 48 * C) * x + (8 * B + 24 * C)) * SIXTH;
22 | return ((12 - 9 * B - 6 * C) * x * x2 + (-18 + 12 * B + 6 * C) * x2 + (6 - 2 * B)) * SIXTH;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/org/sunflow/image/formats/BitmapG8.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.formats;
2 |
3 | import org.sunflow.image.Bitmap;
4 | import org.sunflow.image.Color;
5 |
6 | public class BitmapG8 extends Bitmap {
7 | private int w, h;
8 | private byte[] data;
9 |
10 | public BitmapG8(int w, int h, byte[] data) {
11 | this.w = w;
12 | this.h = h;
13 | this.data = data;
14 | }
15 |
16 | @Override
17 | public int getWidth() {
18 | return w;
19 | }
20 |
21 | @Override
22 | public int getHeight() {
23 | return h;
24 | }
25 |
26 | @Override
27 | public Color readColor(int x, int y) {
28 | return new Color((data[x + y * w] & 0xFF) * INV255);
29 | }
30 |
31 | @Override
32 | public float readAlpha(int x, int y) {
33 | return 1;
34 | }
35 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/camera/SphericalLens.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.camera;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.CameraLens;
5 | import org.sunflow.core.ParameterList;
6 | import org.sunflow.core.Ray;
7 |
8 | public class SphericalLens implements CameraLens {
9 | public boolean update(ParameterList pl, SunflowAPI api) {
10 | return true;
11 | }
12 |
13 | public Ray getRay(float x, float y, int imageWidth, int imageHeight, double lensX, double lensY, double time) {
14 | // Generate environment camera ray direction
15 | double theta = 2 * Math.PI * x / imageWidth + Math.PI / 2;
16 | double phi = Math.PI * (imageHeight - 1 - y) / imageHeight;
17 | return new Ray(0, 0, 0, (float) (Math.cos(theta) * Math.sin(phi)), (float) (Math.cos(phi)), (float) (Math.sin(theta) * Math.sin(phi)));
18 | }
19 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/mel/sunflowCreateMenu.mel:
--------------------------------------------------------------------------------
1 | global proc sunflowCreateMenu(){
2 | global string $gMainWindow;
3 |
4 | if ( `menu -exists sunflowMainWindowMenu` ) deleteUI sunflowMainWindowMenu;
5 |
6 | if ( $gMainWindow != "" ){
7 | setParent $gMainWindow;
8 | menu -label "Sunflow" -tearOff true sunflowMainWindowMenu;
9 | menuItem -label "Helper" -subMenu true;
10 | menuItem -label "File Mesh" -command sunflowCreateFileMeshHelper;
11 | menuItem -label "Infinite Plane" -command sunflowCreateInfinitePlaneHelper;
12 | setParent -menu ..;
13 | }
14 | }
15 |
16 | global proc sunflowCreateFileMeshHelper(){
17 | createNode sunflowHelperNode -n "sunflowFileMesh#";
18 | }
19 |
20 | global proc sunflowCreateInfinitePlaneHelper(){
21 | $infinitePlane = `createNode sunflowHelperNode -n "sunflowInfinitePlane#"`;
22 | setAttr ($infinitePlane+".type") 1;
23 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/Filter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | /**
4 | * Represents a multi-pixel image filter kernel.
5 | */
6 | public interface Filter {
7 | /**
8 | * Width in pixels of the filter extents. The filter will be applied to the
9 | * range of pixels within a box of +/- getSize() / 2 around
10 | * the center of the pixel.
11 | *
12 | * @return width in pixels
13 | */
14 | public float getSize();
15 |
16 | /**
17 | * Get value of the filter at offset (x, y). The filter should never be
18 | * called with values beyond its extents but should return 0 in those cases
19 | * anyway.
20 | *
21 | * @param x x offset in pixels
22 | * @param y y offset in pixels
23 | * @return value of the filter at the specified location
24 | */
25 | public float get(float x, float y);
26 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/ImageSampler.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | /**
4 | * This interface represents an image sampling algorithm capable of rendering
5 | * the entire image. Implementations are responsible for anti-aliasing and
6 | * filtering.
7 | */
8 | public interface ImageSampler {
9 | /**
10 | * Prepare the sampler for rendering an image of w x h pixels
11 | *
12 | * @param w width of the image
13 | * @param h height of the image
14 | */
15 | public boolean prepare(Options options, Scene scene, int w, int h);
16 |
17 | /**
18 | * Render the image to the specified display. The sampler can assume the
19 | * display has been opened and that it will be closed after the method
20 | * returns.
21 | *
22 | * @param display Display driver to send image data to
23 | */
24 | public void render(Display display);
25 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/NormalShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Shader;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.image.Color;
8 | import org.sunflow.math.Vector3;
9 |
10 | public class NormalShader implements Shader {
11 | public boolean update(ParameterList pl, SunflowAPI api) {
12 | return true;
13 | }
14 |
15 | public Color getRadiance(ShadingState state) {
16 | Vector3 n = state.getNormal();
17 | if (n == null)
18 | return Color.BLACK;
19 | float r = (n.x + 1) * 0.5f;
20 | float g = (n.y + 1) * 0.5f;
21 | float b = (n.z + 1) * 0.5f;
22 | return new Color(r, g, b);
23 | }
24 |
25 | public void scatterPhoton(ShadingState state, Color power) {
26 | }
27 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/bucket/DiagonalBucketOrder.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.bucket;
2 |
3 | import org.sunflow.core.BucketOrder;
4 |
5 | public class DiagonalBucketOrder implements BucketOrder {
6 | public int[] getBucketSequence(int nbw, int nbh) {
7 | int[] coords = new int[2 * nbw * nbh];
8 | int x = 0, y = 0, nx = 1, ny = 0;
9 | for (int i = 0; i < nbw * nbh; i++) {
10 | coords[2 * i + 0] = x;
11 | coords[2 * i + 1] = y;
12 | do {
13 | if (y == ny) {
14 | y = 0;
15 | x = nx;
16 | ny++;
17 | nx++;
18 | } else {
19 | x--;
20 | y++;
21 | }
22 | } while ((y >= nbh || x >= nbw) && i != (nbw * nbh - 1));
23 | }
24 | return coords;
25 | }
26 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/bucket/InvertedBucketOrder.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.bucket;
2 |
3 | import org.sunflow.core.BucketOrder;
4 |
5 | public class InvertedBucketOrder implements BucketOrder {
6 | private BucketOrder order;
7 |
8 | public InvertedBucketOrder(BucketOrder order) {
9 | this.order = order;
10 | }
11 |
12 | public int[] getBucketSequence(int nbw, int nbh) {
13 | int[] coords = order.getBucketSequence(nbw, nbh);
14 | for (int i = 0; i < coords.length / 2; i += 2) {
15 | int src = i;
16 | int dst = coords.length - 2 - i;
17 | int tmp = coords[src + 0];
18 | coords[src + 0] = coords[dst + 0];
19 | coords[dst + 0] = tmp;
20 | tmp = coords[src + 1];
21 | coords[src + 1] = coords[dst + 1];
22 | coords[dst + 1] = tmp;
23 | }
24 | return coords;
25 | }
26 | }
--------------------------------------------------------------------------------
/src/org/sunflow/system/FileUtils.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.system;
2 |
3 | import java.io.File;
4 | import java.util.Locale;
5 |
6 | public final class FileUtils {
7 | /**
8 | * Extract the file extension from the specified filename.
9 | *
10 | * @param filename filename to get the extension of
11 | * @return a string representing the file extension, or null
12 | * if the filename doesn't have any extension, or is not a file
13 | */
14 | public static final String getExtension(String filename) {
15 | if (filename == null)
16 | return null;
17 | File f = new File(filename);
18 | if (f.isDirectory())
19 | return null;
20 | String name = new File(filename).getName();
21 | int idx = name.lastIndexOf('.');
22 | return idx == -1 ? null : name.substring(idx + 1).toLowerCase(Locale.ENGLISH);
23 | }
24 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/PrimIDShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Shader;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.image.Color;
8 | import org.sunflow.math.Vector3;
9 |
10 | public class PrimIDShader implements Shader {
11 | private static final Color[] BORDERS = { Color.RED, Color.GREEN,
12 | Color.BLUE, Color.YELLOW, Color.CYAN, Color.MAGENTA };
13 |
14 | public boolean update(ParameterList pl, SunflowAPI api) {
15 | return true;
16 | }
17 |
18 | public Color getRadiance(ShadingState state) {
19 | Vector3 n = state.getNormal();
20 | float f = n == null ? 1.0f : Math.abs(state.getRay().dot(n));
21 | return BORDERS[state.getPrimitiveID() % BORDERS.length].copy().mul(f);
22 | }
23 |
24 | public void scatterPhoton(ShadingState state, Color power) {
25 | }
26 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/ViewCausticsShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.LightSample;
5 | import org.sunflow.core.ParameterList;
6 | import org.sunflow.core.Shader;
7 | import org.sunflow.core.ShadingState;
8 | import org.sunflow.image.Color;
9 |
10 | public class ViewCausticsShader implements Shader {
11 | public boolean update(ParameterList pl, SunflowAPI api) {
12 | return true;
13 | }
14 |
15 | public Color getRadiance(ShadingState state) {
16 | state.faceforward();
17 | state.initCausticSamples();
18 | // integrate a diffuse function
19 | Color lr = Color.black();
20 | for (LightSample sample : state)
21 | lr.madd(sample.dot(state.getNormal()), sample.getDiffuseRadiance());
22 | return lr.mul(1.0f / (float) Math.PI);
23 |
24 | }
25 |
26 | public void scatterPhoton(ShadingState state, Color power) {
27 | }
28 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/formats/BitmapXYZ.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.formats;
2 |
3 | import org.sunflow.image.Bitmap;
4 | import org.sunflow.image.Color;
5 | import org.sunflow.image.XYZColor;
6 |
7 | public class BitmapXYZ extends Bitmap {
8 | private int w, h;
9 | private float[] data;
10 |
11 | public BitmapXYZ(int w, int h, float[] data) {
12 | this.w = w;
13 | this.h = h;
14 | this.data = data;
15 | }
16 |
17 | @Override
18 | public int getWidth() {
19 | return w;
20 | }
21 |
22 | @Override
23 | public int getHeight() {
24 | return h;
25 | }
26 |
27 | @Override
28 | public Color readColor(int x, int y) {
29 | int index = 3 * (x + y * w);
30 | return Color.NATIVE_SPACE.convertXYZtoRGB(new XYZColor(data[index], data[index + 1], data[index + 2])).mul(0.1f);
31 | }
32 |
33 | @Override
34 | public float readAlpha(int x, int y) {
35 | return 1;
36 | }
37 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/TexturedPhongShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.ShadingState;
6 | import org.sunflow.core.Texture;
7 | import org.sunflow.core.TextureCache;
8 | import org.sunflow.image.Color;
9 |
10 | public class TexturedPhongShader extends PhongShader {
11 | private Texture tex;
12 |
13 | public TexturedPhongShader() {
14 | tex = null;
15 | }
16 |
17 | @Override
18 | public boolean update(ParameterList pl, SunflowAPI api) {
19 | String filename = pl.getString("texture", null);
20 | if (filename != null)
21 | tex = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
22 | return tex != null && super.update(pl, api);
23 | }
24 |
25 | @Override
26 | public Color getDiffuse(ShadingState state) {
27 | return tex.getPixel(state.getUV().x, state.getUV().y);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/TexturedDiffuseShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.ShadingState;
6 | import org.sunflow.core.Texture;
7 | import org.sunflow.core.TextureCache;
8 | import org.sunflow.image.Color;
9 |
10 | public class TexturedDiffuseShader extends DiffuseShader {
11 | private Texture tex;
12 |
13 | public TexturedDiffuseShader() {
14 | tex = null;
15 | }
16 |
17 | @Override
18 | public boolean update(ParameterList pl, SunflowAPI api) {
19 | String filename = pl.getString("texture", null);
20 | if (filename != null)
21 | tex = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
22 | return tex != null && super.update(pl, api);
23 | }
24 |
25 | @Override
26 | public Color getDiffuse(ShadingState state) {
27 | return tex.getPixel(state.getUV().x, state.getUV().y);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/TexturedWardShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.ShadingState;
6 | import org.sunflow.core.Texture;
7 | import org.sunflow.core.TextureCache;
8 | import org.sunflow.image.Color;
9 |
10 | public class TexturedWardShader extends AnisotropicWardShader {
11 | private Texture tex;
12 |
13 | public TexturedWardShader() {
14 | tex = null;
15 | }
16 |
17 | @Override
18 | public boolean update(ParameterList pl, SunflowAPI api) {
19 | String filename = pl.getString("texture", null);
20 | if (filename != null)
21 | tex = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
22 | return tex != null && super.update(pl, api);
23 | }
24 |
25 | @Override
26 | public Color getDiffuse(ShadingState state) {
27 | return tex.getPixel(state.getUV().x, state.getUV().y);
28 | }
29 | }
--------------------------------------------------------------------------------
/examples/shader_examples/Mirror001.sc:
--------------------------------------------------------------------------------
1 | shader {
2 | name "ground"
3 | type diffuse
4 | diff 0.800000011921 0.800000011921 0.800000011921
5 | }
6 |
7 | shader {
8 | name "shader01"
9 | type mirror
10 | refl 0.1 0.1 0.1
11 | }
12 |
13 | shader {
14 | name "shader02"
15 | type mirror
16 | refl 0.5 0.5 0.5
17 | }
18 | shader {
19 | name "shader03"
20 | type mirror
21 | refl 1 1 1
22 | }
23 |
24 | shader {
25 | name "shader04"
26 | type mirror
27 | refl 0 0 0.1
28 | }
29 |
30 | shader {
31 | name "shader05"
32 | type mirror
33 | refl 0 0 0.5
34 | }
35 |
36 | shader {
37 | name "shader06"
38 | type mirror
39 | refl 0 0 1
40 | }
41 |
42 | shader {
43 | name "shader07"
44 | type mirror
45 | refl 0.1 0.0 0.0
46 | }
47 |
48 | shader {
49 | name "shader08"
50 | type mirror
51 | refl 0.5 0 0
52 | }
53 |
54 | shader {
55 | name "shader09"
56 | type mirror
57 | refl 1 0 0
58 | }
59 |
60 | include "include/example_array.geo.sc"
61 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/TexturedShinyDiffuseShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.ShadingState;
6 | import org.sunflow.core.Texture;
7 | import org.sunflow.core.TextureCache;
8 | import org.sunflow.image.Color;
9 |
10 | public class TexturedShinyDiffuseShader extends ShinyDiffuseShader {
11 | private Texture tex;
12 |
13 | public TexturedShinyDiffuseShader() {
14 | tex = null;
15 | }
16 |
17 | @Override
18 | public boolean update(ParameterList pl, SunflowAPI api) {
19 | String filename = pl.getString("texture", null);
20 | if (filename != null)
21 | tex = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
22 | return tex != null && super.update(pl, api);
23 | }
24 |
25 | @Override
26 | public Color getDiffuse(ShadingState state) {
27 | return tex.getPixel(state.getUV().x, state.getUV().y);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/bucket/BucketOrderFactory.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.bucket;
2 |
3 | import org.sunflow.PluginRegistry;
4 | import org.sunflow.core.BucketOrder;
5 | import org.sunflow.system.UI;
6 | import org.sunflow.system.UI.Module;
7 |
8 | public class BucketOrderFactory {
9 | public static BucketOrder create(String order) {
10 | boolean flip = false;
11 | if (order.startsWith("inverse") || order.startsWith("invert") || order.startsWith("reverse")) {
12 | String[] tokens = order.split("\\s+");
13 | if (tokens.length == 2) {
14 | order = tokens[1];
15 | flip = true;
16 | }
17 | }
18 | BucketOrder o = PluginRegistry.bucketOrderPlugins.createObject(order);
19 | if (o == null) {
20 | UI.printWarning(Module.BCKT, "Unrecognized bucket ordering: \"%s\" - using hilbert", order);
21 | return create("hilbert");
22 | }
23 | return flip ? new InvertedBucketOrder(o) : o;
24 | }
25 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/src/sunflowBucketToRenderView.h:
--------------------------------------------------------------------------------
1 | #ifndef _SUNFLOW_BUCKET_TO_RENDER_VIEW_H_
2 | #define _SUNFLOW_BUCKET_TO_RENDER_VIEW_H_
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | typedef long sint32 ;
9 | typedef unsigned long uint32 ;
10 | typedef short int sint16 ;
11 | typedef unsigned short int uint16 ;
12 | typedef signed char sint8;
13 | typedef unsigned char uint8 ;
14 |
15 | union data32 {
16 | sint32 sbits32;
17 | uint32 ubits32;
18 | sint16 sbits16[2];
19 | uint16 ubits16[2];
20 | sint8 sbits8[4];
21 | uint8 ubits8[4];
22 | float f;
23 | // TODO: half h[2];
24 | };
25 |
26 | struct DisplayPacket {
27 | data32 type;
28 | data32 data[4];
29 | };
30 |
31 | class bucketToRenderView
32 | {
33 | public:
34 | DisplayPacket getPacket();
35 | void checkStream();
36 |
37 | FILE* renderPipe;
38 |
39 | int renderWidth;
40 | int renderHeight;
41 | MDagPath renderCamera;
42 | };
43 |
44 | #endif /* _SUNFLOW_BUCKET_TO_RENDER_VIEW_H_ */
45 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.ShadingState;
6 | import org.sunflow.core.Texture;
7 | import org.sunflow.core.TextureCache;
8 | import org.sunflow.image.Color;
9 |
10 | public class TexturedAmbientOcclusionShader extends AmbientOcclusionShader {
11 | private Texture tex;
12 |
13 | public TexturedAmbientOcclusionShader() {
14 | tex = null;
15 | }
16 |
17 | @Override
18 | public boolean update(ParameterList pl, SunflowAPI api) {
19 | String filename = pl.getString("texture", null);
20 | if (filename != null)
21 | tex = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
22 | return tex != null && super.update(pl, api);
23 | }
24 |
25 | @Override
26 | public Color getBrightColor(ShadingState state) {
27 | return tex.getPixel(state.getUV().x, state.getUV().y);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/formats/BitmapRGB8.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.formats;
2 |
3 | import org.sunflow.image.Bitmap;
4 | import org.sunflow.image.Color;
5 |
6 | public class BitmapRGB8 extends Bitmap {
7 | private int w, h;
8 | private byte[] data;
9 |
10 | public BitmapRGB8(int w, int h, byte[] data) {
11 | this.w = w;
12 | this.h = h;
13 | this.data = data;
14 | }
15 |
16 | @Override
17 | public int getWidth() {
18 | return w;
19 | }
20 |
21 | @Override
22 | public int getHeight() {
23 | return h;
24 | }
25 |
26 | @Override
27 | public Color readColor(int x, int y) {
28 | int index = 3 * (x + y * w);
29 | float r = (data[index + 0] & 0xFF) * INV255;
30 | float g = (data[index + 1] & 0xFF) * INV255;
31 | float b = (data[index + 2] & 0xFF) * INV255;
32 | return new Color(r, g, b);
33 | }
34 |
35 | @Override
36 | public float readAlpha(int x, int y) {
37 | return 1;
38 | }
39 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2003-2007 Christopher Kulla
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/RenderObject.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import org.sunflow.SunflowAPI;
4 |
5 | /**
6 | * This is the base interface for all public rendering object interfaces. It
7 | * handles incremental updates via {@link ParameterList} objects.
8 | */
9 | public interface RenderObject {
10 | /**
11 | * Update this object given a list of parameters. This method is guarenteed
12 | * to be called at least once on every object, but it should correctly
13 | * handle empty parameter lists. This means that the object should be in a
14 | * valid state from the time it is constructed. This method should also
15 | * return true or false depending on whether the update was succesfull or
16 | * not.
17 | *
18 | * @param pl list of parameters to read from
19 | * @param api reference to the current scene
20 | * @return true if the update is succesfull,
21 | * false otherwise
22 | */
23 | public boolean update(ParameterList pl, SunflowAPI api);
24 | }
--------------------------------------------------------------------------------
/examples/shader_examples/Phong003.sc:
--------------------------------------------------------------------------------
1 | trace-depths {
2 | diff 0
3 | refl 1
4 | refr 0
5 | }
6 |
7 | shader {
8 | name "ground"
9 | type phong
10 | diff { "sRGB nonlinear" 0.3 0.3 0.3 }
11 | spec { "sRGB nonlinear" 0.9 0.9 0.9 } 20
12 | samples 4
13 | }
14 |
15 | shader {
16 | name "boxes"
17 | type phong
18 | diff { "sRGB nonlinear" 0.3 0.3 0.3 }
19 | spec { "sRGB nonlinear" 0.9 0.9 0.9 } 20
20 | samples 4
21 | }
22 |
23 | shader {
24 | name "top_sphere"
25 | type phong
26 | diff { "sRGB nonlinear" 0.3 0.3 0.3 }
27 | spec { "sRGB nonlinear" 0.9 0.9 0.9 } 20
28 | samples 4
29 | }
30 |
31 | shader {
32 | name "left_sphere"
33 | type phong
34 | diff { "sRGB nonlinear" 0.3 0.3 0.3 }
35 | spec { "sRGB nonlinear" 0.9 0.9 0.9 } 20
36 | samples 4
37 | }
38 |
39 | shader {
40 | name "right_sphere"
41 | type phong
42 | diff { "sRGB nonlinear" 0.3 0.3 0.3 }
43 | spec { "sRGB nonlinear" 0.9 0.9 0.9 } 20
44 | samples 4
45 | }
46 |
47 | include "include/example_scene.geo.sc"
48 |
--------------------------------------------------------------------------------
/src/org/sunflow/image/formats/BitmapRGBA8.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.formats;
2 |
3 | import org.sunflow.image.Bitmap;
4 | import org.sunflow.image.Color;
5 |
6 | public class BitmapRGBA8 extends Bitmap {
7 | private int w, h;
8 | private byte[] data;
9 |
10 | public BitmapRGBA8(int w, int h, byte[] data) {
11 | this.w = w;
12 | this.h = h;
13 | this.data = data;
14 | }
15 |
16 | @Override
17 | public int getWidth() {
18 | return w;
19 | }
20 |
21 | @Override
22 | public int getHeight() {
23 | return h;
24 | }
25 |
26 | @Override
27 | public Color readColor(int x, int y) {
28 | int index = 4 * (x + y * w);
29 | float r = (data[index + 0] & 0xFF) * INV255;
30 | float g = (data[index + 1] & 0xFF) * INV255;
31 | float b = (data[index + 2] & 0xFF) * INV255;
32 | return new Color(r, g, b);
33 | }
34 |
35 | @Override
36 | public float readAlpha(int x, int y) {
37 | return (data[4 * (x + y * w) + 3] & 0xFF) * INV255;
38 | }
39 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/XYZColor.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image;
2 |
3 | public final class XYZColor {
4 | private float X, Y, Z;
5 |
6 | public XYZColor() {
7 | }
8 |
9 | public XYZColor(float X, float Y, float Z) {
10 | this.X = X;
11 | this.Y = Y;
12 | this.Z = Z;
13 | }
14 |
15 | public final float getX() {
16 | return X;
17 | }
18 |
19 | public final float getY() {
20 | return Y;
21 | }
22 |
23 | public final float getZ() {
24 | return Z;
25 | }
26 |
27 | public final XYZColor mul(float s) {
28 | X *= s;
29 | Y *= s;
30 | Z *= s;
31 | return this;
32 | }
33 |
34 | public final void normalize() {
35 | float XYZ = X + Y + Z;
36 | if (XYZ < 1e-6f)
37 | return;
38 | float s = 1 / XYZ;
39 | X *= s;
40 | Y *= s;
41 | Z *= s;
42 | }
43 |
44 | @Override
45 | public final String toString() {
46 | return String.format("(%.3f, %.3f, %.3f)", X, Y, Z);
47 | }
48 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/RegularSpectralCurve.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image;
2 |
3 | public class RegularSpectralCurve extends SpectralCurve {
4 | private final float[] spectrum;
5 | private final float lambdaMin, lambdaMax;
6 | private final float delta, invDelta;
7 |
8 | public RegularSpectralCurve(float[] spectrum, float lambdaMin, float lambdaMax) {
9 | this.lambdaMin = lambdaMin;
10 | this.lambdaMax = lambdaMax;
11 | this.spectrum = spectrum;
12 | delta = (lambdaMax - lambdaMin) / (spectrum.length - 1);
13 | invDelta = 1 / delta;
14 | }
15 |
16 | @Override
17 | public float sample(float lambda) {
18 | // reject wavelengths outside the valid range
19 | if (lambda < lambdaMin || lambda > lambdaMax)
20 | return 0;
21 | // interpolate the two closest samples linearly
22 | float x = (lambda - lambdaMin) * invDelta;
23 | int b0 = (int) x;
24 | int b1 = Math.min(b0 + 1, spectrum.length - 1);
25 | float dx = x - b0;
26 | return (1 - dx) * spectrum[b0] + dx * spectrum[b1];
27 | }
28 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/Shader.java:
--------------------------------------------------------------------------------
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 | * Gets the radiance for a specified rendering state. When this method is
11 | * called, you can assume that a hit has been registered in the state and
12 | * that the hit surface information has been computed.
13 | *
14 | * @param state current render state
15 | * @return color emitted or reflected by the shader
16 | */
17 | public Color getRadiance(ShadingState state);
18 |
19 | /**
20 | * Scatter a photon with the specied power. Incoming photon direction is
21 | * specified by the ray attached to the current render state. This method
22 | * can safely do nothing if photon scattering is not supported or relevant
23 | * for the shader type.
24 | *
25 | * @param state current state
26 | * @param power power of the incoming photon.
27 | */
28 | public void scatterPhoton(ShadingState state, Color power);
29 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/modifiers/NormalMapModifier.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.modifiers;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.Modifier;
5 | import org.sunflow.core.ParameterList;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.core.Texture;
8 | import org.sunflow.core.TextureCache;
9 | import org.sunflow.math.OrthoNormalBasis;
10 |
11 | public class NormalMapModifier implements Modifier {
12 | private Texture normalMap;
13 |
14 | public NormalMapModifier() {
15 | normalMap = null;
16 | }
17 |
18 | public boolean update(ParameterList pl, SunflowAPI api) {
19 | String filename = pl.getString("texture", null);
20 | if (filename != null)
21 | normalMap = TextureCache.getTexture(api.resolveTextureFilename(filename), true);
22 | return normalMap != null;
23 | }
24 |
25 | public void modify(ShadingState state) {
26 | // apply normal map
27 | state.getNormal().set(normalMap.getNormal(state.getUV().x, state.getUV().y, state.getBasis()));
28 | state.setBasis(OrthoNormalBasis.makeFromW(state.getNormal()));
29 | }
30 | }
--------------------------------------------------------------------------------
/examples/shader_examples/Glass001.sc:
--------------------------------------------------------------------------------
1 | % photons {
2 | % caustics 10000000 kd 64 0.5
3 | % }
4 |
5 | shader {
6 | name "ground"
7 | type diffuse
8 | diff 0.800000011921 0.800000011921 0.800000011921
9 | }
10 |
11 | shader {
12 | name "shader01"
13 | type glass
14 | eta 1.1
15 | color 1 1 1
16 | }
17 |
18 | shader {
19 | name "shader02"
20 | type glass
21 | eta 1.3
22 | color 1 1 1
23 | }
24 |
25 | shader {
26 | name "shader03"
27 | type glass
28 | eta 1.5
29 | color 1 1 1
30 | }
31 |
32 | shader {
33 | name "shader04"
34 | type glass
35 | eta 1.7
36 | color 1 1 1
37 | }
38 |
39 | shader {
40 | name "shader05"
41 | type glass
42 | eta 1.9
43 | color 1 1 1
44 | }
45 |
46 | shader {
47 | name "shader06"
48 | type glass
49 | eta 2.1
50 | color 1 1 1
51 | }
52 |
53 | shader {
54 | name "shader07"
55 | type glass
56 | eta 2.3
57 | color 1 1 1
58 | }
59 |
60 | shader {
61 | name "shader08"
62 | type glass
63 | eta 2.5
64 | color 1 1 1
65 | }
66 |
67 | shader {
68 | name "shader09"
69 | type glass
70 | eta 2.7
71 | color 1 1 1
72 | }
73 |
74 | include "include/example_array.geo.sc"
75 |
--------------------------------------------------------------------------------
/examples/shader_examples/Phong004.sc:
--------------------------------------------------------------------------------
1 | trace-depths {
2 | diff 0
3 | refl 1
4 | refr 0
5 | }
6 |
7 | shader {
8 | name "boxes"
9 | type phong
10 | diff { "sRGB nonlinear" 0.3 0.3 0.3 }
11 | spec { "sRGB nonlinear" 0.90000000298 0.90000000298 0.90000000298 } 20
12 | samples 4
13 | }
14 |
15 | shader {
16 | name "ground"
17 | type phong
18 | diff { "sRGB nonlinear" 0.3 0.3 0.3 }
19 | spec { "sRGB nonlinear" 1.90000000298 1.90000000298 1.90000000298 } 20
20 | samples 8
21 | }
22 |
23 | shader {
24 | name "left_sphere"
25 | type phong
26 | diff { "sRGB nonlinear" 0.9 0.4 0.0 }
27 | spec { "sRGB nonlinear" 1.00000000298 0.50000000298 0.00000000298 } 20
28 | samples 4
29 | }
30 |
31 | shader {
32 | name "top_sphere"
33 | type phong
34 | diff { "sRGB nonlinear" 0.7 0.1 0.0 }
35 | spec { "sRGB nonlinear" 0.90000000298 0.30000000298 0.00000000298 } 3
36 | samples 4
37 | }
38 |
39 | shader {
40 | name "right_sphere"
41 | type phong
42 | diff { "sRGB nonlinear" 0.0 0.7 1.0 }
43 | spec { "sRGB nonlinear" 0.30000000298 0.40000000298 0.50000000298 } 130
44 | samples 4
45 | }
46 |
47 | include "include/example_scene.geo.sc"
48 |
--------------------------------------------------------------------------------
/examples/sphereflake.sc:
--------------------------------------------------------------------------------
1 | image {
2 | resolution 1920 1080
3 | aa 2 2
4 | samples 4
5 | filter gaussian
6 | }
7 |
8 | trace-depths {
9 | diff 1
10 | refl 1
11 | refr 0
12 | }
13 |
14 |
15 | % |persp|perspShape
16 | camera {
17 | type thinlens
18 | eye -5 0 -0.9
19 | target 0 0 0.2
20 | up 0 0 1
21 | fov 60
22 | aspect 1.77777777777
23 | fdist 5
24 | lensr 0.01
25 | }
26 |
27 | gi { type path samples 16 }
28 |
29 | shader {
30 | name simple1
31 | type diffuse
32 | diff 0.5 0.5 0.5
33 | }
34 |
35 | shader {
36 | name glass
37 | type glass
38 | eta 1.333
39 | color 0.8 0.8 0.8
40 | absorbtion.distance 15
41 | absorbtion.color { "sRGB nonlinear" 0.2 0.7 0.2 }
42 | }
43 |
44 | light {
45 | type sunsky
46 | up 0 0 1
47 | east 0 1 0
48 | sundir -1 1 0.2
49 | turbidity 2
50 | samples 32
51 | }
52 |
53 | shader {
54 | name metal
55 | type phong
56 | diff 0.1 0.1 0.1
57 | spec 0.2 0.2 0.2 30
58 | samples 4
59 | }
60 |
61 |
62 | object {
63 | shader metal
64 | type sphereflake
65 | name left
66 | level 7
67 | }
68 |
69 | object {
70 | shader simple1
71 | type plane
72 | p 0 0 -1
73 | n 0 0 1
74 | }
75 |
76 | shader { name ao type amb-occ diff 1 1 1 }
77 | % override ao true
78 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/AccelerationStructureFactory.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import org.sunflow.PluginRegistry;
4 | import org.sunflow.system.UI;
5 | import org.sunflow.system.UI.Module;
6 |
7 | class AccelerationStructureFactory {
8 | static final AccelerationStructure create(String name, int n, boolean primitives) {
9 | if (name == null || name.equals("auto")) {
10 | if (primitives) {
11 | if (n > 20000000)
12 | name = "uniformgrid";
13 | else if (n > 2000000)
14 | name = "bih";
15 | else if (n > 2)
16 | name = "kdtree";
17 | else
18 | name = "null";
19 | } else {
20 | if (n > 2)
21 | name = "bih";
22 | else
23 | name = "null";
24 | }
25 | }
26 | AccelerationStructure accel = PluginRegistry.accelPlugins.createObject(name);
27 | if (accel == null) {
28 | UI.printWarning(Module.ACCEL, "Unrecognized intersection accelerator \"%s\" - using auto", name);
29 | return create(null, n, primitives);
30 | }
31 | return accel;
32 | }
33 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/modifiers/BumpMappingModifier.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.modifiers;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.Modifier;
5 | import org.sunflow.core.ParameterList;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.core.Texture;
8 | import org.sunflow.core.TextureCache;
9 | import org.sunflow.math.OrthoNormalBasis;
10 |
11 | public class BumpMappingModifier implements Modifier {
12 | private Texture bumpTexture;
13 | private float scale;
14 |
15 | public BumpMappingModifier() {
16 | bumpTexture = null;
17 | scale = 1;
18 | }
19 |
20 | public boolean update(ParameterList pl, SunflowAPI api) {
21 | String filename = pl.getString("texture", null);
22 | if (filename != null)
23 | bumpTexture = TextureCache.getTexture(api.resolveTextureFilename(filename), true);
24 | scale = pl.getFloat("scale", scale);
25 | return bumpTexture != null;
26 | }
27 |
28 | public void modify(ShadingState state) {
29 | // apply bump
30 | state.getNormal().set(bumpTexture.getBump(state.getUV().x, state.getUV().y, state.getBasis(), scale));
31 | state.setBasis(OrthoNormalBasis.makeFromW(state.getNormal()));
32 | }
33 | }
--------------------------------------------------------------------------------
/examples/julia.sc:
--------------------------------------------------------------------------------
1 | image {
2 | resolution 512 512
3 | aa 0 2
4 | filter gaussian
5 | }
6 |
7 | trace-depths {
8 | diff 1
9 | refl 0
10 | refr 0
11 | }
12 |
13 |
14 | % |persp|perspShape
15 | camera {
16 | type pinhole
17 | eye -5 0 0
18 | target 0 0 0
19 | up 0 1 0
20 | fov 58
21 | aspect 1
22 | }
23 |
24 | % background { color { "sRGB nonlinear" 0.5 0.5 0.5 } }
25 |
26 | gi { type path samples 16 }
27 |
28 | shader {
29 | name simple1
30 | type diffuse
31 | diff { "sRGB nonlinear" 0.5 0.5 0.5 }
32 | }
33 |
34 | light {
35 | type spherical
36 | color { "sRGB nonlinear" 1 1 .6 }
37 | radiance 60
38 | center -5 7 5
39 | radius 2
40 | samples 8
41 | }
42 |
43 | light {
44 | type spherical
45 | color { "sRGB nonlinear" .6 .6 1 }
46 | radiance 20
47 | center -15 -17 -15
48 | radius 5
49 | samples 8
50 | }
51 |
52 | object {
53 | shader simple1
54 | transform { scaleu 2 rotatey 45 rotatex -55 }
55 | type julia
56 | name left
57 |
58 | ## q is the main julia set parameter - it defines its shape
59 | % q -0.2 0.4 -0.4 -0.4
60 | % q -1 0.4 0 0
61 | % q -0.08 0.0 -0.83 -0.025
62 | q -0.125 -0.256 0.847 0.0895
63 |
64 | ## iterations/epsilon affect the speed and accuracy of the calculation
65 | ## comment these lines out for very high quality defaults
66 | iterations 8
67 | epsilon 0.001
68 | }
69 |
--------------------------------------------------------------------------------
/src/org/sunflow/system/ui/ConsoleInterface.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.system.ui;
2 |
3 | import org.sunflow.system.UI;
4 | import org.sunflow.system.UserInterface;
5 | import org.sunflow.system.UI.Module;
6 | import org.sunflow.system.UI.PrintLevel;
7 |
8 | /**
9 | * Basic console implementation of a user interface.
10 | */
11 | public class ConsoleInterface implements UserInterface {
12 | private int min;
13 | private int max;
14 | private float invP;
15 | private String task;
16 | private int lastP;
17 |
18 | public ConsoleInterface() {
19 | }
20 |
21 | public void print(Module m, PrintLevel level, String s) {
22 | System.err.println(UI.formatOutput(m, level, s));
23 | }
24 |
25 | public void taskStart(String s, int min, int max) {
26 | task = s;
27 | this.min = min;
28 | this.max = max;
29 | lastP = -1;
30 | invP = 100.0f / (max - min);
31 | }
32 |
33 | public void taskUpdate(int current) {
34 | int p = (min == max) ? 0 : (int) ((current - min) * invP);
35 | if (p != lastP)
36 | System.err.print(task + " [" + (lastP = p) + "%]\r");
37 | }
38 |
39 | public void taskStop() {
40 | System.err.print(" \r");
41 | }
42 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/writers/PNGBitmapWriter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.writers;
2 |
3 | import java.awt.image.BufferedImage;
4 | import java.io.File;
5 | import java.io.IOException;
6 |
7 | import javax.imageio.ImageIO;
8 |
9 | import org.sunflow.image.BitmapWriter;
10 | import org.sunflow.image.Color;
11 |
12 | public class PNGBitmapWriter implements BitmapWriter {
13 | private String filename;
14 | private BufferedImage image;
15 |
16 | public void configure(String option, String value) {
17 | }
18 |
19 | public void openFile(String filename) throws IOException {
20 | this.filename = filename;
21 | }
22 |
23 | public void writeHeader(int width, int height, int tileSize) throws IOException, UnsupportedOperationException {
24 | image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
25 | }
26 |
27 | public void writeTile(int x, int y, int w, int h, Color[] color, float[] alpha) throws IOException {
28 | for (int j = 0, index = 0; j < h; j++)
29 | for (int i = 0; i < w; i++, index++)
30 | image.setRGB(x + i, y + j, color[index].copy().mul(1.0f / alpha[index]).toNonLinear().toRGBA(alpha[index]));
31 | }
32 |
33 | public void closeFile() throws IOException {
34 | ImageIO.write(image, "png", new File(filename));
35 | }
36 | }
--------------------------------------------------------------------------------
/examples/shader_examples/Shiny001.sc:
--------------------------------------------------------------------------------
1 | shader {
2 | name "ground"
3 | type diffuse
4 | diff 0.800000011921 0.800000011921 0.800000011921
5 | }
6 |
7 | shader {
8 | name "shader01"
9 | type shiny
10 | diff { "sRGB nonlinear" 1 .33 .33 }
11 | refl .1
12 | }
13 |
14 | shader {
15 | name "shader02"
16 | type shiny
17 | diff { "sRGB nonlinear" 1 .33 .33 }
18 | refl .2
19 | }
20 |
21 | shader {
22 | name "shader03"
23 | type shiny
24 | diff { "sRGB nonlinear" 1 .33 .33 }
25 | refl .5
26 | }
27 |
28 | shader {
29 | name "shader04"
30 | type shiny
31 | diff { "sRGB nonlinear" 1 .33 .33 }
32 | refl .7
33 | }
34 |
35 | shader {
36 | name "shader05"
37 | type shiny
38 | diff { "sRGB nonlinear" 1 .33 .33 }
39 | refl .9
40 | }
41 |
42 | shader {
43 | name "shader06"
44 | type shiny
45 | diff { "sRGB nonlinear" 1 .33 .33 }
46 | refl 1.1
47 | }
48 |
49 | shader {
50 | name "shader07"
51 | type shiny
52 | diff { "sRGB nonlinear" 1 .33 .33 }
53 | refl 1.3
54 | }
55 |
56 | shader {
57 | name "shader08"
58 | type shiny
59 | diff { "sRGB nonlinear" 1 .33 .33 }
60 | refl 1.5
61 | }
62 |
63 | shader {
64 | name "shader09"
65 | type shiny
66 | diff { "sRGB nonlinear" 1 .33 .33 }
67 | refl 1.6
68 | }
69 |
70 | include "include/example_array.geo.sc"
71 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/primitive/Background.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.primitive;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.IntersectionState;
5 | import org.sunflow.core.ParameterList;
6 | import org.sunflow.core.PrimitiveList;
7 | import org.sunflow.core.Ray;
8 | import org.sunflow.core.ShadingState;
9 | import org.sunflow.math.BoundingBox;
10 | import org.sunflow.math.Matrix4;
11 |
12 | public class Background implements PrimitiveList {
13 | public Background() {
14 | }
15 |
16 | public boolean update(ParameterList pl, SunflowAPI api) {
17 | return true;
18 | }
19 |
20 | public void prepareShadingState(ShadingState state) {
21 | if (state.getDepth() == 0)
22 | state.setShader(state.getInstance().getShader(0));
23 | }
24 |
25 | public int getNumPrimitives() {
26 | return 1;
27 | }
28 |
29 | public float getPrimitiveBound(int primID, int i) {
30 | return 0;
31 | }
32 |
33 | public BoundingBox getWorldBounds(Matrix4 o2w) {
34 | return null;
35 | }
36 |
37 | public void intersectPrimitive(Ray r, int primID, IntersectionState state) {
38 | if (r.getMax() == Float.POSITIVE_INFINITY)
39 | state.setIntersection(0);
40 | }
41 |
42 | public PrimitiveList getBakingPrimitives() {
43 | return null;
44 | }
45 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/camera/PinholeLens.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.camera;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.CameraLens;
5 | import org.sunflow.core.ParameterList;
6 | import org.sunflow.core.Ray;
7 |
8 | public class PinholeLens implements CameraLens {
9 | private float au, av;
10 | private float aspect, fov;
11 | private float shiftX, shiftY;
12 |
13 | public PinholeLens() {
14 | fov = 90;
15 | aspect = 1;
16 | shiftX = shiftY = 0;
17 | update();
18 | }
19 |
20 | public boolean update(ParameterList pl, SunflowAPI api) {
21 | // get parameters
22 | fov = pl.getFloat("fov", fov);
23 | aspect = pl.getFloat("aspect", aspect);
24 | shiftX = pl.getFloat("shift.x", shiftX);
25 | shiftY = pl.getFloat("shift.y", shiftY);
26 | update();
27 | return true;
28 | }
29 |
30 | private void update() {
31 | au = (float) Math.tan(Math.toRadians(fov * 0.5f));
32 | av = au / aspect;
33 | }
34 |
35 | public Ray getRay(float x, float y, int imageWidth, int imageHeight, double lensX, double lensY, double time) {
36 | float du = shiftX - au + ((2.0f * au * x) / (imageWidth - 1.0f));
37 | float dv = shiftY - av + ((2.0f * av * y) / (imageHeight - 1.0f));
38 | return new Ray(0, 0, 0, du, dv, -1);
39 | }
40 | }
--------------------------------------------------------------------------------
/examples/shader_examples/Glass002.sc:
--------------------------------------------------------------------------------
1 | % photons {
2 | % caustics 10000000 kd 64 0.5
3 | % }
4 |
5 | shader {
6 | name "ground"
7 | type diffuse
8 | diff 0.800000011921 0.800000011921 0.800000011921
9 | }
10 |
11 | shader {
12 | name "shader01"
13 | type glass
14 | eta 1.1
15 | color { "sRGB nonlinear" 1 0.5 0.5 }
16 | }
17 |
18 | shader {
19 | name "shader02"
20 | type glass
21 | eta 1.3
22 | color { "sRGB nonlinear" 0.5 1 0.5 }
23 | }
24 |
25 | shader {
26 | name "shader03"
27 | type glass
28 | eta 1.5
29 | color { "sRGB nonlinear" 0.5 0.5 1 }
30 | }
31 |
32 | shader {
33 | name "shader04"
34 | type glass
35 | eta 1.7
36 | color { "sRGB nonlinear" 1 1 0.5 }
37 | }
38 |
39 | shader {
40 | name "shader05"
41 | type glass
42 | eta 1.9
43 | color { "sRGB nonlinear" 1 0.5 1 }
44 | }
45 |
46 | shader {
47 | name "shader06"
48 | type glass
49 | eta 2.1
50 | color { "sRGB nonlinear" 0 0.5 1 }
51 | }
52 |
53 | shader {
54 | name "shader07"
55 | type glass
56 | eta 2.3
57 | color { "sRGB nonlinear" 1 0.66 0.33 }
58 | }
59 |
60 | shader {
61 | name "shader08"
62 | type glass
63 | eta 2.5
64 | color { "sRGB nonlinear" 0.5 1 1 }
65 | }
66 |
67 | shader {
68 | name "shader09"
69 | type glass
70 | eta 2.7
71 | color { "sRGB nonlinear" 1 1 1 }
72 | }
73 |
74 | include "include/example_array.geo.sc"
75 |
--------------------------------------------------------------------------------
/.externalToolBuilders/Ant Build.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/CameraLens.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | /**
4 | * Represents a mapping from the 3D scene onto the final image. A camera lens is
5 | * responsible for determining what ray to cast through each pixel.
6 | */
7 | public interface CameraLens extends RenderObject {
8 | /**
9 | * Create a new {@link Ray ray}to be cast through pixel (x,y) on the image
10 | * plane. Two sampling parameters are provided for lens sampling. They are
11 | * guarenteed to be in the interval [0,1). They can be used to perturb the
12 | * position of the source of the ray on the lens of the camera for DOF
13 | * effects. A third sampling parameter is provided for motion blur effects.
14 | * Note that the {@link Camera} class already handles camera movement motion
15 | * blur. Rays should be generated in camera space - that is, with the eye at
16 | * the origin, looking down the -Z axis, with +Y pointing up.
17 | *
18 | * @param x x coordinate of the (sub)pixel
19 | * @param y y coordinate of the (sub)pixel
20 | * @param imageWidth image width in pixels
21 | * @param imageHeight image height in pixels
22 | * @param lensX x lens sampling parameter
23 | * @param lensY y lens sampling parameter
24 | * @param time time sampling parameter
25 | * @return a new ray passing through the given pixel
26 | */
27 | public Ray getRay(float x, float y, int imageWidth, int imageHeight, double lensX, double lensY, double time);
28 | }
--------------------------------------------------------------------------------
/src/org/sunflow/system/Timer.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.system;
2 |
3 | public class Timer {
4 | private long startTime, endTime;
5 |
6 | public Timer() {
7 | startTime = endTime = 0;
8 | }
9 |
10 | public void start() {
11 | startTime = endTime = System.nanoTime();
12 | }
13 |
14 | public void end() {
15 | endTime = System.nanoTime();
16 | }
17 |
18 | public long nanos() {
19 | return endTime - startTime;
20 | }
21 |
22 | public double seconds() {
23 | return (endTime - startTime) * 1e-9;
24 | }
25 |
26 | public static String toString(long nanos) {
27 | Timer t = new Timer();
28 | t.endTime = nanos;
29 | return t.toString();
30 | }
31 |
32 | public static String toString(double seconds) {
33 | Timer t = new Timer();
34 | t.endTime = (long) (seconds * 1e9);
35 | return t.toString();
36 | }
37 |
38 | @Override
39 | public String toString() {
40 | long millis = nanos() / (1000 * 1000);
41 | if (millis < 10000)
42 | return String.format("%dms", millis);
43 | long hours = millis / (60 * 60 * 1000);
44 | millis -= hours * 60 * 60 * 1000;
45 | long minutes = millis / (60 * 1000);
46 | millis -= minutes * 60 * 1000;
47 | long seconds = millis / 1000;
48 | millis -= seconds * 1000;
49 | return String.format("%d:%02d:%02d.%1d", hours, minutes, seconds, millis / 100);
50 | }
51 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/bucket/SpiralBucketOrder.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.bucket;
2 |
3 | import org.sunflow.core.BucketOrder;
4 |
5 | public class SpiralBucketOrder implements BucketOrder {
6 | public int[] getBucketSequence(int nbw, int nbh) {
7 | int[] coords = new int[2 * nbw * nbh];
8 | for (int i = 0; i < nbw * nbh; i++) {
9 | int bx, by;
10 | int center = (Math.min(nbw, nbh) - 1) / 2;
11 | int nx = nbw;
12 | int ny = nbh;
13 | while (i < (nx * ny)) {
14 | nx--;
15 | ny--;
16 | }
17 | int nxny = nx * ny;
18 | int minnxny = Math.min(nx, ny);
19 | if ((minnxny & 1) == 1) {
20 | if (i <= (nxny + ny)) {
21 | bx = nx - minnxny / 2;
22 | by = -minnxny / 2 + i - nxny;
23 | } else {
24 | bx = nx - minnxny / 2 - (i - (nxny + ny));
25 | by = ny - minnxny / 2;
26 | }
27 | } else {
28 | if (i <= (nxny + ny)) {
29 | bx = -minnxny / 2;
30 | by = ny - minnxny / 2 - (i - nxny);
31 | } else {
32 | bx = -minnxny / 2 + (i - (nxny + ny));
33 | by = -minnxny / 2;
34 | }
35 | }
36 | coords[2 * i + 0] = bx + center;
37 | coords[2 * i + 1] = by + center;
38 | }
39 | return coords;
40 | }
41 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/AmbientOcclusionShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Shader;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.image.Color;
8 |
9 | public class AmbientOcclusionShader implements Shader {
10 | private Color bright;
11 | private Color dark;
12 | private int samples;
13 | private float maxDist;
14 |
15 | public AmbientOcclusionShader() {
16 | bright = Color.WHITE;
17 | dark = Color.BLACK;
18 | samples = 32;
19 | maxDist = Float.POSITIVE_INFINITY;
20 | }
21 |
22 | public AmbientOcclusionShader(Color c, float d) {
23 | this();
24 | bright = c;
25 | maxDist = d;
26 | }
27 |
28 | public boolean update(ParameterList pl, SunflowAPI api) {
29 | bright = pl.getColor("bright", bright);
30 | dark = pl.getColor("dark", dark);
31 | samples = pl.getInt("samples", samples);
32 | maxDist = pl.getFloat("maxdist", maxDist);
33 | if (maxDist <= 0)
34 | maxDist = Float.POSITIVE_INFINITY;
35 | return true;
36 | }
37 |
38 | public Color getBrightColor(ShadingState state) {
39 | return bright;
40 | }
41 |
42 | public Color getRadiance(ShadingState state) {
43 | return state.occlusion(samples, maxDist, getBrightColor(state), dark);
44 | }
45 |
46 | public void scatterPhoton(ShadingState state, Color power) {
47 | }
48 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/Tesselatable.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import org.sunflow.core.primitive.TriangleMesh;
4 | import org.sunflow.math.BoundingBox;
5 | import org.sunflow.math.Matrix4;
6 |
7 | /**
8 | * Represents an object which can be tesselated into a list of primitives such
9 | * as a {@link TriangleMesh}.
10 | */
11 | public interface Tesselatable extends RenderObject {
12 | /**
13 | * Tesselate this object into a {@link PrimitiveList}. This may return
14 | * null if tesselation fails.
15 | *
16 | * @return a list of primitives generated by the tesselation
17 | */
18 | public PrimitiveList tesselate();
19 |
20 | /**
21 | * Compute a bounding box of this object in world space, using the specified
22 | * object-to-world transformation matrix. The bounds should be as exact as
23 | * possible, if they are difficult or expensive to compute exactly, you may
24 | * use {@link Matrix4#transform(BoundingBox)}. If the matrix is
25 | * null no transformation is needed, and object space is
26 | * equivalent to world space. This method may return null if
27 | * these bounds are difficult or impossible to compute, in which case the
28 | * tesselation will be executed right away and the bounds of the resulting
29 | * primitives will be used.
30 | *
31 | * @param o2w object to world transformation matrix
32 | * @return object bounding box in world space
33 | */
34 | public BoundingBox getWorldBounds(Matrix4 o2w);
35 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/BitmapReader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * This is a very simple interface, designed to handle loading of bitmap data.
7 | */
8 | public interface BitmapReader {
9 | /**
10 | * Load the specified filename. This method should throw exception if it
11 | * encounters any errors. If the file is valid but its contents are not
12 | * (invalid header for example), a {@link BitmapFormatException} may be
13 | * thrown. It is an error for this method to return null.
14 | *
15 | * @param filename image filename to load
16 | * @param isLinear if this is true, the bitmap is assumed to
17 | * be already in linear space. This can be usefull when reading
18 | * greyscale images for bump mapping for example. HDR formats can
19 | * ignore this flag since they usually always store data in
20 | * linear form.
21 | * @return a new {@link Bitmap} object
22 | */
23 | public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException;
24 |
25 | /**
26 | * This exception can be used internally by bitmap readers to signal they
27 | * have encountered a valid file but which contains invalid content.
28 | */
29 | @SuppressWarnings("serial")
30 | public static final class BitmapFormatException extends Exception {
31 | public BitmapFormatException(String message) {
32 | super(message);
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/bucket/RandomBucketOrder.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.bucket;
2 |
3 | import org.sunflow.core.BucketOrder;
4 |
5 | public class RandomBucketOrder implements BucketOrder {
6 | public int[] getBucketSequence(int nbw, int nbh) {
7 | int[] coords = new int[2 * nbw * nbh];
8 | for (int i = 0; i < nbw * nbh; i++) {
9 | int by = i / nbw;
10 | int bx = i % nbw;
11 | if ((by & 1) == 1)
12 | bx = nbw - 1 - bx;
13 | coords[2 * i + 0] = bx;
14 | coords[2 * i + 1] = by;
15 | }
16 |
17 | long seed = 2463534242L;
18 | for (int i = 0; i < coords.length; i++) {
19 | // pick 2 random indices
20 | seed = xorshift(seed);
21 | int src = mod((int) seed, nbw * nbh);
22 | seed = xorshift(seed);
23 | int dst = mod((int) seed, nbw * nbh);
24 | int tmp = coords[2 * src + 0];
25 | coords[2 * src + 0] = coords[2 * dst + 0];
26 | coords[2 * dst + 0] = tmp;
27 | tmp = coords[2 * src + 1];
28 | coords[2 * src + 1] = coords[2 * dst + 1];
29 | coords[2 * dst + 1] = tmp;
30 | }
31 |
32 | return coords;
33 | }
34 |
35 | private int mod(int a, int b) {
36 | int m = a % b;
37 | return (m < 0) ? m + b : m;
38 | }
39 |
40 | private long xorshift(long y) {
41 | y = y ^ (y << 13);
42 | y = y ^ (y >>> 17); // unsigned
43 | y = y ^ (y << 5);
44 | return y;
45 | }
46 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/formats/BitmapRGBE.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.formats;
2 |
3 | import org.sunflow.image.Bitmap;
4 | import org.sunflow.image.Color;
5 |
6 | public class BitmapRGBE extends Bitmap {
7 | private int w, h;
8 | private int[] data;
9 | private static final float[] EXPONENT = new float[256];
10 |
11 | static {
12 | EXPONENT[0] = 0;
13 | for (int i = 1; i < 256; i++) {
14 | float f = 1.0f;
15 | int e = i - (128 + 8);
16 | if (e > 0)
17 | for (int j = 0; j < e; j++)
18 | f *= 2.0f;
19 | else
20 | for (int j = 0; j < -e; j++)
21 | f *= 0.5f;
22 | EXPONENT[i] = f;
23 | }
24 | }
25 |
26 | public BitmapRGBE(int w, int h, int[] data) {
27 | this.w = w;
28 | this.h = h;
29 | this.data = data;
30 | }
31 |
32 | @Override
33 | public int getWidth() {
34 | return w;
35 | }
36 |
37 | @Override
38 | public int getHeight() {
39 | return h;
40 | }
41 |
42 | @Override
43 | public Color readColor(int x, int y) {
44 | int rgbe = data[x + y * w];
45 | float f = EXPONENT[rgbe & 0xFF];
46 | float r = f * ((rgbe >>> 24) + 0.5f);
47 | float g = f * (((rgbe >> 16) & 0xFF) + 0.5f);
48 | float b = f * (((rgbe >> 8) & 0xFF) + 0.5f);
49 | return new Color(r, g, b);
50 | }
51 |
52 | @Override
53 | public float readAlpha(int x, int y) {
54 | return 1;
55 | }
56 | }
--------------------------------------------------------------------------------
/examples/wireframe_demo.java:
--------------------------------------------------------------------------------
1 | import org.sunflow.PluginRegistry;
2 | import org.sunflow.core.ShadingState;
3 | import org.sunflow.core.shader.WireframeShader;
4 | import org.sunflow.image.Color;
5 |
6 | public void build() {
7 | PluginRegistry.shaderPlugins.registerPlugin("custom_wireframe", CustomWireShader.class);
8 |
9 | parameter("width", (float) (Math.PI * 0.5 / 8192));
10 | shader("ao_wire", "custom_wireframe");
11 | // you can put the path to your own scene here to use this rendering
12 | // technique just copy this file to the same directory as your main .sc
13 | // file, and swap the fileanme in the line below
14 | include("gumbo_and_teapot.sc");
15 |
16 | // shader override
17 | parameter("override.shader", "ao_wire");
18 | parameter("override.photons", true);
19 |
20 | // this may need to be tweaked if you want really fine lines
21 | // this is higher than most scenes need so if you render with ambocc =
22 | // false, make sure you turn down the sampling rates of
23 | // dof/lights/gi/reflections accordingly
24 | parameter("aa.min", 2);
25 | parameter("aa.max", 2);
26 | parameter("filter", "blackman-harris");
27 | options(DEFAULT_OPTIONS);
28 | }
29 |
30 |
31 | // this class will be registered as a plugin
32 | public static class CustomWireShader extends WireframeShader {
33 | // set to false to overlay wires on regular shaders
34 | private boolean ambocc = true;
35 |
36 | public Color getFillColor(ShadingState state) {
37 | return ambocc ? state.occlusion(16, 6.0f) : state.getShader().getRadiance(state);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/shader_examples/AO001.sc:
--------------------------------------------------------------------------------
1 | shader {
2 | name ground
3 | type amb-occ
4 | bright 1 0 1
5 | dark 0 0 0
6 | samples 128
7 | dist 6
8 | }
9 |
10 | shader {
11 | name "shader01"
12 | type amb-occ
13 | bright 1 0.5 0
14 | dark .3 .1 0
15 | samples 1
16 | dist 6
17 | }
18 |
19 | shader {
20 | name "shader02"
21 | type amb-occ
22 | bright 1 0.5 0
23 | dark .3 .1 0
24 | samples 2
25 | dist 6
26 | }
27 |
28 | shader {
29 | name "shader03"
30 | type amb-occ
31 | bright 1 0.5 0
32 | dark .3 .1 0
33 | samples 4
34 | dist 6
35 | }
36 |
37 | shader {
38 | name "shader04"
39 | type amb-occ
40 | bright 1 0.5 0
41 | dark .3 .1 0
42 | samples 8
43 | dist 10
44 | }
45 |
46 | shader {
47 | name "shader05"
48 | type amb-occ
49 | bright 1 0.5 0
50 | dark .3 .1 0
51 | samples 16
52 | dist 6
53 | }
54 |
55 | shader {
56 | name "shader06"
57 | type amb-occ
58 | bright 1 0.5 0
59 | dark .3 .1 0
60 | samples 32
61 | dist 6
62 | }
63 |
64 | shader {
65 | name "shader07"
66 | type amb-occ
67 | bright 1 0.5 0
68 | dark .3 .1 0
69 | samples 64
70 | dist 6
71 | }
72 |
73 | shader {
74 | name "shader08"
75 | type amb-occ
76 | bright 1 0.5 0
77 | dark .3 .1 0
78 | samples 128
79 | dist 6
80 | }
81 |
82 | shader {
83 | name "shader09"
84 | type amb-occ
85 | bright 1 0.5 0
86 | dark .3 .1 0
87 | samples 256
88 | dist 6
89 | }
90 |
91 | include include/example_array.geo.sc
92 |
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/src/sunflowHelperNode.h:
--------------------------------------------------------------------------------
1 | #ifndef SUNFLOW_HELPER_NODE_H
2 | #define SUNFLOW_HELPER_NODE_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 |
16 |
17 |
18 | class sunflowHelperNode : public MPxLocatorNode
19 | {
20 | public:
21 |
22 | virtual MStatus compute( const MPlug& plug, MDataBlock& data );
23 |
24 | virtual void draw( M3dView & view, const MDagPath & path,
25 | M3dView::DisplayStyle displaystyle,
26 | M3dView::DisplayStatus displaystatus );
27 |
28 | virtual bool isBounded() const;
29 | virtual MBoundingBox boundingBox() const;
30 |
31 | virtual MStatus connectionMade ( const MPlug & plug, const MPlug & otherPlug, bool asSrc );
32 |
33 | static void * creator();
34 | static MStatus initialize();
35 |
36 | static MObject aDummy;
37 | static MObject aHelperType;
38 | static MObject aHelperColor;
39 | static MObject aHelperOpacity;
40 | static MObject aMeshPath;
41 | static MObject aShaderNode;
42 |
43 | public:
44 | static MTypeId id;
45 |
46 | int m_helperType;
47 | MColor m_helperColor;
48 |
49 | };
50 |
51 | #endif /* SUNFLOW_HELPER_NODE_H */
52 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/gi/FakeGIEngine.java:
--------------------------------------------------------------------------------
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 | private Vector3 up;
18 | private Color sky;
19 | private Color ground;
20 |
21 | public Color getIrradiance(ShadingState state, Color diffuseReflectance) {
22 | float cosTheta = Vector3.dot(up, state.getNormal());
23 | float sin2 = (1 - cosTheta * cosTheta);
24 | float sine = sin2 > 0 ? (float) Math.sqrt(sin2) * 0.5f : 0;
25 | if (cosTheta > 0)
26 | return Color.blend(sky, ground, sine);
27 | else
28 | return Color.blend(ground, sky, sine);
29 | }
30 |
31 | public Color getGlobalRadiance(ShadingState state) {
32 | return Color.BLACK;
33 | }
34 |
35 | public boolean init(Options options, Scene scene) {
36 | up = options.getVector("gi.fake.up", new Vector3(0, 1, 0)).normalize();
37 | sky = options.getColor("gi.fake.sky", Color.WHITE).copy();
38 | ground = options.getColor("gi.fake.ground", Color.BLACK).copy();
39 | sky.mul((float) Math.PI);
40 | ground.mul((float) Math.PI);
41 | return true;
42 | }
43 | }
--------------------------------------------------------------------------------
/examples/shader_examples/Phong002.sc:
--------------------------------------------------------------------------------
1 | trace-depths {
2 | diff 0
3 | refl 1
4 | refr 0
5 | }
6 |
7 | shader {
8 | name "ground"
9 | type diffuse
10 | diff 0.800000011921 0.800000011921 0.800000011921
11 | }
12 |
13 | shader {
14 | name "shader01"
15 | type phong
16 | diff { "sRGB nonlinear" 0.33 0.33 1 }
17 | spec 1 1 1 1
18 | samples 4
19 | }
20 |
21 | shader {
22 | name "shader02"
23 | type phong
24 | diff { "sRGB nonlinear" 0.33 0.33 1 }
25 | spec 1 1 1 4
26 | samples 4
27 | }
28 |
29 | shader {
30 | name "shader03"
31 | type phong
32 | diff { "sRGB nonlinear" 0.33 0.33 1 }
33 | spec 1 1 1 8
34 | samples 4
35 | }
36 |
37 | shader {
38 | name "shader04"
39 | type phong
40 | diff { "sRGB nonlinear" 0.33 0.33 1 }
41 | spec 1 1 1 10
42 | samples 4
43 | }
44 |
45 | shader {
46 | name "shader05"
47 | type phong
48 | diff { "sRGB nonlinear" 0.33 0.33 1 }
49 | spec 1 1 1 20
50 | samples 4
51 | }
52 |
53 | shader {
54 | name "shader06"
55 | type phong
56 | diff { "sRGB nonlinear" 0.33 0.33 1 }
57 | spec 1 1 1 30
58 | samples 4
59 | }
60 |
61 | shader {
62 | name "shader07"
63 | type phong
64 | diff { "sRGB nonlinear" 0.33 0.33 1 }
65 | spec 1 1 1 100
66 | samples 4
67 | }
68 |
69 | shader {
70 | name "shader08"
71 | type phong
72 | diff { "sRGB nonlinear" 0.33 0.33 1 }
73 | spec 1 1 1 300
74 | samples 4
75 | }
76 |
77 | shader {
78 | name "shader09"
79 | type phong
80 | diff { "sRGB nonlinear" 0.33 0.33 1 }
81 | spec 1 1 1 600
82 | samples 4
83 | }
84 |
85 | include "include/example_array.geo.sc"
86 |
--------------------------------------------------------------------------------
/src/org/sunflow/image/readers/BMPBitmapReader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.readers;
2 |
3 | import java.awt.image.BufferedImage;
4 | import java.io.File;
5 | import java.io.IOException;
6 |
7 | import javax.imageio.ImageIO;
8 |
9 | import org.sunflow.image.Bitmap;
10 | import org.sunflow.image.BitmapReader;
11 | import org.sunflow.image.Color;
12 | import org.sunflow.image.formats.BitmapRGB8;
13 |
14 | public class BMPBitmapReader implements BitmapReader {
15 | public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
16 | // regular image, load using Java api - ignore alpha channel
17 | BufferedImage bi = ImageIO.read(new File(filename));
18 | int width = bi.getWidth();
19 | int height = bi.getHeight();
20 | byte[] pixels = new byte[3 * width * height];
21 | for (int y = 0, index = 0; y < height; y++) {
22 | for (int x = 0; x < width; x++, index += 3) {
23 | int argb = bi.getRGB(x, height - 1 - y);
24 | pixels[index + 0] = (byte) (argb >> 16);
25 | pixels[index + 1] = (byte) (argb >> 8);
26 | pixels[index + 2] = (byte) argb;
27 | }
28 | }
29 | if (!isLinear) {
30 | for (int index = 0; index < pixels.length; index += 3) {
31 | pixels[index + 0] = Color.NATIVE_SPACE.rgbToLinear(pixels[index + 0]);
32 | pixels[index + 1] = Color.NATIVE_SPACE.rgbToLinear(pixels[index + 1]);
33 | pixels[index + 2] = Color.NATIVE_SPACE.rgbToLinear(pixels[index + 2]);
34 | }
35 | }
36 | return new BitmapRGB8(width, height, pixels);
37 | }
38 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/readers/JPGBitmapReader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.readers;
2 |
3 | import java.awt.image.BufferedImage;
4 | import java.io.File;
5 | import java.io.IOException;
6 |
7 | import javax.imageio.ImageIO;
8 |
9 | import org.sunflow.image.Bitmap;
10 | import org.sunflow.image.BitmapReader;
11 | import org.sunflow.image.Color;
12 | import org.sunflow.image.formats.BitmapRGB8;
13 |
14 | public class JPGBitmapReader implements BitmapReader {
15 | public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
16 | // regular image, load using Java api - ignore alpha channel
17 | BufferedImage bi = ImageIO.read(new File(filename));
18 | int width = bi.getWidth();
19 | int height = bi.getHeight();
20 | byte[] pixels = new byte[3 * width * height];
21 | for (int y = 0, index = 0; y < height; y++) {
22 | for (int x = 0; x < width; x++, index += 3) {
23 | int argb = bi.getRGB(x, height - 1 - y);
24 | pixels[index + 0] = (byte) (argb >> 16);
25 | pixels[index + 1] = (byte) (argb >> 8);
26 | pixels[index + 2] = (byte) argb;
27 | }
28 | }
29 | if (!isLinear) {
30 | for (int index = 0; index < pixels.length; index += 3) {
31 | pixels[index + 0] = Color.NATIVE_SPACE.rgbToLinear(pixels[index + 0]);
32 | pixels[index + 1] = Color.NATIVE_SPACE.rgbToLinear(pixels[index + 1]);
33 | pixels[index + 2] = Color.NATIVE_SPACE.rgbToLinear(pixels[index + 2]);
34 | }
35 | }
36 | return new BitmapRGB8(width, height, pixels);
37 | }
38 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/GIEngine.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import org.sunflow.image.Color;
4 |
5 | /**
6 | * This represents a global illumination algorithm. It provides an interface to
7 | * compute indirect diffuse bounces of light and make those results available to
8 | * shaders.
9 | */
10 | public interface GIEngine {
11 | /**
12 | * This is an optional method for engines that contain a secondary
13 | * illumination engine which can return an approximation of the global
14 | * radiance in the scene (like a photon map). Engines can safely return
15 | * Color.BLACK if they can't or don't wish to support this.
16 | *
17 | * @param state shading state
18 | * @return color approximating global radiance
19 | */
20 | public Color getGlobalRadiance(ShadingState state);
21 |
22 | /**
23 | * Initialize the engine. This is called before rendering begins.
24 | *
25 | * @return true if the init phase succeeded,
26 | * false otherwise
27 | */
28 | public boolean init(Options options, Scene scene);
29 |
30 | /**
31 | * Return the incomming irradiance due to indirect diffuse illumination at
32 | * the specified surface point.
33 | *
34 | * @param state current render state describing the point to be computed
35 | * @param diffuseReflectance diffuse albedo of the point being shaded, this
36 | * can be used for importance tracking
37 | * @return irradiance from indirect diffuse illumination at the specified
38 | * point
39 | */
40 | public Color getIrradiance(ShadingState state, Color diffuseReflectance);
41 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/readers/PNGBitmapReader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.readers;
2 |
3 | import java.awt.image.BufferedImage;
4 | import java.io.File;
5 | import java.io.IOException;
6 |
7 | import javax.imageio.ImageIO;
8 |
9 | import org.sunflow.image.Bitmap;
10 | import org.sunflow.image.BitmapReader;
11 | import org.sunflow.image.Color;
12 | import org.sunflow.image.formats.BitmapRGBA8;
13 |
14 | public class PNGBitmapReader implements BitmapReader {
15 | public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
16 | // regular image, load using Java api
17 | BufferedImage bi = ImageIO.read(new File(filename));
18 | int width = bi.getWidth();
19 | int height = bi.getHeight();
20 | byte[] pixels = new byte[4 * width * height];
21 | for (int y = 0, index = 0; y < height; y++) {
22 | for (int x = 0; x < width; x++, index += 4) {
23 | int argb = bi.getRGB(x, height - 1 - y);
24 | pixels[index + 0] = (byte) (argb >> 16);
25 | pixels[index + 1] = (byte) (argb >> 8);
26 | pixels[index + 2] = (byte) argb;
27 | pixels[index + 3] = (byte) (argb >> 24);
28 | }
29 | }
30 | if (!isLinear) {
31 | for (int index = 0; index < pixels.length; index += 4) {
32 | pixels[index + 0] = Color.NATIVE_SPACE.rgbToLinear(pixels[index + 0]);
33 | pixels[index + 1] = Color.NATIVE_SPACE.rgbToLinear(pixels[index + 1]);
34 | pixels[index + 2] = Color.NATIVE_SPACE.rgbToLinear(pixels[index + 2]);
35 | }
36 | }
37 | return new BitmapRGBA8(width, height, pixels);
38 | }
39 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/mel/AEsunflowHelperNodeTemplate.mel:
--------------------------------------------------------------------------------
1 |
2 | global proc AEsunflowHelperNewGroup(string $shadingGroupPlug )
3 | {
4 | createRenderNode -shadersSG ("connectAttr %nodeSG.message "+$shadingGroupPlug) "";
5 | }
6 |
7 | global proc AEsunflowHelperReplaceGroup( string $shadingGroupPlug, string $dashSource, string $node )
8 | {
9 | connectAttr -f ($node+".message") $shadingGroupPlug;
10 | }
11 |
12 | global proc AEsunflowHelperNodeShaderNew( string $shadingGroupPlug )
13 | {
14 | setUITemplate -pst attributeEditorTemplate;
15 |
16 | attrNavigationControlGrp -label "Shader" shadingGroupOverride;
17 | AEsunflowHelperNodeShaderReplace($shadingGroupPlug);
18 | }
19 |
20 | global proc AEsunflowHelperNodeShaderReplace( string $shadingGroupPlug )
21 | {
22 | attrNavigationControlGrp -edit
23 | -attribute $shadingGroupPlug
24 | -enable true
25 | -createNew ("AEsunflowHelperNewGroup "+$shadingGroupPlug)
26 | -connectToExisting ("AEsunflowHelperReplaceGroup "+$shadingGroupPlug)
27 | shadingGroupOverride;
28 | }
29 |
30 | global proc AEsunflowHelperNodeTemplate( string $nodeName )
31 | {
32 | editorTemplate -beginScrollLayout;
33 | editorTemplate -l "Type" -addControl "type";
34 | editorTemplate -beginLayout "File Mesh Attributes" -collapse 0;
35 | editorTemplate -l "File" -addControl "meshPath";
36 | editorTemplate -endLayout;
37 | editorTemplate -beginLayout "Infinite Plane" -collapse 0;
38 | editorTemplate
39 | -callCustom "AEsunflowHelperNodeShaderNew"
40 | "AEsunflowHelperNodeShaderReplace"
41 | "shaderNode";
42 | editorTemplate -endLayout;
43 | //editorTemplate -addExtraControls;
44 | editorTemplate -endScrollLayout;
45 | }
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/TextureCache.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import java.util.HashMap;
4 |
5 | import org.sunflow.system.UI;
6 | import org.sunflow.system.UI.Module;
7 |
8 | /**
9 | * Maintains a cache of all loaded texture maps. This is usefull if the same
10 | * texture might be used more than once in your scene.
11 | */
12 | public final class TextureCache {
13 | private static HashMap textures = new HashMap();
14 |
15 | private TextureCache() {
16 | }
17 |
18 | /**
19 | * Gets a reference to the texture specified by the given filename. If the
20 | * texture has already been loaded the previous reference is returned,
21 | * otherwise, a new texture is created.
22 | *
23 | * @param filename image file to load
24 | * @param isLinear is the texture gamma corrected?
25 | * @return texture object
26 | * @see Texture
27 | */
28 | public synchronized static Texture getTexture(String filename, boolean isLinear) {
29 | if (textures.containsKey(filename)) {
30 | UI.printInfo(Module.TEX, "Using cached copy for file \"%s\" ...", filename);
31 | return textures.get(filename);
32 | }
33 | UI.printInfo(Module.TEX, "Using file \"%s\" ...", filename);
34 | Texture t = new Texture(filename, isLinear);
35 | textures.put(filename, t);
36 | return t;
37 | }
38 |
39 | /**
40 | * Flush all textures from the cache, this will cause them to be reloaded
41 | * anew the next time they are accessed.
42 | */
43 | public synchronized static void flush() {
44 | UI.printInfo(Module.TEX, "Flushing texture cache");
45 | textures.clear();
46 | }
47 | }
--------------------------------------------------------------------------------
/src/org/sunflow/system/UserInterface.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.system;
2 |
3 | import org.sunflow.system.UI.Module;
4 | import org.sunflow.system.UI.PrintLevel;
5 |
6 | public interface UserInterface {
7 | /**
8 | * Displays some information to the user from the specified module with the
9 | * specified print level. A user interface is free to show or ignore any
10 | * message. Level filtering is done in the core and shouldn't be
11 | * re-implemented by the user interface. All messages will be short enough
12 | * to fit on one line.
13 | *
14 | * @param m module the message came from
15 | * @param level seriousness of the message
16 | * @param s string to display
17 | */
18 | void print(Module m, PrintLevel level, String s);
19 |
20 | /**
21 | * Prepare a progress bar representing a lengthy task. The actual progress
22 | * is first shown by the call to update and closed when update is closed
23 | * with the max value. It is currently not possible to nest calls to
24 | * setTask, so only one task needs to be tracked at a time.
25 | *
26 | * @param s desriptive string
27 | * @param min minimum value of the task
28 | * @param max maximum value of the task
29 | */
30 | void taskStart(String s, int min, int max);
31 |
32 | /**
33 | * Updates the current progress bar to a value between the current min and
34 | * max. When min or max are passed the progressed bar is shown or hidden
35 | * respectively.
36 | *
37 | * @param current current value of the task in progress.
38 | */
39 | void taskUpdate(int current);
40 |
41 | /**
42 | * Closes the current progress bar to indicate the task is over
43 | */
44 | void taskStop();
45 | }
--------------------------------------------------------------------------------
/examples/shader_examples/Glass003.sc:
--------------------------------------------------------------------------------
1 | %photons {
2 | % caustics 10000000 kd 64 0.5
3 | %}
4 |
5 | shader {
6 | name "ground"
7 | type diffuse
8 | diff 0.800000011921 0.800000011921 0.800000011921
9 | }
10 |
11 | shader {
12 | name "shader01"
13 | type glass
14 | eta 1.55
15 | color 1 1 1
16 | absorbtion.distance 2
17 | absorbtion.color 0.8 0.2 0.2
18 | }
19 |
20 | shader {
21 | name "shader02"
22 | type glass
23 | eta 1.55
24 | color 1 1 1
25 | absorbtion.distance 1
26 | absorbtion.color 0.8 0.2 0.2
27 | }
28 |
29 | shader {
30 | name "shader03"
31 | type glass
32 | eta 1.55
33 | color 1 1 1
34 | absorbtion.distance 0.5
35 | absorbtion.color 0.8 0.2 0.2
36 | }
37 |
38 | shader {
39 | name "shader04"
40 | type glass
41 | eta 1.55
42 | color 1 1 1
43 | absorbtion.distance 2
44 | absorbtion.color 0.1 0.7 0.1
45 | }
46 |
47 | shader {
48 | name "shader05"
49 | type glass
50 | eta 1.55
51 | color 1 1 1
52 | absorbtion.distance 1
53 | absorbtion.color 0.1 0.7 0.1
54 | }
55 |
56 | shader {
57 | name "shader06"
58 | type glass
59 | eta 1.55
60 | color 1 1 1
61 | absorbtion.distance 0.5
62 | absorbtion.color 0.1 0.7 0.1
63 | }
64 |
65 | shader {
66 | name "shader07"
67 | type glass
68 | eta 1.55
69 | color 1 1 1
70 | absorbtion.distance 2
71 | absorbtion.color 0.3 0.3 0.6
72 | }
73 |
74 | shader {
75 | name "shader08"
76 | type glass
77 | eta 1.55
78 | color 1 1 1
79 | absorbtion.distance 1
80 | absorbtion.color 0.3 0.3 0.6
81 | }
82 |
83 | shader {
84 | name "shader09"
85 | type glass
86 | eta 1.55
87 | color 1 1 1
88 | absorbtion.distance 0.5
89 | absorbtion.color 0.3 0.3 0.6
90 | }
91 |
92 | include "include/example_array.geo.sc"
93 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/PhotonStore.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import org.sunflow.image.Color;
4 | import org.sunflow.math.BoundingBox;
5 | import org.sunflow.math.Vector3;
6 |
7 | /**
8 | * Describes an object which can store photons.
9 | */
10 | public interface PhotonStore {
11 | /**
12 | * Number of photons to emit from this surface.
13 | *
14 | * @return number of photons
15 | */
16 | int numEmit();
17 |
18 | /**
19 | * Initialize this object for the specified scene size.
20 | *
21 | * @param sceneBounds scene bounding box
22 | */
23 | void prepare(Options options, BoundingBox sceneBounds);
24 |
25 | /**
26 | * Store the specified photon.
27 | *
28 | * @param state shading state
29 | * @param dir photon direction
30 | * @param power photon power
31 | * @param diffuse diffuse color at the hit point
32 | */
33 | void store(ShadingState state, Vector3 dir, Color power, Color diffuse);
34 |
35 | /**
36 | * Initialize the map after all photons have been stored. This can be used
37 | * to balance a kd-tree based photon map for example.
38 | */
39 | void init();
40 |
41 | /**
42 | * Allow photons reflected diffusely?
43 | *
44 | * @return true if diffuse bounces should be traced
45 | */
46 | boolean allowDiffuseBounced();
47 |
48 | /**
49 | * Allow specularly reflected photons?
50 | *
51 | * @return true if specular reflection bounces should be
52 | * traced
53 | */
54 | boolean allowReflectionBounced();
55 |
56 | /**
57 | * Allow refracted photons?
58 | *
59 | * @return true if refracted bounces should be traced
60 | */
61 | boolean allowRefractionBounced();
62 | }
--------------------------------------------------------------------------------
/examples/shader_examples/Ward001.sc:
--------------------------------------------------------------------------------
1 | trace-depths {
2 | diff 0
3 | refl 1
4 | refr 0
5 | }
6 |
7 | shader {
8 | name "ground"
9 | type diffuse
10 | diff 0.800000011921 0.800000011921 0.800000011921
11 | }
12 |
13 | shader {
14 | name "shader01"
15 | type ward
16 | diff { "sRGB nonlinear" .33 1 .33 }
17 | spec { "sRGB nonlinear" 1 1 1 }
18 | rough .4 .01
19 | }
20 |
21 | shader {
22 | name "shader02"
23 | type ward
24 | diff { "sRGB nonlinear" .33 1 .33 }
25 | spec { "sRGB nonlinear" 1 1 1 }
26 | rough .35 .01
27 | }
28 |
29 | shader {
30 | name "shader03"
31 | type ward
32 | diff { "sRGB nonlinear" .33 1 .33 }
33 | spec { "sRGB nonlinear" 1 1 1 }
34 | rough .3 .01
35 | samples 4
36 | }
37 |
38 | shader {
39 | name "shader04"
40 | type ward
41 | diff { "sRGB nonlinear" .33 1 .33 }
42 | spec 1 1 1
43 | rough .25 .01
44 | samples 4
45 | }
46 |
47 | shader {
48 | name "shader05"
49 | type ward
50 | diff { "sRGB nonlinear" .33 1 .33 }
51 | spec 1 1 1
52 | rough .2 .01
53 | samples 4
54 | }
55 |
56 | shader {
57 | name "shader06"
58 | type ward
59 | diff { "sRGB nonlinear" .33 1 .33 }
60 | spec 1 1 1
61 | rough .15 .01
62 | samples 4
63 | }
64 |
65 | shader {
66 | name "shader07"
67 | type ward
68 | diff { "sRGB nonlinear" .33 1 .33 }
69 | spec 1 1 1
70 | rough .1 .01
71 | samples 4
72 | }
73 |
74 | shader {
75 | name "shader08"
76 | type ward
77 | diff { "sRGB nonlinear" .33 1 .33 }
78 | spec { "sRGB nonlinear" 1 1 1 }
79 | rough .05 .01
80 | samples 4
81 | }
82 |
83 | shader {
84 | name "shader09"
85 | type ward
86 | diff { "sRGB nonlinear" .33 1 .33 }
87 | spec 1 1 1
88 | rough .01 .01
89 | samples 4
90 | }
91 |
92 | include "include/example_array.geo.sc"
93 |
--------------------------------------------------------------------------------
/examples/shader_examples/Phong001.sc:
--------------------------------------------------------------------------------
1 | trace-depths {
2 | diff 0
3 | refl 1
4 | refr 0
5 | }
6 |
7 | shader {
8 | name "ground"
9 | type diffuse
10 | diff 0.800000011921 0.800000011921 0.800000011921
11 | }
12 |
13 | shader {
14 | name "shader01"
15 | type phong
16 | diff { "sRGB nonlinear" 0.1 0.1 0.7 }
17 | spec { "sRGB nonlinear" 0.28 1 1 } 1
18 | samples 4
19 | }
20 |
21 | shader {
22 | name "shader02"
23 | type phong
24 | diff { "sRGB nonlinear" 0.1 0.1 0.7 }
25 | spec { "sRGB nonlinear" 0.28 1 1 } 4
26 | samples 4
27 | }
28 |
29 | shader {
30 | name "shader03"
31 | type phong
32 | diff { "sRGB nonlinear" 0.1 0.1 0.7 }
33 | spec { "sRGB nonlinear" 0.28 1 1 } 8
34 | samples 4
35 | }
36 |
37 | shader {
38 | name "shader04"
39 | type phong
40 | diff { "sRGB nonlinear" 0.1 0.1 0.7 }
41 | spec { "sRGB nonlinear" 0.28 1 1 } 10
42 | samples 4
43 | }
44 |
45 | shader {
46 | name "shader05"
47 | type phong
48 | diff { "sRGB nonlinear" 0.1 0.1 0.7 }
49 | spec { "sRGB nonlinear" 0.28 1 1 } 20
50 | samples 4
51 | }
52 |
53 | shader {
54 | name "shader06"
55 | type phong
56 | diff { "sRGB nonlinear" 0.1 0.1 0.7 }
57 | spec { "sRGB nonlinear" 0.28 1 1 } 30
58 | samples 4
59 | }
60 |
61 | shader {
62 | name "shader07"
63 | type phong
64 | diff { "sRGB nonlinear" 0.1 0.1 0.7 }
65 | spec { "sRGB nonlinear" 0.28 1 1 } 100
66 | samples 4
67 | }
68 |
69 | shader {
70 | name "shader08"
71 | type phong
72 | diff { "sRGB nonlinear" 0.1 0.1 0.7 }
73 | spec { "sRGB nonlinear" 0.28 1 1 } 300
74 | samples 4
75 | }
76 |
77 | shader {
78 | name "shader09"
79 | type phong
80 | diff { "sRGB nonlinear" 0.1 0.1 0.7 }
81 | spec { "sRGB nonlinear" 0.28 1 1 } 600
82 | samples 4
83 | }
84 |
85 | include "include/example_array.geo.sc"
86 |
--------------------------------------------------------------------------------
/src/org/sunflow/image/writers/HDRBitmapWriter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.writers;
2 |
3 | import java.io.BufferedOutputStream;
4 | import java.io.FileOutputStream;
5 | import java.io.IOException;
6 | import java.io.OutputStream;
7 |
8 | import org.sunflow.image.BitmapWriter;
9 | import org.sunflow.image.Color;
10 | import org.sunflow.image.ColorEncoder;
11 |
12 | public class HDRBitmapWriter implements BitmapWriter {
13 | private String filename;
14 | private int width, height;
15 | private int[] data;
16 |
17 | public void configure(String option, String value) {
18 | }
19 |
20 | public void openFile(String filename) throws IOException {
21 | this.filename = filename;
22 | }
23 |
24 | public void writeHeader(int width, int height, int tileSize) throws IOException, UnsupportedOperationException {
25 | this.width = width;
26 | this.height = height;
27 | data = new int[width * height];
28 | }
29 |
30 | public void writeTile(int x, int y, int w, int h, Color[] color, float[] alpha) throws IOException {
31 | int[] tileData = ColorEncoder.encodeRGBE(color);
32 | for (int j = 0, index = 0, pixel = x + y * width; j < h; j++, pixel += width - w)
33 | for (int i = 0; i < w; i++, index++, pixel++)
34 | data[pixel] = tileData[index];
35 | }
36 |
37 | public void closeFile() throws IOException {
38 | OutputStream f = new BufferedOutputStream(new FileOutputStream(filename));
39 | f.write("#?RGBE\n".getBytes());
40 | f.write("FORMAT=32-bit_rle_rgbe\n\n".getBytes());
41 | f.write(("-Y " + height + " +X " + width + "\n").getBytes());
42 | for (int i = 0; i < data.length; i++) {
43 | int rgbe = data[i];
44 | f.write(rgbe >> 24);
45 | f.write(rgbe >> 16);
46 | f.write(rgbe >> 8);
47 | f.write(rgbe);
48 | }
49 | f.close();
50 | }
51 | }
--------------------------------------------------------------------------------
/examples/shader_examples/Ward002.sc:
--------------------------------------------------------------------------------
1 | trace-depths {
2 | diff 0
3 | refl 1
4 | refr 0
5 | }
6 |
7 | shader {
8 | name "ground"
9 | type diffuse
10 | diff 0.800000011921 0.800000011921 0.800000011921
11 | }
12 |
13 | shader {
14 | name "shader01"
15 | type ward
16 | diff { "sRGB nonlinear" .33 1 .33 }
17 | spec { "sRGB nonlinear" 1 1 1 }
18 | rough .07 .1
19 | samples 4
20 | }
21 |
22 | shader {
23 | name "shader02"
24 | type ward
25 | diff { "sRGB nonlinear" .33 1 .33 }
26 | spec { "sRGB nonlinear" 1 1 1 }
27 | rough .07 .2
28 | samples 4
29 | }
30 |
31 | shader {
32 | name "shader03"
33 | type ward
34 | diff { "sRGB nonlinear" .33 1 .33 }
35 | spec { "sRGB nonlinear" 1 1 1 }
36 | rough .07 .3
37 | samples 4
38 | }
39 |
40 | shader {
41 | name "shader04"
42 | type ward
43 | diff { "sRGB nonlinear" .33 1 .33 }
44 | spec { "sRGB nonlinear" 1 1 1 }
45 | rough .07 .4
46 | samples 4
47 | }
48 |
49 | shader {
50 | name "shader05"
51 | type ward
52 | diff { "sRGB nonlinear" .33 1 .33 }
53 | spec { "sRGB nonlinear" 1 1 1 }
54 | rough .07 .5
55 | samples 4
56 | }
57 |
58 | shader {
59 | name "shader06"
60 | type ward
61 | diff { "sRGB nonlinear" .33 1 .33 }
62 | spec { "sRGB nonlinear" 1 1 1 }
63 | rough .07 .6
64 | samples 4
65 | }
66 |
67 | shader {
68 | name "shader07"
69 | type ward
70 | diff { "sRGB nonlinear" .33 1 .33 }
71 | spec { "sRGB nonlinear" 1 1 1 }
72 | rough .07 .7
73 | samples 4
74 | }
75 |
76 | shader {
77 | name "shader08"
78 | type ward
79 | diff { "sRGB nonlinear" .33 1 .33 }
80 | spec { "sRGB nonlinear" 1 1 1 }
81 | rough .07 .8
82 | samples 4
83 | }
84 |
85 | shader {
86 | name "shader09"
87 | type ward
88 | diff { "sRGB nonlinear" .33 1 .33 }
89 | spec { "sRGB nonlinear" 1 1 1 }
90 | rough .07 .9
91 | samples 4
92 | }
93 |
94 | include "include/example_array.geo.sc"
95 |
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/src/sunflowGlobalsNode.h:
--------------------------------------------------------------------------------
1 | #ifndef SUNFLOW_GLOBALS_NODE_H
2 | #define SUNFLOW_GLOBALS_NODE_H
3 |
4 | /////////////////////////////////////////////////////////////////////////////////////////
5 | //Sunflow Render Globals Node
6 | /////////////////////////////////////////////////////////////////////////////////////////
7 |
8 | #include
9 |
10 | class sunflowGlobalsNode : public MPxNode
11 | {
12 | public:
13 | sunflowGlobalsNode(){};
14 | virtual ~sunflowGlobalsNode(){};
15 |
16 | virtual MStatus compute( const MPlug& plug, MDataBlock& data );
17 |
18 | static void* creator();
19 | static MStatus initialize();
20 |
21 | static MObject renderMode;
22 | static MObject preset;
23 | static MObject pixelFilter;
24 | static MObject minSamples;
25 | static MObject maxSamples;
26 |
27 | static MObject enablePhotons;
28 | static MObject Photons;
29 | static MObject PhotonsKd;
30 | static MObject PhotonsRadius;
31 |
32 | static MObject diffuseDepth;
33 | static MObject reflectionDepth;
34 | static MObject refractionDepth;
35 |
36 | static MObject enableGI;
37 | static MObject GIMode;
38 |
39 | static MObject PTSamples;
40 |
41 | static MObject IGISamples;
42 | static MObject IGISets;
43 | static MObject IGIBias;
44 | static MObject IGIBSamples;
45 |
46 | static MObject ICSamples;
47 | static MObject ICTolerance;
48 | static MObject ICSpacingMin;
49 | static MObject ICSpacingMax;
50 |
51 | static MObject skyNode;
52 | static MObject skySize;
53 | static MObject skyResolution;
54 | static MObject skyTurbidity;
55 | static MObject skySamples;
56 | static MObject skyExposure;
57 |
58 | static MObject materialOverride;
59 | static MObject ambOverrideDist;
60 |
61 | static MObject bucketOrder;
62 | static MObject bucketSize;
63 | static MObject bucketReverse;
64 |
65 | static MObject exportPath;
66 |
67 | static MTypeId id;
68 | };
69 |
70 | #endif /* SUNFLOW_GLOBALS_NODE_H */
71 |
--------------------------------------------------------------------------------
/src/org/sunflow/util/IntArray.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.util;
2 |
3 | public final class IntArray {
4 | private int[] array;
5 | private int size;
6 |
7 | public IntArray() {
8 | array = new int[10];
9 | size = 0;
10 | }
11 |
12 | public IntArray(int capacity) {
13 | array = new int[capacity];
14 | size = 0;
15 | }
16 |
17 | /**
18 | * Append an integer to the end of the array.
19 | *
20 | * @param i
21 | */
22 | public final void add(int i) {
23 | if (size == array.length) {
24 | int[] oldArray = array;
25 | array = new int[(size * 3) / 2 + 1];
26 | System.arraycopy(oldArray, 0, array, 0, size);
27 | }
28 | array[size] = i;
29 | size++;
30 | }
31 |
32 | /**
33 | * Write a value to the specified index. Assumes the array is already big
34 | * enough.
35 | *
36 | * @param index
37 | * @param value
38 | */
39 | public final void set(int index, int value) {
40 | array[index] = value;
41 | }
42 |
43 | /**
44 | * Read value from the array.
45 | *
46 | * @param index index into the array
47 | * @return value at the specified index
48 | */
49 | public final int get(int index) {
50 | return array[index];
51 | }
52 |
53 | /**
54 | * Returns the number of elements added to the array.
55 | *
56 | * @return current size of the array
57 | */
58 | public final int getSize() {
59 | return size;
60 | }
61 |
62 | /**
63 | * Return a copy of the array, trimmed to fit the size of its contents
64 | * exactly.
65 | *
66 | * @return a new array of exactly the right length
67 | */
68 | public final int[] trim() {
69 | if (size < array.length) {
70 | int[] oldArray = array;
71 | array = new int[size];
72 | System.arraycopy(oldArray, 0, array, 0, size);
73 | }
74 | return array;
75 | }
76 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/sunflowExport.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 9.00
3 | # Visual Studio 2005
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sunflowExport", "sunflowExport.vcproj", "{CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Maya_7.0_Debug|Win32 = Maya_7.0_Debug|Win32
9 | Maya_7.0_Release|Win32 = Maya_7.0_Release|Win32
10 | Maya_8.0_Debug|Win32 = Maya_8.0_Debug|Win32
11 | Maya_8.0_Release|Win32 = Maya_8.0_Release|Win32
12 | Maya_8.5_Debug|Win32 = Maya_8.5_Debug|Win32
13 | Maya_8.5_Release|Win32 = Maya_8.5_Release|Win32
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_7.0_Debug|Win32.ActiveCfg = Maya_7.0_Debug|Win32
17 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_7.0_Debug|Win32.Build.0 = Maya_7.0_Debug|Win32
18 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_7.0_Release|Win32.ActiveCfg = Maya_7.0_Release|Win32
19 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_7.0_Release|Win32.Build.0 = Maya_7.0_Release|Win32
20 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_8.0_Debug|Win32.ActiveCfg = Maya_8.0_Debug|Win32
21 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_8.0_Debug|Win32.Build.0 = Maya_8.0_Debug|Win32
22 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_8.0_Release|Win32.ActiveCfg = Maya_8.0_Release|Win32
23 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_8.0_Release|Win32.Build.0 = Maya_8.0_Release|Win32
24 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_8.5_Debug|Win32.ActiveCfg = Maya_8.5_Release|Win32
25 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_8.5_Debug|Win32.Build.0 = Maya_8.5_Release|Win32
26 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_8.5_Release|Win32.ActiveCfg = Maya_8.5_Release|Win32
27 | {CD4CF0BD-AE53-48D8-9152-B34A2E397FC6}.Maya_8.5_Release|Win32.Build.0 = Maya_8.5_Release|Win32
28 | EndGlobalSection
29 | GlobalSection(SolutionProperties) = preSolution
30 | HideSolutionNode = FALSE
31 | EndGlobalSection
32 | EndGlobal
33 |
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/mel/sunflowUtils.mel:
--------------------------------------------------------------------------------
1 | global proc string sunflowGetPrefix() {
2 | return "sunflow";
3 | }
4 |
5 | global proc string sunflowCheckGlobals(){
6 | string $sel[]= `ls -sl`;
7 | string $globalsNode;
8 | string $globalsNodes[] = stringArrayRemove({""},`lsType sunflowGlobalsNode`);
9 | if(size($globalsNodes)){
10 | $globalsNode = $globalsNodes[0];
11 | string $unusedNodes[] = stringArrayRemove({$globalsNode},$globalsNodes);
12 | if(size($unusedNodes))
13 | delete $unusedNodes;
14 | }else{
15 | $globalsNode = `createNode sunflowGlobalsNode`;
16 | }
17 | string $projPath = `workspace -q -rd`;
18 | string $tmpPath = $projPath+"sunflowScenes/";
19 | string $exportPath = `getAttr ($globalsNode+".exportPath")`;
20 | if(!`filetest -d $tmpPath`)
21 | sysFile -makeDir $tmpPath;
22 | if($exportPath=="")
23 | setAttr -type "string" ($globalsNode+".exportPath") $tmpPath;
24 | select $sel;
25 | return $globalsNode;
26 | }
27 |
28 | global proc string[] sunflowCreateSunSky(){
29 | string $sunLightShape = `createNode directionalLight`;
30 | addAttr -ln "isSunSkyLight" -at bool $sunLightShape;
31 | setAttr ($sunLightShape+".isSunSkyLight") true;
32 | string $sunLight[] = `pickWalk -d up`;
33 | $sunLight[0] = `rename $sunLight[0] "sunflowSun#"`;
34 | setAttr ($sunLight[0]+".rotateX") -45;
35 | setAttr ($sunLight[0]+".rotateY") 45;
36 | setAttr ($sunLight[0]+".rotateZ") 0;
37 | string $sky = sunflowCreateSky($sunLight[0]);
38 | return {$sunLight[0], $sky};
39 | }
40 |
41 | global proc string sunflowCreateSky(string $light){
42 | string $lightShape[] = `listRelatives -s $light`;
43 | string $skyShape = `createNode sunflowSkyNode`;
44 | string $sky[] = `pickWalk -d up`;
45 | $sky[0] = `rename $sky[0] "sunflowSky#"`;
46 | string $tmp[] = `pickWalk -d down`;$skyShape=$tmp[0];
47 | connectAttr -f ($lightShape[0]+".message") ($skyShape+".sunLight");
48 | setAttr ($skyShape+".template") 1;
49 | setAttr ($skyShape+".size") 0.5;
50 | pointConstraint -offset 0 0 0 -weight 1 $light $sky[0];
51 | return $skyShape;
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/src/org/sunflow/util/FloatArray.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.util;
2 |
3 | public final class FloatArray {
4 | private float[] array;
5 | private int size;
6 |
7 | public FloatArray() {
8 | array = new float[10];
9 | size = 0;
10 | }
11 |
12 | public FloatArray(int capacity) {
13 | array = new float[capacity];
14 | size = 0;
15 | }
16 |
17 | /**
18 | * Append a float to the end of the array.
19 | *
20 | * @param f
21 | */
22 | public final void add(float f) {
23 | if (size == array.length) {
24 | float[] oldArray = array;
25 | array = new float[(size * 3) / 2 + 1];
26 | System.arraycopy(oldArray, 0, array, 0, size);
27 | }
28 | array[size] = f;
29 | size++;
30 | }
31 |
32 | /**
33 | * Write a value to the specified index. Assumes the array is already big
34 | * enough.
35 | *
36 | * @param index
37 | * @param value
38 | */
39 | public final void set(int index, float value) {
40 | array[index] = value;
41 | }
42 |
43 | /**
44 | * Read value from the array.
45 | *
46 | * @param index index into the array
47 | * @return value at the specified index
48 | */
49 | public final float get(int index) {
50 | return array[index];
51 | }
52 |
53 | /**
54 | * Returns the number of elements added to the array.
55 | *
56 | * @return current size of the array
57 | */
58 | public final int getSize() {
59 | return size;
60 | }
61 |
62 | /**
63 | * Return a copy of the array, trimmed to fit the size of its contents
64 | * exactly.
65 | *
66 | * @return a new array of exactly the right length
67 | */
68 | public final float[] trim() {
69 | if (size < array.length) {
70 | float[] oldArray = array;
71 | array = new float[size];
72 | System.arraycopy(oldArray, 0, array, 0, size);
73 | }
74 | return array;
75 | }
76 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/ShadingCache.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import org.sunflow.image.Color;
4 |
5 | public class ShadingCache {
6 | private Sample first;
7 | private int depth;
8 | // stats
9 | long hits;
10 | long misses;
11 | long sumDepth;
12 | long numCaches;
13 |
14 | private static class Sample {
15 | Instance i;
16 | Shader s;
17 | float nx, ny, nz;
18 | float dx, dy, dz;
19 | Color c;
20 | Sample next; // linked list
21 | }
22 |
23 | public ShadingCache() {
24 | reset();
25 | hits = 0;
26 | misses = 0;
27 | }
28 |
29 | public void reset() {
30 | sumDepth += depth;
31 | if (depth > 0)
32 | numCaches++;
33 | first = null;
34 | depth = 0;
35 | }
36 |
37 | public Color lookup(ShadingState state, Shader shader) {
38 | if (state.getNormal() == null)
39 | return null;
40 | // search further
41 | for (Sample s = first; s != null; s = s.next) {
42 | if (s.i != state.getInstance())
43 | continue;
44 | if (s.s != shader)
45 | continue;
46 | if (state.getRay().dot(s.dx, s.dy, s.dz) < 0.999f)
47 | continue;
48 | if (state.getNormal().dot(s.nx, s.ny, s.nz) < 0.99f)
49 | continue;
50 | // we have a match
51 | hits++;
52 | return s.c;
53 | }
54 | misses++;
55 | return null;
56 | }
57 |
58 | public void add(ShadingState state, Shader shader, Color c) {
59 | if (state.getNormal() == null)
60 | return;
61 | depth++;
62 | Sample s = new Sample();
63 | s.i = state.getInstance();
64 | s.s = shader;
65 | s.c = c;
66 | s.dx = state.getRay().dx;
67 | s.dy = state.getRay().dy;
68 | s.dz = state.getRay().dz;
69 | s.nx = state.getNormal().x;
70 | s.ny = state.getNormal().y;
71 | s.nz = state.getNormal().z;
72 | s.next = first;
73 | first = s;
74 | }
75 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/gi/AmbientOcclusionGIEngine.java:
--------------------------------------------------------------------------------
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 | private Color bright;
14 | private Color dark;
15 | private int samples;
16 | private float maxDist;
17 |
18 | public Color getGlobalRadiance(ShadingState state) {
19 | return Color.BLACK;
20 | }
21 |
22 | public boolean init(Options options, Scene scene) {
23 | bright = options.getColor("gi.ambocc.bright", Color.WHITE);
24 | dark = options.getColor("gi.ambocc.dark", Color.BLACK);
25 | samples = options.getInt("gi.ambocc.samples", 32);
26 | maxDist = options.getFloat("gi.ambocc.maxdist", 0);
27 | maxDist = (maxDist <= 0) ? Float.POSITIVE_INFINITY : maxDist;
28 | return true;
29 | }
30 |
31 | public Color getIrradiance(ShadingState state, Color diffuseReflectance) {
32 | OrthoNormalBasis onb = state.getBasis();
33 | Vector3 w = new Vector3();
34 | Color result = Color.black();
35 | for (int i = 0; i < samples; i++) {
36 | float xi = (float) state.getRandom(i, 0, samples);
37 | float xj = (float) state.getRandom(i, 1, samples);
38 | float phi = (float) (2 * Math.PI * xi);
39 | float cosPhi = (float) Math.cos(phi);
40 | float sinPhi = (float) Math.sin(phi);
41 | float sinTheta = (float) Math.sqrt(xj);
42 | float cosTheta = (float) Math.sqrt(1.0f - xj);
43 | w.x = cosPhi * sinTheta;
44 | w.y = sinPhi * sinTheta;
45 | w.z = cosTheta;
46 | onb.transform(w);
47 | Ray r = new Ray(state.getPoint(), w);
48 | r.setMax(maxDist);
49 | result.add(Color.blend(bright, dark, state.traceShadow(r)));
50 | }
51 | return result.mul((float) Math.PI / samples);
52 | }
53 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/mel/registerSunflowRenderer.mel:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////
2 | // Description: This procedure is called to register the
3 | // sunflow renderer with other renderers in Maya.
4 | ///////////////////////////////////////////////////////////////////////////////
5 |
6 | global proc registerSunflowRenderer()
7 | {
8 | renderer
9 | -rendererUIName "Sunflow"
10 | -renderProcedure "sunflowRender"
11 | -commandRenderProcedure "sunflowRender"
12 | -batchRenderProcedure "sunflowRender"
13 | -showRenderLogProcedure ""
14 | -batchRenderOptionsProcedure ""
15 | -cancelBatchRenderProcedure "sunflowCancelBatch"
16 | -showBatchRenderProcedure ""
17 | -showBatchRenderLogProcedure ""
18 | -iprRenderProcedure ""
19 | -startIprRenderProcedure ""
20 | -stopIprRenderProcedure ""
21 | -changeIprRegionProcedure ""
22 | -iprOptionsMenuLabel ""
23 | -iprOptionsSubMenuProcedure ""
24 | -renderDiagnosticsProcedure ""
25 | -renderRegionProcedure ""
26 | -textureBakingProcedure ""
27 | -polyPrelightProcedure ""
28 | -renderingEditorsSubMenuProcedure ""
29 | -addGlobalsNode "sunflowRenderGlobals"
30 | -logoImageName "sunflowRender.xpm"
31 | -logoCallbackProcedure "sunflowLogoCallback"
32 | sunflow;
33 |
34 | //
35 | //The first argument of the "-addGlobalsTab" flag is used in creating layout names
36 | //and should not be localized.
37 | //
38 |
39 | renderer
40 | -edit
41 | -addGlobalsTab "Common"
42 | "createMayaSoftwareCommonGlobalsTab"
43 | "updateMayaSoftwareCommonGlobalsTab"
44 | sunflow;
45 | renderer
46 | -edit
47 | -addGlobalsTab "Sunflow"
48 | "createSunflowGlobalsTab"
49 | "updateSunflowGlobalsTab"
50 | sunflow;
51 | }
52 |
53 | global proc sunflowLogoCallback(){
54 | string $url = "http://sunflow.sourceforge.net/";
55 | evalDeferred ("showHelp -absolute \""+$url+"\"" );
56 | }
57 |
58 | global proc string renderSettingsTabLabel_melToUI (string $mel){
59 | string $result = $mel;
60 |
61 | if($mel == "Sunflow"){
62 | $result = "Sunflow";
63 | }
64 |
65 | return $result;
66 | }
67 |
--------------------------------------------------------------------------------
/src/org/sunflow/image/formats/GenericBitmap.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.formats;
2 |
3 | import java.io.IOException;
4 |
5 | import org.sunflow.PluginRegistry;
6 | import org.sunflow.image.Bitmap;
7 | import org.sunflow.image.BitmapWriter;
8 | import org.sunflow.image.Color;
9 | import org.sunflow.system.FileUtils;
10 | import org.sunflow.system.UI;
11 | import org.sunflow.system.UI.Module;
12 |
13 | /**
14 | * This is a generic and inefficient bitmap format which may be used for
15 | * debugging purposes (dumping small images), when memory usage is not a
16 | * concern.
17 | */
18 | public class GenericBitmap extends Bitmap {
19 | private int w, h;
20 | private Color[] color;
21 | private float[] alpha;
22 |
23 | public GenericBitmap(int w, int h) {
24 | this.w = w;
25 | this.h = h;
26 | color = new Color[w * h];
27 | alpha = new float[w * h];
28 | }
29 |
30 | @Override
31 | public int getWidth() {
32 | return w;
33 | }
34 |
35 | @Override
36 | public int getHeight() {
37 | return h;
38 | }
39 |
40 | @Override
41 | public Color readColor(int x, int y) {
42 | return color[x + y * w];
43 | }
44 |
45 | @Override
46 | public float readAlpha(int x, int y) {
47 | return alpha[x + y * w];
48 | }
49 |
50 | public void writePixel(int x, int y, Color c, float a) {
51 | color[x + y * w] = c;
52 | alpha[x + y * w] = a;
53 | }
54 |
55 | public void save(String filename) {
56 | String extension = FileUtils.getExtension(filename);
57 | BitmapWriter writer = PluginRegistry.bitmapWriterPlugins.createObject(extension);
58 | if (writer == null) {
59 | UI.printError(Module.IMG, "Unable to save file \"%s\" - unknown file format: %s", filename, extension);
60 | return;
61 | }
62 | try {
63 | writer.openFile(filename);
64 | writer.writeHeader(w, h, Math.max(w, h));
65 | writer.writeTile(0, 0, w, h, color, alpha);
66 | writer.closeFile();
67 | } catch (IOException e) {
68 | UI.printError(Module.IMG, "Unable to save file \"%s\" - %s", filename, e.getLocalizedMessage());
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/DiffuseShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Ray;
6 | import org.sunflow.core.Shader;
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 DiffuseShader implements Shader {
13 | private Color diff;
14 |
15 | public DiffuseShader() {
16 | diff = Color.WHITE;
17 | }
18 |
19 | public boolean update(ParameterList pl, SunflowAPI api) {
20 | diff = pl.getColor("diffuse", diff);
21 | return true;
22 | }
23 |
24 | public Color getDiffuse(ShadingState state) {
25 | return diff;
26 | }
27 |
28 | public Color getRadiance(ShadingState state) {
29 | // make sure we are on the right side of the material
30 | state.faceforward();
31 | // setup lighting
32 | state.initLightSamples();
33 | state.initCausticSamples();
34 | return state.diffuse(getDiffuse(state));
35 | }
36 |
37 | public void scatterPhoton(ShadingState state, Color power) {
38 | Color diffuse;
39 | // make sure we are on the right side of the material
40 | if (Vector3.dot(state.getNormal(), state.getRay().getDirection()) > 0.0) {
41 | state.getNormal().negate();
42 | state.getGeoNormal().negate();
43 | }
44 | diffuse = getDiffuse(state);
45 | state.storePhoton(state.getRay().getDirection(), power, diffuse);
46 | float avg = diffuse.getAverage();
47 | double rnd = state.getRandom(0, 0, 1);
48 | if (rnd < avg) {
49 | // photon is scattered
50 | power.mul(diffuse).mul(1.0f / avg);
51 | OrthoNormalBasis onb = state.getBasis();
52 | double u = 2 * Math.PI * rnd / avg;
53 | double v = state.getRandom(0, 1, 1);
54 | float s = (float) Math.sqrt(v);
55 | float s1 = (float) Math.sqrt(1.0 - v);
56 | Vector3 w = new Vector3((float) Math.cos(u) * s, (float) Math.sin(u) * s, s1);
57 | w = onb.transform(w, new Vector3());
58 | state.traceDiffusePhoton(new Ray(state.getPoint(), w), power);
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/InstanceList.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.math.BoundingBox;
5 | import org.sunflow.math.Matrix4;
6 |
7 | final class InstanceList implements PrimitiveList {
8 | private Instance[] instances;
9 | private Instance[] lights;
10 |
11 | InstanceList() {
12 | instances = new Instance[0];
13 | clearLightSources();
14 | }
15 |
16 | InstanceList(Instance[] instances) {
17 | this.instances = instances;
18 | clearLightSources();
19 | }
20 |
21 | void addLightSourceInstances(Instance[] lights) {
22 | this.lights = lights;
23 | }
24 |
25 | void clearLightSources() {
26 | lights = new Instance[0];
27 | }
28 |
29 | public final float getPrimitiveBound(int primID, int i) {
30 | if (primID < instances.length)
31 | return instances[primID].getBounds().getBound(i);
32 | else
33 | return lights[primID - instances.length].getBounds().getBound(i);
34 | }
35 |
36 | public final BoundingBox getWorldBounds(Matrix4 o2w) {
37 | BoundingBox bounds = new BoundingBox();
38 | for (Instance i : instances)
39 | bounds.include(i.getBounds());
40 | for (Instance i : lights)
41 | bounds.include(i.getBounds());
42 | return bounds;
43 | }
44 |
45 | public final void intersectPrimitive(Ray r, int primID, IntersectionState state) {
46 | if (primID < instances.length)
47 | instances[primID].intersect(r, state);
48 | else
49 | lights[primID - instances.length].intersect(r, state);
50 | }
51 |
52 | public final int getNumPrimitives() {
53 | return instances.length + lights.length;
54 | }
55 |
56 | public final int getNumPrimitives(int primID) {
57 | return primID < instances.length ? instances[primID].getNumPrimitives() : lights[primID - instances.length].getNumPrimitives();
58 | }
59 |
60 | public final void prepareShadingState(ShadingState state) {
61 | state.getInstance().prepareShadingState(state);
62 | }
63 |
64 | public boolean update(ParameterList pl, SunflowAPI api) {
65 | return true;
66 | }
67 |
68 | public PrimitiveList getBakingPrimitives() {
69 | return null;
70 | }
71 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/src/sunflowExportCmd.h:
--------------------------------------------------------------------------------
1 | #ifndef SUNFLOW_EXPORT_CMD_H
2 | #define SUNFLOW_EXPORT_CMD_H
3 | /////////////////////////////////////////////////////////////////////////////////////////
4 | //Sunflow Export Command
5 | /////////////////////////////////////////////////////////////////////////////////////////
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | class sunflowExportCmd : public MPxCommand
16 | {
17 | public:
18 | sunflowExportCmd(){};
19 | virtual ~sunflowExportCmd(){};
20 |
21 | virtual MStatus doIt ( const MArgList& args );
22 |
23 | static void* creator();
24 |
25 | void getCustomAttribute(MFloatVector &colorAttribute, MString attribute, MFnDependencyNode &node);
26 | void getCustomAttribute(MString &texture, MFloatVector &colorAttribute, MString attribute, MFnDependencyNode &node);
27 | void getCustomAttribute(float &floatAttribute, MString attribute, MFnDependencyNode &node);
28 | void getCustomAttribute(int &intAttribute, MString attribute, MFnDependencyNode &node);
29 | void getCustomAttribute(MString &stringAttribute, MString attribute, MFnDependencyNode &node);
30 | void getCustomAttribute(bool &boolAttribute, MString attribute, MFnDependencyNode &node);
31 |
32 | bool isObjectVisible(const MDagPath& path);
33 | bool areObjectAndParentsVisible(const MDagPath& path);
34 | bool isCameraRenderable(const MDagPath& path);
35 | int getAttributeInt(const std::string& node, const std::string& attributeName, int defaultValue);
36 | float getAttributeFloat(const std::string& node, const std::string& attributeName, float defaultValue);
37 | bool getShaderFromEngine(const MObject& obj, MFnDependencyNode& node);
38 | bool getShaderFromGeometry(const MDagPath& path, MFnDependencyNode& node);
39 | void exportMesh(const MDagPath& path, std::ofstream& file);
40 | void exportSurface(const MDagPath& path, std::ofstream& file);
41 | void exportCamera(const MDagPath& path, std::ofstream& file);
42 |
43 | bool getBumpFromShader(MFnDependencyNode& node, MString &texturePath, float &depth, MObject &bumpObject);
44 | MObjectArray shaderList;
45 | bool findShaderInList(MString shader);
46 |
47 | MDagPath renderCamera;
48 | };
49 |
50 | #endif /* SUNFLOW_EXPORT_CMD_H */
51 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/gi/PathTracingGIEngine.java:
--------------------------------------------------------------------------------
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 | import org.sunflow.system.UI;
12 | import org.sunflow.system.UI.Module;
13 |
14 | public class PathTracingGIEngine implements GIEngine {
15 | private int samples;
16 |
17 | public boolean init(Options options, Scene scene) {
18 | samples = options.getInt("gi.path.samples", 16);
19 | samples = Math.max(0, samples);
20 | UI.printInfo(Module.LIGHT, "Path tracer settings:");
21 | UI.printInfo(Module.LIGHT, " * Samples: %d", samples);
22 | return true;
23 | }
24 |
25 | public Color getIrradiance(ShadingState state, Color diffuseReflectance) {
26 | if (samples <= 0)
27 | return Color.BLACK;
28 | // compute new sample
29 | Color irr = Color.black();
30 | OrthoNormalBasis onb = state.getBasis();
31 | Vector3 w = new Vector3();
32 | int n = state.getDiffuseDepth() == 0 ? samples : 1;
33 | for (int i = 0; i < n; i++) {
34 | float xi = (float) state.getRandom(i, 0, n);
35 | float xj = (float) state.getRandom(i, 1, n);
36 | float phi = (float) (xi * 2 * Math.PI);
37 | float cosPhi = (float) Math.cos(phi);
38 | float sinPhi = (float) Math.sin(phi);
39 | float sinTheta = (float) Math.sqrt(xj);
40 | float cosTheta = (float) Math.sqrt(1.0f - xj);
41 | w.x = cosPhi * sinTheta;
42 | w.y = sinPhi * sinTheta;
43 | w.z = cosTheta;
44 | onb.transform(w);
45 | ShadingState temp = state.traceFinalGather(new Ray(state.getPoint(), w), i);
46 | if (temp != null) {
47 | temp.getInstance().prepareShadingState(temp);
48 | if (temp.getShader() != null)
49 | irr.add(temp.getShader().getRadiance(temp));
50 | }
51 | }
52 | irr.mul((float) Math.PI / n);
53 | return irr;
54 | }
55 |
56 | public Color getGlobalRadiance(ShadingState state) {
57 | return Color.BLACK;
58 | }
59 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/MirrorShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Ray;
6 | import org.sunflow.core.Shader;
7 | import org.sunflow.core.ShadingState;
8 | import org.sunflow.image.Color;
9 | import org.sunflow.math.Vector3;
10 |
11 | public class MirrorShader implements Shader {
12 | private Color color;
13 |
14 | public MirrorShader() {
15 | color = Color.WHITE;
16 | }
17 |
18 | public boolean update(ParameterList pl, SunflowAPI api) {
19 | color = pl.getColor("color", color);
20 | return true;
21 | }
22 |
23 | public Color getRadiance(ShadingState state) {
24 | if (!state.includeSpecular())
25 | return Color.BLACK;
26 | state.faceforward();
27 | float cos = state.getCosND();
28 | float dn = 2 * cos;
29 | Vector3 refDir = new Vector3();
30 | refDir.x = (dn * state.getNormal().x) + state.getRay().getDirection().x;
31 | refDir.y = (dn * state.getNormal().y) + state.getRay().getDirection().y;
32 | refDir.z = (dn * state.getNormal().z) + state.getRay().getDirection().z;
33 | Ray refRay = new Ray(state.getPoint(), refDir);
34 |
35 | // compute Fresnel term
36 | cos = 1 - cos;
37 | float cos2 = cos * cos;
38 | float cos5 = cos2 * cos2 * cos;
39 | Color ret = Color.white();
40 | ret.sub(color);
41 | ret.mul(cos5);
42 | ret.add(color);
43 | return ret.mul(state.traceReflection(refRay, 0));
44 | }
45 |
46 | public void scatterPhoton(ShadingState state, Color power) {
47 | float avg = color.getAverage();
48 | double rnd = state.getRandom(0, 0, 1);
49 | if (rnd >= avg)
50 | return;
51 | state.faceforward();
52 | float cos = state.getCosND();
53 | power.mul(color).mul(1.0f / avg);
54 | // photon is reflected
55 | float dn = 2 * cos;
56 | Vector3 dir = new Vector3();
57 | dir.x = (dn * state.getNormal().x) + state.getRay().getDirection().x;
58 | dir.y = (dn * state.getNormal().y) + state.getRay().getDirection().y;
59 | dir.z = (dn * state.getNormal().z) + state.getRay().getDirection().z;
60 | state.traceReflectionPhoton(new Ray(state.getPoint(), dir), power);
61 | }
62 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/light/PointLight.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.light;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.Instance;
5 | import org.sunflow.core.LightSample;
6 | import org.sunflow.core.LightSource;
7 | import org.sunflow.core.ParameterList;
8 | import org.sunflow.core.Ray;
9 | import org.sunflow.core.ShadingState;
10 | import org.sunflow.image.Color;
11 | import org.sunflow.math.Point3;
12 | import org.sunflow.math.Vector3;
13 |
14 | public class PointLight implements LightSource {
15 | private Point3 lightPoint;
16 | private Color power;
17 |
18 | public PointLight() {
19 | lightPoint = new Point3(0, 0, 0);
20 | power = Color.WHITE;
21 | }
22 |
23 | public boolean update(ParameterList pl, SunflowAPI api) {
24 | lightPoint = pl.getPoint("center", lightPoint);
25 | power = pl.getColor("power", power);
26 | return true;
27 | }
28 |
29 | public int getNumSamples() {
30 | return 1;
31 | }
32 |
33 | public void getSamples(ShadingState state) {
34 | Vector3 d = Point3.sub(lightPoint, state.getPoint(), new Vector3());
35 | if (Vector3.dot(d, state.getNormal()) > 0 && Vector3.dot(d, state.getGeoNormal()) > 0) {
36 | LightSample dest = new LightSample();
37 | // prepare shadow ray
38 | dest.setShadowRay(new Ray(state.getPoint(), lightPoint));
39 | float scale = 1.0f / (float) (4 * Math.PI * lightPoint.distanceToSquared(state.getPoint()));
40 | dest.setRadiance(power, power);
41 | dest.getDiffuseRadiance().mul(scale);
42 | dest.getSpecularRadiance().mul(scale);
43 | dest.traceShadow(state);
44 | state.addSample(dest);
45 | }
46 | }
47 |
48 | public void getPhoton(double randX1, double randY1, double randX2, double randY2, Point3 p, Vector3 dir, Color power) {
49 | p.set(lightPoint);
50 | float phi = (float) (2 * Math.PI * randX1);
51 | float s = (float) Math.sqrt(randY1 * (1.0f - randY1));
52 | dir.x = (float) Math.cos(phi) * s;
53 | dir.y = (float) Math.sin(phi) * s;
54 | dir.z = (float) (1 - 2 * randY1);
55 | power.set(this.power);
56 | }
57 |
58 | public float getPower() {
59 | return power.getLuminance();
60 | }
61 |
62 | public Instance createInstance() {
63 | return null;
64 | }
65 | }
--------------------------------------------------------------------------------
/src/org/sunflow/system/SearchPath.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.system;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.LinkedList;
6 |
7 | import org.sunflow.system.UI.Module;
8 |
9 | public class SearchPath {
10 | private LinkedList searchPath;
11 | private String type;
12 |
13 | public SearchPath(String type) {
14 | this.type = type;
15 | searchPath = new LinkedList();
16 | }
17 |
18 | public void resetSearchPath() {
19 | searchPath.clear();
20 | }
21 |
22 | public void addSearchPath(String path) {
23 | File f = new File(path);
24 | if (f.exists() && f.isDirectory()) {
25 | try {
26 | path = f.getCanonicalPath();
27 | for (String prefix : searchPath)
28 | if (prefix.equals(path))
29 | return;
30 | UI.printInfo(Module.SYS, "Adding %s search path: \"%s\"", type, path);
31 | searchPath.add(path);
32 | } catch (IOException e) {
33 | UI.printError(Module.SYS, "Invalid %s search path specification: \"%s\" - %s", type, path, e.getMessage());
34 | }
35 | } else
36 | UI.printError(Module.SYS, "Invalid %s search path specification: \"%s\" - invalid directory", type, path);
37 | }
38 |
39 | public String resolvePath(String filename) {
40 | // account for relative naming schemes from 3rd party softwares
41 | if (filename.startsWith("//"))
42 | filename = filename.substring(2);
43 | UI.printDetailed(Module.SYS, "Resolving %s path \"%s\" ...", type, filename);
44 | File f = new File(filename);
45 | if (!f.isAbsolute()) {
46 | for (String prefix : searchPath) {
47 | UI.printDetailed(Module.SYS, " * searching: \"%s\" ...", prefix);
48 | if (prefix.endsWith(File.separator) || filename.startsWith(File.separator))
49 | f = new File(prefix + filename);
50 | else
51 | f = new File(prefix + File.separator + filename);
52 | if (f.exists()) {
53 | // suggested path exists - try it
54 | return f.getAbsolutePath();
55 | }
56 | }
57 | }
58 | // file was not found in the search paths - return the filename itself
59 | return filename;
60 | }
61 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/shader/QuickGrayShader.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.shader;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.ParameterList;
5 | import org.sunflow.core.Ray;
6 | import org.sunflow.core.Shader;
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 QuickGrayShader implements Shader {
13 | public QuickGrayShader() {
14 | }
15 |
16 | public boolean update(ParameterList pl, SunflowAPI api) {
17 | return true;
18 | }
19 |
20 | public Color getRadiance(ShadingState state) {
21 | if (state.getNormal() == null) {
22 | // if this shader has been applied to an infinite instance because
23 | // of shader overrides
24 | // run the default shader, otherwise, just shade black
25 | return state.getShader() != this ? state.getShader().getRadiance(state) : Color.BLACK;
26 | }
27 | // make sure we are on the right side of the material
28 | state.faceforward();
29 | // setup lighting
30 | state.initLightSamples();
31 | state.initCausticSamples();
32 | return state.diffuse(Color.GRAY);
33 | }
34 |
35 | public void scatterPhoton(ShadingState state, Color power) {
36 | Color diffuse;
37 | // make sure we are on the right side of the material
38 | if (Vector3.dot(state.getNormal(), state.getRay().getDirection()) > 0.0) {
39 | state.getNormal().negate();
40 | state.getGeoNormal().negate();
41 | }
42 | diffuse = Color.GRAY;
43 | state.storePhoton(state.getRay().getDirection(), power, diffuse);
44 | float avg = diffuse.getAverage();
45 | double rnd = state.getRandom(0, 0, 1);
46 | if (rnd < avg) {
47 | // photon is scattered
48 | power.mul(diffuse).mul(1.0f / avg);
49 | OrthoNormalBasis onb = state.getBasis();
50 | double u = 2 * Math.PI * rnd / avg;
51 | double v = state.getRandom(0, 1, 1);
52 | float s = (float) Math.sqrt(v);
53 | float s1 = (float) Math.sqrt(1.0 - v);
54 | Vector3 w = new Vector3((float) Math.cos(u) * s, (float) Math.sin(u) * s, s1);
55 | w = onb.transform(w, new Vector3());
56 | state.traceDiffusePhoton(new Ray(state.getPoint(), w), power);
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/src/org/sunflow/image/writers/TGABitmapWriter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.writers;
2 |
3 | import java.io.BufferedOutputStream;
4 | import java.io.FileOutputStream;
5 | import java.io.IOException;
6 | import java.io.OutputStream;
7 |
8 | import org.sunflow.image.BitmapWriter;
9 | import org.sunflow.image.Color;
10 | import org.sunflow.image.ColorEncoder;
11 |
12 | public class TGABitmapWriter implements BitmapWriter {
13 | private String filename;
14 | private int width, height;
15 | private byte[] data;
16 |
17 | public void configure(String option, String value) {
18 | }
19 |
20 | public void openFile(String filename) throws IOException {
21 | this.filename = filename;
22 | }
23 |
24 | public void writeHeader(int width, int height, int tileSize) throws IOException, UnsupportedOperationException {
25 | this.width = width;
26 | this.height = height;
27 | data = new byte[width * height * 4]; // RGBA8
28 | }
29 |
30 | public void writeTile(int x, int y, int w, int h, Color[] color, float[] alpha) throws IOException {
31 | color = ColorEncoder.unlinearize(color); // gamma correction
32 | byte[] tileData = ColorEncoder.quantizeRGBA8(color, alpha);
33 | for (int j = 0, index = 0; j < h; j++) {
34 | int imageIndex = 4 * (x + (height - 1 - (y + j)) * width);
35 | for (int i = 0; i < w; i++, index += 4, imageIndex += 4) {
36 | // swap bytes around so buffer is in native BGRA order
37 | data[imageIndex + 0] = tileData[index + 2];
38 | data[imageIndex + 1] = tileData[index + 1];
39 | data[imageIndex + 2] = tileData[index + 0];
40 | data[imageIndex + 3] = tileData[index + 3];
41 | }
42 | }
43 | }
44 |
45 | public void closeFile() throws IOException {
46 | // actually write the file from here
47 | OutputStream f = new BufferedOutputStream(new FileOutputStream(filename));
48 | // no id, no colormap, uncompressed 32bpp RGBA
49 | byte[] tgaHeader = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
50 | f.write(tgaHeader);
51 | // then the size info
52 | f.write(width & 0xFF);
53 | f.write((width >> 8) & 0xFF);
54 | f.write(height & 0xFF);
55 | f.write((height >> 8) & 0xFF);
56 | // bitsperpixel and filler
57 | f.write(32);
58 | f.write(0);
59 | f.write(data); // write image data bytes (already in BGRA order)
60 | f.close();
61 | }
62 | }
--------------------------------------------------------------------------------
/examples/cornell_box_jensen.sc:
--------------------------------------------------------------------------------
1 | image {
2 | resolution 800 600
3 | aa 0 2
4 | filter gaussian
5 | }
6 |
7 | trace-depths {
8 | diff 4
9 | refl 3
10 | refr 2
11 | }
12 |
13 | photons {
14 | caustics 1000000 kd 100 0.5
15 | }
16 |
17 |
18 | % uncomment this block and comment the following GI block to switch gi engines
19 | /*
20 | gi {
21 | type irr-cache
22 | samples 512
23 | tolerance 0.01
24 | spacing 0.05 5.0
25 | % comment the following line to use path tracing for secondary bounces
26 | global 1000000 grid 100 0.75
27 | }
28 | */
29 |
30 | gi {
31 | type igi
32 | samples 64 % number of virtual photons per set
33 | sets 1 % number of sets (increase this to translate shadow boundaries into noise)
34 | b 0.00003 % bias - decrease this values until bright spots dissapear
35 | bias-samples 0 % set this >0 to make the algorithm unbiased
36 | }
37 |
38 | shader {
39 | name debug_caustics
40 | type view-caustics
41 | }
42 |
43 | shader {
44 | name debug_globals
45 | type view-global
46 | }
47 |
48 | shader {
49 | name debug_gi
50 | type view-irradiance
51 | }
52 |
53 | %% use these to view the effect of the individual gi components
54 | % override debug_caustics false
55 | % override debug_globals false
56 | % override debug_gi false
57 |
58 |
59 | camera {
60 | type pinhole
61 | eye 0 -205 50
62 | target 0 0 50
63 | up 0 0 1
64 | fov 45
65 | aspect 1.333333
66 | }
67 |
68 | shader {
69 | name Grey
70 | type diffuse
71 | diff 0.7 0.7 0.7
72 | }
73 |
74 | shader {
75 | name Blue
76 | type diffuse
77 | diff 0.25 0.25 0.8
78 | }
79 |
80 | shader {
81 | name Red
82 | type diffuse
83 | diff 0.8 0.25 0.25
84 | }
85 |
86 | shader {
87 | name Mirror
88 | type mirror
89 | refl 0.7 0.7 0.7
90 | }
91 |
92 | shader {
93 | name Glass
94 | type glass
95 | eta 1.6
96 | color 1 1 1
97 | }
98 |
99 | light {
100 | type cornellbox
101 | corner0 -60 -60 0
102 | corner1 60 60 100
103 | left 0.80 0.25 0.25
104 | right 0.25 0.25 0.80
105 | top 0.70 0.70 0.70
106 | bottom 0.70 0.70 0.70
107 | back 0.70 0.70 0.70
108 | emit 15 15 15
109 | samples 32
110 | }
111 |
112 | object {
113 | shader Mirror
114 | type sphere
115 | c -30 30 20
116 | r 20
117 | }
118 |
119 | object {
120 | shader Glass
121 | type sphere
122 | c 28 2 20
123 | r 20
124 | }
125 |
--------------------------------------------------------------------------------
/src/org/sunflow/image/IrregularSpectralCurve.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image;
2 |
3 | /**
4 | * This class allows spectral curves to be defined from irregularly sampled
5 | * data. Note that the wavelength array is assumed to be sorted low to high. Any
6 | * values beyond the defined range will simply be extended to infinity from the
7 | * end points. Points inside the valid range will be linearly interpolated
8 | * between the two nearest samples. No explicit error checking is performed, but
9 | * this class will run into {@link ArrayIndexOutOfBoundsException}s if the
10 | * array lengths don't match.
11 | */
12 | public class IrregularSpectralCurve extends SpectralCurve {
13 | private final float[] wavelengths;
14 | private final float[] amplitudes;
15 |
16 | /**
17 | * Define an irregular spectral curve from the provided (sorted) wavelengths
18 | * and amplitude data. The wavelength array is assumed to contain values in
19 | * nanometers. Array lengths must match.
20 | *
21 | * @param wavelengths sampled wavelengths in nm
22 | * @param amplitudes amplitude of the curve at the sampled points
23 | */
24 | public IrregularSpectralCurve(float[] wavelengths, float[] amplitudes) {
25 | this.wavelengths = wavelengths;
26 | this.amplitudes = amplitudes;
27 | if (wavelengths.length != amplitudes.length)
28 | throw new RuntimeException(String.format("Error creating irregular spectral curve: %d wavelengths and %d amplitudes", wavelengths.length, amplitudes.length));
29 | for (int i = 1; i < wavelengths.length; i++)
30 | if (wavelengths[i - 1] >= wavelengths[i])
31 | throw new RuntimeException(String.format("Error creating irregular spectral curve: values are not sorted - error at index %d", i));
32 | }
33 |
34 | @Override
35 | public float sample(float lambda) {
36 | if (wavelengths.length == 0)
37 | return 0; // no data
38 | if (wavelengths.length == 1 || lambda <= wavelengths[0])
39 | return amplitudes[0];
40 | if (lambda >= wavelengths[wavelengths.length - 1])
41 | return amplitudes[wavelengths.length - 1];
42 | for (int i = 1; i < wavelengths.length; i++) {
43 | if (lambda < wavelengths[i]) {
44 | float dx = (lambda - wavelengths[i - 1]) / (wavelengths[i] - wavelengths[i - 1]);
45 | return (1 - dx) * amplitudes[i - 1] + dx * amplitudes[i];
46 | }
47 | }
48 | return amplitudes[wavelengths.length - 1];
49 | }
50 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/display/FileDisplay.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.display;
2 |
3 | import java.io.IOException;
4 |
5 | import org.sunflow.PluginRegistry;
6 | import org.sunflow.core.Display;
7 | import org.sunflow.image.BitmapWriter;
8 | import org.sunflow.image.Color;
9 | import org.sunflow.system.FileUtils;
10 | import org.sunflow.system.UI;
11 | import org.sunflow.system.UI.Module;
12 |
13 | public class FileDisplay implements Display {
14 | private BitmapWriter writer;
15 | private String filename;
16 |
17 | public FileDisplay(boolean saveImage) {
18 | this(saveImage ? "output.png" : ".none");
19 | }
20 |
21 | public FileDisplay(String filename) {
22 | this.filename = filename == null ? "output.png" : filename;
23 | String extension = FileUtils.getExtension(filename);
24 | writer = PluginRegistry.bitmapWriterPlugins.createObject(extension);
25 | }
26 |
27 | public void imageBegin(int w, int h, int bucketSize) {
28 | if (writer == null)
29 | return;
30 | try {
31 | writer.openFile(filename);
32 | writer.writeHeader(w, h, bucketSize);
33 | } catch (IOException e) {
34 | UI.printError(Module.IMG, "I/O error occured while preparing image for display: %s", e.getMessage());
35 | }
36 | }
37 |
38 | public void imagePrepare(int x, int y, int w, int h, int id) {
39 | // does nothing for files
40 | }
41 |
42 | public void imageUpdate(int x, int y, int w, int h, Color[] data, float[] alpha) {
43 | if (writer == null)
44 | return;
45 | try {
46 | writer.writeTile(x, y, w, h, data, alpha);
47 | } catch (IOException e) {
48 | UI.printError(Module.IMG, "I/O error occured while writing image tile [(%d,%d) %dx%d] image for display: %s", x, y, w, h, e.getMessage());
49 | }
50 | }
51 |
52 | public void imageFill(int x, int y, int w, int h, Color c, float alpha) {
53 | if (writer == null)
54 | return;
55 | Color[] colorTile = new Color[w * h];
56 | float[] alphaTile = new float[w * h];
57 | for (int i = 0; i < colorTile.length; i++) {
58 | colorTile[i] = c;
59 | alphaTile[i] = alpha;
60 | }
61 | imageUpdate(x, y, w, h, colorTile, alphaTile);
62 | }
63 |
64 | public void imageEnd() {
65 | if (writer == null)
66 | return;
67 | try {
68 | writer.closeFile();
69 | } catch (IOException e) {
70 | UI.printError(Module.IMG, "I/O error occured while closing the display: %s", e.getMessage());
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/src/org/sunflow/core/parser/RA3Parser.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.parser;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.FileNotFoundException;
6 | import java.io.IOException;
7 | import java.nio.ByteOrder;
8 | import java.nio.FloatBuffer;
9 | import java.nio.IntBuffer;
10 | import java.nio.MappedByteBuffer;
11 | import java.nio.channels.FileChannel;
12 |
13 | import org.sunflow.SunflowAPIInterface;
14 | import org.sunflow.core.SceneParser;
15 | import org.sunflow.system.UI;
16 | import org.sunflow.system.UI.Module;
17 |
18 | public class RA3Parser implements SceneParser {
19 | public boolean parse(String filename, SunflowAPIInterface api) {
20 | try {
21 | UI.printInfo(Module.USER, "RA3 - Reading geometry: \"%s\" ...", filename);
22 | File file = new File(filename);
23 | FileInputStream stream = new FileInputStream(filename);
24 | MappedByteBuffer map = stream.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
25 | map.order(ByteOrder.LITTLE_ENDIAN);
26 | IntBuffer ints = map.asIntBuffer();
27 | FloatBuffer buffer = map.asFloatBuffer();
28 | int numVerts = ints.get(0);
29 | int numTris = ints.get(1);
30 | UI.printInfo(Module.USER, "RA3 - * Reading %d vertices ...", numVerts);
31 | float[] verts = new float[3 * numVerts];
32 | for (int i = 0; i < verts.length; i++)
33 | verts[i] = buffer.get(2 + i);
34 | UI.printInfo(Module.USER, "RA3 - * Reading %d triangles ...", numTris);
35 | int[] tris = new int[3 * numTris];
36 | for (int i = 0; i < tris.length; i++)
37 | tris[i] = ints.get(2 + verts.length + i);
38 | stream.close();
39 | UI.printInfo(Module.USER, "RA3 - * Creating mesh ...");
40 |
41 | // create geometry
42 | api.parameter("triangles", tris);
43 | api.parameter("points", "point", "vertex", verts);
44 | api.geometry(filename, "triangle_mesh");
45 |
46 | // create default shader (this will simply error out if the shader
47 | // already exists)
48 | api.shader("ra3shader", "simple");
49 | // create instance
50 | api.parameter("shaders", "ra3shader");
51 | api.instance(filename + ".instance", filename);
52 | } catch (FileNotFoundException e) {
53 | e.printStackTrace();
54 | return false;
55 | } catch (IOException e) {
56 | e.printStackTrace();
57 | return false;
58 | }
59 | return true;
60 | }
61 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/src/sunflowShaderNode.h:
--------------------------------------------------------------------------------
1 | #ifndef SUNFLOW_SHADER_NODE_H
2 | #define SUNFLOW_SHADER_NODE_H
3 |
4 | #include
5 | #include
6 |
7 | //
8 | // DESCRIPTION:
9 | ///////////////////////////////////////////////////////
10 | class sunflowShaderNode : public MPxNode
11 | {
12 | public:
13 | sunflowShaderNode();
14 | virtual ~sunflowShaderNode();
15 |
16 | virtual MStatus compute( const MPlug&, MDataBlock& );
17 | virtual void postConstructor();
18 |
19 | MColor getDiffuseComponent(MDataBlock& block);
20 | MColor getPhongComponent(MFloatVector &specular, float power, MDataBlock& block);
21 |
22 | static void * creator();
23 | static MStatus initialize();
24 | static MTypeId id;
25 |
26 | private:
27 | static MObject aShader;
28 | //PHONG SHADER
29 | static MObject phong_specular;
30 | static MObject phong_power;
31 | static MObject phong_samples;
32 | //AMB_OCC SHADER
33 | static MObject amb_dark;
34 | static MObject amb_samples;
35 | static MObject amb_maxdist;
36 |
37 | //GLASS SHADER
38 | static MObject glass_eta;
39 | static MObject glass_absorbtion_distance;
40 | static MObject glass_absorbtion_color;
41 |
42 | //SHINY SHADER
43 | static MObject shiny_shiny;
44 |
45 | //WARD SHADER
46 | static MObject ward_specular;
47 | static MObject ward_upower;
48 | static MObject ward_vpower;
49 | static MObject ward_samples;
50 |
51 | //UBER SHADER
52 | static MObject uber_diffuse_texture;
53 | static MObject uber_diffuse_blend;
54 | static MObject uber_specular;
55 | static MObject uber_specular_texture;
56 | static MObject uber_specular_blend;
57 | static MObject uber_gloss;
58 | static MObject uber_samples;
59 |
60 | static MObject aColor;
61 | static MObject aPointCamera;
62 | static MObject aNormalCamera;
63 | static MObject aLightDirection;
64 | static MObject aLightIntensity;
65 | static MObject aPower;
66 | static MObject aSpecularity;
67 | static MObject aLightAmbient;
68 | static MObject aLightDiffuse;
69 | static MObject aLightSpecular;
70 | static MObject aLightShadowFraction;
71 | static MObject aPreShadowIntensity;
72 | static MObject aLightBlindData;
73 | static MObject aLightData;
74 |
75 | static MObject aRayOrigin;
76 | static MObject aRayDirection;
77 |
78 | static MObject aObjectId;
79 | static MObject aRaySampler;
80 | static MObject aRayDepth;
81 |
82 | static MObject aReflectGain;
83 |
84 | static MObject aTriangleNormalCamera;
85 |
86 | static MObject aOutColor;
87 |
88 | };
89 |
90 | #endif /* SUNFLOW_SHADER_NODE_H */
91 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/PrimitiveList.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import org.sunflow.math.BoundingBox;
4 | import org.sunflow.math.Matrix4;
5 |
6 | /**
7 | * This class represents an object made up of many primitives.
8 | */
9 | public interface PrimitiveList extends RenderObject {
10 | /**
11 | * Compute a bounding box of this object in world space, using the specified
12 | * object-to-world transformation matrix. The bounds should be as exact as
13 | * possible, if they are difficult or expensive to compute exactly, you may
14 | * use {@link Matrix4#transform(BoundingBox)}. If the matrix is
15 | * null no transformation is needed, and object space is
16 | * equivalent to world space.
17 | *
18 | * @param o2w object to world transformation matrix
19 | * @return object bounding box in world space
20 | */
21 | public BoundingBox getWorldBounds(Matrix4 o2w);
22 |
23 | /**
24 | * Returns the number of individual primtives in this aggregate object.
25 | *
26 | * @return number of primitives
27 | */
28 | public int getNumPrimitives();
29 |
30 | /**
31 | * Retrieve the bounding box component of a particular primitive in object
32 | * space. Even indexes get minimum values, while odd indexes get the maximum
33 | * values for each axis.
34 | *
35 | * @param primID primitive index
36 | * @param i bounding box side index
37 | * @return value of the request bound
38 | */
39 | public float getPrimitiveBound(int primID, int i);
40 |
41 | /**
42 | * Intersect the specified primitive in local space.
43 | *
44 | * @param r ray in the object's local space
45 | * @param primID primitive index to intersect
46 | * @param state intersection state
47 | * @see Ray#setMax(float)
48 | * @see IntersectionState#setIntersection(int, float, float)
49 | */
50 | public void intersectPrimitive(Ray r, int primID, IntersectionState state);
51 |
52 | /**
53 | * Prepare the specified {@link ShadingState} by setting all of its internal
54 | * parameters.
55 | *
56 | * @param state shading state to fill in
57 | */
58 | public void prepareShadingState(ShadingState state);
59 |
60 | /**
61 | * Create a new {@link PrimitiveList} object suitable for baking lightmaps.
62 | * This means a set of primitives laid out in the unit square UV space. This
63 | * method is optional, objects which do not support it should simply return
64 | * null.
65 | *
66 | * @return a list of baking primitives
67 | */
68 | public PrimitiveList getBakingPrimitives();
69 | }
--------------------------------------------------------------------------------
/src/org/sunflow/system/BenchmarkFramework.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.system;
2 |
3 | import org.sunflow.system.UI.Module;
4 |
5 | /**
6 | * This class provides a very simple framework for running a BenchmarkTest
7 | * kernel several times and time the results.
8 | */
9 | public class BenchmarkFramework {
10 | private Timer[] timers;
11 | private int timeLimit; // time limit in seconds
12 |
13 | public BenchmarkFramework(int iterations, int timeLimit) {
14 | this.timeLimit = timeLimit;
15 | timers = new Timer[iterations];
16 | }
17 |
18 | public void execute(BenchmarkTest test) {
19 | // clear previous results
20 | for (int i = 0; i < timers.length; i++)
21 | timers[i] = null;
22 | // loop for the specified number of iterations or until the time limit
23 | long startTime = System.nanoTime();
24 | for (int i = 0; i < timers.length && ((System.nanoTime() - startTime) / 1000000000) < timeLimit; i++) {
25 | UI.printInfo(Module.BENCH, "Running iteration %d", (i + 1));
26 | timers[i] = new Timer();
27 | test.kernelBegin();
28 | timers[i].start();
29 | test.kernelMain();
30 | timers[i].end();
31 | test.kernelEnd();
32 | }
33 | // report stats
34 | double avg = 0;
35 | double min = Double.POSITIVE_INFINITY;
36 | double max = Double.NEGATIVE_INFINITY;
37 | int n = 0;
38 | for (Timer t : timers) {
39 | if (t == null)
40 | break;
41 | double s = t.seconds();
42 | min = Math.min(min, s);
43 | max = Math.max(max, s);
44 | avg += s;
45 | n++;
46 | }
47 | if (n == 0)
48 | return;
49 | avg /= n;
50 | double stdDev = 0;
51 | for (Timer t : timers) {
52 | if (t == null)
53 | break;
54 | double s = t.seconds();
55 | stdDev += (s - avg) * (s - avg);
56 | }
57 | stdDev = Math.sqrt(stdDev / n);
58 | UI.printInfo(Module.BENCH, "Benchmark results:");
59 | UI.printInfo(Module.BENCH, " * Iterations: %d", n);
60 | UI.printInfo(Module.BENCH, " * Average: %s", Timer.toString(avg));
61 | UI.printInfo(Module.BENCH, " * Fastest: %s", Timer.toString(min));
62 | UI.printInfo(Module.BENCH, " * Longest: %s", Timer.toString(max));
63 | UI.printInfo(Module.BENCH, " * Deviation: %s", Timer.toString(stdDev));
64 | for (int i = 0; i < timers.length && timers[i] != null; i++)
65 | UI.printDetailed(Module.BENCH, " * Iteration %d: %s", i + 1, timers[i]);
66 | }
67 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/src/sunflowBucketToRenderView.cpp:
--------------------------------------------------------------------------------
1 | #include "sunflowBucketToRenderView.h"
2 | #include
3 |
4 | DisplayPacket bucketToRenderView::getPacket(){
5 | DisplayPacket p;
6 | p.type.sbits8[3] = fgetc( renderPipe );
7 | p.type.sbits8[2] = fgetc( renderPipe );
8 | p.type.sbits8[1] = fgetc( renderPipe );
9 | p.type.sbits8[0] = fgetc( renderPipe );
10 | for (int i = 0; i < 4; i++) {
11 | p.data[i].sbits8[3] = fgetc( renderPipe );
12 | p.data[i].sbits8[2] = fgetc( renderPipe );
13 | p.data[i].sbits8[1] = fgetc( renderPipe );
14 | p.data[i].sbits8[0] = fgetc( renderPipe );
15 | }
16 | //std::cout << "Recieved packet "< 1:
14 | ## on windows, more than one file is created when shared libraries are built
15 | local_env.InstallAs(os.path.join('plugin', version, 'sunflowExport.mll'), dll[0])
16 | else:
17 | ## on *nix just one file is created
18 | local_env.InstallAs(os.path.join('plugin', version, 'sunflowExport.so'), dll)
19 |
20 |
21 | ## find source code automatically
22 | source_files = []
23 | for f in glob.glob('src/*.cpp'):
24 | source_files += [ f ]
25 |
26 |
27 | if sys.platform == 'win32':
28 | ## windows XP x64
29 | sdk_base = "C:\\Program Files\\Microsoft Platform SDK for Windows Server 2003 R2\\"
30 | env64 = Environment(
31 | CCFLAGS = Split('/nologo /W3 /GR /EHsc /MT /O2 /Ox'),
32 | CPPDEFINES = Split('_CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_DEPRECATE NDEBUG WIN32 _WINDOWS NT_PLUGIN REQUIRE_IOSTREAM Bits64_'),
33 | LINKFLAGS = Split('/nologo /incremental:no /MACHINE:AMD64 /export:initializePlugin /export:uninitializePlugin'),
34 | LIBS = Split('Foundation OpenMaya OpenMayaUI opengl32 shell32 bufferoverflowU'))
35 |
36 | env64.Append(CPPPATH = [ "%s\\Include\\" % (sdk_base) ])
37 | env64.Append(CPPPATH = [ "%s\\INCLUDE\\crt\\" % (sdk_base) ])
38 | env64.Append(LIBPATH = [ "%s\\Lib\\AMD64\\" % (sdk_base) ])
39 |
40 | env64['ENV']['PATH'] = "%s\\Bin\\win64\\x86\\AMD64;" % (sdk_base)
41 | # env64['ENV']['INCLUDE'] = "%s\\Include;%s\\INCLUDE\\crt" % (sdk_base, sdk_base)
42 | # env64['ENV']['LIB'] = "%s\\Lib\\AMD64;" % (sdk_base)
43 |
44 | compile_maya(env64, "C:\\Program Files\\Autodesk\\Maya8.5\\" , "85_x64")
45 | compile_maya(env64, "C:\\Program Files\\Alias\\Maya8.0\\" , "80_x64")
46 | elif sys.platform == 'linux2':
47 | env = Environment(
48 | CCFLAGS = Split('-g -O2 -Wno-deprecated -Wall'),
49 | CPPDEFINES = Split('LINUX _BOOL REQUIRE_IOSTREAM'),
50 | CPPINCLUDE= Split('/usr/X11R6/include/'),
51 | LIBS = Split('OpenMaya OpenMayaUI GL'),
52 | LIBPATH = Split('/usr/X11R6/lib/'))
53 | compile_maya(env, "/usr/aw/maya7.0/", "70")
54 | compile_maya(env, "/usr/aw/maya8.0/", "80")
55 | compile_maya(env, "/usr/autodesk/maya8.5/", "85")
56 | else:
57 | print 'Unsupported platform: %s' % (sys.platform)
58 |
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/src/pluginMain.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "sunflowGlobalsNode.h"
5 | #include "sunflowExportCmd.h"
6 | #include "sunflowShaderNode.h"
7 | #include "sunflowSkyNode.h"
8 | #include "sunflowHelperNode.h"
9 |
10 | MStatus initializePlugin( MObject obj )
11 | {
12 | MStatus status;
13 | MFnPlugin plugin( obj, "Alias", "3.0", "Any");
14 |
15 | status = plugin.registerNode( "sunflowGlobalsNode", sunflowGlobalsNode::id, &sunflowGlobalsNode::creator, &sunflowGlobalsNode::initialize, MPxNode::kDependNode );
16 | if (!status) { status.perror("registerNode: sunflowGlobalsNode"); return status;}
17 |
18 | status = plugin.registerCommand("sunflowExportCmd", sunflowExportCmd::creator );
19 | if (!status) status.perror("registerCommand: sunflowExportCmd");
20 |
21 | const MString UserClassify( "shader/surface" );
22 | status = plugin.registerNode( "sunflowShader", sunflowShaderNode::id, sunflowShaderNode::creator, sunflowShaderNode::initialize, MPxNode::kDependNode, &UserClassify );
23 | if (!status) status.perror("registerNode: sunflowShaderNode");
24 |
25 | status = plugin.registerNode( "sunflowSkyNode", sunflowSkyNode::id, &sunflowSkyNode::creator, &sunflowSkyNode::initialize, MPxNode::kLocatorNode );
26 | if (!status) status.perror("registerNode: sunflowSkyNode");
27 |
28 | status = plugin.registerNode( "sunflowHelperNode", sunflowHelperNode::id, sunflowHelperNode::creator, sunflowHelperNode::initialize, MPxNode::kLocatorNode );
29 | if (!status) status.perror("registerNode: sunflowHelperNode");
30 |
31 | status = MGlobal::executeCommand("source sunflowStartup.mel");
32 | status = plugin.registerUI("sunflowStartup", "sunflowShutdown");
33 | if (!status) { status.perror("Can't register sunflowStartup and sunflowShutdown interface scripts"); return status;}
34 | return status;
35 | }
36 |
37 | MStatus uninitializePlugin( MObject obj)
38 | {
39 | MStatus status;
40 | MFnPlugin plugin( obj );
41 |
42 | status = plugin.deregisterNode( sunflowGlobalsNode::id );
43 | if (!status) { status.perror("deregisterNode: sunflowGlobalsNode"); return status;}
44 |
45 | status = plugin.deregisterCommand("sunflowExportCmd");
46 | if (!status) status.perror("deregisterCommand: sunflowExportCmd");
47 |
48 | status = plugin.deregisterNode( sunflowShaderNode::id );
49 | if (!status) status.perror("deregisterNode: sunflowShaderNode");
50 |
51 | status = plugin.deregisterNode( sunflowSkyNode::id );
52 | if (!status) status.perror("deregisterNode: sunflowSkyNode");
53 |
54 | status = plugin.deregisterNode( sunflowHelperNode::id );
55 | if (!status) status.perror("deregisterNode: sunflowHelperNode");
56 |
57 | //MGlobal::executeCommandOnIdle("unregisterSunflowRenderer");
58 | return status;
59 | }
60 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/LightSource.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core;
2 |
3 | import org.sunflow.image.Color;
4 | import org.sunflow.math.Point3;
5 | import org.sunflow.math.Vector3;
6 |
7 | /**
8 | * This interface is used to represent any light emitting primitive. It permits
9 | * efficient sampling of direct illumination and photon shooting.
10 | */
11 | public interface LightSource extends RenderObject {
12 | /**
13 | * Get the maximum number of samples that can be taken from this light
14 | * source. This is currently only used for statistics reporting.
15 | *
16 | * @return maximum number of samples to be taken from this light source
17 | */
18 | public int getNumSamples();
19 |
20 | /**
21 | * Samples the light source to compute direct illumination. Light samples
22 | * can be created using the {@link LightSample} class and added to the
23 | * current {@link ShadingState}. This method is responsible for the
24 | * shooting of shadow rays which allows for non-physical lights that don't
25 | * cast shadows. It is recommended that only a single shadow ray be shot if
26 | * {@link ShadingState#getDiffuseDepth()} is greater than 0. This avoids an
27 | * exponential number of shadow rays from being traced.
28 | *
29 | * @param state current state, including point to be shaded
30 | * @see LightSample
31 | */
32 | public void getSamples(ShadingState state);
33 |
34 | /**
35 | * Gets a photon to emit from this light source by setting each of the
36 | * arguments. The two sampling parameters are points on the unit square that
37 | * can be used to sample a position and/or direction for the emitted photon.
38 | *
39 | * @param randX1 sampling parameter
40 | * @param randY1 sampling parameter
41 | * @param randX2 sampling parameter
42 | * @param randY2 sampling parameter
43 | * @param p position to shoot the photon from
44 | * @param dir direction to shoot the photon in
45 | * @param power power of the photon
46 | */
47 | public void getPhoton(double randX1, double randY1, double randX2, double randY2, Point3 p, Vector3 dir, Color power);
48 |
49 | /**
50 | * Get the total power emitted by this light source. Lights that have 0
51 | * power will not emit any photons.
52 | *
53 | * @return light source power
54 | */
55 | public float getPower();
56 |
57 | /**
58 | * Create an instance which represents the geometry of this light source.
59 | * This instance will be created just before and removed immediately after
60 | * rendering. Non-area light sources can return null to
61 | * indicate that no geometry needs to be created.
62 | *
63 | * @return an instance describing the light source
64 | */
65 | public Instance createInstance();
66 | }
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/src/sunflowSkyNode.h:
--------------------------------------------------------------------------------
1 | #ifndef SUNFLOW_SKY_NODE_H
2 | #define SUNFLOW_SKY_NODE_H
3 |
4 | #include "skylight.h"
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | #define PI 3.14159265358979323846
24 | #define TWOPI 6.2831853071795864769
25 |
26 | #define DRAWMODE 0
27 |
28 | class sunflowSkyNode : public MPxLocatorNode
29 | {
30 | public:
31 | sunflowSkyNode();
32 | virtual ~sunflowSkyNode();
33 |
34 | virtual MStatus compute( const MPlug& plug, MDataBlock& data );
35 |
36 | virtual void draw( M3dView & view, const MDagPath & path,
37 | M3dView::DisplayStyle style,
38 | M3dView::DisplayStatus status );
39 |
40 | virtual bool isBounded() const;
41 | virtual MBoundingBox boundingBox() const;
42 |
43 | static void * creator();
44 | static MStatus initialize();
45 |
46 | static MObject size; // The size of the dome
47 | static MObject resolution;
48 |
49 | SunSky skyDome;
50 | void drawTriDome(M3dView & view, M3dView::DisplayStatus status);
51 | MStatus subdivide(M3dView & view, MVector v1, MVector v2, MVector v3, int depth, int drawMode);
52 | void drawTriangle(M3dView & view, MVector v1, MVector v2, MVector v3, int drawMode);
53 |
54 | void drawQuadDome(M3dView & view, M3dView::DisplayStatus status);
55 | void quadDome(M3dView & view, int drawMode);
56 |
57 | public:
58 | static MTypeId id;
59 | protected:
60 | static MObject sunVectorX;
61 | static MObject sunVectorY;
62 | static MObject sunVectorZ;
63 | static MObject sunVector;
64 | static MObject turbidity;
65 | static MObject exposure;
66 | static MObject sunLight;
67 | static MObject domeAlpha;
68 |
69 | MVectorArray vData;
70 | MVectorArray tData;
71 |
72 | float radius;
73 | float domeOpacity;
74 |
75 | float m_radius;
76 | float m_multiplier;
77 | float m_triRes;
78 | float m_quadRes;
79 | float m_exposure;
80 | float m_alpha;
81 |
82 | //static MObject Gamma;
83 | //static MObject enableGround;
84 | //static MObject groundColorR;
85 | //static MObject groundColorG;
86 | //static MObject groundColorB;
87 | //static MObject groundColor;
88 |
89 | };
90 |
91 | #endif /* SUNFLOW_SKY_NODE_H */
92 |
--------------------------------------------------------------------------------
/src/org/sunflow/image/writers/IGIBitmapWriter.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.image.writers;
2 |
3 | import java.io.BufferedOutputStream;
4 | import java.io.FileOutputStream;
5 | import java.io.IOException;
6 | import java.io.OutputStream;
7 |
8 | import org.sunflow.image.BitmapWriter;
9 | import org.sunflow.image.Color;
10 | import org.sunflow.image.XYZColor;
11 |
12 | /**
13 | * Writes images in Indigo's native XYZ format.
14 | * http://www2.indigorenderer.com/joomla/forum/viewtopic.php?p=11430
15 | */
16 | public class IGIBitmapWriter implements BitmapWriter {
17 | private String filename;
18 | private int width, height;
19 | private float[] xyz;
20 |
21 | public void configure(String option, String value) {
22 | }
23 |
24 | public void openFile(String filename) throws IOException {
25 | this.filename = filename;
26 | }
27 |
28 | public void writeHeader(int width, int height, int tileSize) throws IOException, UnsupportedOperationException {
29 | this.width = width;
30 | this.height = height;
31 | xyz = new float[width * height * 3];
32 | }
33 |
34 | public void writeTile(int x, int y, int w, int h, Color[] color, float[] alpha) throws IOException {
35 | for (int j = 0, index = 0, pixel = 3 * (x + y * width); j < h; j++, pixel += 3 * (width - w)) {
36 | for (int i = 0; i < w; i++, index++, pixel += 3) {
37 | XYZColor c = Color.NATIVE_SPACE.convertRGBtoXYZ(color[index]);
38 | xyz[pixel + 0] = c.getX();
39 | xyz[pixel + 1] = c.getY();
40 | xyz[pixel + 2] = c.getZ();
41 | }
42 | }
43 | }
44 |
45 | public void closeFile() throws IOException {
46 | OutputStream stream = new BufferedOutputStream(new FileOutputStream(filename));
47 | write32(stream, 66613373); // magic number
48 | write32(stream, 1); // version
49 | write32(stream, 0); // this should be a double - assume it won't be used
50 | write32(stream, 0);
51 | write32(stream, width);
52 | write32(stream, height);
53 | write32(stream, 1); // super sampling factor
54 | write32(stream, 0); // compression
55 | write32(stream, width * height * 12); // data size
56 | write32(stream, 0); // colorspace
57 | stream.write(new byte[5000]);
58 | for (float f : xyz)
59 | write32(stream, f);
60 | stream.close();
61 | }
62 |
63 | private static final void write32(OutputStream stream, int i) throws IOException {
64 | stream.write(i & 0xFF);
65 | stream.write((i >> 8) & 0xFF);
66 | stream.write((i >> 16) & 0xFF);
67 | stream.write((i >> 24) & 0xFF);
68 | }
69 |
70 | private static final void write32(OutputStream stream, float f) throws IOException {
71 | write32(stream, Float.floatToIntBits(f));
72 | }
73 | }
--------------------------------------------------------------------------------
/examples/shader_examples/include/example_array.geo.sc:
--------------------------------------------------------------------------------
1 | %% common settings
2 |
3 | image {
4 | resolution 600 600
5 | aa 0 2
6 | filter mitchell
7 | }
8 |
9 | %% camera
10 |
11 | camera {
12 | type pinhole
13 | eye 3.27743673325 -9.07978439331 9.93055152893
14 | target 0 0 0
15 | up 0 0 1
16 | fov 40
17 | aspect 1
18 | }
19 |
20 |
21 | %% light sources
22 |
23 | light {
24 | type meshlight
25 | name "meshlight"
26 | emit 1 1 1
27 | radiance 16
28 | samples 32
29 | points 4
30 | -1.79750967026 -6.22097349167 5.70054674149
31 | -2.28231739998 -7.26064729691 4.06224298477
32 | -4.09493303299 -6.41541051865 4.06224298477
33 | -3.61012482643 -5.37573671341 5.70054721832
34 | triangles 2
35 | 0 1 2
36 | 0 2 3
37 | }
38 |
39 | light {
40 | type meshlight
41 | name "meshlight.001"
42 | emit 1 1 1
43 | radiance 15
44 | samples 32
45 | points 4
46 | -4.25819396973 -4.8784570694 5.70054674149
47 | -5.13696432114 -5.61583280563 4.06224298477
48 | -6.422539711 -4.08374404907 4.06224298477
49 | -5.54376888275 -3.34636831284 5.70054721832
50 | triangles 2
51 | 0 1 2
52 | 0 2 3
53 | }
54 |
55 |
56 | %% geometry
57 |
58 | object {
59 | shader ground
60 | type generic-mesh
61 | name "Plane"
62 | points 8
63 | 3.1 3.1 0
64 | 3.1 -3.1 0
65 | -3.1 -3.1 0
66 | -3.1 3.1 0
67 | -3.1 3.1 -0.61
68 | -3.1 -3.1 -0.61
69 | 3.1 -3.1 -0.61
70 | 3.1 3.1 -0.61
71 | triangles 12
72 | 0 3 2
73 | 0 2 1
74 | 2 3 4
75 | 2 4 5
76 | 3 0 7
77 | 3 7 4
78 | 0 1 6
79 | 0 6 7
80 | 1 2 5
81 | 1 5 6
82 | 5 4 7
83 | 5 7 6
84 | normals none
85 | uvs none
86 | }
87 |
88 | object {
89 | shader "shader01"
90 | type sphere
91 | c -2 2 0.7
92 | r 0.7
93 | }
94 |
95 | object {
96 | shader "shader02"
97 | type sphere
98 | c 0 2 0.7
99 | r 0.7
100 | }
101 |
102 | object {
103 | shader "shader03"
104 | type sphere
105 | c 2 2 0.7
106 | r 0.7
107 | }
108 |
109 | object {
110 | shader "shader04"
111 | type sphere
112 | c -2 0 0.7
113 | r 0.7
114 | }
115 | object {
116 | shader "shader05"
117 | type sphere
118 | c 0 0 0.7
119 | r 0.7
120 | }
121 |
122 | object {
123 | shader "shader06"
124 | type sphere
125 | c 2 0 0.7
126 | r 0.7
127 | }
128 |
129 | object {
130 | shader "shader07"
131 | type sphere
132 | c -2 -2 0.7
133 | r 0.7
134 | }
135 |
136 | object {
137 | shader "shader08"
138 | type sphere
139 | c 0 -2 0.7
140 | r 0.7
141 | }
142 |
143 | object {
144 | shader "shader09"
145 | type sphere
146 | c 2 -2 0.7
147 | r 0.7
148 | }
149 |
--------------------------------------------------------------------------------
/exporters/maya/sunflowExporter/src/skylight.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////
2 | // copyright : (C) 2006 by Mad Crew
3 | // Email : fredrik (at) madcrew (dot) se
4 | // Website : http://www.madcrew.se
5 | // Created : 2006-11-03
6 | ////////////////////////////////////////////////////////////////////////////
7 |
8 | ////////////////////////////////////////////////////////////////////////////
9 | // //
10 | // This program is free software; you can redistribute it and/or modify //
11 | // it under the terms of the GNU General Public License as published by //
12 | // the Free Software Foundation; either version 2 of the License, or //
13 | // (at your option) any later version. //
14 | // //
15 | ////////////////////////////////////////////////////////////////////////////
16 |
17 |
18 | #ifndef SUNSKY_H
19 | #define SUNSKY_H
20 |
21 | #include
22 | #include
23 | #include
24 | //=============================================================================
25 | // SunSky
26 | class SunSky
27 | {
28 | public:
29 | SunSky();
30 | SunSky( MVector position, double size, double turbidity );
31 | // [in] position - the location of the sun.
32 | // [in] angle - the number of degrees of arc occupied by the sun.
33 | // [in] turbidity- is the ratio of the optical thickness of the haze and
34 | // molecules to haze. Turbidity = (Tm + Th) / Tm. It is the fraction of
35 | // scattering due to haze as opposed to molecules. 2-6 are good for clear
36 | // days
37 |
38 | MColor getSkyColor(const MVector& direction ) const;
39 | // returns the color of the sky in a particular direction
40 |
41 | void setTurbidity( double t ) { turbidity = t; }
42 | void setPosition( MVector pos ) { position = pos; }
43 | void initialize();
44 | MColor gammaCorrect( MColor& color, float gamma );
45 |
46 | private:
47 | double perez_x[5], // coefficients for the perez functions
48 | perez_y[5],
49 | perez_Y[5];
50 | double zenith_x, // chromaticity at the zenith
51 | zenith_y,
52 | zenith_Y; // in cd/m^2
53 | MVector position; // normalized MVector pointing to the sun
54 | double theta, phi; // spherical coordinates of the sun position
55 | double turbidity; // turbitity of the atmosphere
56 |
57 |
58 | SunSky( const SunSky& );
59 | // copy constructor - unimplemented
60 |
61 | SunSky& operator=( const SunSky& );
62 | // assigment - unimplemented
63 |
64 | double perezFunction(const double *coeff, double thetaV, double gamma, double Yz ) const;
65 | MColor toRGB(double x, double y, double Ys ) const;
66 | };
67 |
68 | #endif /* SUNSKY_H */
69 |
--------------------------------------------------------------------------------
/src/org/sunflow/core/modifiers/PerlinModifier.java:
--------------------------------------------------------------------------------
1 | package org.sunflow.core.modifiers;
2 |
3 | import org.sunflow.SunflowAPI;
4 | import org.sunflow.core.Modifier;
5 | import org.sunflow.core.ParameterList;
6 | import org.sunflow.core.ShadingState;
7 | import org.sunflow.math.OrthoNormalBasis;
8 | import org.sunflow.math.PerlinScalar;
9 | import org.sunflow.math.Point3;
10 | import org.sunflow.math.Vector3;
11 |
12 | public class PerlinModifier implements Modifier {
13 | private int function = 0;
14 | private float scale = 50;
15 | private float size = 1;
16 |
17 | public boolean update(ParameterList pl, SunflowAPI api) {
18 | function = pl.getInt("function", function);
19 | size = pl.getFloat("size", size);
20 | scale = pl.getFloat("scale", scale);
21 | return true;
22 | }
23 |
24 | public void modify(ShadingState state) {
25 | Point3 p = state.transformWorldToObject(state.getPoint());
26 | p.x *= size;
27 | p.y *= size;
28 | p.z *= size;
29 | Vector3 normal = state.transformNormalWorldToObject(state.getNormal());
30 | double f0 = f(p.x, p.y, p.z);
31 | double fx = f(p.x + .0001, p.y, p.z);
32 | double fy = f(p.x, p.y + .0001, p.z);
33 | double fz = f(p.x, p.y, p.z + .0001);
34 |
35 | normal.x -= scale * (fx - f0) / .0001;
36 | normal.y -= scale * (fy - f0) / .0001;
37 | normal.z -= scale * (fz - f0) / .0001;
38 | normal.normalize();
39 |
40 | state.getNormal().set(state.transformNormalObjectToWorld(normal));
41 | state.getNormal().normalize();
42 | state.setBasis(OrthoNormalBasis.makeFromW(state.getNormal()));
43 | }
44 |
45 | double f(double x, double y, double z) {
46 | switch (function) {
47 | case 0:
48 | return .03 * noise(x, y, z, 8);
49 | case 1:
50 | return .01 * stripes(x + 2 * turbulence(x, y, z, 1), 1.6);
51 | default:
52 | return -.10 * turbulence(x, y, z, 1);
53 | }
54 | }
55 |
56 | private static final double stripes(double x, double f) {
57 | double t = .5 + .5 * Math.sin(f * 2 * Math.PI * x);
58 | return t * t - .5;
59 | }
60 |
61 | private static final double turbulence(double x, double y, double z, double freq) {
62 | double t = -.5;
63 | for (; freq <= 300 / 12; freq *= 2)
64 | t += Math.abs(noise(x, y, z, freq) / freq);
65 | return t;
66 | }
67 |
68 | private static final double noise(double x, double y, double z, double freq) {
69 | double x1, y1, z1;
70 | x1 = .707 * x - .707 * z;
71 | z1 = .707 * x + .707 * z;
72 | y1 = .707 * x1 + .707 * y;
73 | x1 = .707 * x1 - .707 * y;
74 | return PerlinScalar.snoise((float) (freq * x1 + 100), (float) (freq * y1), (float) (freq * z1));
75 | }
76 | }
--------------------------------------------------------------------------------