├── .gitignore
├── .gitmodules
├── LICENSE.txt
├── README.md
├── prj
├── shaderbox.sln
├── shaderbox.vcxproj
└── shaderbox.vcxproj.filters
├── src
├── .c4droid
├── IK.h
├── Makefile
├── _hlsltoy.cmd
├── _inclxpnd.cmd
├── app_2d.h
├── app_atmosphere.h
├── app_clouds.h
├── app_clouds_best.h
├── app_egg.h
├── app_func.h
├── app_planet.h
├── app_raytracer.h
├── app_sdf_ao.h
├── app_vinyl.h
├── cornell_box.h
├── def.h
├── fbm.h
├── intersect.h
├── light.h
├── main.h
├── material.h
├── noise_iq.h
├── noise_worley.h
├── reference
│ ├── VolumetricIntegration.frag
│ ├── anisotropic.frag
│ ├── beer_lambert.frag
│ ├── elevated.frag
│ ├── improved_perlin.frag
│ ├── musgrave_fbm.frag
│ ├── noise_lab.frag
│ ├── primitives.frag
│ ├── seascape.frag
│ └── simplex_noise.frag
├── sdf.h
├── uniform_buffer.h
├── util.h
├── util_optics.h
└── volumetric.h
├── submodules.sh
├── ue4
└── volumetric_clouds
│ ├── Config
│ ├── DefaultEditor.ini
│ ├── DefaultEngine.ini
│ └── DefaultGame.ini
│ ├── Content
│ ├── Main.umap
│ └── clouds_material.uasset
│ ├── Shaders
│ └── app_clouds.usf
│ └── volumetric_clouds.uproject
└── util
├── ddsvolgen
├── README.md
├── prj
│ ├── ddsvolgen.vcxproj
│ └── ddsvolgen.vcxproj.filters
└── src
│ └── ddsvolgen.cpp
├── hlsltoy
├── README.md
├── prj
│ ├── hlsltoy.rc
│ ├── hlsltoy.vcxproj
│ ├── hlsltoy.vcxproj.filters
│ ├── icon.ico
│ ├── resource.h
│ └── vertex_shader.hlsl.bin
└── src
│ └── hlsltoy.cpp
└── inclxpnd
├── README.md
├── prj
├── inclxpnd.vcxproj
└── inclxpnd.vcxproj.filters
└── src
└── inclxpnd.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files
2 | *.slo
3 | *.lo
4 | *.o
5 | *.obj
6 |
7 | # Precompiled Headers
8 | *.gch
9 | *.pch
10 |
11 | # Compiled Dynamic libraries
12 | *.so
13 | *.dylib
14 | *.dll
15 |
16 | # Fortran module files
17 | *.mod
18 |
19 | # Compiled Static libraries
20 | *.lai
21 | *.la
22 | *.a
23 | *.lib
24 |
25 | # Executables
26 | *.out
27 | *.app
28 |
29 | ## Ignore Visual Studio temporary files, build results, and
30 | ## files generated by popular Visual Studio add-ons.
31 |
32 | # User-specific files
33 | *.suo
34 | *.user
35 | *.userosscache
36 | *.sln.docstates
37 |
38 | # User-specific files (MonoDevelop/Xamarin Studio)
39 | *.userprefs
40 |
41 | # Build results
42 | [Dd]ebug/
43 | [Dd]ebugPublic/
44 | [Rr]elease/
45 | [Rr]eleases/
46 | x64/
47 | x86/
48 | build/
49 | bld/
50 | [Bb]in/
51 | [Oo]bj/
52 |
53 | # Visual Studio 2015 cache/options directory
54 | .vs/
55 | # Uncomment if you have tasks that create the project's static files in wwwroot
56 | #wwwroot/
57 |
58 | # MSTest test Results
59 | [Tt]est[Rr]esult*/
60 | [Bb]uild[Ll]og.*
61 |
62 | # NUNIT
63 | *.VisualState.xml
64 | TestResult.xml
65 |
66 | # Build Results of an ATL Project
67 | [Dd]ebugPS/
68 | [Rr]eleasePS/
69 | dlldata.c
70 |
71 | # DNX
72 | project.lock.json
73 | artifacts/
74 |
75 | *_i.c
76 | *_p.c
77 | *_i.h
78 | *.ilk
79 | *.meta
80 | *.obj
81 | *.pch
82 | *.pdb
83 | *.pgc
84 | *.pgd
85 | *.rsp
86 | *.sbr
87 | *.tlb
88 | *.tli
89 | *.tlh
90 | *.tmp
91 | *.tmp_proj
92 | *.log
93 | *.vspscc
94 | *.vssscc
95 | .builds
96 | *.pidb
97 | *.svclog
98 | *.scc
99 |
100 | # Chutzpah Test files
101 | _Chutzpah*
102 |
103 | # Visual C++ cache files
104 | ipch/
105 | *.aps
106 | *.ncb
107 | *.opensdf
108 | *.sdf
109 | *.cachefile
110 |
111 | # Visual Studio profiler
112 | *.psess
113 | *.vsp
114 | *.vspx
115 | *.sap
116 |
117 | # TFS 2012 Local Workspace
118 | $tf/
119 |
120 | # Guidance Automation Toolkit
121 | *.gpState
122 |
123 | # ReSharper is a .NET coding add-in
124 | _ReSharper*/
125 | *.[Rr]e[Ss]harper
126 | *.DotSettings.user
127 |
128 | # JustCode is a .NET coding add-in
129 | .JustCode
130 |
131 | # TeamCity is a build add-in
132 | _TeamCity*
133 |
134 | # DotCover is a Code Coverage Tool
135 | *.dotCover
136 |
137 | # NCrunch
138 | _NCrunch_*
139 | .*crunch*.local.xml
140 | nCrunchTemp_*
141 |
142 | # MightyMoose
143 | *.mm.*
144 | AutoTest.Net/
145 |
146 | # Web workbench (sass)
147 | .sass-cache/
148 |
149 | # Installshield output folder
150 | [Ee]xpress/
151 |
152 | # DocProject is a documentation generator add-in
153 | DocProject/buildhelp/
154 | DocProject/Help/*.HxT
155 | DocProject/Help/*.HxC
156 | DocProject/Help/*.hhc
157 | DocProject/Help/*.hhk
158 | DocProject/Help/*.hhp
159 | DocProject/Help/Html2
160 | DocProject/Help/html
161 |
162 | # Click-Once directory
163 | publish/
164 |
165 | # Publish Web Output
166 | *.[Pp]ublish.xml
167 | *.azurePubxml
168 | # TODO: Comment the next line if you want to checkin your web deploy settings
169 | # but database connection strings (with potential passwords) will be unencrypted
170 | *.pubxml
171 | *.publishproj
172 |
173 | # NuGet Packages
174 | *.nupkg
175 | # The packages folder can be ignored because of Package Restore
176 | **/packages/*
177 | # except build/, which is used as an MSBuild target.
178 | !**/packages/build/
179 | # Uncomment if necessary however generally it will be regenerated when needed
180 | #!**/packages/repositories.config
181 |
182 | # Windows Azure Build Output
183 | csx/
184 | *.build.csdef
185 |
186 | # Windows Azure Emulator
187 | efc/
188 | rfc/
189 |
190 | # Windows Store app package directory
191 | AppPackages/
192 |
193 | # Visual Studio cache files
194 | # files ending in .cache can be ignored
195 | *.[Cc]ache
196 | # but keep track of directories ending in .cache
197 | !*.[Cc]ache/
198 |
199 | # Others
200 | ClientBin/
201 | [Ss]tyle[Cc]op.*
202 | ~$*
203 | *~
204 | *.dbmdl
205 | *.dbproj.schemaview
206 | *.pfx
207 | *.publishsettings
208 | node_modules/
209 | orleans.codegen.cs
210 |
211 | # RIA/Silverlight projects
212 | Generated_Code/
213 |
214 | # Backup & report files from converting an old project file
215 | # to a newer Visual Studio version. Backup files are not needed,
216 | # because we have git ;-)
217 | _UpgradeReport_Files/
218 | Backup*/
219 | UpgradeLog*.XML
220 | UpgradeLog*.htm
221 |
222 | # SQL Server files
223 | *.mdf
224 | *.ldf
225 |
226 | # Business Intelligence projects
227 | *.rdl.data
228 | *.bim.layout
229 | *.bim_*.settings
230 |
231 | # Microsoft Fakes
232 | FakesAssemblies/
233 |
234 | # GhostDoc plugin setting file
235 | *.GhostDoc.xml
236 |
237 | # Node.js Tools for Visual Studio
238 | .ntvs_analysis.dat
239 |
240 | # Visual Studio 6 build log
241 | *.plg
242 |
243 | # Visual Studio 6 workspace options file
244 | *.opt
245 |
246 | # Visual Studio LightSwitch build output
247 | **/*.HTMLClient/GeneratedArtifacts
248 | **/*.DesktopClient/GeneratedArtifacts
249 | **/*.DesktopClient/ModelManifest.xml
250 | **/*.Server/GeneratedArtifacts
251 | **/*.Server/ModelManifest.xml
252 | _Pvt_Extensions
253 |
254 | # Paket dependency manager
255 | .paket/paket.exe
256 |
257 | # FAKE - F# Make
258 | .fake/
259 |
260 | *.db
261 | *.opendb
262 |
263 | /ue4/standalone/WindowsNoEditor
264 | /ue4/volumetric_clouds/DerivedDataCache
265 | /ue4/volumetric_clouds/Intermediate
266 | /ue4/volumetric_clouds/Saved
267 | *.shader
268 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/DirectXTex"]
2 | path = lib/DirectXTex
3 | url = https://github.com/Microsoft/DirectXTex.git
4 | [submodule "lib/imgui"]
5 | path = lib/imgui
6 | url = https://github.com/ocornut/imgui.git
7 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Valentin Galea
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # shader box
2 | 
3 |
4 | Various experiments with raytracing and
5 | raymarching done only in pixel (fragment) shaders.
6 |
7 | Written in **GLSL** but supports **C++** and **HLSL** using preprocessor macro tricks.
8 |
9 | C++ is possible due to my other library: [VML](https://github.com/valentingalea/vml)
10 | (NOTE: needs to be placed outside this repo, in the same parent folder)
11 |
12 | ## Projects
13 | The various submodules are enabled via global defines:
14 |
15 | Project define | Description | Live on shadertoy.com
16 | ---------------|----------------------------------------------------|-------------------------
17 | APP_PLANET | stylized procedural terrain and clouds | https://www.shadertoy.com/view/ldyXRw
18 | APP_CLOUDS | study of volumetric clouds | https://www.shadertoy.com/view/XtBXDw
19 | APP_VINYL | vinyl turntable animation | https://www.shadertoy.com/view/XtG3DD
20 | APP_EGG | signed distance field raymarcher animation | https://www.shadertoy.com/view/MlsGDf
21 | APP_RAYTRACER | simple PBR raytracer with reflection | https://www.shadertoy.com/view/Xl2XW1
22 | APP_ATMOSPHERE | study of Rayleigh/Mie air scattering | https://www.shadertoy.com/view/XtBXDz
23 |
24 | ## Compiler Support
25 | * Visual Studio C++ 2017 (15.5) +
26 | * GCC 6.x +
27 | * clang 3.6 +
28 |
29 | ## Environment Support
30 | * Android - [C4droid](https://play.google.com/store/apps/details?id=com.n0n3m4.droidc&hl=en_GB)
31 | * Web - [Shadertoy](https://www.shadertoy.com/) and [GLSL Sandbox](http://glslsandbox.com/)
32 | * Desktop - any DirectX 11 HLSL environment; tested with included _hlsltoy_ utility
33 |
34 | ## Features
35 | Over time various things were added and some
36 | can be extracted and used separately.
37 |
38 | * minimal raytracer framework
39 | * minimal Cook-Torrence lighting and material setup
40 | * signed distance field functions and operators
41 | * 2D two bone IK solver
42 | * a library of different noise functions
43 | * Rayleigh/Mie atmospheric scattering solver
44 |
45 | ## Utilities
46 | The `util/` folder contains separate, independent projects:
47 |
48 | Project | Description
49 | ----------|-----------------------------------------------------------------------------------
50 | inclxpnd | a bare-bones #include expander utility to compose files
51 | hlsltoy | minimal one-file DX 11 framework that runs a fullscreen pixel shader
52 | ddsvolgen | 3D noise texture generator
53 |
--------------------------------------------------------------------------------
/prj/shaderbox.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2047
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaderbox", "shaderbox.vcxproj", "{AB8221E4-5804-4577-8DA1-A8D87480F6E8}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inclxpnd", "..\util\inclxpnd\prj\inclxpnd.vcxproj", "{4C4B967A-ABE6-4992-8ED3-27828AC8A3E1}"
9 | EndProject
10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hlsltoy", "..\util\hlsltoy\prj\hlsltoy.vcxproj", "{F663DDF3-DF54-4DB7-B7A1-48B6D4E9EA0D}"
11 | EndProject
12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ddsvolgen", "..\util\ddsvolgen\prj\ddsvolgen.vcxproj", "{204D1B9B-465C-4941-B6A1-39E9E95B8BC2}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|x64 = Debug|x64
17 | Release|x64 = Release|x64
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {AB8221E4-5804-4577-8DA1-A8D87480F6E8}.Debug|x64.ActiveCfg = Debug|x64
21 | {AB8221E4-5804-4577-8DA1-A8D87480F6E8}.Debug|x64.Build.0 = Debug|x64
22 | {AB8221E4-5804-4577-8DA1-A8D87480F6E8}.Release|x64.ActiveCfg = Release|x64
23 | {AB8221E4-5804-4577-8DA1-A8D87480F6E8}.Release|x64.Build.0 = Release|x64
24 | {4C4B967A-ABE6-4992-8ED3-27828AC8A3E1}.Debug|x64.ActiveCfg = Debug|x64
25 | {4C4B967A-ABE6-4992-8ED3-27828AC8A3E1}.Debug|x64.Build.0 = Debug|x64
26 | {4C4B967A-ABE6-4992-8ED3-27828AC8A3E1}.Release|x64.ActiveCfg = Release|x64
27 | {4C4B967A-ABE6-4992-8ED3-27828AC8A3E1}.Release|x64.Build.0 = Release|x64
28 | {F663DDF3-DF54-4DB7-B7A1-48B6D4E9EA0D}.Debug|x64.ActiveCfg = Debug|x64
29 | {F663DDF3-DF54-4DB7-B7A1-48B6D4E9EA0D}.Debug|x64.Build.0 = Debug|x64
30 | {F663DDF3-DF54-4DB7-B7A1-48B6D4E9EA0D}.Release|x64.ActiveCfg = Release|x64
31 | {F663DDF3-DF54-4DB7-B7A1-48B6D4E9EA0D}.Release|x64.Build.0 = Release|x64
32 | {204D1B9B-465C-4941-B6A1-39E9E95B8BC2}.Debug|x64.ActiveCfg = Debug|x64
33 | {204D1B9B-465C-4941-B6A1-39E9E95B8BC2}.Debug|x64.Build.0 = Debug|x64
34 | {204D1B9B-465C-4941-B6A1-39E9E95B8BC2}.Release|x64.ActiveCfg = Release|x64
35 | {204D1B9B-465C-4941-B6A1-39E9E95B8BC2}.Release|x64.Build.0 = Release|x64
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {B1141EB9-4B92-422B-B071-F0BC33717C50}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/prj/shaderbox.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 | {AB8221E4-5804-4577-8DA1-A8D87480F6E8}
15 | practicalraytracer
16 | 10.0
17 |
18 |
19 |
20 | Application
21 | true
22 | v142
23 |
24 |
25 | Application
26 | false
27 | v142
28 | true
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Level4
45 | Disabled
46 | false
47 | ..\src;..\..\vml\test\SDL_app\SDL-1.2.15\include;%(AdditionalIncludeDirectories)
48 | SCR_W8=240;SCR_H8=240;%(PreprocessorDefinitions)
49 | true
50 | false
51 | stdcpp17
52 | Fast
53 | false
54 |
55 |
56 | true
57 | ..\..\vml\test\SDL_app\SDL-1.2.15\lib\x64;%(AdditionalLibraryDirectories)
58 | Console
59 | SDLmain.lib;SDL.lib;%(AdditionalDependencies)
60 |
61 |
62 |
63 |
64 | Level4
65 | MaxSpeed
66 | true
67 | true
68 | false
69 | ..\src;..\..\vml\test\SDL_app\SDL-1.2.15\include;%(AdditionalIncludeDirectories)
70 | true
71 | AdvancedVectorExtensions2
72 | Fast
73 | false
74 | false
75 | false
76 | SCR_W8=240;SCR_H8=240;APP_PLANET;%(PreprocessorDefinitions)
77 | true
78 | stdcpp17
79 |
80 |
81 | true
82 | true
83 | ..\..\vml\test\SDL_app\SDL-1.2.15\lib\x64;%(AdditionalLibraryDirectories)
84 | Console
85 | SDLmain.lib;SDL.lib;%(AdditionalDependencies)
86 | No
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/prj/shaderbox.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
11 |
12 |
13 | {8a4efd42-e905-4f16-9b4a-c246ce0e7357}
14 |
15 |
16 |
17 |
18 | Source Files
19 |
20 |
21 | Source Files
22 |
23 |
24 | Source Files
25 |
26 |
27 | Source Files
28 |
29 |
30 | Source Files
31 |
32 |
33 | Source Files
34 |
35 |
36 | Source Files
37 |
38 |
39 | Source Files
40 |
41 |
42 | Source Files
43 |
44 |
45 | Source Files
46 |
47 |
48 | Source Files
49 |
50 |
51 | Source Files
52 |
53 |
54 | Source Files
55 |
56 |
57 | Source Files
58 |
59 |
60 | Source Files
61 |
62 |
63 | Source Files
64 |
65 |
66 | Source Files
67 |
68 |
69 | Source Files
70 |
71 |
72 | Source Files
73 |
74 |
75 | Source Files
76 |
77 |
78 | Source Files
79 |
80 |
81 | Source Files
82 |
83 |
84 | Source Files
85 |
86 |
87 | Source Files
88 |
89 |
90 | Source Files
91 |
92 |
93 | Source Files\vml%28external%29
94 |
95 |
96 |
97 |
98 | Source Files
99 |
100 |
101 |
102 |
103 | Source Files\vml%28external%29
104 |
105 |
106 |
--------------------------------------------------------------------------------
/src/.c4droid:
--------------------------------------------------------------------------------
1 | #Sun Jul 07 00:12:38 GMT+01:00 2019
2 | binary_fname=shaderbox
3 | run_mode=1
4 | use_cmake=false
5 | sm_names=
6 | qmake_cmd=export PATH\=(c4droid\:GCCROOT)qt/bin/\:$PATH\nqmake -spec android-g++
7 | cmake_cmd=cmake .
8 | prepare_cmds=export PATH\=/busybox-virtual\:(c4droid\:DATADIR)\:(c4droid\:GCCROOT)bin\:(c4droid\:GCCROOT)(c4droid\:PREFIX)/bin/\:$PATH\nexport CC\="(c4droid\:PREFIX)-gcc (c4droid\:PIE) (c4droid\:MAKEMODEARGS)"\nexport CXX\="(c4droid\:PREFIX)-g++ (c4droid\:PIE) (c4droid\:MAKEMODEARGS)"\nexport SHELL\="(c4droid\:DATADIR)sh"\ncd (c4droid\:CURSRCDIR)
9 | comp_mode=1
10 | make_cmd=make CC\="$CC" CXX\="$CXX" SHELL\="$SHELL"
11 | conf_patch=true
12 | conf_cmd=export PATH\=/busybox-virtual\:(c4droid\:DATADIR)\:(c4droid\:GCCROOT)bin\:(c4droid\:GCCROOT)(c4droid\:PREFIX)/bin/\:$PATH\nexport CFLAGS\="-Os -s (c4droid\:PIE)"\nexport CXXFLAGS\="-Os -s (c4droid\:PIE)"\nexport SHELL\="(c4droid\:DATADIR)sh"\nexport CONFIG_SHELL\="sh"\nexport PKG_CONFIG_PATH\=(c4droid\:GCCROOT)(c4droid\:PREFIX)/lib/pkgconfig\ncd (c4droid\:CURSRCDIR)\nfind . -exec touch {} \\;\ncd (c4droid\:BUILDDIR)\n(c4droid\:CURSRCDIR)/configure --host\=(c4droid\:PREFIX) --prefix\=(c4droid\:GCCROOT)(c4droid\:PREFIX) CFLAGS\="$CFLAGS" CXXFLAGS\="$CXXFLAGS" --build\=i686-linux --disable-shared --enable-static\nmake SHELL\="$SHELL"\nmake install SHELL\="$SHELL"
13 | conf_internal=false
14 |
--------------------------------------------------------------------------------
/src/IK.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Inverse Kinematics solvers
3 | // ----------------------------------------------------------------------------
4 |
5 | vec3 ik_2_bone_centered_solver(
6 | _in(vec3) goal,
7 | _in(float) L1,
8 | _in(float) L2
9 | ){
10 | #if 0 // from https://www.shadertoy.com/view/ldlGR7
11 | vec3 q = goal*(0.5 + 0.5*(L1*L1 - L2*L2) / dot(goal, goal));
12 |
13 | float s = L1*L1 - dot(q, q);
14 | s = max(s, 0.0);
15 | q += sqrt(s)*normalize(cross(goal, vec3(0, 0, 1)));
16 |
17 | return q;
18 | #else // naive version with law of cosines
19 | float G = length(goal);
20 |
21 | // tetha is the angle between bone1 and goal direction
22 | // get it from law of cosines applied to the
23 | // triangle with sides: bone1, bone2, pivot_of_bone1<->goal
24 | float cos_theta = (L1*L1 + G*G - L2*L2) / (2.*L1*G);
25 |
26 | // sin^2 + cos^2 = 1 (Pythagoras in unit circle)
27 | float sin_theta = sqrt(1. - cos_theta * cos_theta);
28 |
29 | // rotation matrix by theta amount around the axis
30 | // perpendicular to the plane created by bone1 and bone2
31 | mat3 rot = mat3(
32 | cos_theta, -sin_theta, 0,
33 | sin_theta, cos_theta, 0,
34 | 0, 0, 1.
35 | );
36 |
37 | // get the end of bone1 aka the pivot of bone2
38 | // by getting a vector from the goal direction
39 | // and rotating along with the newly found theta angle
40 | return mul(rot, (normalize(goal) * L1));
41 | #endif
42 | }
43 |
44 | vec3 ik_solver(
45 | _in(vec3) start,
46 | _in(vec3) goal,
47 | _in(float) bone_length_1,
48 | _in(float) bone_length_2
49 | ){
50 | return start + ik_2_bone_centered_solver(
51 | goal - start, bone_length_1, bone_length_2);
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/src/Makefile:
--------------------------------------------------------------------------------
1 | # mini help
2 | # $@ is the name of the file to be made.
3 | # $? is the names of the changed dependents.
4 | # $< the name of the related file that caused the action.
5 | # $* the prefix shared by target and dependent files.
6 |
7 | all: app
8 |
9 | APP = -DAPP_PLANET
10 | SIZE = -DSCR_W8=240 -DSCR_H8=240
11 |
12 | CXXFLAGS += -Wall -std=c++17 -DC4DROID -fsingle-precision-constant
13 | CXXFLAGS += -Ofast -march=native -funroll-loops
14 |
15 | INCLUDES += -I../src -I../../vml/test/SDL_app/SDL-1.2.15/include
16 | LIBS += -lSDL
17 | OUT = shaderbox
18 |
19 | app: app.o
20 | $(CXX) $(CXXFLAGS) -o $(OUT) app.o $(LIBS)
21 | app.o: ../../vml/test/SDL_app/SDL_app.cpp
22 | $(CXX) $(CXXFLAGS) $(INCLUDES) $(APP) $(SIZE) -c -o app.o $<
23 |
24 | clean:
25 | rm *.o
26 | rm $(OUT)
--------------------------------------------------------------------------------
/src/_hlsltoy.cmd:
--------------------------------------------------------------------------------
1 | ..\bin\hlsltoy.exe %1
--------------------------------------------------------------------------------
/src/_inclxpnd.cmd:
--------------------------------------------------------------------------------
1 | ..\bin\inclxpnd.exe %1 > %~n1.shader
--------------------------------------------------------------------------------
/src/app_2d.h:
--------------------------------------------------------------------------------
1 | #include "def.h"
2 |
3 | //#define USE_TEXTURE
4 |
5 | #ifdef USE_TEXTURE
6 | #ifdef __cplusplus
7 | sampler2D u_tex0("", sampler2D::Repeat);
8 | #endif
9 | #ifdef SHADERTOY
10 | #define u_tex0 iChannel0
11 | #endif
12 | #ifdef HLSL
13 | Texture2D u_tex0 : register(t0);
14 | SamplerState u_sampler0 : register(s0);
15 | #endif
16 | #else
17 | #include "util.h"
18 | #endif
19 |
20 |
21 | vec4 sample (
22 | _in(vec2) uv
23 | ){
24 | #ifdef USE_TEXTURE
25 | #ifdef HLSL
26 | return u_tex0.Sample(u_sampler0, uv);
27 | #else
28 | return texture(u_tex0, uv);
29 | #endif
30 | #else
31 | float cb = checkboard_pattern(uv, 2.);
32 | return vec4(cb, cb, cb, 1);
33 | #endif
34 | }
35 |
36 | vec2 perturb_road (
37 | _in(vec2) uv,
38 | _in(float) time
39 | ){
40 | vec2 p = 2.*uv - 1.;
41 |
42 | float s = p.x / abs(p.y);
43 | float t = 1. / abs(p.y);
44 |
45 | return vec2 (s, t - time);
46 | }
47 |
48 | vec2 perturb_tunnel (
49 | _in(vec2) uv,
50 | _in(float) time,
51 | _inout(float) r
52 | ){
53 | vec2 p = 2.*uv - 1.;
54 |
55 | r = sqrt (dot (p, p));
56 | float a = atan (p.y, p.x) + time;
57 |
58 | float s = 1. / r + time;
59 | float t = 4. * (a / PI);
60 |
61 | return vec2 (s, t);
62 | }
63 |
64 | float tent_filter ( // -1 to 1, peak at 0
65 | _in(float) t
66 | ){
67 | return max (1. - abs (t) , 0);
68 | }
69 |
70 | void mainImage(
71 | out vec4 fragColor,
72 | in vec2 fragCoord
73 | ){
74 | vec2 uv = fragCoord / u_res.xy;
75 |
76 | vec2 st;
77 | vec4 color;
78 | float d = 1.;
79 | float t = mod (u_time, 16.);
80 |
81 | if (t < 4.) {
82 | st = perturb_tunnel (uv, u_time, d);
83 | color = sample (st);
84 | color *= d;
85 | }
86 |
87 | if (t > 4. && t < 8.) {
88 | st = perturb_tunnel (uv, 1., d);
89 | vec2 st2 = perturb_road (uv, 1.);
90 | color = sample (mix (st, st2, (t - 4.) / 4.));
91 | color *= d;
92 | }
93 |
94 | if (t > 8. && t < 12.) {
95 | st = perturb_road (uv, u_time);
96 | color = sample (st);
97 | }
98 |
99 | if (t > 12.) {
100 | st = perturb_tunnel (uv, 1., d);
101 | vec2 st2 = perturb_road (uv, 1.);
102 | color = sample (mix (st2, st, (t - 12.) / 4.));
103 | color *= d;
104 | }
105 |
106 | color *= 1. - tent_filter (2.*uv.y - 1.);
107 |
108 | // debug
109 | //color = vec4 (vec2 (fmod (st.x, 1.), fmod (st.y, 1.)),0, 1.);
110 |
111 | fragColor = color;
112 | }
--------------------------------------------------------------------------------
/src/app_atmosphere.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Rayleigh and Mie scattering atmosphere system
3 | //
4 | // implementation of the techniques described here:
5 | // http://www.scratchapixel.com/old/lessons/3d-advanced-lessons/simulating-the-colors-of-the-sky/atmospheric-scattering/
6 | // ----------------------------------------------------------------------------
7 |
8 | #include "def.h"
9 | #include "util.h"
10 | #include "intersect.h"
11 |
12 | #define hg_g (.76)
13 | #include "volumetric.h"
14 |
15 | bool isect_sphere(_in(ray_t) ray, _in(sphere_t) sphere, _inout(float) t0, _inout(float) t1)
16 | {
17 | vec3 rc = sphere.origin - ray.origin;
18 | float radius2 = sphere.radius * sphere.radius;
19 | float tca = dot(rc, ray.direction);
20 | float d2 = dot(rc, rc) - tca * tca;
21 | float thc = sqrt(radius2 - d2);
22 | t0 = tca - thc;
23 | t1 = tca + thc;
24 |
25 | return d2 < radius2;
26 | }
27 |
28 | // scattering coefficients at sea level (m)
29 | _constant(vec3) betaR = vec3(5.5e-6, 13.0e-6, 22.4e-6); // Rayleigh
30 | _constant(vec3) betaM = vec3(21e-6, 21e-6, 21e-6); // Mie
31 |
32 | // scale height (m)
33 | // thickness of the atmosphere if its density were uniform
34 | _constant(float) hR = 7994.0; // Rayleigh
35 | _constant(float) hM = 1200.0; // Mie
36 |
37 | _constant(float) earth_radius = 6360e3; // (m)
38 | _constant(float) atmosphere_radius = 6420e3; // (m)
39 |
40 | _mutable(vec3) sun_dir = vec3(0, 1, 0);
41 | _constant(float) sun_power = 20.0;
42 |
43 | _constant(sphere_t) atmosphere = _begin(sphere_t)
44 | vec3(0, 0, 0), atmosphere_radius, 0
45 | _end;
46 |
47 | _constant(int) num_samples = 16;
48 | _constant(int) num_samples_light = 8;
49 |
50 | bool get_sun_light(
51 | _in(ray_t) ray,
52 | _inout(float) optical_depthR,
53 | _inout(float) optical_depthM
54 | ){
55 | float t0, t1;
56 | isect_sphere(ray, atmosphere, t0, t1);
57 |
58 | float march_pos = 0.;
59 | float march_step = t1 / float(num_samples_light);
60 |
61 | for (int i = 0; i < num_samples_light; i++) {
62 | vec3 sample =
63 | ray.origin +
64 | ray.direction * (march_pos + 0.5 * march_step);
65 | float height = length(sample) - earth_radius;
66 | if (height < 0.)
67 | return false;
68 |
69 | optical_depthR += exp(-height / hR) * march_step;
70 | optical_depthM += exp(-height / hM) * march_step;
71 |
72 | march_pos += march_step;
73 | }
74 |
75 | return true;
76 | }
77 |
78 | vec3 get_incident_light(_in(ray_t) ray)
79 | {
80 | // "pierce" the atmosphere with the viewing ray
81 | float t0, t1;
82 | #ifdef HLSL
83 | [flatten]
84 | #endif
85 | if (!isect_sphere(
86 | ray, atmosphere, t0, t1)) {
87 | return vec3(0., 0., 0.);
88 | }
89 |
90 | float march_step = t1 / float(num_samples);
91 |
92 | // cosine of angle between view and light directions
93 | float mu = dot(ray.direction, sun_dir);
94 |
95 | // Rayleigh and Mie phase functions
96 | // A black box indicating how light is interacting with the material
97 | // Similar to BRDF except
98 | // * it usually considers a single angle
99 | // (the phase angle between 2 directions)
100 | // * integrates to 1 over the entire sphere of directions
101 | float phaseR = rayleigh_phase_func(mu);
102 | float phaseM =
103 | #if 1
104 | henyey_greenstein_phase_func(mu);
105 | #else
106 | schlick_phase_func(mu);
107 | #endif
108 |
109 | // optical depth (or "average density")
110 | // represents the accumulated extinction coefficients
111 | // along the path, multiplied by the length of that path
112 | float optical_depthR = 0.;
113 | float optical_depthM = 0.;
114 |
115 | vec3 sumR = vec3(0, 0, 0);
116 | vec3 sumM = vec3(0, 0, 0);
117 | float march_pos = 0.;
118 |
119 | for (int i = 0; i < num_samples; i++) {
120 | vec3 sample =
121 | ray.origin +
122 | ray.direction * (march_pos + 0.5 * march_step);
123 | float height = length(sample) - earth_radius;
124 |
125 | // integrate the height scale
126 | float hr = exp(-height / hR) * march_step;
127 | float hm = exp(-height / hM) * march_step;
128 | optical_depthR += hr;
129 | optical_depthM += hm;
130 |
131 | // gather the sunlight
132 | ray_t light_ray = _begin(ray_t)
133 | sample,
134 | sun_dir
135 | _end;
136 | float optical_depth_lightR = 0.;
137 | float optical_depth_lightM = 0.;
138 | bool overground = get_sun_light(
139 | light_ray,
140 | optical_depth_lightR,
141 | optical_depth_lightM);
142 |
143 | if (overground) {
144 | vec3 tau =
145 | betaR * (optical_depthR + optical_depth_lightR) +
146 | betaM * 1.1 * (optical_depthM + optical_depth_lightM);
147 | vec3 attenuation = exp(-tau);
148 |
149 | sumR += hr * attenuation;
150 | sumM += hm * attenuation;
151 | }
152 |
153 | march_pos += march_step;
154 | }
155 |
156 | return
157 | sun_power *
158 | (sumR * phaseR * betaR +
159 | sumM * phaseM * betaM);
160 | }
161 |
162 | #define FROM_SPACE 1
163 |
164 | void setup_camera(
165 | _inout(vec3) eye,
166 | _inout(vec3) look_at
167 | ){
168 | #ifdef FROM_SPACE
169 | eye = vec3(0, 0, 0);
170 | look_at = vec3(0, 1, 0);
171 | #else
172 | eye = vec3(0, earth_radius + 1., 0);
173 | look_at = vec3(0, earth_radius + 1.5, -1);
174 | #endif
175 | }
176 |
177 | void setup_scene()
178 | {
179 | mat3 rot = rotate_around_x(-abs(sin(u_time / 2.)) * 90.);
180 | sun_dir = mul(sun_dir, rot);
181 | }
182 |
183 | vec3 render(
184 | _in(ray_t) eye,
185 | _in(vec3) point_cam
186 | ){
187 | vec3 col = vec3(0, 0, 0);
188 |
189 |
190 | #ifdef FROM_SPACE
191 | #ifdef HLSL
192 | #define atan(y, x) atan2(x, y)
193 | #endif
194 | // sky dome angles
195 | vec3 p = point_cam;
196 | float z2 = p.x * p.x + p.y * p.y;
197 | float phi = atan(p.y, p.x);
198 | float theta = acos(1.0 - z2);
199 | vec3 dir = vec3(
200 | sin(theta) * cos(phi),
201 | cos(theta),
202 | sin(theta) * sin(phi));
203 |
204 | ray_t ray = _begin(ray_t)
205 | vec3(0, earth_radius + 1., 0),
206 | dir
207 | _end;
208 |
209 | col = get_incident_light(ray);
210 | #else
211 | plane_t terrain = _begin(plane_t)
212 | vec3 (0, -1, 0),
213 | earth_radius,
214 | 0
215 | _end;
216 |
217 | hit_t hit = no_hit;
218 | intersect_plane (eye, terrain, hit);
219 |
220 | if (hit.t > max_dist) {
221 | col = get_incident_light(eye);
222 | } else {
223 | col = vec3 (.33, .33, .33);
224 | }
225 | #endif
226 |
227 | return col;
228 | }
229 |
230 | #define FOV 1. // 45 degrees
231 | #include "main.h"
232 |
--------------------------------------------------------------------------------
/src/app_clouds.h:
--------------------------------------------------------------------------------
1 | #include "def.h"
2 | #include "util.h"
3 | #include "intersect.h"
4 |
5 | #define hg_g (.2)
6 | #include "volumetric.h"
7 |
8 | //#define SKY_SPHERE
9 | //#define USE_NOISE_TEX
10 |
11 | // ----------------------------------------------------------------------------
12 | // Scene
13 | // ----------------------------------------------------------------------------
14 | #ifdef SKY_SPHERE
15 | _constant(sphere_t) atmosphere = _begin(sphere_t)
16 | vec3(0, atm_ground_y, 0), atm_radius, 0
17 | _end;
18 | #define cld_noise_factor ((1. / atmosphere.radius) * 10.)
19 | #else
20 | #define cld_noise_factor .001
21 | #endif
22 |
23 | void setup_camera(
24 | _inout(vec3) eye,
25 | _inout(vec3) look_at
26 | ){
27 | eye = vec3(0, -.5, 0);
28 | float angle = u_mouse.x * .5;
29 | look_at = mul(rotate_around_y(angle), vec3(0, 0, -1));
30 | }
31 |
32 | void setup_scene()
33 | {
34 | }
35 |
36 | vec3 render_sky_color(
37 | _in(vec3) eye_dir
38 | ){
39 | float sun_amount = max(dot(eye_dir, sun_dir), 0.);
40 |
41 | vec3 sky = mix(vec3(.0, .1, .4), vec3(.3, .6, .8), 1.0 - eye_dir.y);
42 | sky += sun_color * min(pow(sun_amount, 1500.0) * 5.0, 1.0);
43 | sky += sun_color * min(pow(sun_amount, 10.0) * .6, 1.0);
44 |
45 | return abs(sky);
46 | }
47 |
48 | // ----------------------------------------------------------------------------
49 | // Density
50 | // ----------------------------------------------------------------------------
51 | #ifdef USE_NOISE_TEX
52 | Texture2D u_tex : register(t0);
53 | Texture3D u_tex_noise : register(t1);
54 | Texture3D u_tex_noise_2 : register(t2);
55 | SamplerState u_sampler0 : register(s0);
56 | #else
57 | #include "noise_iq.h"
58 | #include "fbm.h"
59 | DECL_FBM_FUNC(fbm, 4, noise_iq(p))
60 | #endif
61 |
62 | float density_func(
63 | _in(vec3) pos_in,
64 | _in(float) height
65 | ){
66 | vec3 pos = pos_in * cld_noise_factor;
67 |
68 | float shape =
69 | #ifdef USE_NOISE_TEX
70 | u_tex_noise.SampleLevel(u_sampler0, pos, 0).r;
71 | #else
72 | fbm(pos * 2.03, 2.64, .5, .5);
73 | #endif
74 |
75 | #ifdef USE_NOISE_TEX
76 | float w =
77 | //fbm_worley_tile(pos, 7., 1., .5);
78 | u_tex_noise_2.SampleLevel(u_sampler0, pos, 0).r;
79 | float ww = mix(w, 1. - w, height);// exp(height) / 3.23);
80 | shape = remap(shape, ww * .7, 1., 0., 1.);
81 | #endif
82 |
83 | const float cov = 1. - cld_coverage;
84 | return shape * smoothstep(cov, cov + .0135, shape);
85 | //return smoothstep(cld_coverage, 1., shape);
86 | }
87 |
88 | // ----------------------------------------------------------------------------
89 | // Volumetrics
90 | // ----------------------------------------------------------------------------
91 | float illuminate_volume(
92 | _in(vec3) origin,
93 | _in(float) height,
94 | _in(vec3) V,
95 | _in(vec3) L
96 | ){
97 | #if 0
98 | float luminance = exp(height) / 2.;
99 | #else
100 | const float dt = cld_thick / float(cld_march_steps);
101 | volume_sampler_t vol = construct_volume(origin);
102 | vol.pos += L * dt; // don't sample just where the main raymarcher is
103 |
104 | #ifdef HLSL
105 | [fastopt] [loop]
106 | #endif
107 | for (int i = 0; i < illum_march_steps; i++) {
108 | vol.height = float(i) / float(illum_march_steps);
109 | float density = density_func(vol.pos, vol.height);
110 |
111 | vol.transmittance *= exp(- density * sigma_scattering * dt);
112 | vol.pos += L * dt;
113 | }
114 |
115 | float luminance = vol.transmittance;
116 | #endif
117 |
118 | #if 0
119 | return luminance;
120 | #else
121 | return luminance * sun_power * henyey_greenstein_phase_func(clamp(dot(L, V), 0., 1.));
122 | #endif
123 | }
124 |
125 | void integrate_volume(
126 | _inout(volume_sampler_t) vol,
127 | _in(vec3) V,
128 | _in(vec3) L,
129 | _in(float) density,
130 | _in(float) dt
131 | ){
132 | if (density < .005) return;
133 |
134 | // change in transmittance (follows Beer-Lambert law)
135 | float T_i = exp(-density * sigma_scattering * dt);
136 | // Update accumulated transmittance
137 | vol.transmittance *= T_i;
138 |
139 | // integrate output radiance (here essentially color)
140 | vol.radiance +=
141 | (density * sigma_scattering) *
142 | illuminate_volume(vol.pos, vol.height, V, L) *
143 | vol.transmittance *
144 | dt;
145 |
146 | // accumulate opacity
147 | vol.alpha += (1. - T_i) * (1. - vol.alpha);
148 | }
149 |
150 | // ----------------------------------------------------------------------------
151 | // Raymarching
152 | // ----------------------------------------------------------------------------
153 | vec4 render_clouds(
154 | _in(ray_t) eye
155 | ){
156 | #ifdef SKY_SPHERE
157 | hit_t hit = no_hit;
158 | intersect_sphere_from_inside(eye, atmosphere, hit);
159 |
160 | vec3 projection = eye.direction;
161 | vec3 origin = hit.origin;
162 | mat3 rot = rotate_around_x(u_time);
163 | origin = mul(rot, origin - atmosphere.origin);
164 | #else
165 | vec3 projection = eye.direction / eye.direction.y;
166 | vec3 origin = eye.origin + projection * 150.;
167 | origin += wind_dir * u_time * (1. / cld_noise_factor);
168 | #endif
169 |
170 | #if 0
171 | vec3 tex = u_tex.Sample(u_sampler0, origin.xz * cld_noise_factor).rgb;
172 | return abs(vec4(tex, 1.));
173 | #endif
174 |
175 | volume_sampler_t cloud = construct_volume(origin);
176 | float t = 0.;
177 | const float dt = cld_thick / float(cld_march_steps);
178 |
179 | #ifdef HLSL
180 | [fastopt] [loop]
181 | #endif
182 | for (int i = 0; i < cld_march_steps; i++) {
183 | cloud.height = float(i) / float(cld_march_steps);
184 |
185 | cloud.pos = cloud.origin + t * projection;
186 | t += dt;
187 |
188 | float density = density_func(cloud.pos, cloud.height);
189 |
190 | integrate_volume(
191 | cloud,
192 | eye.direction,
193 | sun_dir,
194 | density,
195 | dt);
196 |
197 | if (cloud.alpha > .999) break;
198 | }
199 |
200 | float cutoff = dot(eye.direction, vec3(0, 1, 0));
201 | return vec4(cloud.radiance, cloud.alpha * smoothstep(.0, .2, cutoff));
202 | }
203 |
204 | vec3 render(
205 | _in(ray_t) eye_ray,
206 | _in(vec3) point_cam
207 | ){
208 | vec3 sky = render_sky_color(eye_ray.direction);
209 | #ifdef HLSL
210 | [flatten]
211 | #endif
212 | if (dot(eye_ray.direction, vec3(0, 1, 0)) < 0.05) return sky;
213 |
214 | vec4 cld = render_clouds(eye_ray);
215 | vec3 col = mix(sky, cld.rgb, cld.a);
216 |
217 | return abs(col);
218 | }
219 |
220 | #define FOV 1.//tan(radians(30.))
221 | #include "main.h"
--------------------------------------------------------------------------------
/src/app_egg.h:
--------------------------------------------------------------------------------
1 | #include "def.h"
2 | #include "util.h"
3 | #include "IK.h"
4 | #include "sdf.h"
5 |
6 | // ----------------------------------------------------------------------------
7 | // Vectorpark Egg
8 | // ----------------------------------------------------------------------------
9 |
10 | vec3 background(_in(ray_t) ray)
11 | {
12 | return vec3(.1, .1, .7);
13 | }
14 |
15 | void setup_scene()
16 | {
17 | #define mat_debug 0
18 | #define mat_egg 1
19 | #define mat_bike 2
20 | #define mat_ground 3
21 | }
22 |
23 | void setup_camera(_inout(vec3) eye, _inout(vec3) look_at)
24 | {
25 | eye = vec3(.0, .25, 5.25);
26 | look_at = vec3(.0, .25, .0);
27 | }
28 |
29 | vec3 illuminate(_in(hit_t) hit)
30 | {
31 | if (hit.material_id == mat_ground) return vec3(13. / 255., 104. / 255., 0. / 255.);
32 | if (hit.material_id == mat_egg) return vec3(0.9, 0.95, 0.95);
33 | if (hit.material_id == mat_bike) return vec3(.2, .2, .2);
34 | return vec3(1, 1, 1);
35 | }
36 |
37 | #define BEZIER
38 | vec2 sdf(_in(vec3) P)
39 | {
40 | vec3 p = mul(rotate_around_y(u_time * -100.0), P)
41 | - vec3(0, 0.5, 3.5);
42 |
43 | int material = mat_egg;
44 |
45 | float egg_y = 0.65;
46 | #if 1
47 | float egg_m = sd_sphere(p - vec3(0, egg_y, 0), 0.475);
48 | float egg_b = sd_sphere(p - vec3(0, egg_y - 0.45, 0), 0.25);
49 | float egg_t = sd_sphere(p - vec3(0, egg_y + 0.45, 0), 0.25);
50 | float egg_1 = op_blend(egg_m, egg_b, .5);
51 | float egg_2 = op_blend(egg_1, egg_t, .5);
52 | vec2 egg = vec2(egg_2, material);
53 | #else
54 | float s = 1.55;
55 | mat3 scale = mat3(
56 | s, 0, 0,
57 | 0, 1, 0,
58 | 0, 0, 1);
59 | mat3 iscale = mat3(
60 | 1./s, 0, 0,
61 | 0, 1./s, 0,
62 | 0, 0, 1.);
63 | vec2 egg = vec2(
64 | sd_sphere(iscale * (scale * (p - vec3(0, egg_y, 0))), 0.475),
65 | material);
66 | #endif
67 |
68 | vec3 wheel_pos = vec3(0, 1.2, 0);
69 | float pedal_radius = 0.3;
70 | float pedal_speed = 400.;
71 | float pedal_off = 0.2;
72 |
73 | mat3 rot_z = rotate_around_z(-u_time * pedal_speed);
74 | vec3 left_foot_pos = wheel_pos + mul(rot_z, vec3(0., pedal_radius, pedal_off));
75 |
76 | rot_z = rotate_around_z(-u_time * pedal_speed);
77 | vec3 right_foot_pos = wheel_pos + mul(rot_z, vec3(0., -pedal_radius, -pedal_off));
78 |
79 | vec3 side = vec3(0, 0, pedal_off);
80 | float femur = 0.8;
81 | float tibia = 0.75;
82 | float thick = .05;
83 |
84 | vec3 pelvis = vec3(0, 0., 0) + side;
85 | vec3 knee_l = ik_solver(pelvis, left_foot_pos, femur, tibia);
86 | #ifndef BEZIER
87 | vec2 left_leg_a = vec2(
88 | sd_cylinder(p + pelvis, vec3(0., 0., 0.), knee_l - side, thick),
89 | material);
90 | vec2 left_leg_b = vec2(
91 | sd_cylinder(p + knee_l, vec3(0., 0., 0.), left_foot_pos - knee_l, thick),
92 | material);
93 | #endif
94 |
95 | pelvis = vec3(0, 0., 0) - side;
96 | vec3 knee_r = ik_solver(pelvis, right_foot_pos, femur, tibia);
97 | #ifndef BEZIER
98 | vec2 right_leg_a = vec2(
99 | sd_cylinder(p + pelvis, vec3(0., 0., 0.), knee_r + side, thick),
100 | material);
101 | vec2 right_leg_b = vec2(
102 | sd_cylinder(p + knee_r, vec3(0., 0., 0.), right_foot_pos - knee_r, thick),
103 | material);
104 | #endif
105 |
106 | vec2 legs = op_add(
107 | #ifndef BEZIER
108 | vec2(op_blend(left_leg_a.x, left_leg_b.x, .01), material),
109 | op_add(right_leg_a, right_leg_b)
110 | #else
111 | vec2(
112 | sd_bezier(-(vec3(0., 0., 0.) + side), -knee_l, -left_foot_pos, p, thick).x,
113 | material),
114 | vec2(
115 | sd_bezier(-(vec3(0., 0., 0.) - side), -knee_r, -right_foot_pos, p, thick).x,
116 | material)
117 | #endif
118 | );
119 |
120 | vec3 left_toe = normalize(vec3(left_foot_pos.y - knee_l.y, knee_l.x - left_foot_pos.x, 0));
121 | vec2 left_foot = vec2(
122 | sd_cylinder(p + left_foot_pos, vec3(0., 0., 0.), left_toe / 8., thick),
123 | material);
124 |
125 | vec3 right_toe = normalize(vec3(right_foot_pos.y - knee_r.y, knee_r.x - right_foot_pos.x, 0));
126 | vec2 right_foot = vec2(
127 | sd_cylinder(p + right_foot_pos, vec3(0., 0., 0.), right_toe / 8., thick),
128 | material);
129 |
130 | vec2 feet = op_add(left_foot, right_foot);
131 |
132 | vec2 bike = vec2(
133 | sd_torus(p + wheel_pos, 1., .03),
134 | mat_bike);
135 |
136 | vec2 ground = vec2(
137 | sd_plane(P, vec3(0., 1., 0.), wheel_pos.y + 0.5),
138 | mat_ground);
139 |
140 | vec2 _1 = op_add(feet, bike);
141 | vec2 _2 = op_add(egg, _1);
142 | vec2 _3 = op_add(legs, _2);
143 | return op_add(ground, _3);
144 | }
145 |
146 | vec3 sdf_normal(_in(vec3) p)
147 | {
148 | float dt = 0.05;
149 | vec3 x = vec3(dt, 0, 0);
150 | vec3 y = vec3(0, dt, 0);
151 | vec3 z = vec3(0, 0, dt);
152 | return normalize(vec3(
153 | sdf(p + x).r - sdf(p - x).r,
154 | sdf(p + y).r - sdf(p - y).r,
155 | sdf(p + z).r - sdf(p - z).r
156 | ));
157 | }
158 |
159 | #define EPSILON 0.001
160 |
161 | float shadowmarch(_in(ray_t) ray)
162 | {
163 | const int steps = 20;
164 | const float end = 10.;
165 | const float penumbra_factor = 15.;
166 | const float darkest = 0.1;
167 |
168 | float t = 0.;
169 | float umbra = 1.;
170 | for (int i = 0; i < steps; i++) {
171 | vec3 p = ray.origin + ray.direction * t;
172 | vec2 d = sdf(p);
173 |
174 | if (t > end) break;
175 | if (d.x < EPSILON) {
176 | return darkest;
177 | }
178 |
179 | t += d.x;
180 |
181 | // from http://iquilezles.org/www/articles/rmshadows/rmshadows.htm
182 | umbra = min(umbra, penumbra_factor * d.x / t);
183 | }
184 |
185 | return umbra;
186 | }
187 |
188 | _mutable(float) depth = -max_dist;
189 |
190 | vec3 render_scene(_in(ray_t) ray)
191 | {
192 | const int steps = 80;
193 | const float end = 15.;
194 |
195 | float t = 0.;
196 | for (int i = 0; i < steps; i++) {
197 | vec3 p = ray.origin + ray.direction * t;
198 | vec2 d = sdf(p);
199 |
200 | if (t > end) break;
201 | if (d.x < EPSILON) {
202 | hit_t h = _begin(hit_t)
203 | t, // ray length at impact
204 | int(d.y), // material id
205 | vec3(0, 0, 0), // sdf_normal(p),
206 | p // point of impact
207 | _end;
208 |
209 | if (h.material_id == mat_egg || h.material_id == mat_bike) {
210 | depth = max(depth, p.z);
211 | }
212 |
213 | float s = 1.;
214 | #if 1 // soft shadows
215 | if (int(d.y) == mat_ground) {
216 | vec3 sh_dir = vec3(0, 1, 1);
217 | ray_t sh_ray = _begin(ray_t)
218 | p + sh_dir * 0.05, sh_dir
219 | _end;
220 | s = shadowmarch(sh_ray);
221 | }
222 | #endif
223 |
224 | return illuminate(h) * s;
225 | }
226 |
227 | t += d.x;
228 | }
229 |
230 | return background(ray);
231 | }
232 |
233 | vec3 render(
234 | _in(ray_t) eye,
235 | _in(vec3) point_cam
236 | ){
237 | vec3 final_color = render_scene(eye);
238 |
239 | #if 1
240 | // from https://www.shadertoy.com/view/4sjGzc
241 | #define BAR_SEPARATION 0.6
242 | #define BAR_WIDTH 0.05
243 | #define BAR_DEPTH 1.
244 | #define BAR_COLOR vec3(.6, .6, .6)
245 | float bar_factor = 1.0 - smoothstep(0.0, 0.01, abs((abs(point_cam.x) - BAR_SEPARATION)) - BAR_WIDTH);
246 | float depth_factor = 1. - step(BAR_DEPTH, depth);
247 | final_color = mix(final_color, BAR_COLOR, bar_factor * depth_factor);
248 | #endif
249 |
250 | return abs(final_color);
251 | }
252 |
253 | #define FOV 1. // 45 degrees
254 | #include "main.h"
255 |
--------------------------------------------------------------------------------
/src/app_func.h:
--------------------------------------------------------------------------------
1 | #include "def.h"
2 |
3 | #include "../lib/ashima-noise/src/common.glsl"
4 | #include "../lib/ashima-noise/src/classicnoise3d.glsl"
5 | #include "../lib/ashima-noise/src/noise3d.glsl"
6 | #include "../lib/ashima-noise/src/cellular3d.glsl"
7 | #include "noise_worley.h"
8 |
9 | #include "fbm.h"
10 | DECL_FBM_FUNC(fbm_perlin, 4, abs(cnoise(p)))
11 | DECL_FBM_FUNC(fbm_simplex, 4, abs(snoise(p)))
12 | DECL_FBM_FUNC(fbm_worley, 3, (1. - cellular(p).r))
13 |
14 | DECL_FBM_FUNC_TILE(fbm_worley_tile, 4, (1. - (noise_w(p, L).r + .25)))
15 | DECL_FBM_FUNC_TILE(fbm_perlin_tile, 4, abs(pcnoise(p, L)))
16 |
17 | float worley_tex_left(_in(vec3) pos)
18 | {
19 | float w1 = (1. - (noise_w(pos, 4.).r + .015));
20 | float w2 = (1. - (noise_w(pos, 8.).r + .015));
21 | float w3 = (1. - (noise_w(pos, 16.).r + .015));
22 | return w1 * .625 + w2 * .25 + w3 * .125;
23 | }
24 |
25 | float worley_tex_middle(_in(vec3) pos)
26 | {
27 | float w1 = (1. - (noise_w(pos, 8.).r + .015));
28 | float w2 = (1. - (noise_w(pos, 16.).r + .015));
29 | float w3 = (1. - (noise_w(pos, 32.).r + .015));
30 | return w1 * .625 + w2 * .25 + w3 * .125;
31 | }
32 |
33 | float worley_tex_right(_in(vec3) pos)
34 | {
35 | float w1 = (1. - (noise_w(pos, 24.).r + .015));
36 | float w2 = (1. - (noise_w(pos, 32.).r + .015));
37 | float w3 = (1. - (noise_w(pos, 64.).r + .015));
38 | return w1 * .625 + w2 * .25 + w3 * .125;
39 | }
40 |
41 | float worley_fbm(_in(vec3) pos)
42 | {
43 | float w1 = worley_tex_left(pos);
44 | float w2 = worley_tex_middle(pos);
45 | float w3 = worley_tex_right(pos);
46 | return w1 * .625 + w2 * .25 + w3 * .125;
47 | }
48 |
49 | #define SCALE 1.
50 | #define D (.0125 * SCALE)
51 |
52 | vec3 plot(
53 | _in(float) f,
54 | _in(float) x,
55 | _in(vec3) color
56 | ){
57 | float y = smoothstep (f-D, f+D, x);
58 | y *= 1.- y;
59 |
60 | return y * color * 5.;
61 | }
62 |
63 | void mainImage(
64 | _out(vec4) fragColor,
65 | #ifdef SHADERTOY
66 | vec2 fragCoord
67 | #else
68 | _in(vec2) fragCoord
69 | #endif
70 | ){
71 | // go from [0..resolution] to [0..1]
72 | vec2 t = (fragCoord.xy + .5) / u_res.xy;
73 | #ifdef HLSL
74 | t.y = 1. - t.y;
75 | #endif
76 |
77 | vec3 col = vec3(0, 0, 0);
78 |
79 | #if 1 // 2D
80 | vec3 pos = vec3(t, 0);
81 | float n =
82 | //fbm_worley_tile(pos, 2, 1., .5);
83 | worley_fbm(pos);
84 |
85 | col += vec3(n, n, n);
86 | #else // 1D
87 |
88 | // optional: center around origin by going to [-1, +1] and scale
89 | t = (t * 2. - 1.) * SCALE;
90 |
91 | // plot the axes
92 | col += plot(0., t.y, vec3(1, 1, 1));
93 | col += plot(t.x, 0., vec3(1, 1, 1));
94 |
95 | // optional: animate
96 | t.x += u_time * SCALE;
97 |
98 | // plot custom functions
99 | //col += plot(sin(t.x), t.y, vec3(1, 0, 0));
100 | //col += plot(cos(t.x), t.y, vec3(0, 1, 0));
101 | //col += plot(abs(t.x), t.y, vec3(0, 0, 1));
102 |
103 | vec3 pos = vec3(t.x, 0, 0);
104 | col += plot(fbm_perlin(pos, 2., .5, .5), t.y, vec3(1, 0, 0));
105 | col += plot(fbm_simplex(pos, 2., .5, .5), t.y, vec3(0, 1, 0));
106 | //col += plot(fbm_worley(pos, 2., .5, .5), t.y, vec3(0, 0, 1));
107 |
108 | #endif
109 | // output
110 | fragColor = vec4 (col, 1);
111 | }
--------------------------------------------------------------------------------
/src/app_planet.h:
--------------------------------------------------------------------------------
1 | #include "def.h"
2 | #include "util.h"
3 | #include "intersect.h"
4 |
5 | #define hg_g (.76)
6 | #include "volumetric.h"
7 |
8 | #include "noise_iq.h"
9 | #define noise(x) noise_iq(x)
10 |
11 | #include "fbm.h"
12 |
13 | // ----------------------------------------------------------------------------
14 | // Planet
15 | // ----------------------------------------------------------------------------
16 | _constant(sphere_t) planet = _begin(sphere_t)
17 | vec3(0, 0, 0), 1., 0
18 | _end;
19 |
20 | #define max_height .4
21 | #define max_ray_dist (max_height * 4.)
22 |
23 | vec3 background(
24 | _in(ray_t) eye
25 | ){
26 | #if 0
27 | return vec3(.15, .3, .4);
28 | #else
29 | _constant(vec3) sun_color = vec3(1., .9, .55);
30 | float sun_amount = clamp(dot(eye.direction, vec3(0, 0, 1)), 0., 1.);
31 |
32 | vec3 sky = mix(
33 | vec3(.0, .05, .2),
34 | vec3(.15, .3, .4),
35 | 1.0 - eye.direction.y);
36 | sky += sun_color * clamp(pow(sun_amount, 30.0) * 5.0, 0., 1.);
37 | sky += sun_color * clamp(pow(sun_amount, 10.0) * .6, 0., 1.);
38 |
39 | return abs(sky);
40 | #endif
41 | }
42 |
43 | void setup_scene()
44 | {
45 | }
46 |
47 | void setup_camera(
48 | _inout(vec3) eye,
49 | _inout(vec3) look_at
50 | ){
51 | #if 0
52 | eye = vec3(.0, 0, -1.93);
53 | look_at = vec3(-.1, .9, 2);
54 | #else
55 | eye = vec3(0, 0, -2.5);
56 | look_at = vec3(0, 0, 2);
57 | #endif
58 | }
59 |
60 | // ----------------------------------------------------------------------------
61 | // Clouds
62 | // ----------------------------------------------------------------------------
63 | #define CLOUDS
64 |
65 | #define anoise (abs(noise(p) * 2. - 1.))
66 | DECL_FBM_FUNC(fbm_clouds, 4, anoise)
67 |
68 | #define vol_coeff_absorb 30.034
69 | _mutable(volume_sampler_t) cloud;
70 |
71 | float illuminate_volume(
72 | _inout(volume_sampler_t) cloud,
73 | _in(vec3) V,
74 | _in(vec3) L
75 | ){
76 | return exp(cloud.height) / .055;
77 | }
78 |
79 | void integrate_volume(
80 | _inout(volume_sampler_t) vol,
81 | _in(vec3) V,
82 | _in(vec3) L,
83 | _in(float) density,
84 | _in(float) dt
85 | ){
86 | // change in transmittance (follows Beer-Lambert law)
87 | float T_i = exp(-vol_coeff_absorb * density * dt);
88 | // Update accumulated transmittance
89 | vol.transmittance *= T_i;
90 |
91 | // integrate output radiance (here essentially color)
92 | vol.radiance +=
93 | density *
94 | illuminate_volume(vol, V, L) *
95 | vol.transmittance *
96 | dt;
97 |
98 | // accumulate opacity
99 | vol.alpha += (1. - T_i) * (1. - vol.alpha);
100 | }
101 |
102 | void clouds_map(
103 | _inout(volume_sampler_t) cloud,
104 | _in(float) t_step
105 | ){
106 | float dens = fbm_clouds(
107 | cloud.pos * 3.2343 + vec3(.35, 13.35, 2.67),
108 | 2.0276, .5, .5);
109 |
110 | #define cld_coverage .29475675 // higher=less clouds
111 | #define cld_fuzzy .0335 // higher=fuzzy, lower=blockier
112 | dens *= smoothstep(cld_coverage, cld_coverage + cld_fuzzy, dens);
113 |
114 | dens *= band(.2, .35, .65, cloud.height);
115 |
116 | integrate_volume(cloud,
117 | cloud.pos, cloud.pos, // unused dummies
118 | dens, t_step);
119 | }
120 |
121 | void clouds_march(
122 | _in(ray_t) eye,
123 | _inout(volume_sampler_t) cloud,
124 | _in(float) max_travel,
125 | _in(mat3) rot
126 | ){
127 | const int steps = 75;
128 | const float t_step = max_ray_dist / float(steps);
129 | float t = 0.;
130 |
131 | for (int i = 0; i < steps; i++) {
132 | if (t > max_travel || cloud.alpha >= 1.) return;
133 |
134 | vec3 o = cloud.origin + t * eye.direction;
135 | cloud.pos = mul(rot, o - planet.origin);
136 |
137 | cloud.height = (length(cloud.pos) - planet.radius) / max_height;
138 | t += t_step;
139 | clouds_map(cloud, t_step);
140 | }
141 | }
142 |
143 | void clouds_shadow_march(
144 | _in(vec3) dir,
145 | _inout(volume_sampler_t) cloud,
146 | _in(mat3) rot
147 | ){
148 | const int steps = 5;
149 | const float t_step = max_height / float(steps);
150 | float t = 0.;
151 |
152 | for (int i = 0; i < steps; i++) {
153 | vec3 o = cloud.origin + t * dir;
154 | cloud.pos = mul(rot, o - planet.origin);
155 |
156 | cloud.height = (length(cloud.pos) - planet.radius) / max_height;
157 | t += t_step;
158 | clouds_map(cloud, t_step);
159 | }
160 | }
161 |
162 | // ----------------------------------------------------------------------------
163 | // Terrain
164 | // ----------------------------------------------------------------------------
165 | #define TERR_STEPS 120
166 | #define TERR_EPS .005
167 | #define rnoise (1. - abs(noise(p) * 2. - 1.))
168 |
169 | DECL_FBM_FUNC(fbm_terr, 3, noise(p))
170 | DECL_FBM_FUNC(fbm_terr_r, 3, rnoise)
171 |
172 | DECL_FBM_FUNC(fbm_terr_normals, 7, noise(p))
173 | DECL_FBM_FUNC(fbm_terr_r_normals, 7, rnoise)
174 |
175 | vec2 sdf_terrain_map(_in(vec3) pos)
176 | {
177 | float h0 = fbm_terr(pos * 2.0987, 2.0244, .454, .454);
178 | float n0 = smoothstep(.35, 1., h0);
179 |
180 | float h1 = fbm_terr_r(pos * 1.50987 + vec3(1.9489, 2.435, .5483), 2.0244, .454, .454);
181 | float n1 = smoothstep(.6, 1., h1);
182 |
183 | float n = n0 + n1;
184 |
185 | return vec2(length(pos) - planet.radius - n * max_height, n / max_height);
186 | }
187 |
188 | vec2 sdf_terrain_map_detail(_in(vec3) pos)
189 | {
190 | float h0 = fbm_terr_normals(pos * 2.0987, 2.0244, .454, .454);
191 | float n0 = smoothstep(.35, 1., h0);
192 |
193 | float h1 = fbm_terr_r_normals(pos * 1.50987 + vec3(1.9489, 2.435, .5483), 2.0244, .454, .454);
194 | float n1 = smoothstep(.6, 1., h1);
195 |
196 | float n = n0 + n1;
197 |
198 | return vec2(length(pos) - planet.radius - n * max_height, n / max_height);
199 | }
200 |
201 | vec3 sdf_terrain_normal(_in(vec3) p)
202 | {
203 | #define F(t) sdf_terrain_map_detail(t).x
204 | vec3 dt = vec3(0.001, 0, 0);
205 |
206 | return normalize(vec3(
207 | F(p + dt.xzz) - F(p - dt.xzz),
208 | F(p + dt.zxz) - F(p - dt.zxz),
209 | F(p + dt.zzx) - F(p - dt.zzx)
210 | ));
211 | #undef F
212 | }
213 |
214 | // ----------------------------------------------------------------------------
215 | // Lighting
216 | // ----------------------------------------------------------------------------
217 | vec3 setup_lights(
218 | _in(vec3) L,
219 | _in(vec3) normal
220 | ){
221 | vec3 diffuse = vec3(0, 0, 0);
222 |
223 | // key light
224 | vec3 c_L = vec3(7, 5, 3);
225 | diffuse += max(0., dot(L, normal)) * c_L;
226 |
227 | // fill light 1 - faked hemisphere
228 | float hemi = clamp(.25 + .5 * normal.y, .0, 1.);
229 | diffuse += hemi * vec3(.4, .6, .8) * .2;
230 |
231 | // fill light 2 - ambient (reversed key)
232 | float amb = clamp(.12 + .8 * max(0., dot(-L, normal)), 0., 1.);
233 | diffuse += amb * vec3(.4, .5, .6);
234 |
235 | return diffuse;
236 | }
237 |
238 | vec3 illuminate(
239 | _in(vec3) pos,
240 | _in(vec3) eye,
241 | _in(mat3) local_xform,
242 | _in(vec2) df
243 | ){
244 | // current terrain height at position
245 | float h = df.y;
246 | //return vec3 (h);
247 |
248 | vec3 w_normal = normalize(pos);
249 | #define LIGHT
250 | #ifdef LIGHT
251 | vec3 normal = sdf_terrain_normal(pos);
252 | float N = dot(normal, w_normal);
253 | #else
254 | float N = w_normal.y;
255 | #endif
256 |
257 | // materials
258 | #define c_water vec3(.015, .110, .455)
259 | #define c_grass vec3(.086, .132, .018)
260 | #define c_beach vec3(.153, .172, .121)
261 | #define c_rock vec3(.080, .050, .030)
262 | #define c_snow vec3(.600, .600, .600)
263 |
264 | // limits
265 | #define l_water .05
266 | #define l_shore .17
267 | #define l_grass .211
268 | #define l_rock .351
269 |
270 | float s = smoothstep(.4, 1., h);
271 | vec3 rock = mix(
272 | c_rock, c_snow,
273 | smoothstep(1. - .3*s, 1. - .2*s, N));
274 |
275 | vec3 grass = mix(
276 | c_grass, rock,
277 | smoothstep(l_grass, l_rock, h));
278 |
279 | vec3 shoreline = mix(
280 | c_beach, grass,
281 | smoothstep(l_shore, l_grass, h));
282 |
283 | vec3 water = mix(
284 | c_water / 2., c_water,
285 | smoothstep(0., l_water, h));
286 |
287 | #ifdef LIGHT
288 | vec3 L = mul(local_xform, normalize(vec3(1, 1, 0)));
289 | shoreline *= setup_lights(L, normal);
290 | vec3 ocean = setup_lights(L, w_normal) * water;
291 | #else
292 | vec3 ocean = water;
293 | #endif
294 |
295 | return mix(
296 | ocean, shoreline,
297 | smoothstep(l_water, l_shore, h));
298 | }
299 |
300 | // ----------------------------------------------------------------------------
301 | // Rendering
302 | // ----------------------------------------------------------------------------
303 | vec3 render(
304 | _in(ray_t) eye,
305 | _in(vec3) point_cam
306 | ){
307 | mat3 rot_y = rotate_around_y(27.);
308 | mat3 rot = mul(rotate_around_x(u_time * -12.), rot_y);
309 | mat3 rot_cloud = mul(rotate_around_x(u_time * 8.), rot_y);
310 |
311 | sphere_t atmosphere = planet;
312 | atmosphere.radius += max_height;
313 |
314 | hit_t hit = no_hit;
315 | intersect_sphere(eye, atmosphere, hit);
316 | #ifdef HLSL
317 | [flatten]
318 | #endif
319 | if (hit.material_id < 0) {
320 | return background(eye);
321 | }
322 |
323 | float t = 0.;
324 | vec2 df = vec2(1, max_height);
325 | vec3 pos;
326 | float max_cld_ray_dist = max_ray_dist;
327 |
328 | for (int i = 0; i < TERR_STEPS; i++) {
329 | if (t > max_ray_dist) break;
330 |
331 | vec3 o = hit.origin + t * eye.direction;
332 | pos = mul(rot, o - planet.origin);
333 |
334 | df = sdf_terrain_map(pos);
335 |
336 | if (df.x < TERR_EPS) {
337 | max_cld_ray_dist = t;
338 | break;
339 | }
340 |
341 | t += df.x * .4567;
342 | }
343 |
344 | #ifdef CLOUDS
345 | cloud = construct_volume(hit.origin);
346 | clouds_march(eye, cloud, max_cld_ray_dist, rot_cloud);
347 | #endif
348 |
349 | if (df.x < TERR_EPS) {
350 | vec3 c_terr = illuminate(pos, eye.direction, rot, df);
351 | vec3 c_cld = cloud.radiance;
352 | float alpha = cloud.alpha;
353 | float shadow = 1.;
354 |
355 | #ifdef CLOUDS // clouds ground shadows
356 | pos = mul(transpose(rot), pos);
357 | cloud = construct_volume(pos);
358 | vec3 local_up = normalize(pos);
359 | clouds_shadow_march(local_up, cloud, rot_cloud);
360 | shadow = mix(.7, 1., step(cloud.alpha, 0.33));
361 | #endif
362 |
363 | return abs(mix(c_terr * shadow, c_cld, alpha));
364 | } else {
365 | return abs(mix(background(eye), cloud.radiance, cloud.alpha));
366 | }
367 | }
368 |
369 | #define FOV tan(radians(30.))
370 | #include "main.h"
--------------------------------------------------------------------------------
/src/app_raytracer.h:
--------------------------------------------------------------------------------
1 | #include "def.h"
2 | #include "util.h"
3 | #include "util_optics.h"
4 | #include "material.h"
5 | #include "light.h"
6 | #include "intersect.h"
7 | #include "cornell_box.h"
8 |
9 | // ----------------------------------------------------------------------------
10 | // Raytracer
11 | // ----------------------------------------------------------------------------
12 |
13 | vec3 background(_in(ray_t) ray)
14 | {
15 | return vec3(0, 0, 0);
16 | }
17 |
18 | void setup_scene()
19 | {
20 | materials[mat_debug].base_color = vec3(1., 1., 1.);
21 | materials[mat_debug].metallic = 0.;
22 | materials[mat_debug].roughness = 0.;
23 | materials[mat_debug].ior = 1.;
24 | materials[mat_debug].reflectivity = 0.;
25 | materials[mat_debug].translucency = 0.;
26 |
27 | setup_cornell_box();
28 |
29 | #if 1
30 | float _sin = sin(u_time);
31 | float _cos = cos(u_time);
32 | cb_spheres[cb_sphere_left].origin += vec3(0, abs(_sin), _cos + 1.);
33 | cb_spheres[cb_sphere_right].origin.z = 0.;// += vec3(0, abs(_cos), _cos);
34 | lights[0].L.z = 1.5;
35 | #endif
36 | }
37 |
38 | void setup_camera(_inout(vec3) eye, _inout(vec3) look_at)
39 | {
40 | vec2 mouse = u_mouse.x < BIAS ? vec2(0, 0) : 2. * (u_res.xy / u_mouse.xy) - 1.;
41 | mat3 rot_y = rotate_around_y(mouse.x * 30.);
42 | eye = mul(rot_y, vec3(0, cb_plane_dist, 2.333 * cb_plane_dist));
43 | look_at = vec3(0, cb_plane_dist, 0);
44 | }
45 |
46 | vec3 illuminate(_in(vec3) eye, _in(hit_t) hit) // TODO: find a way to account for more light types
47 | {
48 | material_t mat = get_material(hit.material_id);
49 |
50 | // special case for debug stuff - just solid paint it
51 | if (hit.material_id == mat_debug) {
52 | return materials[mat_debug].base_color;
53 | }
54 |
55 | vec3 accum = ambient_light; // really cheap equivalent for indirect light
56 |
57 | vec3 V = normalize(eye - hit.origin); // view direction
58 | vec3 L = get_light_direction(lights[0], hit);
59 |
60 | // TODO: more lights
61 | #if 0
62 | accum += illum_blinn_phong(V, L, hit, mat);
63 | #else
64 | accum += illum_cook_torrance(V, L, hit, mat);
65 | #endif
66 |
67 | return accum;
68 | }
69 |
70 | hit_t raytrace_iteration(_in(ray_t) ray, _in(int) mat_to_ignore)
71 | {
72 | hit_t hit = no_hit;
73 | int i;
74 |
75 | for (i = 0; i < num_cb_planes; ++i) {
76 | intersect_plane(ray, cb_planes[i], hit);
77 | }
78 |
79 | for (i = 0; i < num_cb_spheres; ++i) {
80 | if (cb_spheres[i].material != mat_to_ignore) {
81 | intersect_sphere(ray, cb_spheres[i], hit);
82 | }
83 | }
84 |
85 | return hit;
86 | }
87 |
88 | vec3 render(
89 | _in(ray_t) primary_ray,
90 | _in(vec3) point_cam
91 | ){
92 | vec3 color = vec3(0, 0, 0);
93 | vec3 accum = vec3(1, 1, 1);
94 | ray_t ray = primary_ray;
95 |
96 | for (int i = 0; i < 2; i++) {
97 | hit_t hit = raytrace_iteration(ray, mat_invalid);
98 |
99 | if (hit.t >= max_dist) {
100 | color += accum * background(ray);
101 | break;
102 | }
103 |
104 | float f = fresnel_factor(1., 1., dot(hit.normal, -ray.direction));
105 | color += (1. - f) * accum * illuminate(primary_ray.origin, hit);
106 |
107 | #if 1 // shadow ray
108 | if (i == 0) {
109 | vec3 shadow_line = lights[0].L - hit.origin; // TODO: more light types
110 | vec3 shadow_dir = normalize(shadow_line);
111 |
112 | ray_t shadow_trace = _begin(ray_t)
113 | hit.origin + shadow_dir * BIAS,
114 | shadow_dir
115 | _end;
116 | hit_t shadow_hit = raytrace_iteration(shadow_trace, mat_debug);
117 |
118 | if (shadow_hit.t < length(shadow_line)) {
119 | color *= 0.1;
120 | }
121 | }
122 | #endif
123 |
124 | material_t mat = get_material(hit.material_id);
125 | if (mat.reflectivity > 0.) {
126 | accum *= f;
127 | vec3 reflect_dir = normalize(reflect(hit.normal, ray.direction));
128 | ray.origin = hit.origin + reflect_dir * BIAS;
129 | ray.direction = reflect_dir;
130 | } else {
131 | break;
132 | }
133 | }
134 |
135 | return color;
136 | }
137 |
138 | #define FOV tan(radians(30.))
139 | #include "main.h"
--------------------------------------------------------------------------------
/src/app_sdf_ao.h:
--------------------------------------------------------------------------------
1 | #include "def.h"
2 | #include "util.h"
3 | #include "sdf.h"
4 |
5 | // ----------------------------------------------------------------------------
6 | // Distance Fields Ambient Occlusion
7 | // ----------------------------------------------------------------------------
8 |
9 | vec3 background(_in(ray_t) ray)
10 | {
11 | return vec3(.1, .1, .7);
12 | }
13 |
14 | #define mat_debug 0
15 | #define mat_ground 1
16 | #define mat_pipe 2
17 | #define mat_bottom 3
18 | #define mat_deck 4
19 | #define mat_coping 5
20 | #define mat_count 6
21 | _mutable(vec3) materials[mat_count];
22 |
23 | vec3 get_material(_in(int) index)
24 | {
25 | vec3 mat;
26 | for (int i = 0; i < mat_count; ++i) {
27 | if (i == index) {
28 | mat = materials[i];
29 | break;
30 | }
31 | }
32 | return mat;
33 | }
34 |
35 | void setup_scene()
36 | {
37 | materials[mat_debug] = vec3(1, 1, 1);
38 | materials[mat_ground] = vec3(0, .2, 0);
39 | materials[mat_pipe] = vec3(.1, .1, .1);
40 | materials[mat_bottom] = materials[mat_pipe];
41 | materials[mat_deck] = materials[mat_pipe];
42 | materials[mat_coping] = vec3(.4, .4, .4);
43 | }
44 |
45 | void setup_camera(_inout(vec3) eye, _inout(vec3) look_at)
46 | {
47 | mat3 rot = rotate_around_y (u_time * 50.);
48 | eye = mul(rot, vec3(0, 3, 5));
49 | look_at = vec3(0, 0, 0);
50 | }
51 |
52 | _constant(vec3) size = vec3(1.3, 1., 1.25);
53 |
54 | vec2 sdf_pipe(_in(vec3) pos)
55 | {
56 | // origin
57 | // ramp(box and cylinder)
58 | vec3 p = pos - vec3(0, size.y, 0);
59 |
60 | float b = sd_box(p, size);
61 |
62 | p -= vec3(.7, .5, 0);
63 | p = mul(p, rotate_around_x(-90.));
64 | float c = sd_y_cylinder(p,
65 | size.y + .55, // radius
66 | 2. * size.z + .1); // height
67 |
68 | vec2 pipe = vec2(
69 | op_sub(b, c),
70 | mat_pipe);
71 |
72 | // revert
73 | // coping bars
74 | p = pos - vec3(0, size.y, 0);
75 |
76 | p -= vec3(-size.x + .525, size.y, 0);
77 | p = mul(p, rotate_around_x(-90.));
78 | vec2 coping = vec2(
79 | sd_y_cylinder(p,
80 | .025, // radius
81 | 2. * size.z), // height
82 | mat_coping);
83 |
84 | // revert
85 | // the deck railing
86 | p = pos - vec3(0, size.y * 2., 0);
87 |
88 | float rail = sd_box(
89 | p + vec3(size.x, -.25, 0),
90 | vec3(.025, .05, size.z));
91 |
92 | const vec3 B = vec3(.025, .125, .025);
93 | const float H = -.125;
94 | float bar_1 = sd_box(p + vec3(size.x, H, 0), B);
95 | float bar_2 = sd_box(p + vec3(size.x, H, size.z / 2.), B);
96 | float bar_3 = sd_box(p + vec3(size.x, H, size.z), B);
97 | float bar_4 = sd_box(p + vec3(size.x, H, -size.z / 2.), B);
98 | float bar_5 = sd_box(p + vec3(size.x, H, -size.z), B);
99 | float b_a = op_add(bar_1, bar_2);
100 | float b_b = op_add(b_a, bar_3);
101 | float b_c = op_add(bar_4, bar_5);
102 | float b_d = op_add(b_b, b_c);
103 | float bars = b_d;
104 |
105 | vec2 railing = vec2(
106 | op_add(rail, bars),
107 | mat_deck);
108 | vec2 deck = op_add(railing, coping);
109 |
110 | return op_add(pipe, deck);
111 | }
112 |
113 | vec2 sdf(_in(vec3) pos)
114 | {
115 | // NOTE: everything is centered around origin
116 | // change coord frame by offseting
117 | // with inverse then doing
118 | // the opposite before next
119 | // effectively doing push/pop
120 |
121 | // NOTE: all measurements are in halfs
122 | // due to the above
123 |
124 | const float B = .15;
125 | vec3 p = pos -vec3(0, B, 0);
126 |
127 | vec2 bottom = vec2(
128 | sd_box(p, vec3(2.25 * size.x, B, size.z)),
129 | mat_bottom);
130 |
131 | vec2 pipe1 = sdf_pipe(p + vec3(1.25 * size.x, 0, 0));
132 |
133 | p -= vec3(1.25 * size.x, 0, 0);
134 | p = mul(p, rotate_around_y(180.));
135 | vec2 pipe2 = sdf_pipe(p);
136 |
137 | vec2 pipe = op_add(pipe1, pipe2);
138 |
139 | vec2 ref = vec2(
140 | sd_box(pos, vec3(.025, 15, .025)),
141 | mat_debug);
142 |
143 | vec2 ground = vec2(
144 | sd_plane(pos, vec3(0, 1, 0), 0.),
145 | mat_ground);
146 |
147 | vec2 g = op_add(ground, ref);
148 | vec2 b = op_add(pipe, bottom);
149 | return op_add(b, g);
150 | }
151 |
152 | vec3 sdf_normal(_in(vec3) p)
153 | {
154 | float dt = 0.001;
155 | vec3 x = vec3(dt, 0, 0);
156 | vec3 y = vec3(0, dt, 0);
157 | vec3 z = vec3(0, 0, dt);
158 | return normalize(vec3(
159 | sdf(p + x).r - sdf(p - x).r,
160 | sdf(p + y).r - sdf(p - y).r,
161 | sdf(p + z).r - sdf(p - z).r
162 | ));
163 | }
164 |
165 | vec3 sdf_ao(_in(hit_t) hit)
166 | {
167 | const float dt = .5;
168 | const int steps = 5;
169 | float d = 0.;
170 | float occlusion = 0.;
171 |
172 | for (float i = 1.; i <= float(steps); i += 1.) {
173 | vec3 p = hit.origin + dt * i * hit.normal;
174 | d = sdf (p).x;
175 |
176 | occlusion += 1. / pow(2., i) * (dt * i - d);
177 | }
178 |
179 | float c = 1. - clamp(occlusion, 0., 1.);
180 | return vec3 (c, c, c);
181 | }
182 |
183 | float sdf_shadow(_in(ray_t) ray)
184 | {
185 | const int steps = 20;
186 | const float end = 20.;
187 | const float penumbra_factor = 32.;
188 | const float darkest = .05;
189 | float t = 0.;
190 | float umbra = 1.;
191 |
192 | for (int i = 0; i < steps; i++) {
193 | vec3 p = ray.origin + ray.direction * t;
194 | vec2 d = sdf(p);
195 |
196 | if (t > end) break;
197 | if (d.x < .005) {
198 | return darkest;
199 | }
200 |
201 | t += d.x;
202 | // from http://iquilezles.org/www/articles/rmshadows/rmshadows.htm
203 | umbra = min(umbra, penumbra_factor * d.x / t);
204 | }
205 |
206 | return umbra;
207 | }
208 |
209 | _constant(vec3) sun_dir = normalize (vec3 (1, 2, 1));
210 |
211 | vec3 illuminate(
212 | _in(vec3) eye,
213 | _in(hit_t) hit,
214 | _in(float) ao,
215 | _in(float) sh
216 | ) {
217 | #if 0 // debug: output the raymarching steps
218 | return vec3(hit.normal);
219 | #endif
220 | vec3 V = normalize(eye - hit.origin); // view direction
221 | vec3 accum = vec3(0, 0, 0);
222 |
223 | // key light - the sun
224 | float sun_ray = max(0., dot(sun_dir, hit.normal));
225 | accum += sh * sun_ray * vec3(1.2, 1.3, 1.);
226 |
227 | // fill light 1 - hemisphere (faked)
228 | float h = hit.normal.y;
229 | accum += ao * h * vec3(.15, .15, .4);
230 |
231 | // fill light 2 - indirect
232 | float ind = max(0., dot(sun_dir * vec3(-1, 0, -1), hit.normal));
233 | accum += ao * ind * vec3(.4, .28, .2);
234 |
235 | // base diffuse color
236 | vec3 mat_c = get_material(hit.material_id);
237 | if (hit.material_id == mat_ground) {
238 | float cb = checkboard_pattern(hit.origin.xz, .5);
239 | mat_c = mix(mat_c - .15 * mat_c, mat_c + .15 * mat_c, cb);
240 | }
241 |
242 | return accum * mat_c;
243 | }
244 |
245 | vec4 render_impl(
246 | _in(ray_t) ray,
247 | _in(vec3) point_cam
248 | ){
249 | const int steps = 70;
250 | const float end = 20.;
251 |
252 | float t = 0.;
253 | for (int i = 0; i < steps; i++) {
254 | vec3 p = ray.origin + ray.direction * t;
255 | vec2 d = sdf(p);
256 |
257 | if (t > end) break;
258 | if (d.x < .005) {
259 | hit_t h = _begin(hit_t)
260 | t, // ray length at impact
261 | int(d.y), // material id
262 | sdf_normal(p),
263 | p // point of impact
264 | _end;
265 |
266 | float ao = sdf_ao (h).x;
267 |
268 | float sh = 1.;
269 | #if 0
270 | ray_t sh_ray = _begin(ray_t)
271 | p + sun_dir * 0.05, sun_dir
272 | _end;
273 | sh = sdf_shadow (sh_ray);
274 | #endif
275 |
276 | return vec4(
277 | illuminate(ray.origin, h, ao, sh),
278 | t);
279 | }
280 |
281 | t += d.x;
282 | }
283 |
284 | return vec4(background(ray), t);
285 | }
286 |
287 | vec3 render(
288 | _in(ray_t) ray,
289 | _in(vec3) point_cam
290 | ){
291 | // apply fog
292 | // theory: http://iquilezles.org/www/articles/fog/fog.htm
293 | // proof: https://sandbox.open.wolframcloud.com/
294 | // d[y_] := dens Exp[-falloff y]
295 | // ray[t_] := orig + t dir
296 | // Integrate[d[ray[t]], {t, 0, T}]
297 |
298 | vec4 orig = render_impl(ray, point_cam);
299 | const float t = orig.w;
300 |
301 | const vec3 fog_color = vec3(1, 1, 1);
302 | const float density = fog_density;
303 | const float falloff = fog_falloff;
304 |
305 | float fog_factor =
306 | density * exp(-ray.origin.y * falloff)
307 | * (1. - exp(- t * ray.direction.y * falloff))
308 | / (ray.direction.y * falloff);
309 |
310 | return abs(mix(orig.rgb, fog_color, fog_factor));
311 | }
312 |
313 | #define FOV 1. // 45 degrees
314 | #include "main.h"
--------------------------------------------------------------------------------
/src/app_vinyl.h:
--------------------------------------------------------------------------------
1 | #include "def.h"
2 | #include "util.h"
3 | #include "sdf.h"
4 | #include "material.h"
5 |
6 | #include "noise_iq.h"
7 | #include "fbm.h"
8 | #define noise_func ((noise_iq(p) * 2. - 1.))
9 | DECL_FBM_FUNC(fbm, 4, noise_func)
10 |
11 | // ----------------------------------------------------------------------------
12 | // Vinyl disk animation
13 | // ----------------------------------------------------------------------------
14 |
15 | vec3 background(_in(ray_t) ray)
16 | {
17 | return vec3(1, 1, 1);
18 | }
19 |
20 | #define mat_groove 1
21 | #define mat_dead_wax 2
22 | #define mat_label 3
23 | #define mat_logo 4
24 | #define mat_shiny 5
25 |
26 | void setup_mat(
27 | _inout(material_t) mat,
28 | _in(vec3) diffuse,
29 | _in(float) metallic,
30 | _in(float) roughness
31 | ){
32 | mat.base_color = diffuse;
33 | mat.metallic = metallic;
34 | mat.roughness = roughness;
35 | mat.ior = 1.;
36 | mat.reflectivity = 0.;
37 | mat.translucency = 0.;
38 | }
39 |
40 | void setup_scene()
41 | {
42 | setup_mat(materials[mat_debug],
43 | vec3(1, 1, 1), .0, .0);
44 | setup_mat(materials[mat_groove],
45 | vec3(.01, .01, .01), .0, .013);
46 | setup_mat(materials[mat_dead_wax],
47 | vec3(.05, .05, .05), .0, .005);
48 | setup_mat(materials[mat_label],
49 | vec3(.5, .5, .0), .0, .5);
50 | setup_mat(materials[mat_logo],
51 | vec3(0, 0, .7), .0, .5);
52 | setup_mat(materials[mat_shiny],
53 | vec3(.7, .7, .7), 1., .01);
54 | }
55 |
56 | void setup_camera(
57 | _inout(vec3) eye,
58 | _inout(vec3) look_at
59 | ){
60 | #if 1
61 | eye = vec3(0, 5.75, 6.75);
62 | look_at = vec3(0, -2.5, 0);
63 | #else
64 | eye = vec3(-2, 1.5, 5.5);
65 | look_at = vec3(-1.5, 0, 0);
66 | #endif
67 | }
68 |
69 | _mutable(mat3) platter_rot;
70 |
71 | float sdf_logo(
72 | _in(vec3) pos,
73 | _in(float) thick
74 | ){
75 | vec3 b = vec3(.25, thick, 1.2);
76 | vec3 d = vec3(.7, 0, 0);
77 |
78 | vec3 p = mul(pos, rotate_around_y(30.));
79 | float v1 = sd_box(p - d, b);
80 |
81 | p = mul(pos, rotate_around_y(-30.));
82 | float v2 = sd_box(p + d, b);
83 |
84 | float x = sd_box(pos, vec3(1.5, thick, 1.35));
85 | float v = op_add(v1, v2);
86 | return op_intersect(v, x);
87 | }
88 |
89 | vec2 sdf_platter(_in(vec3) p)
90 | {
91 | const float thick = .1;
92 |
93 | vec2 lead_in = vec2(
94 | sd_y_cylinder(p, 6., thick - .05),
95 | mat_dead_wax);
96 | vec2 groove = vec2(
97 | sd_y_cylinder(p, 5.9, thick),
98 | mat_groove);
99 | vec2 dead_wax = vec2(
100 | sd_y_cylinder(p, 3., thick),
101 | mat_dead_wax);
102 | vec2 label = vec2(sd_y_cylinder(p, 2., thick),
103 | mat_label);
104 | vec2 logo = vec2(
105 | sdf_logo(p, thick - .0175),
106 | mat_logo);
107 | float spc = sd_y_cylinder(p, .10, .6);
108 | float sps = sd_sphere(p - vec3(0, .3, 0), .10);
109 | vec2 spindle = vec2(
110 | op_add(spc, sps), mat_shiny);
111 |
112 | vec2 d0 = op_add(groove, lead_in);
113 | vec2 d1 = op_add(d0, dead_wax);
114 | vec2 d2 = op_add(label, logo);
115 | vec2 d3 = op_add(d1, d2);
116 | vec2 d4 = op_add(d3, spindle);
117 |
118 | // cut some holes at the edges of the disk
119 | // to make the rotation more visible
120 | float defect1 = sd_sphere(p + vec3(6.05, 0, 0), .1);
121 | float defect2 = sd_sphere(p + vec3(-6.05, 0, 0), .1);
122 | float defect = op_add(defect1, defect2);
123 |
124 | return vec2(op_sub(d4.x, defect), d4.y);
125 | }
126 |
127 | vec2 sdf_tonearm(_in(vec3) pos)
128 | {
129 | vec3 base_p = vec3(-7, 0, -5);
130 |
131 | float platter = sd_y_cylinder(pos, 6.25, 1.);
132 | float base_0 = sd_y_cylinder(pos - base_p, 3., .25);
133 | float base_1 = op_sub(base_0, platter);
134 | float base_2 = sd_y_cylinder(pos - base_p, 1.25, 1.);
135 | float base_12 = op_add(base_1, base_2);
136 | vec2 base_a = vec2(base_12, mat_shiny);
137 | vec2 base_b = vec2(sd_y_cylinder(pos - base_p, 0.5, 2.5), mat_shiny);
138 | vec2 base = op_add(base_a, base_b);
139 |
140 | // slight wobble to mimic needle going up/down
141 | vec3 p = mul(pos, rotate_around_x(
142 | sin(u_time * 3.6758) * .1));
143 |
144 | const float R = .1;
145 | const float H = .8;
146 | vec3 a1 = vec3(-6, H, -3);
147 | vec3 a11 = vec3(-4.25, H, 2);
148 | vec3 a2 = vec3(-4.1, H, 2.45);
149 | vec3 a33 = vec3(-3.5, H, 3);
150 | vec3 a3 = vec3(-2, H, 4);
151 | float arm1 = sd_capsule(p, base_p + vec3(-1, H, -2), a1, R);
152 | float arm2 = sd_capsule(p, a1, a11, R);
153 | float arm3 = sd_capsule(p, a33, a3, R);
154 | vec2 armb = sd_bezier(a11, a2, a33, p, R);
155 | float arm_link1 = op_add(arm1, arm2);
156 | float arm_link2 = op_add(arm_link1, arm3);
157 | vec2 arm = vec2(
158 | op_add(arm_link2, armb.x),
159 | mat_shiny);
160 |
161 | // construct a rotation matrix
162 | // from the orientation of the arm
163 | vec3 arm_fwd = normalize(a3 - a33);
164 | vec3 arm_up = vec3(0, 1, 0);
165 | vec3 arm_right = cross(arm_fwd, arm_up);
166 | mat3 arm_xform = mat3(
167 | arm_fwd,
168 | arm_up,
169 | arm_right);
170 |
171 | // collar 'clr' (or flange)
172 | vec3 clr_p = p - a3;
173 | float clr_r = R * 1.5;
174 | float collar = sd_cylinder(clr_p,
175 | vec3(0, 0, 0),
176 | vec3(0, 0, 0) + arm_fwd * .05,
177 | clr_r);
178 |
179 | // finger lift (or grip) 'fl'
180 | const float fl_w = .045;
181 | const float fl_h = .020;
182 | float fl_len1 = clr_r * 1.;
183 | float fl_len2 = fl_len1 * 1.2;
184 |
185 | // the first fl part is rotated
186 | // and 'pushed' back to fit inside the collar
187 | // a new (local) transform space is created by
188 | // combining the arm one plus a new rotation
189 | mat3 fl_rot =
190 | mul(arm_xform, rotate_around_x(45.));
191 | vec3 fl_p = mul(clr_p -
192 | arm_right * clr_r -
193 | arm_up * clr_r,
194 | fl_rot);
195 | float fl1 = sd_box(fl_p,
196 | vec3(fl_w, fl_h, fl_len1));
197 |
198 | // the second fl part is positioned
199 | // relative to the first, working in this
200 | // new local transform space
201 | mat3 fl_rot2 = rotate_around_x(-45.);
202 | float fl2 = sd_box(
203 | mul(fl_p - vec3(0, 0, fl_len1), fl_rot2)
204 | - vec3(0, 0, fl_len2),
205 | vec3(fl_w, fl_h, fl_len2));
206 | float finger_lift = op_add(fl1, fl2);
207 |
208 | vec2 headshell = vec2(
209 | op_add(collar, finger_lift),
210 | mat_shiny);
211 |
212 | // the cartridge 'ctg'
213 | const float ctg_w = .05;
214 | const float ctg_h = .05;
215 | float ctg_len1 = .3;
216 | float ctg_len2 = .5;
217 |
218 | vec3 ctg_p = mul(clr_p, arm_xform);
219 | float ctg1 = sd_box(ctg_p,
220 | vec3(ctg_len1, ctg_h, ctg_w));
221 | mat3 ctg_rot = rotate_around_z(44.);
222 | vec3 ctg2_p =
223 | mul(ctg_p - vec3(ctg_len1, 0, 0), ctg_rot)
224 | - vec3(ctg_len2 - 0.03, -.01, 0);
225 | float ctg2 = sd_box(
226 | ctg2_p,
227 | vec3(ctg_len2, ctg_h, ctg_w));
228 |
229 | // a series of boxes that will be used
230 | // to carve out the shape of the 'needle'
231 | float cut = sd_box(mul(
232 | mul(ctg2_p, rotate_around_x(10.)) - vec3(0, .05, .175),
233 | rotate_around_y(-5.)),
234 | vec3(ctg_len2 * 2., ctg_h * 3., ctg_w * 3.2));
235 | float cut2 = sd_box(
236 | mul(ctg2_p - vec3(.3, .2, 0),
237 | rotate_around_z(10.)),
238 | vec3(.4, .2, .3));
239 |
240 | float ctg12 = op_add(ctg1, ctg2);
241 | float ctg12c = op_sub(ctg12, cut);
242 | vec2 cartridge = vec2(
243 | op_sub(ctg12c, cut2),
244 | mat_shiny);
245 |
246 | vec2 tone1 = op_add(base, arm);
247 | vec2 tone2 = op_add(headshell, cartridge);
248 | return op_add(tone1, tone2);
249 | }
250 |
251 | vec2 sdf(_in(vec3) pos)
252 | {
253 | vec3 p = mul(pos, platter_rot);
254 | vec2 plat = sdf_platter(p);
255 |
256 | vec2 arm = sdf_tonearm(pos);
257 |
258 | return op_add(plat, arm);
259 | }
260 |
261 | vec3 sdf_normal(_in(vec3) p)
262 | {
263 | float dt = 0.001;
264 | vec3 x = vec3(dt, 0, 0);
265 | vec3 y = vec3(0, dt, 0);
266 | vec3 z = vec3(0, 0, dt);
267 | return normalize(vec3(
268 | sdf(p + x).r - sdf(p - x).r,
269 | sdf(p + y).r - sdf(p - y).r,
270 | sdf(p + z).r - sdf(p - z).r
271 | ));
272 | }
273 |
274 | float saw(_in(float) x)
275 | {
276 | return x - floor(x);
277 | }
278 |
279 | float pulse(_in(float) x)
280 | {
281 | return saw(x + .5) - saw(x);
282 | }
283 |
284 | _mutable(vec3) sun_dir =
285 | normalize(vec3(-1, 4, -3));
286 |
287 | vec3 illuminate(
288 | _in(vec3) eye,
289 | _inout(hit_t) hit
290 | ){
291 | #if 0
292 | return vec3(hit.normal);
293 | #endif
294 |
295 | vec3 L = sun_dir;
296 | vec3 V = normalize(eye - hit.origin);
297 |
298 | material_t mat = get_material(hit.material_id);
299 |
300 | if (hit.material_id == mat_groove ||
301 | hit.material_id == mat_dead_wax) {
302 | hit.origin = mul(hit.origin, platter_rot);
303 | L = mul(L, platter_rot);
304 | V = mul(V, platter_rot);
305 |
306 | float r = length(hit.origin);
307 | vec3 B = hit.origin / r;
308 | vec3 N = vec3(0, 1, 0);
309 | if (hit.material_id == mat_groove) {
310 | float rr = r + .07575 *
311 | noise_iq(hit.origin * 2.456);
312 | //fbm(hit.origin * 4.07, 2.08, .5, .5);
313 | float s = pulse(rr * 24.);
314 | if (s > 0.) {
315 | N = normalize(N + B);
316 | N = reflect(N, vec3(0, 1, 0));
317 | }
318 | }
319 | if (hit.material_id == mat_dead_wax) {
320 | float s = saw(r * 4.);
321 | N = normalize(N + B * float(s > .9));
322 | }
323 | //return N;
324 | vec3 T = cross(B, N);
325 |
326 | const float ro_diff = 1.;
327 | const float ro_spec = .0725;
328 | const float a_x = .025;
329 | const float a_y = .5;
330 |
331 | vec3 H = normalize(V + L);
332 | float dotLN = dot(L, N);
333 |
334 | vec3 diffuse = mat.base_color *
335 | (ro_diff / PI) *
336 | max(0., dotLN);
337 |
338 | float spec_a = ro_spec /
339 | sqrt(dotLN * dot(V, N));
340 |
341 | float spec_b = 1. /
342 | (4. * PI * a_x * a_y);
343 |
344 | float ht = dot(H, T) / a_x;
345 | float hb = dot(H, B) / a_y;
346 | float spec_c = -2. *
347 | (ht * ht + hb * hb) /
348 | (1. + dot(H, N));
349 |
350 | vec3 specular = vec3(1, 1, 1) *
351 | spec_a * spec_b * exp(spec_c);
352 |
353 | return diffuse + specular;
354 | } else {
355 | hit.normal = sdf_normal(hit.origin);
356 |
357 | #if 0
358 | if (hit.material_id == mat_label || hit.material_id == mat_logo) {
359 | float r = length(hit.origin);
360 | vec3 B = hit.origin / r;
361 | float s = saw(r * .9);
362 | hit.normal = normalize(hit.normal + B * float(s > .975));
363 | }
364 | #endif
365 |
366 | #ifdef SHADERTOY
367 | if (hit.material_id == mat_shiny) {
368 | vec3 refl = (reflect(V, hit.normal));
369 | return textureCube(iChannel0, refl).rgb;
370 | }
371 | #endif
372 |
373 | vec3 diffuse = mat.base_color * max(0., dot(L, hit.normal));
374 | vec3 H = normalize(V + L);
375 | vec3 specular = pow(max(0., dot(H, hit.normal)), 50.)
376 | * vec3(1, 1, 1);
377 | return diffuse + specular;
378 | }
379 | }
380 |
381 | float sdf_shadow(_in(ray_t) ray)
382 | {
383 | const int steps = 20;
384 | const float end = 5.;
385 | const float penumbra_factor = 16.;
386 | const float darkest = .05;
387 | float t = 0.;
388 | float umbra = 1.;
389 |
390 | for (int i = 0; i < steps; i++) {
391 | vec3 p = ray.origin + ray.direction * t;
392 | vec2 d = sdf(p);
393 |
394 | if (t > end) break;
395 | if (d.x < .005) {
396 | return darkest;
397 | }
398 |
399 | t += d.x;
400 | // from http://iquilezles.org/www/articles/rmshadows/rmshadows.htm
401 | umbra = min(umbra, penumbra_factor * d.x / t);
402 | }
403 |
404 | return umbra;
405 | }
406 |
407 | vec3 render(
408 | _in(ray_t) ray,
409 | _in(vec3) point_cam
410 | ){
411 | const int steps =
412 | #ifdef __cplusplus
413 | 60;
414 | #else
415 | 180;
416 | #endif
417 | const float end = 40.;
418 |
419 | float rot = u_time * 200.;
420 | #ifdef SHADERTOY
421 | // scratching support :)
422 | if (u_mouse.z > 0.) {
423 | rot = u_mouse.y;
424 | }
425 | #endif
426 | platter_rot = mul(
427 | rotate_around_y(rot),
428 | rotate_around_x(sin(u_time) * .1));
429 |
430 | float t = 0.;
431 | for (int i = 0; i < steps; i++) {
432 | vec3 p = ray.origin + ray.direction * t;
433 | vec2 d = sdf(p);
434 |
435 | if (t > end) break;
436 | if (d.x < .005) {
437 | hit_t h = _begin(hit_t)
438 | t, // ray length at impact
439 | int(d.y), // material id
440 | vec3(0, 1, 0), // normal
441 | p // point of impact
442 | _end;
443 |
444 | float sh = 1.;
445 | #if 1
446 | ray_t sh_ray = _begin(ray_t)
447 | p + sun_dir * 0.05, sun_dir
448 | _end;
449 | sh = sdf_shadow(sh_ray);
450 | #endif
451 | return illuminate(ray.origin, h) * sh;
452 | }
453 |
454 | t += d.x;
455 | }
456 |
457 | return background(ray);
458 | }
459 |
460 | #define FOV 1. // 45 degrees
461 | #include "main.h"
--------------------------------------------------------------------------------
/src/cornell_box.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Cornell Box definition
3 | // http://www.graphics.cornell.edu/online/box/
4 | // ----------------------------------------------------------------------------
5 |
6 | // reuses materials array
7 |
8 | #define num_cb_planes 6
9 | _mutable(plane_t) cb_planes[num_cb_planes];
10 |
11 | #define num_cb_spheres 3
12 | _mutable(sphere_t) cb_spheres[num_cb_spheres];
13 |
14 | void setup_material(
15 | _inout(material_t) mat,
16 | _in(vec3) diffuse,
17 | _in(float) metallic,
18 | _in(float) roughness
19 | ){
20 | mat.base_color = diffuse;
21 | mat.metallic = metallic;
22 | mat.roughness = roughness;
23 | mat.ior = 1.;
24 | mat.reflectivity = 0.;
25 | mat.translucency = 0.;
26 | }
27 |
28 | void setup_plane(
29 | _inout(plane_t) p,
30 | _in(vec3) n,
31 | _in(float) d,
32 | _in(int) mat_id
33 | ){
34 | p.direction = n;
35 | p.distance = d;
36 | p.material = mat_id;
37 | }
38 |
39 | void setup_cornell_box()
40 | {
41 | #define cb_mat_white 1
42 | #define cb_mat_red 2
43 | #define cb_mat_blue 3
44 | #define cb_mat_reflect 4
45 | #define cb_mat_refract 5
46 | #define cb_mat_green 6
47 | setup_material(materials[cb_mat_white], vec3(0.7913, 0.7913, 0.7913), .0, .5);
48 | setup_material(materials[cb_mat_red], vec3(0.6795, 0.0612, 0.0529), 0., .5);
49 | setup_material(materials[cb_mat_blue], vec3(0.1878, 0.1274, 0.4287), 0., .5);
50 | setup_material(materials[cb_mat_reflect], vec3(0.95, 0.64, 0.54), 1., .1);
51 | materials[cb_mat_reflect].reflectivity = 1.;
52 | setup_material(materials[cb_mat_refract], vec3(1., 0.77, 0.345), 1., .05);
53 | materials[cb_mat_refract].reflectivity = 1.;
54 | materials[cb_mat_refract].translucency = 0.;
55 | materials[cb_mat_refract].ior = 1.333;
56 |
57 | #define cb_plane_ground 0
58 | #define cb_plane_behind 1
59 | #define cb_plane_front 2
60 | #define cb_plane_ceiling 3
61 | #define cb_plane_left 4
62 | #define cb_plane_right 5
63 | #define cb_plane_dist 2.
64 | setup_plane(cb_planes[cb_plane_ground], vec3(0, -1, 0), 0., cb_mat_white);
65 | setup_plane(cb_planes[cb_plane_ceiling], vec3(0, 1, 0), 2. * cb_plane_dist, cb_mat_white);
66 | setup_plane(cb_planes[cb_plane_behind], vec3(0, 0, -1), -cb_plane_dist, cb_mat_white);
67 | setup_plane(cb_planes[cb_plane_front], vec3(0, 0, 1), cb_plane_dist, cb_mat_white);
68 | setup_plane(cb_planes[cb_plane_left], vec3(1, 0, 0), cb_plane_dist, cb_mat_red);
69 | setup_plane(cb_planes[cb_plane_right], vec3(-1, 0, 0), -cb_plane_dist, cb_mat_blue);
70 |
71 | #define cb_sphere_light 0
72 | #define cb_sphere_left 1
73 | #define cb_sphere_right 2
74 | cb_spheres[cb_sphere_light].origin = vec3(0, 2.5 * cb_plane_dist + 0.4, 0);
75 | cb_spheres[cb_sphere_light].radius = 1.5;
76 | cb_spheres[cb_sphere_light].material = mat_debug;
77 | cb_spheres[cb_sphere_left].origin = vec3(0.75, 1, -0.75);
78 | cb_spheres[cb_sphere_left].radius = 0.75;
79 | cb_spheres[cb_sphere_left].material = cb_mat_reflect;
80 | cb_spheres[cb_sphere_right].origin = vec3(-0.75, 0.75, 0.75);
81 | cb_spheres[cb_sphere_right].radius = 0.75;
82 | cb_spheres[cb_sphere_right].material = cb_mat_refract;
83 |
84 | lights[0].type = LIGHT_POINT;
85 | lights[0].L = vec3(0, 2. * cb_plane_dist - 0.2, 0);
86 | lights[0].color = vec3(1., 1., 1.);
87 | }
88 |
89 |
--------------------------------------------------------------------------------
/src/def.h:
--------------------------------------------------------------------------------
1 | #ifdef __cplusplus
2 | #define _in(T) const T &
3 | #define _inout(T) T &
4 | #define _out(T) T &
5 | #define _begin(type) type {
6 | #define _end }
7 | #define _mutable(T) thread_local T
8 | #define _constant(T) const thread_local T
9 | #define mul(a, b) (a) * (b)
10 | #endif
11 |
12 | #if defined(GL_ES) || defined(GL_SHADING_LANGUAGE_VERSION)
13 | #define _in(T) const in T
14 | #define _inout(T) inout T
15 | #define _out(T) out T
16 | #define _begin(type) type (
17 | #define _end )
18 | #define _mutable(T) T
19 | #define _constant(T) const T
20 | #define mul(a, b) (a) * (b)
21 | precision mediump float;
22 | #endif
23 |
24 | #ifdef HLSL
25 | #define _in(T) const in T
26 | #define _inout(T) inout T
27 | #define _out(T) out T
28 | #define _begin(type) {
29 | #define _end }
30 | #define _mutable(T) static T
31 | #define _constant(T) static const T
32 | #define vec2 float2
33 | #define vec3 float3
34 | #define vec4 float4
35 | #define mat2 float2x2
36 | #define mat3 float3x3
37 | #define mat4 float4x4
38 | #define mix lerp
39 | #define fract frac
40 | #define mod fmod
41 | #pragma pack_matrix(row_major)
42 | #endif
43 |
44 | #ifdef HLSLTOY
45 | void mainImage(out float4 fragColor, in float2 fragCoord);
46 | float4 main(float4 uv : SV_Position) : SV_Target{ float4 col; mainImage(col, uv.xy); return col; }
47 | #endif
48 |
49 | #include "uniform_buffer.h"
50 |
51 | #define PI 3.14159265359
52 |
53 | struct ray_t {
54 | vec3 origin;
55 | vec3 direction;
56 | };
57 | #define BIAS 1e-4 // small offset to avoid self-intersections
58 |
59 | struct sphere_t {
60 | vec3 origin;
61 | float radius;
62 | int material;
63 | };
64 |
65 | struct plane_t {
66 | vec3 direction;
67 | float distance;
68 | int material;
69 | };
70 |
71 | struct hit_t {
72 | float t;
73 | int material_id;
74 | vec3 normal;
75 | vec3 origin;
76 | };
77 | #define max_dist 1e8
78 | _constant(hit_t) no_hit = _begin(hit_t)
79 | float(max_dist + 1e1), // 'infinite' distance
80 | -1, // material id
81 | vec3(0., 0., 0.), // normal
82 | vec3(0., 0., 0.) // origin
83 | _end;
84 |
85 |
--------------------------------------------------------------------------------
/src/fbm.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Fractional Brownian Motion
3 | // macro function generators, depend on custom basis function
4 | // ----------------------------------------------------------------------------
5 |
6 | #define DECL_FBM_FUNC(_name, _octaves, _basis) float _name(_in(vec3) pos, _in(float) lacunarity, _in(float) init_gain, _in(float) gain) { vec3 p = pos; float H = init_gain; float t = 0.; for (int i = 0; i < _octaves; i++) { t += _basis * H; p *= lacunarity; H *= gain; } return t; }
7 |
8 | #define DECL_FBM_FUNC_TILE(_name, _octaves, _basis) float _name(_in(vec3) pos, _in(float) lacunarity, _in(float) init_gain, _in(float) gain) { vec3 p = pos; float H = init_gain; float L = lacunarity; float t = 0.; for (int i = 0; i < _octaves; i++) { t += _basis * H; L *= lacunarity; H *= gain; } return t; }
9 |
10 |
--------------------------------------------------------------------------------
/src/intersect.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Analytical surface-ray intersection routines
3 | // ----------------------------------------------------------------------------
4 |
5 | // geometrical solution
6 | // info: http://www.scratchapixel.com/old/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-sphere-intersection/
7 | void intersect_sphere(
8 | _in(ray_t) ray,
9 | _in(sphere_t) sphere,
10 | _inout(hit_t) hit
11 | ){
12 | vec3 rc = sphere.origin - ray.origin;
13 | float radius2 = sphere.radius * sphere.radius;
14 | float tca = dot(rc, ray.direction);
15 | if (tca < 0.) return;
16 |
17 | float d2 = dot(rc, rc) - tca * tca;
18 | if (d2 > radius2) return;
19 |
20 | float thc = sqrt(radius2 - d2);
21 | float t0 = tca - thc;
22 | float t1 = tca + thc;
23 |
24 | if (t0 < 0.) t0 = t1;
25 | if (t0 > hit.t) return;
26 |
27 | vec3 impact = ray.origin + ray.direction * t0;
28 |
29 | hit.t = t0;
30 | hit.material_id = sphere.material;
31 | hit.origin = impact;
32 | hit.normal = (impact - sphere.origin) / sphere.radius;
33 | }
34 |
35 | void intersect_sphere_from_inside(
36 | _in(ray_t) ray,
37 | _in(sphere_t) sphere,
38 | _inout(hit_t) hit
39 | ){
40 | vec3 rc = sphere.origin - ray.origin;
41 | float radius2 = sphere.radius * sphere.radius;
42 | float tca = dot(rc, ray.direction);
43 | float d2 = dot(rc, rc) - tca * tca;
44 | float thc = sqrt(radius2 - d2);
45 | float t0 = tca - thc;
46 | float t1 = tca + thc;
47 |
48 | vec3 impact = ray.origin + ray.direction * t0;
49 | hit.t = t0;
50 | hit.material_id = sphere.material;
51 | hit.origin = impact;
52 | hit.normal = (impact - sphere.origin) / sphere.radius;
53 | }
54 |
55 | // Plane is defined by normal N and distance to origin P0 (which is on the plane itself)
56 | // a plane eq is: (P - P0) dot N = 0
57 | // which means that any line on the plane is perpendicular to the plane normal
58 | // a ray eq: P = O + t*D
59 | // substitution and solving for t gives:
60 | // t = ((P0 - O) dot N) / (N dot D)
61 | void intersect_plane(
62 | _in(ray_t) ray,
63 | _in(plane_t) p,
64 | _inout(hit_t) hit
65 | ){
66 | float denom = dot(p.direction, ray.direction);
67 | if (denom < 1e-6) return;
68 |
69 | vec3 P0 = vec3(p.distance, p.distance, p.distance);
70 | float t = dot(P0 - ray.origin, p.direction) / denom;
71 | if (t < 0. || t > hit.t) return;
72 |
73 | hit.t = t;
74 | hit.material_id = p.material;
75 | hit.origin = ray.origin + ray.direction * t;
76 | hit.normal = faceforward(p.direction, ray.direction, p.direction);
77 | }
78 |
79 |
--------------------------------------------------------------------------------
/src/light.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Lighting models
3 | // ----------------------------------------------------------------------------
4 |
5 | #define LIGHT_POINT 1
6 | #define LIGHT_DIR 2
7 |
8 | struct light_t {
9 | int type;
10 | vec3 L; // origin for point lights, direction otherwise
11 | vec3 color;
12 | };
13 |
14 | _mutable(light_t) lights[8];
15 |
16 | _mutable(vec3) ambient_light = vec3(.01, .01, .01);
17 |
18 | vec3 get_light_direction(
19 | _in(light_t) light,
20 | _in(hit_t) P
21 | ){
22 | if (light.type == LIGHT_DIR) {
23 | return light.L;
24 | } else {
25 | return normalize(light.L - P.origin);
26 | }
27 | }
28 |
29 | // R V N H L L dir to light
30 | // ^ ^ ^ ^ ^ V dir to eye
31 | // . \ | / . N normal
32 | // . \ | / . H half between L and V
33 | // . \ | / . R reflected
34 | // n1 . \|/ . O hit point
35 | // -----------------O---------------- T refracted
36 | // n2 . n1 index of refraction of outgoing medium
37 | // . n2 index of refraction of incoming medium
38 | // .
39 | // .
40 | // .
41 | // \/_ T
42 | //
43 |
44 | vec3 illum_blinn_phong(
45 | _in(vec3) V,
46 | _in(vec3) L,
47 | _in(hit_t) hit,
48 | _in(material_t) mat
49 | ){
50 | vec3 diffuse = max(0., dot(L, hit.normal)) * mat.base_color;
51 |
52 | const float spec_factor = 50.;
53 | #if 0 // Blinn specular
54 | vec3 H = normalize(L + V);
55 | vec3 specular = pow(max(0., dot(H, hit.normal)), spec_factor); // * light.color * specular color
56 | #else // Phong specular
57 | vec3 R = reflect(-L, hit.normal);
58 | vec3 specular = pow(max(0., dot(R, V)), spec_factor) * vec3(1, 1, 1); // * light.color * specular color
59 | #endif
60 |
61 | return diffuse + specular;
62 | }
63 |
64 | vec3 illum_cook_torrance(
65 | _in(vec3) V,
66 | _in(vec3) L,
67 | _in(hit_t) hit,
68 | _in(material_t) mat
69 | ){
70 | vec3 H = normalize(L + V);
71 | float NdotL = dot(hit.normal, L);
72 | float NdotH = dot(hit.normal, H);
73 | float NdotV = dot(hit.normal, V);
74 | float VdotH = dot(V, H);
75 |
76 | // geometric term
77 | float geo_a = (2. * NdotH * NdotV) / VdotH;
78 | float geo_b = (2. * NdotH * NdotL) / VdotH;
79 | float geo_term = min(1., min(geo_a, geo_b));
80 |
81 | // roughness term -using Beckmann Distribution
82 | float rough_sq = mat.roughness * mat.roughness;
83 | float rough_a = 1. / (rough_sq * NdotH * NdotH * NdotH * NdotH);
84 | float rough_exp = (NdotH * NdotH - 1.) / (rough_sq * NdotH * NdotH);
85 | float rough_term = rough_a * exp(rough_exp);
86 |
87 | // Fresnel term
88 | float fresnel_term = fresnel_factor(1., mat.ior, VdotH);
89 |
90 | float specular = (geo_term * rough_term * fresnel_term) / (PI * NdotV * NdotL);
91 | return max(0., NdotL) * (specular + mat.base_color);
92 | }
93 |
--------------------------------------------------------------------------------
/src/main.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Main Rendering function
3 | // depends on external defines: FOV
4 | // ----------------------------------------------------------------------------
5 |
6 | void mainImage(
7 | out vec4 fragColor,
8 | in vec2 fragCoord
9 | ){
10 | // The pipeline transform
11 | //
12 | // 1. fragCoord is in raster space [0..resolution]
13 | // 2. convert to NDC [0..1] by dividing to the resolution
14 | // 3. convert to camera space:
15 | // a. xy gets [-1, +1] by 2 * NDC - 1; z fixed at -1
16 | // c. apply aspect & fov
17 | // d. apply the look-at algoritm which will
18 | // produce the 3 camera axis:
19 | //
20 | // R ^ -Y ^ -Y E eye/ray origin
21 | // . |\ | . R R primary ray
22 | // .| \ | . @ fov angle
23 | // -Z | .\ +Z | .
24 | // ------0---E---> -X -------0-------> +X
25 | // | @/ |
26 | // | / |
27 | // |/ | +Y
28 | // +Y
29 | //
30 | // NOTE: everything is expressed in this space, NOT world
31 |
32 | // assuming screen width is larger than height
33 | vec2 aspect_ratio = vec2(u_res.x / u_res.y, 1);
34 |
35 | vec3 eye, look_at;
36 | setup_camera(eye, look_at);
37 |
38 | setup_scene();
39 |
40 | vec2 point_ndc = fragCoord.xy / u_res.xy;
41 | #ifdef HLSL
42 | point_ndc.y = 1. - point_ndc.y;
43 | #endif
44 | vec3 point_cam = vec3(
45 | (2.0 * point_ndc - 1.0) * aspect_ratio * FOV,
46 | -1.0);
47 |
48 | ray_t ray = get_primary_ray(point_cam, eye, look_at);
49 |
50 | vec3 color = render(ray, point_cam);
51 |
52 | fragColor = vec4(linear_to_srgb(color), 1);
53 | }
--------------------------------------------------------------------------------
/src/material.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Materials system definitions
3 | // ----------------------------------------------------------------------------
4 |
5 | struct material_t {
6 | vec3 base_color;
7 | float metallic;
8 | float roughness;
9 | float ior; // index of refraction
10 | float reflectivity;
11 | float translucency;
12 | };
13 |
14 | #define num_materials 8
15 | #define mat_invalid -1
16 | #define mat_debug 0
17 | _mutable(material_t) materials[num_materials];
18 |
19 | material_t get_material(
20 | _in(int) index
21 | ){
22 | #if defined(HLSL) && defined(__cplusplus)
23 | return materials[index];
24 | #else
25 | material_t mat;
26 |
27 | for (int i = 0; i < num_materials; ++i) {
28 | if (i == index) {
29 | mat = materials[i];
30 | break;
31 | }
32 | }
33 |
34 | return mat;
35 | #endif
36 | }
37 |
--------------------------------------------------------------------------------
/src/noise_iq.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Noise function by iq from https://www.shadertoy.com/view/4sfGzS
3 | // ----------------------------------------------------------------------------
4 |
5 | float hash(
6 | _in(float) n
7 | ){
8 | return fract(sin(n)*753.5453123);
9 | }
10 |
11 | float noise_iq(
12 | _in(vec3) x
13 | ){
14 | vec3 p = floor(x);
15 | vec3 f = fract(x);
16 | f = f*f*(3.0 - 2.0*f);
17 |
18 | #if 1
19 | float n = p.x + p.y*157.0 + 113.0*p.z;
20 | return mix(mix(mix( hash(n+ 0.0), hash(n+ 1.0),f.x),
21 | mix( hash(n+157.0), hash(n+158.0),f.x),f.y),
22 | mix(mix( hash(n+113.0), hash(n+114.0),f.x),
23 | mix( hash(n+270.0), hash(n+271.0),f.x),f.y),f.z);
24 | #else
25 | vec2 uv = (p.xy + vec2(37.0, 17.0)*p.z) + f.xy;
26 | vec2 rg = texture2D(iChannel0, (uv + 0.5) / 256.0, -100.0).yx;
27 | return mix(rg.x, rg.y, f.z);
28 | #endif
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/src/noise_worley.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Noise function by iq from https://www.shadertoy.com/view/ldl3Dl
3 | // ----------------------------------------------------------------------------
4 |
5 | vec3 hash_w(
6 | _in(vec3) x
7 | ){
8 | #if 1
9 | vec3 xx = vec3(dot(x, vec3(127.1, 311.7, 74.7)),
10 | dot(x, vec3(269.5, 183.3, 246.1)),
11 | dot(x, vec3(113.5, 271.9, 124.6)));
12 |
13 | return fract(sin(xx)*43758.5453123);
14 | #else
15 | return texture2D(iChannel0, (x.xy + vec2(3.0, 1.0)*x.z + 0.5) / 256.0, -100.0).xyz;
16 | #endif
17 | }
18 |
19 | // returns closest, second closest, and cell id
20 | vec3 noise_w(
21 | _in(vec3) pos,
22 | _in(float) domain_repeat
23 | ){
24 | vec3 x = pos * domain_repeat;
25 |
26 | vec3 p = floor(x);
27 | vec3 f = fract(x);
28 |
29 | float id = 0.0;
30 | vec2 res = vec2(100.0, 100.0);
31 | for (int k = -1; k <= 1; k++)
32 | for (int j = -1; j <= 1; j++)
33 | for (int i = -1; i <= 1; i++)
34 | {
35 | vec3 b = vec3(float(i), float(j), float(k));
36 | vec3 r = vec3(b) - f + hash_w(mod(p + b, domain_repeat));
37 | float d = dot(r, r);
38 |
39 | if (d < res.x)
40 | {
41 | id = dot(p + b, vec3(1.0, 57.0, 113.0));
42 | res = vec2(d, res.x);
43 | }
44 | else if (d < res.y)
45 | {
46 | res.y = d;
47 | }
48 | }
49 |
50 | return vec3(sqrt(res), abs(id));
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/src/reference/VolumetricIntegration.frag:
--------------------------------------------------------------------------------
1 | /* Hi there!
2 | * Here is a demo presenting volumetric rendering single with shadowing.
3 | * Did it quickly so I hope I have not made any big mistakes :)
4 | *
5 | * I also added the improved scattering integration I propose in my SIGGRAPH'15 presentation
6 | * about Frostbite new volumetric system I have developed. See slide 28 at http://www.frostbite.com/2015/08/physically-based-unified-volumetric-rendering-in-frostbite/
7 | * Basically it improves the scattering integration for each step with respect to extinction
8 | * The difference is mainly visible for some participating media having a very strong scattering value.
9 | * I have setup some pre-defined settings for you to checkout below (to present the case it improves):
10 | * - D_DEMO_SHOW_IMPROVEMENT_xxx: shows improvement (on the right side of the screen). You can still see aliasing due to volumetric shadow and the low amount of sample we take for it.
11 | * - D_DEMO_SHOW_IMPROVEMENT_xxx_NOVOLUMETRICSHADOW: same as above but without volumetric shadow
12 | *
13 | * To increase the volumetric rendering accuracy, I constrain the ray marching steps to a maximum distance.
14 | *
15 | * Volumetric shadows are evaluated by raymarching toward the light to evaluate transmittance for each view ray steps (ouch!)
16 | *
17 | * Do not hesitate to contact me to discuss about all that :)
18 | * SebH
19 | */
20 |
21 |
22 |
23 | /*
24 | * This are predefined settings you can quickly use
25 | * - D_DEMO_FREE play with parameters as you would like
26 | * - D_DEMO_SHOW_IMPROVEMENT_FLAT show improved integration on flat surface
27 | * - D_DEMO_SHOW_IMPROVEMENT_NOISE show improved integration on noisy surface
28 | * - the two previous without volumetric shadows
29 | */
30 | #define D_DEMO_FREE
31 | //#define D_DEMO_SHOW_IMPROVEMENT_FLAT
32 | //#define D_DEMO_SHOW_IMPROVEMENT_NOISE
33 | //#define D_DEMO_SHOW_IMPROVEMENT_FLAT_NOVOLUMETRICSHADOW
34 | //#define D_DEMO_SHOW_IMPROVEMENT_NOISE_NOVOLUMETRICSHADOW
35 |
36 |
37 |
38 |
39 |
40 | #ifdef D_DEMO_FREE
41 | // Apply noise on top of the height fog?
42 | #define D_FOG_NOISE 1.0
43 |
44 | // Height fog multiplier to show off improvement with new integration formula
45 | #define D_STRONG_FOG 0.0
46 |
47 | // Enable/disable volumetric shadow (single scattering shadow)
48 | #define D_VOLUME_SHADOW_ENABLE 1
49 |
50 | // Use imporved scattering?
51 | // In this mode it is full screen and can be toggle on/off.
52 | #define D_USE_IMPROVE_INTEGRATION 1
53 |
54 | //
55 | // Pre defined setup to show benefit of the new integration. Use D_DEMO_FREE to play with parameters
56 | //
57 | #elif defined(D_DEMO_SHOW_IMPROVEMENT_FLAT)
58 | #define D_STRONG_FOG 10.0
59 | #define D_FOG_NOISE 0.0
60 | #define D_VOLUME_SHADOW_ENABLE 1
61 | #elif defined(D_DEMO_SHOW_IMPROVEMENT_NOISE)
62 | #define D_STRONG_FOG 5.0
63 | #define D_FOG_NOISE 1.0
64 | #define D_VOLUME_SHADOW_ENABLE 1
65 | #elif defined(D_DEMO_SHOW_IMPROVEMENT_FLAT_NOVOLUMETRICSHADOW)
66 | #define D_STRONG_FOG 10.0
67 | #define D_FOG_NOISE 0.0
68 | #define D_VOLUME_SHADOW_ENABLE 0
69 | #elif defined(D_DEMO_SHOW_IMPROVEMENT_NOISE_NOVOLUMETRICSHADOW)
70 | #define D_STRONG_FOG 3.0
71 | #define D_FOG_NOISE 1.0
72 | #define D_VOLUME_SHADOW_ENABLE 0
73 | #endif
74 |
75 |
76 |
77 | /*
78 | * Other options you can tweak
79 | */
80 |
81 | // Used to control wether transmittance is updated before or after scattering (when not using improved integration)
82 | // If 0 strongly scattering participating media will not be energy conservative
83 | // If 1 participating media will look too dark especially for strong extinction (as compared to what it should be)
84 | // Toggle only visible zhen not using the improved scattering integration.
85 | #define D_UPDATE_TRANS_FIRST 0
86 |
87 | // Apply bump mapping on walls
88 | #define D_DETAILED_WALLS 0
89 |
90 | // Use to restrict ray marching length. Needed for volumetric evaluation.
91 | #define D_MAX_STEP_LENGTH_ENABLE 1
92 |
93 | // Light position and color
94 | #define LPOS vec3( 20.0+15.0*sin(iGlobalTime), 15.0+12.0*cos(iGlobalTime),-20.0)
95 | #define LCOL (600.0*vec3( 1.0, 0.9, 0.5))
96 |
97 |
98 | float displacementSimple( vec2 p )
99 | {
100 | float f;
101 | f = 0.5000* texture2D( iChannel0, p ).x; p = p*2.0;
102 | f += 0.2500* texture2D( iChannel0, p ).x; p = p*2.0;
103 | f += 0.1250* texture2D( iChannel0, p ).x; p = p*2.0;
104 | f += 0.0625* texture2D( iChannel0, p ).x; p = p*2.0;
105 |
106 | return f;
107 | }
108 |
109 |
110 | vec3 getSceneColor(vec3 p, float material)
111 | {
112 | if(material==1.0)
113 | {
114 | return vec3(1.0, 0.5, 0.5);
115 | }
116 | else if(material==2.0)
117 | {
118 | return vec3(0.5, 1.0, 0.5);
119 | }
120 | else if(material==3.0)
121 | {
122 | return vec3(0.5, 0.5, 1.0);
123 | }
124 |
125 | return vec3(0.0, 0.0, 0.0);
126 | }
127 |
128 |
129 | float getClosestDistance(vec3 p, out float material)
130 | {
131 | float d = 0.0;
132 | #if D_MAX_STEP_LENGTH_ENABLE
133 | float minD = 1.0; // restrict max step for better scattering evaluation
134 | #else
135 | float minD = 10000000.0;
136 | #endif
137 | material = 0.0;
138 |
139 | float yNoise = 0.0;
140 | float xNoise = 0.0;
141 | float zNoise = 0.0;
142 | #if D_DETAILED_WALLS
143 | yNoise = 1.0*clamp(displacementSimple(p.xz*0.005),0.0,1.0);
144 | xNoise = 2.0*clamp(displacementSimple(p.zy*0.005),0.0,1.0);
145 | zNoise = 0.5*clamp(displacementSimple(p.xy*0.01),0.0,1.0);
146 | #endif
147 |
148 | d = max(0.0, p.y - yNoise);
149 | if(d0) // freedom/tweakable version
279 | #else
280 | if(improvedScattering)
281 | #endif
282 | {
283 | // See slide 28 at http://www.frostbite.com/2015/08/physically-based-unified-volumetric-rendering-in-frostbite/
284 | vec3 S = evaluateLight(p) * muS * phaseFunction()* volumetricShadow(p,lightPos);// incoming light
285 | vec3 Sint = (S - S * exp(-muE * dd)) / muE; // integrate along the current step segment
286 | scatteredLight += transmittance * Sint; // accumulate and also take into account the transmittance from previous steps
287 |
288 | // Evaluate transmittance to view independentely
289 | transmittance *= exp(-muE * dd);
290 | }
291 | else
292 | {
293 | // Basic scatering/transmittance integration
294 | #if D_UPDATE_TRANS_FIRST
295 | transmittance *= exp(-muE * dd);
296 | #endif
297 | scatteredLight += muS * evaluateLight(p) * phaseFunction() * volumetricShadow(p,lightPos) * transmittance * dd;
298 | #if !D_UPDATE_TRANS_FIRST
299 | transmittance *= exp(-muE * dd);
300 | #endif
301 | }
302 |
303 |
304 | dd = getClosestDistance(p, material);
305 | if(dd<0.2)
306 | break; // give back a lot of performance without too much visual loss
307 | d += dd;
308 | }
309 |
310 | albedo = getSceneColor(p, material);
311 |
312 | finalPos = rO + d*rD;
313 |
314 | normal = calcNormal(finalPos);
315 |
316 | scatTrans = vec4(scatteredLight, transmittance);
317 | }
318 |
319 |
320 | void mainImage( out vec4 fragColor, in vec2 fragCoord )
321 | {
322 | //iGlobalTime
323 | //iMouse
324 | //iResolution
325 |
326 | vec2 uv = fragCoord.xy / iResolution.xy;
327 | vec2 uv2 = 2.0*fragCoord.xy / iResolution.xy - 1.0;
328 |
329 | vec3 camPos = vec3( 20.0, 18.0,-50.0);
330 | if(iMouse.x+iMouse.y > 0.0) // to handle first loading and see somthing on screen
331 | camPos += vec3(0.05,0.12,0.0)*(vec3(iMouse.x, iMouse.y, 0.0)-vec3(iResolution.xy*0.5, 0.0));
332 | vec3 camX = vec3( 1.0, 0.0, 0.0) *0.75;
333 | vec3 camY = vec3( 0.0, 1.0, 0.0) *0.5;
334 | vec3 camZ = vec3( 0.0, 0.0, 1.0);
335 |
336 | vec3 rO = camPos;
337 | vec3 rD = normalize(uv2.x*camX + uv2.y*camY + camZ);
338 | vec3 finalPos = rO;
339 | vec3 albedo = vec3( 0.0, 0.0, 0.0 );
340 | vec3 normal = vec3( 0.0, 0.0, 0.0 );
341 | vec4 scatTrans = vec4( 0.0, 0.0, 0.0, 0.0 );
342 | traceScene( fragCoord.x>(iResolution.x/2.0),
343 | rO, rD, finalPos, normal, albedo, scatTrans);
344 |
345 |
346 | //lighting
347 | vec3 color = (albedo/3.14) * evaluateLight(finalPos, normal) * volumetricShadow(finalPos, LPOS);
348 | // Apply scattering/transmittance
349 | color = color * scatTrans.w + scatTrans.xyz;
350 |
351 | // Gamma correction
352 | color = pow(color, vec3(1.0/2.2)); // simple linear to gamma, exposure of 1.0
353 |
354 | #ifndef D_DEMO_FREE
355 | // Separation line
356 | if(abs(fragCoord.x-(iResolution.x*0.5))<0.6)
357 | color.r = 0.5;
358 | #endif
359 |
360 | fragColor = vec4(color ,1.0);
361 | }
362 |
363 |
364 |
365 |
--------------------------------------------------------------------------------
/src/reference/anisotropic.frag:
--------------------------------------------------------------------------------
1 | // https://www.shadertoy.com/view/MdjSzt
2 |
3 | float WardAnisotropy (in vec3 vNormal, in vec3 vDirection, in vec3 vEye, in vec3 vLight,in vec2 Roughness)
4 | {
5 | vec3 A = normalize(vEye+vLight);
6 |
7 | float X = dot(A,normalize(cross(vNormal,vDirection)))/Roughness.x;
8 |
9 | float Y = dot(A,normalize(cross(vNormal,A)))/Roughness.y;
10 |
11 | float B = 1.0+dot(A,vNormal);
12 |
13 | float XY = -2.0*(pow(X,2.0)+pow(Y,2.0)) / B;
14 |
15 | float C = exp(XY) * (1.0/12.5664*Roughness.x*Roughness.y);
16 |
17 | return C * (1.0/sqrt(max(dot(vEye,vNormal),0.0)/max(dot(vLight,vNormal),0.0)));
18 | }
19 |
20 | void mainImage( out vec4 fragColor, in vec2 fragCoord )
21 | {
22 | vec2 uv = fragCoord.xy / iResolution.yy;
23 |
24 | vec2 uvl = fragCoord.xy / iResolution.xy-0.5;
25 |
26 | //Cones
27 | float s1 = 1.0-clamp(length(uv*4.0-vec2(1.5,1.2)),0.0,1.0);
28 |
29 | float s2 = 1.0-clamp(length(uv*4.0-vec2(5.67,1.2)),0.0,1.0);
30 |
31 | float s3 = 1.0-clamp(length(uv*4.0-vec2(3.67,2.8)),0.0,1.0);
32 |
33 | float sph = s1+s2+s3;
34 |
35 | float spm = clamp((s1+s2+s3)*96.0,0.0,1.0);
36 |
37 |
38 | //Normals
39 | float dx = dFdx(sph)*iResolution.x/15.0*spm;
40 |
41 | float dy = dFdy(sph)*iResolution.x/15.0*spm;
42 |
43 | vec3 vNormal = normalize(vec3(dx,dy,sqrt(clamp(1.0-dx*dx-dy*dy,0.0,1.0))));
44 |
45 |
46 | //Shading
47 | vec2 Roughness = vec2(0.2,0.8);
48 |
49 | vec3 Dir1 = normalize(vec3(fract(uv.x*4.0)-0.5,fract(uv.y*4.0)-0.5,0.0));
50 |
51 | vec3 Dir2 = normalize(vec3(0.0,1.0,0.0));
52 |
53 | vec3 Dir3 = normalize(vec3(uv.x*4.0-5.67,uv.y*4.0-1.2,0.0));
54 |
55 | vec3 vLight = normalize(vec3(uvl.x+(0.5*sin(iGlobalTime)),uvl.y+(0.5*cos(iGlobalTime)),0.5));
56 |
57 | vec3 vEye = vec3(0.0,0.0,1.0);
58 |
59 | float sh = clamp(dot(vNormal,vLight),0.0,1.0);
60 |
61 | vec3 Dir = mix(mix(Dir1,Dir2,spm),Dir3,min(s1*48.0,1.0));
62 |
63 | vec3 sp = WardAnisotropy(vNormal,Dir,vEye,vLight,Roughness)*vec3(24.0);
64 |
65 | vec3 Color = vec3(0.15)+vec3(0.45)*sh+sp;
66 |
67 | fragColor = vec4(Color,1.0);
68 | }
--------------------------------------------------------------------------------
/src/reference/beer_lambert.frag:
--------------------------------------------------------------------------------
1 | // https://www.shadertoy.com/view/Mlc3Ds
2 |
3 | float BeerLambert(float sigma_t, float d)
4 | {
5 | return exp(-sigma_t * d);
6 | }
7 |
8 | void mainImage( out vec4 fragColor, in vec2 fragCoord )
9 | {
10 | // compute length of medium from mouse X
11 | float d = iMouse.x / iResolution.x * 5.0;
12 | // compute extinction factor from mouse Y
13 | float sigma_t = iMouse.y / iResolution.y * 20.0;
14 |
15 | // default input (for shadertoy preview)
16 | if (iMouse.xy == vec2(0.0)) {
17 | d = 2.0;
18 | sigma_t = 5.0;
19 | }
20 |
21 | // how far the current pixel has traveled in the medium
22 | float x = fragCoord.x / iResolution.x * d;
23 | // compute the extinction function for this pixel's distance in the medium
24 | float T = BeerLambert(sigma_t, x);
25 |
26 | // convert to a color
27 | vec4 color = vec4(vec3(T),1.0);
28 | // gamma-correct it
29 | color.rgb = pow(color.rgb, vec3(1.0/2.2));
30 |
31 | // display color
32 | fragColor = color;
33 | }
--------------------------------------------------------------------------------
/src/reference/elevated.frag:
--------------------------------------------------------------------------------
1 | // Created by inigo quilez - iq/2013
2 | // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
3 |
4 | #define SC (250.0)
5 |
6 | // value noise, and its analytical derivatives
7 | vec3 noised( in vec2 x )
8 | {
9 | vec2 p = floor(x);
10 | vec2 f = fract(x);
11 | vec2 u = f*f*(3.0-2.0*f);
12 | float a = texture2D(iChannel0,(p+vec2(0.5,0.5))/256.0,-100.0).x;
13 | float b = texture2D(iChannel0,(p+vec2(1.5,0.5))/256.0,-100.0).x;
14 | float c = texture2D(iChannel0,(p+vec2(0.5,1.5))/256.0,-100.0).x;
15 | float d = texture2D(iChannel0,(p+vec2(1.5,1.5))/256.0,-100.0).x;
16 | return vec3(a+(b-a)*u.x+(c-a)*u.y+(a-b-c+d)*u.x*u.y,
17 | 6.0*f*(1.0-f)*(vec2(b-a,c-a)+(a-b-c+d)*u.yx));
18 | }
19 |
20 | const mat2 m2 = mat2(0.8,-0.6,0.6,0.8);
21 |
22 | float detailH( in vec2 x )
23 | {
24 | float d = 0.0;//50.0*texture2D( iChannel2, x*0.03/SC, 0.0 ).x;
25 | return d + 0.5*texture2D( iChannel2, x*2.0/SC, 0.0 ).x;
26 | }
27 |
28 | float detailM( in vec2 x )
29 | {
30 | float d = 0.0;//50.0*texture2D( iChannel2, x*0.03/SC, 0.0 ).x;
31 | return d;
32 | }
33 |
34 | float terrainH( in vec2 x )
35 | {
36 | vec2 p = x*0.003/SC;
37 | float a = 0.0;
38 | float b = 1.0;
39 | vec2 d = vec2(0.0);
40 | for( int i=0; i<15; i++ )
41 | {
42 | vec3 n = noised(p);
43 | d += n.yz;
44 | a += b*n.x/(1.0+dot(d,d));
45 | b *= 0.5;
46 | p = m2*p*2.0;
47 | }
48 |
49 | float de = detailH(x);
50 | return SC*100.0*a - de;
51 | }
52 |
53 | float terrainM( in vec2 x )
54 | {
55 | vec2 p = x*0.003/SC;
56 | float a = 0.0;
57 | float b = 1.0;
58 | vec2 d = vec2(0.0);
59 | for( int i=0; i<9; i++ )
60 | {
61 | vec3 n = noised(p);
62 | d += n.yz;
63 | a += b*n.x/(1.0+dot(d,d));
64 | b *= 0.5;
65 | p = m2*p*2.0;
66 | }
67 | return SC*100.0*a - detailH(x);
68 | }
69 |
70 | float terrainL( in vec2 x )
71 | {
72 | vec2 p = x*0.003/SC;
73 | float a = 0.0;
74 | float b = 1.0;
75 | vec2 d = vec2(0.0);
76 | for( int i=0; i<7; i++ )
77 | {
78 | vec3 n = noised(p);
79 | d += n.yz;
80 | a += b*n.x/(1.0+dot(d,d));
81 | b *= 0.5;
82 | p = m2*p*2.0;
83 | }
84 |
85 | return SC*100.0*a;
86 | }
87 |
88 | float interesct( in vec3 ro, in vec3 rd, in float tmin, in float tmax )
89 | {
90 | float t = tmin;
91 | for( int i=0; i<256; i++ )
92 | {
93 | vec3 pos = ro + t*rd;
94 | float h = pos.y - terrainM( pos.xz );
95 | if( h<(0.002*t) || t>tmax ) break;
96 | t += 0.5*h;
97 | }
98 |
99 | return t;
100 | }
101 |
102 | float softShadow(in vec3 ro, in vec3 rd )
103 | {
104 | // real shadows
105 | float res = 1.0;
106 | float t = 0.001;
107 | for( int i=0; i<80; i++ )
108 | {
109 | vec3 p = ro + t*rd;
110 | float h = p.y - terrainM( p.xz );
111 | res = min( res, 16.0*h/t );
112 | t += h;
113 | if( res<0.001 ||p.y>(SC*200.0) ) break;
114 | }
115 | return clamp( res, 0.0, 1.0 );
116 | }
117 |
118 | vec3 calcNormal( in vec3 pos, float t )
119 | {
120 | vec2 eps = vec2( 0.002*t, 0.0 );
121 | return normalize( vec3( terrainH(pos.xz-eps.xy) - terrainH(pos.xz+eps.xy),
122 | 2.0*eps.x,
123 | terrainH(pos.xz-eps.yx) - terrainH(pos.xz+eps.yx) ) );
124 | }
125 |
126 | vec3 camPath( float time )
127 | {
128 | return SC*1100.0*vec3( cos(0.0+0.23*time), 0.0, cos(1.5+0.21*time) );
129 | }
130 |
131 | float fbm( vec2 p )
132 | {
133 | float f = 0.0;
134 | f += 0.5000*texture2D( iChannel0, p/256.0 ).x; p = m2*p*2.02;
135 | f += 0.2500*texture2D( iChannel0, p/256.0 ).x; p = m2*p*2.03;
136 | f += 0.1250*texture2D( iChannel0, p/256.0 ).x; p = m2*p*2.01;
137 | f += 0.0625*texture2D( iChannel0, p/256.0 ).x;
138 | return f/0.9375;
139 | }
140 |
141 | mat3 setCamera( in vec3 ro, in vec3 ta, in float cr )
142 | {
143 | vec3 cw = normalize(ta-ro);
144 | vec3 cp = vec3(sin(cr), cos(cr),0.0);
145 | vec3 cu = normalize( cross(cw,cp) );
146 | vec3 cv = normalize( cross(cu,cw) );
147 | return mat3( cu, cv, cw );
148 | }
149 |
150 | vec3 render( in vec3 ro, in vec3 rd )
151 | {
152 | vec3 light1 = normalize( vec3(-0.8,0.4,-0.3) );
153 | // bounding plane
154 | float tmin = 1.0;
155 | float tmax = 1000.0*SC;
156 | #if 1
157 | float maxh = 300.0*SC;
158 | float tp = (maxh-ro.y)/rd.y;
159 | if( tp>0.0 )
160 | {
161 | if( ro.y>maxh ) tmin = max( tmin, tp );
162 | else tmax = min( tmax, tp );
163 | }
164 | #endif
165 | float sundot = clamp(dot(rd,light1),0.0,1.0);
166 | vec3 col;
167 | float t = interesct( ro, rd, tmin, tmax );
168 | if( t>tmax)
169 | {
170 | // sky
171 | col = vec3(0.3,.55,0.8)*(1.0-0.8*rd.y)*0.9;
172 | // sun
173 | col += 0.25*vec3(1.0,0.7,0.4)*pow( sundot,5.0 );
174 | col += 0.25*vec3(1.0,0.8,0.6)*pow( sundot,64.0 );
175 | col += 0.2*vec3(1.0,0.8,0.6)*pow( sundot,512.0 );
176 | // clouds
177 | vec2 sc = ro.xz + rd.xz*(SC*1000.0-ro.y)/rd.y;
178 | col = mix( col, vec3(1.0,0.95,1.0), 0.5*smoothstep(0.5,0.8,fbm(0.0005*sc/SC)) );
179 | // horizon
180 | col = mix( col, vec3(0.7,0.75,0.8), pow( 1.0-max(rd.y,0.0), 8.0 ) );
181 | }
182 | else
183 | {
184 | // mountains
185 | vec3 pos = ro + t*rd;
186 | vec3 nor = calcNormal( pos, t );
187 | //nor = normalize( nor + 0.5*( vec3(-1.0,0.0,-1.0) + vec3(2.0,1.0,2.0)*texture2D(iChannel1,0.01*pos.xz).xyz) );
188 | vec3 ref = reflect( rd, nor );
189 | float fre = clamp( 1.0+dot(rd,nor), 0.0, 1.0 );
190 |
191 | // rock
192 | float r = texture2D( iChannel0, (7.0/SC)*pos.xz/256.0 ).x;
193 | col = (r*0.25+0.75)*0.9*mix( vec3(0.08,0.05,0.03), vec3(0.10,0.09,0.08),
194 | texture2D(iChannel0,0.00007*vec2(pos.x,pos.y*48.0)/SC).x );
195 | col = mix( col, 0.20*vec3(0.45,.30,0.15)*(0.50+0.50*r),smoothstep(0.70,0.9,nor.y) );
196 | col = mix( col, 0.15*vec3(0.30,.30,0.10)*(0.25+0.75*r),smoothstep(0.95,1.0,nor.y) );
197 |
198 | // snow
199 | float h = smoothstep(55.0,80.0,pos.y/SC + 25.0*fbm(0.01*pos.xz/SC) );
200 | float e = smoothstep(1.0-0.5*h,1.0-0.1*h,nor.y);
201 | float o = 0.3 + 0.7*smoothstep(0.0,0.1,nor.x+h*h);
202 | float s = h*e*o;
203 | col = mix( col, 0.29*vec3(0.62,0.65,0.7), smoothstep( 0.1, 0.9, s ) );
204 |
205 | // lighting
206 | float amb = clamp(0.5+0.5*nor.y,0.0,1.0);
207 | float dif = clamp( dot( light1, nor ), 0.0, 1.0 );
208 | float bac = clamp( 0.2 + 0.8*dot( normalize( vec3(-light1.x, 0.0, light1.z ) ), nor ), 0.0, 1.0 );
209 | float sh = 1.0; if( dif>=0.0001 ) sh = softShadow(pos+light1*20.0,light1);
210 |
211 | vec3 lin = vec3(0.0);
212 | lin += dif*vec3(7.00,5.00,3.00)*vec3( sh, sh*sh*0.5+0.5*sh, sh*sh*0.8+0.2*sh );
213 | lin += amb*vec3(0.40,0.60,0.80)*1.2;
214 | lin += bac*vec3(0.40,0.50,0.60);
215 | col *= lin;
216 |
217 | col += s*0.1*pow(fre,4.0)*vec3(7.0,5.0,3.0)*sh * pow( clamp(dot(light1,ref), 0.0, 1.0),16.0);
218 | col += s*0.1*pow(fre,4.0)*vec3(0.4,0.5,0.6)*smoothstep(0.0,0.6,ref.y);
219 |
220 | // fog
221 | //float fo = 1.0-exp(-0.000004*t*t/(SC*SC) );
222 | float fo = 1.0-exp(-0.001*t/SC );
223 | vec3 fco = 0.7*vec3(0.5,0.7,0.9) + 0.1*vec3(1.0,0.8,0.5)*pow( sundot, 4.0 );
224 | col = mix( col, fco, fo );
225 |
226 | // sun scatter
227 | col += 0.3*vec3(1.0,0.8,0.4)*pow( sundot, 8.0 )*(1.0-exp(-0.002*t/SC));
228 | }
229 |
230 | // gamma
231 | col = pow(col,vec3(0.4545));
232 |
233 | return col;
234 | }
235 |
236 | void mainImage( out vec4 fragColor, in vec2 fragCoord )
237 | {
238 | vec2 xy = -1.0 + 2.0*fragCoord.xy/iResolution.xy;
239 | vec2 s = xy*vec2(iResolution.x/iResolution.y,1.0);
240 |
241 | float time = iGlobalTime*0.15 + 0.3 + 4.0*iMouse.x/iResolution.x;
242 |
243 | // camera position
244 | vec3 ro = camPath( time );
245 | vec3 ta = camPath( time + 3.0 );
246 | ro.y = terrainL( ro.xz ) + 11.0*SC;
247 | ta.y = ro.y - 20.0*SC;
248 | float cr = 0.2*cos(0.1*time);
249 |
250 | //ro = vec3(0.0,0.0,0.0); ro += camPath(20.0 ); ro.y += terrainM( ro.xz ) + 4.0; cr = 0.0; ta = ro + vec3(0.0,0.0,-1.0);
251 |
252 | // camera2world transform
253 | mat3 cam = setCamera( ro, ta, cr );
254 |
255 | // camera ray
256 | vec3 rd = cam * normalize(vec3(s.xy,2.0));
257 |
258 | vec3 col = render( ro, rd );
259 |
260 | // vignetting
261 | col *= 0.5 + 0.5*pow( (xy.x+1.0)*(xy.y+1.0)*(xy.x-1.0)*(xy.y-1.0), 0.1 );
262 |
263 | fragColor = vec4( col, 1.0 );
264 | }
265 |
266 | void mainVR( out vec4 fragColor, in vec2 fragCoord, in vec3 fragRayOri, in vec3 fragRayDir )
267 | {
268 | vec3 ro = fragRayOri;
269 | ro = camPath( 20.0 );
270 | ro.y += terrainM( ro.xz ) + 2.0;
271 |
272 | fragColor = vec4( render( ro, fragRayDir ), 1.0 );
273 | }
--------------------------------------------------------------------------------
/src/reference/improved_perlin.frag:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Linearly Re-maps a value from one range to another
4 | */
5 | float map(float value, float old_lo, float old_hi, float new_lo, float new_hi)
6 | {
7 | float old_range = old_hi - old_lo;
8 | if (old_range == 0.0) {
9 | return new_lo;
10 | } else {
11 | float new_range = new_hi - new_lo;
12 | return (((value - old_lo) * new_range) / old_range) + new_lo;
13 | }
14 | }
15 |
16 | /**
17 | * The canonical GLSL hash function
18 | */
19 | float hash(float x)
20 | {
21 | return fract(sin(x) * 43758.5453123);
22 | }
23 |
24 | /**
25 | * Nothing is mathematically sound about anything below:
26 | * I just chose values based on experimentation and some
27 | * intuitions I have about what makes a good hash function
28 | */
29 | vec3 gradient(vec3 cell)
30 | {
31 | float h_i = hash(cell.x);
32 | float h_j = hash(cell.y + pow(h_i, 3.0));
33 | float h_k = hash(cell.z + pow(h_j, 5.0));
34 | float ii = map(fract(h_i + h_j + h_k), 0.0, 1.0, -1.0, 1.0);
35 | float jj = map(fract(h_j + h_k), 0.0, 1.0, -1.0, 1.0);
36 | float kk = map(h_k, 0.0, 1.0, -1.0, 1.0);
37 | return normalize(vec3(ii, jj, kk));
38 | }
39 |
40 | /**
41 | * Perlin's "ease-curve" fade function
42 | */
43 | float fade(float t)
44 | {
45 | float t3 = t * t * t;
46 | float t4 = t3 * t;
47 | float t5 = t4 * t;
48 | return (6.0 * t5) - (15.0 * t4) + (10.0 * t3);
49 | }
50 |
51 | /**
52 | * The meat of it:
53 | *
54 | * It helps to visualize the unit cube:
55 | *
56 | * (0,1,1)----------------(1,1,1)
57 | * /| /|
58 | * / | / |
59 | * / | / |
60 | * / | / |
61 | * (0,1,0)-+--------------(1,1,0) |
62 | * | | | |
63 | * | | | |
64 | * | | | |
65 | * | (0,0,1)--------------+-(1,0,1)
66 | * | / | /
67 | * | / | /
68 | * | / | /
69 | * |/ |/
70 | * (0,0,0)----------------(1,0,0)
71 | */
72 | float noise(in vec3 coord)
73 | {
74 | vec3 cell = floor(coord);
75 | vec3 unit = fract(coord);
76 |
77 | vec3 unit_000 = unit;
78 | vec3 unit_100 = unit - vec3(1.0, 0.0, 0.0);
79 | vec3 unit_001 = unit - vec3(0.0, 0.0, 1.0);
80 | vec3 unit_101 = unit - vec3(1.0, 0.0, 1.0);
81 | vec3 unit_010 = unit - vec3(0.0, 1.0, 0.0);
82 | vec3 unit_110 = unit - vec3(1.0, 1.0, 0.0);
83 | vec3 unit_011 = unit - vec3(0.0, 1.0, 1.0);
84 | vec3 unit_111 = unit - 1.0;
85 |
86 | vec3 c_000 = cell;
87 | vec3 c_100 = cell + vec3(1.0, 0.0, 0.0);
88 | vec3 c_001 = cell + vec3(0.0, 0.0, 1.0);
89 | vec3 c_101 = cell + vec3(1.0, 0.0, 1.0);
90 | vec3 c_010 = cell + vec3(0.0, 1.0, 0.0);
91 | vec3 c_110 = cell + vec3(1.0, 1.0, 0.0);
92 | vec3 c_011 = cell + vec3(0.0, 1.0, 1.0);
93 | vec3 c_111 = cell + 1.0;
94 |
95 | float wx = fade(unit.x);
96 | float wy = fade(unit.y);
97 | float wz = fade(unit.z);
98 |
99 | float x000 = dot(gradient(c_000), unit_000);
100 | float x100 = dot(gradient(c_100), unit_100);
101 | float x001 = dot(gradient(c_001), unit_001);
102 | float x101 = dot(gradient(c_101), unit_101);
103 | float x010 = dot(gradient(c_010), unit_010);
104 | float x110 = dot(gradient(c_110), unit_110);
105 | float x011 = dot(gradient(c_011), unit_011);
106 | float x111 = dot(gradient(c_111), unit_111);
107 |
108 | // (0,0,0) - (1,0,0)
109 | // (0,0,1) - (1,0,1)
110 | // (0,1,0) - (1,1,0)
111 | // (0,1,1) - (1,1,1)
112 | float y0 = mix(x000, x100, wx);
113 | float y1 = mix(x001, x101, wx);
114 | float y2 = mix(x010, x110, wx);
115 | float y3 = mix(x011, x111, wx);
116 |
117 | float z0 = mix(y0, y2, wy);
118 | float z1 = mix(y1, y3, wy);
119 |
120 | return mix(z0, z1, wz);
121 | }
122 |
123 | void mainImage(out vec4 fragColor, in vec2 fragCoord)
124 | {
125 | float freq = 1.0 / 64.0;
126 | if (iMouse.y != 0.0) {
127 | freq = 1.0 / iMouse.y;
128 | }
129 |
130 | float blendAmount = 0.0;
131 | if (iMouse.x != 0.0) {
132 | blendAmount = iMouse.x / iResolution.x;
133 | }
134 |
135 | vec3 coord = vec3(fragCoord.xy, float(iFrame) * 0.75);
136 | float v = noise(coord * freq);
137 |
138 | float v_0 = map(v, -1.0, 1.0, 0.0, 1.0);
139 | float v_1 = 1.0 - abs(v);
140 | float v_p = mix(v_0, v_1, blendAmount);
141 |
142 | fragColor = vec4(v_p, v_p, v_p, 1.0);
143 | }
--------------------------------------------------------------------------------
/src/reference/musgrave_fbm.frag:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valentingalea/shaderbox/4d18b45cac9c9ef75de85697fae497c966e9f76f/src/reference/musgrave_fbm.frag
--------------------------------------------------------------------------------
/src/reference/noise_lab.frag:
--------------------------------------------------------------------------------
1 | //#define Use_Perlin
2 | //#define Use_Value
3 | #define Use_Simplex
4 |
5 | // ========= Hash ===========
6 |
7 | vec3 hashOld33(vec3 p)
8 | {
9 | p = vec3( dot(p,vec3(127.1,311.7, 74.7)),
10 | dot(p,vec3(269.5,183.3,246.1)),
11 | dot(p,vec3(113.5,271.9,124.6)));
12 |
13 | return -1.0 + 2.0 * fract(sin(p)*43758.5453123);
14 | }
15 |
16 | float hashOld31(vec3 p)
17 | {
18 | float h = dot(p,vec3(127.1,311.7, 74.7));
19 |
20 | return -1.0 + 2.0 * fract(sin(h)*43758.5453123);
21 | }
22 |
23 | // Grab from https://www.shadertoy.com/view/4djSRW
24 | #define MOD3 vec3(.1031,.11369,.13787)
25 | //#define MOD3 vec3(443.8975,397.2973, 491.1871)
26 | float hash31(vec3 p3)
27 | {
28 | p3 = fract(p3 * MOD3);
29 | p3 += dot(p3, p3.yzx + 19.19);
30 | return -1.0 + 2.0 * fract((p3.x + p3.y) * p3.z);
31 | }
32 |
33 | vec3 hash33(vec3 p3)
34 | {
35 | p3 = fract(p3 * MOD3);
36 | p3 += dot(p3, p3.yxz+19.19);
37 | return -1.0 + 2.0 * fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
38 | }
39 |
40 | // ========= Noise ===========
41 |
42 | float value_noise(vec3 p)
43 | {
44 | vec3 pi = floor(p);
45 | vec3 pf = p - pi;
46 |
47 | vec3 w = pf * pf * (3.0 - 2.0 * pf);
48 |
49 | return mix(
50 | mix(
51 | mix(hash31(pi + vec3(0, 0, 0)), hash31(pi + vec3(1, 0, 0)), w.x),
52 | mix(hash31(pi + vec3(0, 0, 1)), hash31(pi + vec3(1, 0, 1)), w.x),
53 | w.z),
54 | mix(
55 | mix(hash31(pi + vec3(0, 1, 0)), hash31(pi + vec3(1, 1, 0)), w.x),
56 | mix(hash31(pi + vec3(0, 1, 1)), hash31(pi + vec3(1, 1, 1)), w.x),
57 | w.z),
58 | w.y);
59 | }
60 |
61 | float perlin_noise(vec3 p)
62 | {
63 | vec3 pi = floor(p);
64 | vec3 pf = p - pi;
65 |
66 | vec3 w = pf * pf * (3.0 - 2.0 * pf);
67 |
68 | return mix(
69 | mix(
70 | mix(dot(pf - vec3(0, 0, 0), hash33(pi + vec3(0, 0, 0))),
71 | dot(pf - vec3(1, 0, 0), hash33(pi + vec3(1, 0, 0))),
72 | w.x),
73 | mix(dot(pf - vec3(0, 0, 1), hash33(pi + vec3(0, 0, 1))),
74 | dot(pf - vec3(1, 0, 1), hash33(pi + vec3(1, 0, 1))),
75 | w.x),
76 | w.z),
77 | mix(
78 | mix(dot(pf - vec3(0, 1, 0), hash33(pi + vec3(0, 1, 0))),
79 | dot(pf - vec3(1, 1, 0), hash33(pi + vec3(1, 1, 0))),
80 | w.x),
81 | mix(dot(pf - vec3(0, 1, 1), hash33(pi + vec3(0, 1, 1))),
82 | dot(pf - vec3(1, 1, 1), hash33(pi + vec3(1, 1, 1))),
83 | w.x),
84 | w.z),
85 | w.y);
86 | }
87 |
88 | float simplex_noise(vec3 p)
89 | {
90 | const float K1 = 0.333333333;
91 | const float K2 = 0.166666667;
92 |
93 | vec3 i = floor(p + (p.x + p.y + p.z) * K1);
94 | vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);
95 |
96 | // thx nikita: https://www.shadertoy.com/view/XsX3zB
97 | vec3 e = step(vec3(0.0), d0 - d0.yzx);
98 | vec3 i1 = e * (1.0 - e.zxy);
99 | vec3 i2 = 1.0 - e.zxy * (1.0 - e);
100 |
101 | vec3 d1 = d0 - (i1 - 1.0 * K2);
102 | vec3 d2 = d0 - (i2 - 2.0 * K2);
103 | vec3 d3 = d0 - (1.0 - 3.0 * K2);
104 |
105 | vec4 h = max(0.6 - vec4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0);
106 | vec4 n = h * h * h * h * vec4(dot(d0, hash33(i)), dot(d1, hash33(i + i1)), dot(d2, hash33(i + i2)), dot(d3, hash33(i + 1.0)));
107 |
108 | return dot(vec4(31.316), n);
109 | }
110 |
111 | float noise(vec3 p) {
112 | #ifdef Use_Perlin
113 | return perlin_noise(p * 2.0);
114 | #elif defined Use_Value
115 | return value_noise(p * 2.0);
116 | #elif defined Use_Simplex
117 | return simplex_noise(p);
118 | #endif
119 |
120 | return 0.0;
121 | }
122 |
123 | // ========== Different function ==========
124 |
125 | float noise_itself(vec3 p)
126 | {
127 | return noise(p * 8.0);
128 | }
129 |
130 | float noise_sum(vec3 p)
131 | {
132 | float f = 0.0;
133 | p = p * 4.0;
134 | f += 1.0000 * noise(p); p = 2.0 * p;
135 | f += 0.5000 * noise(p); p = 2.0 * p;
136 | f += 0.2500 * noise(p); p = 2.0 * p;
137 | f += 0.1250 * noise(p); p = 2.0 * p;
138 | f += 0.0625 * noise(p); p = 2.0 * p;
139 |
140 | return f;
141 | }
142 |
143 | float noise_sum_abs(vec3 p)
144 | {
145 | float f = 0.0;
146 | p = p * 3.0;
147 | f += 1.0000 * abs(noise(p)); p = 2.0 * p;
148 | f += 0.5000 * abs(noise(p)); p = 2.0 * p;
149 | f += 0.2500 * abs(noise(p)); p = 2.0 * p;
150 | f += 0.1250 * abs(noise(p)); p = 2.0 * p;
151 | f += 0.0625 * abs(noise(p)); p = 2.0 * p;
152 |
153 | return f;
154 | }
155 |
156 | float noise_sum_abs_sin(vec3 p)
157 | {
158 | float f = noise_sum_abs(p);
159 | f = sin(f * 2.5 + p.x * 5.0 - 1.5);
160 |
161 | return f * f;
162 | }
163 |
164 |
165 | // ========== Draw ==========
166 |
167 | vec3 draw_simple(float f)
168 | {
169 | f = f * 0.5 + 0.5;
170 | return f * vec3(25.0/255.0, 161.0/255.0, 245.0/255.0);
171 | }
172 |
173 | vec3 draw_cloud(float f)
174 | {
175 | f = f * 0.5 + 0.5;
176 | return mix( vec3(8.0/255.0, 65.0/255.0, 82.0/255.0),
177 | vec3(178.0/255.0, 161.0/255.0, 205.0/255.0),
178 | f*f);
179 | }
180 |
181 | vec3 draw_fire(float f)
182 | {
183 | f = f * 0.5 + 0.5;
184 | return mix( vec3(131.0/255.0, 8.0/255.0, 0.0/255.0),
185 | vec3(204.0/255.0, 194.0/255.0, 56.0/255.0),
186 | pow(f, 3.));
187 | }
188 |
189 | vec3 draw_marble(float f)
190 | {
191 | f = f * 0.5 + 0.5;
192 | return mix( vec3(31.0/255.0, 14.0/255.0, 4.0/255.0),
193 | vec3(172.0/255.0, 153.0/255.0, 138.0/255.0),
194 | 1.0 - pow(f, 3.));
195 | }
196 |
197 | vec3 draw_circle_outline(vec2 p, float radius, vec3 col)
198 | {
199 | p = 2.0 * p - vec2(iResolution.x/iResolution.y, 1.0);
200 | return mix(vec3(0.0), col, smoothstep(0.0, 0.02, abs(length(p) - radius)));
201 |
202 | }
203 |
204 | // ========= Marching ===========
205 | #define FAR 30.0
206 | #define PRECISE 0.001
207 | #define SPEED 0.05
208 |
209 | float map(vec3 pos)
210 | {
211 | return length(pos - (vec3(0.0, 0.0, 1.5) + iGlobalTime * vec3(0.0, 0.0, SPEED))) - 1.0;
212 | }
213 |
214 | vec3 normal(vec3 pos) {
215 | vec2 eps = vec2(0.001, 0.0);
216 | return normalize(vec3( map(pos + eps.xyy) - map(pos - eps.xyy),
217 | map(pos + eps.yxy) - map(pos - eps.yxy),
218 | map(pos + eps.yyx) - map(pos - eps.yyx)));
219 | }
220 |
221 | vec3 getBackground(vec2 uv, vec2 split)
222 | {
223 | vec3 pos = vec3(uv * vec2(iResolution.x/iResolution.y, 1.0), iGlobalTime * SPEED);
224 | float f;
225 | if (uv.x < split.x && uv.y > split.y) {
226 | f = noise_itself(pos);
227 | } else if (uv.x < split.x && uv.y <= split.y) {
228 | f = noise_sum(pos);
229 | } else if (uv.x >= split.x && uv.y < split.y) {
230 | f = noise_sum_abs(pos);
231 | } else {
232 | f = noise_sum_abs_sin(pos);
233 | }
234 |
235 | return vec3(f * 0.5 + 0.5);
236 | }
237 |
238 | vec3 getColor(vec2 uv, vec3 pos, vec3 rd, vec2 split)
239 | {
240 | vec3 nor = normal(pos);
241 | vec3 light = normalize(vec3(0.5, 1.0, -0.2));
242 |
243 | float diff = dot(light, nor);
244 | diff = diff * 0.5 + 0.5;
245 |
246 | vec3 col;
247 | float f;
248 | if (uv.x < split.x && uv.y > split.y) {
249 | f = noise_itself(pos);
250 | col = draw_simple(f);
251 | } else if (uv.x < split.x && uv.y <= split.y) {
252 | f = noise_sum(pos);
253 | col = draw_cloud(f);
254 | } else if (uv.x >= split.x && uv.y < split.y) {
255 | f = noise_sum_abs(pos);
256 | col = draw_fire(f);
257 | } else {
258 | f = noise_sum_abs_sin(pos);
259 | col = draw_marble(f);
260 | }
261 |
262 | vec3 edge = col * pow((1.0 - clamp(dot(nor, -rd), 0.0, 1.0)), 5.0);
263 |
264 | return col + edge;
265 | }
266 |
267 | vec3 marching(vec3 ro, vec3 rd, vec2 uv, vec2 split)
268 | {
269 | float t = 0.0;
270 | float d = 1.0;
271 | vec3 pos;
272 | for (int i = 0; i < 50; i++) {
273 | pos = ro + rd * t;
274 | d = map(pos);
275 | t += d;
276 | if (d < PRECISE || t > FAR) break;
277 | }
278 |
279 | vec3 col = getBackground(uv, split);
280 |
281 | if (t < FAR) {
282 | pos = ro + rd * t;
283 | col = getColor(uv, pos, rd, split);
284 | }
285 |
286 | return col;
287 | }
288 |
289 | void mainImage( out vec4 fragColor, in vec2 fragCoord )
290 | {
291 | vec2 p = fragCoord.xy / iResolution.xy;
292 | vec2 split = vec2(0.5, 0.5);
293 | if (iMouse.z > 0.0) {
294 | split += 2.0 * iMouse.xy/iResolution.xy - 1.0;
295 | }
296 |
297 | vec3 col = vec3(0.0, 0.0, 0.0);
298 |
299 | vec3 ro = vec3(0.0, 0.0, 0.0) + iGlobalTime * vec3(0.0, 0.0, SPEED);
300 | vec3 rd = vec3((p * 2.0 - 1.0) * vec2(iResolution.x/iResolution.y, 1.0), 1.0);
301 | col = marching(ro, rd, p, split);
302 |
303 | col = draw_circle_outline(p * vec2(iResolution.x/iResolution.y, 1.0), 0.9, col);
304 | col = mix(vec3(0.3, 0.0, 0.0), col, smoothstep(0.0, 0.005, abs(p.x - split.x)));
305 | col = mix(vec3(0.3, 0.0, 0.0), col, smoothstep(0.0, 0.005*iResolution.x/iResolution.y, abs(p.y - split.y)));
306 |
307 | fragColor = vec4(col, 1.0);
308 | }
--------------------------------------------------------------------------------
/src/reference/primitives.frag:
--------------------------------------------------------------------------------
1 | // Created by inigo quilez - iq/2013
2 | // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
3 |
4 | // A list of usefull distance function to simple primitives, and an example on how to
5 | // do some interesting boolean operations, repetition and displacement.
6 | //
7 | // More info here: http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
8 |
9 | float sdPlane( vec3 p )
10 | {
11 | return p.y;
12 | }
13 |
14 | float sdSphere( vec3 p, float s )
15 | {
16 | return length(p)-s;
17 | }
18 |
19 | float sdBox( vec3 p, vec3 b )
20 | {
21 | vec3 d = abs(p) - b;
22 | return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
23 | }
24 |
25 | float sdEllipsoid( in vec3 p, in vec3 r )
26 | {
27 | return (length( p/r ) - 1.0) * min(min(r.x,r.y),r.z);
28 | }
29 |
30 | float udRoundBox( vec3 p, vec3 b, float r )
31 | {
32 | return length(max(abs(p)-b,0.0))-r;
33 | }
34 |
35 | float sdTorus( vec3 p, vec2 t )
36 | {
37 | return length( vec2(length(p.xz)-t.x,p.y) )-t.y;
38 | }
39 |
40 | float sdHexPrism( vec3 p, vec2 h )
41 | {
42 | vec3 q = abs(p);
43 | #if 0
44 | return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x);
45 | #else
46 | float d1 = q.z-h.y;
47 | float d2 = max((q.x*0.866025+q.y*0.5),q.y)-h.x;
48 | return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);
49 | #endif
50 | }
51 |
52 | float sdCapsule( vec3 p, vec3 a, vec3 b, float r )
53 | {
54 | vec3 pa = p-a, ba = b-a;
55 | float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
56 | return length( pa - ba*h ) - r;
57 | }
58 |
59 | float sdTriPrism( vec3 p, vec2 h )
60 | {
61 | vec3 q = abs(p);
62 | #if 0
63 | return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);
64 | #else
65 | float d1 = q.z-h.y;
66 | float d2 = max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5;
67 | return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);
68 | #endif
69 | }
70 |
71 | float sdCylinder( vec3 p, vec2 h )
72 | {
73 | vec2 d = abs(vec2(length(p.xz),p.y)) - h;
74 | return min(max(d.x,d.y),0.0) + length(max(d,0.0));
75 | }
76 |
77 | float sdCone( in vec3 p, in vec3 c )
78 | {
79 | vec2 q = vec2( length(p.xz), p.y );
80 | float d1 = -q.y-c.z;
81 | float d2 = max( dot(q,c.xy), q.y);
82 | return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);
83 | }
84 |
85 | float sdConeSection( in vec3 p, in float h, in float r1, in float r2 )
86 | {
87 | float d1 = -p.y - h;
88 | float q = p.y - h;
89 | float si = 0.5*(r1-r2)/h;
90 | float d2 = max( sqrt( dot(p.xz,p.xz)*(1.0-si*si)) + q*si - r2, q );
91 | return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);
92 | }
93 |
94 |
95 | float length2( vec2 p )
96 | {
97 | return sqrt( p.x*p.x + p.y*p.y );
98 | }
99 |
100 | float length6( vec2 p )
101 | {
102 | p = p*p*p; p = p*p;
103 | return pow( p.x + p.y, 1.0/6.0 );
104 | }
105 |
106 | float length8( vec2 p )
107 | {
108 | p = p*p; p = p*p; p = p*p;
109 | return pow( p.x + p.y, 1.0/8.0 );
110 | }
111 |
112 | float sdTorus82( vec3 p, vec2 t )
113 | {
114 | vec2 q = vec2(length2(p.xz)-t.x,p.y);
115 | return length8(q)-t.y;
116 | }
117 |
118 | float sdTorus88( vec3 p, vec2 t )
119 | {
120 | vec2 q = vec2(length8(p.xz)-t.x,p.y);
121 | return length8(q)-t.y;
122 | }
123 |
124 | float sdCylinder6( vec3 p, vec2 h )
125 | {
126 | return max( length6(p.xz)-h.x, abs(p.y)-h.y );
127 | }
128 |
129 | //----------------------------------------------------------------------
130 |
131 | float opS( float d1, float d2 )
132 | {
133 | return max(-d2,d1);
134 | }
135 |
136 | vec2 opU( vec2 d1, vec2 d2 )
137 | {
138 | return (d1.x0.0 ) tmax = min( tmax, tp1 );
200 | float tp2 = (1.6-ro.y)/rd.y; if( tp2>0.0 ) { if( ro.y>1.6 ) tmin = max( tmin, tp2 );
201 | else tmax = min( tmax, tp2 ); }
202 | #endif
203 |
204 | float precis = 0.002;
205 | float t = tmin;
206 | float m = -1.0;
207 | for( int i=0; i<50; i++ )
208 | {
209 | vec2 res = map( ro+rd*t );
210 | if( res.xtmax ) break;
211 | t += res.x;
212 | m = res.y;
213 | }
214 |
215 | if( t>tmax ) m=-1.0;
216 | return vec2( t, m );
217 | }
218 |
219 |
220 | float softshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax )
221 | {
222 | float res = 1.0;
223 | float t = mint;
224 | for( int i=0; i<16; i++ )
225 | {
226 | float h = map( ro + rd*t ).x;
227 | res = min( res, 8.0*h/t );
228 | t += clamp( h, 0.02, 0.10 );
229 | if( h<0.001 || t>tmax ) break;
230 | }
231 | return clamp( res, 0.0, 1.0 );
232 |
233 | }
234 |
235 | vec3 calcNormal( in vec3 pos )
236 | {
237 | vec3 eps = vec3( 0.001, 0.0, 0.0 );
238 | vec3 nor = vec3(
239 | map(pos+eps.xyy).x - map(pos-eps.xyy).x,
240 | map(pos+eps.yxy).x - map(pos-eps.yxy).x,
241 | map(pos+eps.yyx).x - map(pos-eps.yyx).x );
242 | return normalize(nor);
243 | }
244 |
245 | float calcAO( in vec3 pos, in vec3 nor )
246 | {
247 | float occ = 0.0;
248 | float sca = 1.0;
249 | for( int i=0; i<5; i++ )
250 | {
251 | float hr = 0.01 + 0.12*float(i)/4.0;
252 | vec3 aopos = nor * hr + pos;
253 | float dd = map( aopos ).x;
254 | occ += -(dd-hr)*sca;
255 | sca *= 0.95;
256 | }
257 | return clamp( 1.0 - 3.0*occ, 0.0, 1.0 );
258 | }
259 |
260 |
261 |
262 |
263 | vec3 render( in vec3 ro, in vec3 rd )
264 | {
265 | vec3 col = vec3(0.7, 0.9, 1.0) +rd.y*0.8;
266 | vec2 res = castRay(ro,rd);
267 | float t = res.x;
268 | float m = res.y;
269 | if( m>-0.5 )
270 | {
271 | vec3 pos = ro + t*rd;
272 | vec3 nor = calcNormal( pos );
273 | vec3 ref = reflect( rd, nor );
274 |
275 | // material
276 | col = 0.45 + 0.3*sin( vec3(0.05,0.08,0.10)*(m-1.0) );
277 |
278 | if( m<1.5 )
279 | {
280 |
281 | float f = mod( floor(5.0*pos.z) + floor(5.0*pos.x), 2.0);
282 | col = 0.4 + 0.1*f*vec3(1.0);
283 | }
284 |
285 | // lighitng
286 | float occ = calcAO( pos, nor );
287 | vec3 lig = normalize( vec3(-0.6, 0.7, -0.5) );
288 | float amb = clamp( 0.5+0.5*nor.y, 0.0, 1.0 );
289 | float dif = clamp( dot( nor, lig ), 0.0, 1.0 );
290 | float bac = clamp( dot( nor, normalize(vec3(-lig.x,0.0,-lig.z))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0);
291 | float dom = smoothstep( -0.1, 0.1, ref.y );
292 | float fre = pow( clamp(1.0+dot(nor,rd),0.0,1.0), 2.0 );
293 | float spe = pow(clamp( dot( ref, lig ), 0.0, 1.0 ),16.0);
294 |
295 | dif *= softshadow( pos, lig, 0.02, 2.5 );
296 | dom *= softshadow( pos, ref, 0.02, 2.5 );
297 |
298 | vec3 lin = vec3(0.0);
299 | lin += 1.20*dif*vec3(1.00,0.85,0.55);
300 | lin += 1.20*spe*vec3(1.00,0.85,0.55)*dif;
301 | lin += 0.20*amb*vec3(0.50,0.70,1.00)*occ;
302 | lin += 0.30*dom*vec3(0.50,0.70,1.00)*occ;
303 | lin += 0.30*bac*vec3(0.25,0.25,0.25)*occ;
304 | lin += 0.40*fre*vec3(1.00,1.00,1.00)*occ;
305 | col = col*lin;
306 |
307 | col = mix( col, vec3(0.8,0.9,1.0), 1.0-exp( -0.002*t*t ) );
308 |
309 | }
310 |
311 | return vec3( clamp(col,0.0,1.0) );
312 | }
313 |
314 | mat3 setCamera( in vec3 ro, in vec3 ta, float cr )
315 | {
316 | vec3 cw = normalize(ta-ro);
317 | vec3 cp = vec3(sin(cr), cos(cr),0.0);
318 | vec3 cu = normalize( cross(cw,cp) );
319 | vec3 cv = normalize( cross(cu,cw) );
320 | return mat3( cu, cv, cw );
321 | }
322 |
323 | void mainImage( out vec4 fragColor, in vec2 fragCoord )
324 | {
325 | vec2 q = fragCoord.xy/iResolution.xy;
326 | vec2 p = -1.0+2.0*q;
327 | p.x *= iResolution.x/iResolution.y;
328 | vec2 mo = iMouse.xy/iResolution.xy;
329 |
330 | float time = 15.0 + iGlobalTime;
331 |
332 | // camera
333 | vec3 ro = vec3( -0.5+3.5*cos(0.1*time + 6.0*mo.x), 1.0 + 2.0*mo.y, 0.5 + 3.5*sin(0.1*time + 6.0*mo.x) );
334 | vec3 ta = vec3( -0.5, -0.4, 0.5 );
335 |
336 | // camera-to-world transformation
337 | mat3 ca = setCamera( ro, ta, 0.0 );
338 |
339 | // ray direction
340 | vec3 rd = ca * normalize( vec3(p.xy,2.0) );
341 |
342 | // render
343 | vec3 col = render( ro, rd );
344 |
345 | col = pow( col, vec3(0.4545) );
346 |
347 | fragColor=vec4( col, 1.0 );
348 | }
--------------------------------------------------------------------------------
/src/reference/simplex_noise.frag:
--------------------------------------------------------------------------------
1 | /* Created by Nikita Miropolskiy, nikat/2013
2 | * This work is licensed under a
3 | * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
4 | * http://creativecommons.org/licenses/by-nc-sa/3.0/
5 | * - You must attribute the work in the source code
6 | * (link to https://www.shadertoy.com/view/XsX3zB).
7 | * - You may not use this work for commercial purposes.
8 | * - You may distribute a derivative work only under the same license.
9 | */
10 |
11 | /* discontinuous pseudorandom uniformly distributed in [-0.5, +0.5]^3 */
12 | vec3 random3(vec3 c) {
13 | float j = 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0)));
14 | vec3 r;
15 | r.z = fract(512.0*j);
16 | j *= .125;
17 | r.x = fract(512.0*j);
18 | j *= .125;
19 | r.y = fract(512.0*j);
20 | return r-0.5;
21 | }
22 |
23 | /* skew constants for 3d simplex functions */
24 | const float F3 = 0.3333333;
25 | const float G3 = 0.1666667;
26 |
27 | /* 3d simplex noise */
28 | float simplex3d(vec3 p) {
29 | /* 1. find current tetrahedron T and it's four vertices */
30 | /* s, s+i1, s+i2, s+1.0 - absolute skewed (integer) coordinates of T vertices */
31 | /* x, x1, x2, x3 - unskewed coordinates of p relative to each of T vertices*/
32 |
33 | /* calculate s and x */
34 | vec3 s = floor(p + dot(p, vec3(F3)));
35 | vec3 x = p - s + dot(s, vec3(G3));
36 |
37 | /* calculate i1 and i2 */
38 | vec3 e = step(vec3(0.0), x - x.yzx);
39 | vec3 i1 = e*(1.0 - e.zxy);
40 | vec3 i2 = 1.0 - e.zxy*(1.0 - e);
41 |
42 | /* x1, x2, x3 */
43 | vec3 x1 = x - i1 + G3;
44 | vec3 x2 = x - i2 + 2.0*G3;
45 | vec3 x3 = x - 1.0 + 3.0*G3;
46 |
47 | /* 2. find four surflets and store them in d */
48 | vec4 w, d;
49 |
50 | /* calculate surflet weights */
51 | w.x = dot(x, x);
52 | w.y = dot(x1, x1);
53 | w.z = dot(x2, x2);
54 | w.w = dot(x3, x3);
55 |
56 | /* w fades from 0.6 at the center of the surflet to 0.0 at the margin */
57 | w = max(0.6 - w, 0.0);
58 |
59 | /* calculate surflet components */
60 | d.x = dot(random3(s), x);
61 | d.y = dot(random3(s + i1), x1);
62 | d.z = dot(random3(s + i2), x2);
63 | d.w = dot(random3(s + 1.0), x3);
64 |
65 | /* multiply d by w^4 */
66 | w *= w;
67 | w *= w;
68 | d *= w;
69 |
70 | /* 3. return the sum of the four surflets */
71 | return dot(d, vec4(52.0));
72 | }
73 |
74 | float simplex3d_fractal(vec3 m) {
75 | return 0.5333333*simplex3d(m)
76 | +0.2666667*simplex3d(2.0*m)
77 | +0.1333333*simplex3d(4.0*m)
78 | +0.0666667*simplex3d(8.0*m);
79 | }
80 |
81 | void mainImage( out vec4 fragColor, in vec2 fragCoord )
82 | {
83 | vec2 p = fragCoord.xy/iResolution.x;
84 | vec3 p3 = vec3(p, iGlobalTime*0.025);
85 |
86 | float value;
87 |
88 | if (p.x <= 0.6) {
89 | value = simplex3d(p3*32.0);
90 | } else {
91 | value = simplex3d_fractal(p3*8.0+8.0);
92 | }
93 |
94 | value = 0.5 + 0.5*value;
95 | value *= smoothstep(0.0, 0.005, abs(0.6-p.x)); // hello, iq :)
96 |
97 | fragColor = vec4(
98 | vec3(value),
99 | 1.0);
100 | return;
101 | }
--------------------------------------------------------------------------------
/src/sdf.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Signed Distance Fields functions
3 | // ----------------------------------------------------------------------------
4 |
5 | vec2 op_add( // union
6 | _in(vec2) d1,
7 | _in(vec2) d2
8 | ){
9 | // minimum distance (preserving material info)
10 | return d1.x < d2.x ? d1 : d2;
11 | }
12 |
13 | float op_add( // union
14 | _in(float) d1,
15 | _in(float) d2
16 | ){
17 | return min(d1, d2);
18 | }
19 |
20 | float op_sub( // difference
21 | _in(float) d1,
22 | _in(float) d2
23 | ){
24 | // intersection between first and
25 | // complement of the second field
26 | // aka the second 'carved out' from the first
27 | return max(d1, -d2);
28 | }
29 |
30 | float op_intersect( // intersection
31 | _in(float) d1,
32 | _in(float) d2
33 | ){
34 | // what's common for both fields
35 | return max(d1, d2);
36 | }
37 |
38 | float op_blend(
39 | _in(float) a,
40 | _in(float) b,
41 | _in(float) k // factor of smoothing
42 | ){
43 | // from http://iquilezles.org/www/articles/smin/smin.htm
44 | // NOTE: not true distance but estimate
45 | float h = clamp(0.5 + 0.5*(b - a) / k, 0.0, 1.0);
46 | return mix(b, a, h) - k*h*(1.0 - h);
47 | }
48 |
49 | float sd_plane(
50 | _in(vec3) p,
51 | _in(vec3) n, // normal
52 | _in(float) d // distance
53 | ){
54 | // distance from point to plane
55 | // http://mathworld.wolfram.com/Point-PlaneDistance.html
56 | return dot(n, p) + d;
57 | }
58 |
59 | float sd_sphere(
60 | _in(vec3) p,
61 | _in(float) r
62 | ){
63 | // distance to center of sphere offset by the radius
64 | return length(p) - r;
65 | }
66 |
67 | float sd_box(
68 | _in(vec3) p,
69 | _in(vec3) b // dimensions of box
70 | ){
71 | // intersection of 3 axis aligned 'slabs'
72 | return max(abs(p.x) - b.x, max(abs(p.y) - b.y, abs(p.z) - b.z));
73 | }
74 |
75 | float sd_torus( // around Z axis
76 | _in(vec3) p,
77 | _in(float) R, // 'donut' radius
78 | _in(float) r // thickness
79 | ){
80 | // projected circle of radius R on xy plane
81 | // combined with circle of radius r around z axis
82 | return length(vec2(length(p.xy) - R, p.z)) - r;
83 | }
84 |
85 | float sd_y_cylinder(
86 | _in(vec3) p,
87 | _in(float) r, // radius
88 | _in(float) h // height
89 | ){
90 | // distance to the Y axis, offset (aka inflated) by the cylinder radius
91 | // then intersected with 2 cutting planes
92 | return max(length(p.xz) - r, abs(p.y) - h / 2.);
93 | }
94 |
95 | float sd_cylinder(
96 | _in(vec3) P,
97 | _in(vec3) P0, // start point (relative to 'p')
98 | _in(vec3) P1, // end point (relative to 'p')
99 | _in(float) R // thickness
100 | ){
101 | // distance to segment -- http://geomalgorithms.com/a02-_lines.html
102 | // then cut it with 2 planes at the ends
103 | // then offset it with radius
104 | vec3 dir = normalize(P1 - P0);
105 | float dist = length(cross(dir, P - P0));
106 | float plane_1 = sd_plane(P, dir, length(P1));
107 | float plane_2 = sd_plane(P, -dir, -length(P0));
108 | return op_sub(op_sub(dist, plane_1), plane_2) - R;
109 | }
110 |
111 | // 3D Bezier curved cylinder
112 | // original by http://research.microsoft.com/en-us/um/people/hoppe/ravg.pdf
113 | // adapted by iq https://www.shadertoy.com/view/ldj3Wh
114 | float det2(
115 | _in(vec2) a,
116 | _in(vec2) b
117 | ){
118 | return a.x*b.y - b.x*a.y;
119 | }
120 | vec3 sd_bezier_get_closest(
121 | _in(vec2) b0,
122 | _in(vec2) b1,
123 | _in(vec2) b2
124 | ){
125 | float a = det2(b0, b2);
126 | float b = 2.0*det2(b1, b0);
127 | float d = 2.0*det2(b2, b1);
128 | float f = b*d - a*a;
129 | vec2 d21 = b2 - b1;
130 | vec2 d10 = b1 - b0;
131 | vec2 d20 = b2 - b0;
132 | vec2 gf = 2.0*(b*d21 + d*d10 + a*d20); gf = vec2(gf.y, -gf.x);
133 | vec2 pp = -f*gf / dot(gf, gf);
134 | vec2 d0p = b0 - pp;
135 | float ap = det2(d0p, d20);
136 | float bp = 2.0*det2(d10, d0p);
137 | float t = clamp((ap + bp) / (2.0*a + b + d), 0.0, 1.0);
138 | return vec3(mix(mix(b0, b1, t), mix(b1, b2, t), t), t);
139 | }
140 | vec2 sd_bezier(
141 | _in(vec3) a, // start
142 | _in(vec3) b, // knot (control point)
143 | _in(vec3) c, // end
144 | _in(vec3) p,
145 | _in(float) thickness
146 | ){
147 | vec3 w = normalize(cross(c - b, a - b));
148 | vec3 u = normalize(c - b);
149 | vec3 v = normalize(cross(w, u));
150 |
151 | vec2 a2 = vec2(dot(a - b, u), dot(a - b, v));
152 | vec2 b2 = vec2(0., 0.);
153 | vec2 c2 = vec2(dot(c - b, u), dot(c - b, v));
154 | vec3 p3 = vec3(dot(p - b, u), dot(p - b, v), dot(p - b, w));
155 |
156 | vec3 cp = sd_bezier_get_closest(a2 - p3.xy, b2 - p3.xy, c2 - p3.xy);
157 |
158 | return vec2(0.85*(sqrt(dot(cp.xy, cp.xy) + p3.z*p3.z) - thickness), cp.z);
159 | }
160 |
161 | // adapted from http://mercury.sexy/hg_sdf/
162 | float sd_capsule(
163 | _in(vec3) p,
164 | _in(vec3) a,
165 | _in(vec3) b,
166 | _in(float) r
167 | ){
168 | vec3 ab = b - a;
169 | float t = clamp(dot(p - a, ab) / dot(ab, ab), 0., 1.);
170 | return length((ab*t + a) - p) - r;
171 | }
--------------------------------------------------------------------------------
/src/uniform_buffer.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Uniform buffer cross-language definitions
3 | // ----------------------------------------------------------------------------
4 | #if defined(HLSLTOY) && defined(__cplusplus)
5 | #define _begin_ubuffer(name, num) struct alignas(16) name {
6 | #define _end_ubuffer }
7 | #define _uniform(type, name, default_value) type name = default_value
8 | #define _pack(x)
9 | #else
10 | #if defined(__cplusplus) || defined(GL_ES) || defined(GL_SHADING_LANGUAGE_VERSION)
11 | #define _begin_ubuffer(name, num) /* uniform name { */
12 | #define _end_ubuffer
13 | #define _uniform(type, name, default_value) const type name = default_value
14 | #define _pack(x)
15 | #endif
16 | #endif
17 |
18 | #ifdef HLSL
19 | #define _begin_ubuffer(name, num) cbuffer name : register(num) {
20 | #define _end_ubuffer }
21 | #define _uniform(type, name, default_value) type name
22 | #define _pack(x) : packoffset(x)
23 | #endif
24 |
25 | #if defined(HLSLTOY) || defined(HLSL)
26 | _begin_ubuffer(main_uniform_buffer_t, b0)
27 | _uniform(vec2, u_res, vec2(0, 0)) _pack(c0.x);
28 | _uniform(vec2, u_mouse, vec2(0, 0)) _pack(c0.z);
29 | _uniform(float, u_time, (0.)) _pack(c1);
30 | _end_ubuffer;
31 | #else
32 | #if defined(__cplusplus) || defined(SHADERTOY)
33 | #define u_res iResolution
34 | #define u_time iGlobalTime
35 | #define u_mouse iMouse
36 | #endif
37 | #endif
38 |
39 | #if defined(APP_CLOUDS)
40 | _begin_ubuffer(aux_uniform_buffer_t, b1)
41 | _uniform(vec3, wind_dir, vec3(0, 0, .2)) _pack(c0);
42 | _uniform(vec3, sun_dir, vec3(0, 0, -1)) _pack(c1);
43 | _uniform(vec3, sun_color, vec3(1., .7, .55)) _pack(c2);
44 | _uniform(float, sun_power, (8.)) _pack(c3.x);
45 |
46 | _uniform(int, cld_march_steps, (100)) _pack(c3.y);
47 | _uniform(int, illum_march_steps, (6)) _pack(c3.z);
48 |
49 | _uniform(float, sigma_scattering, (.15)) _pack(c3.w);
50 | _uniform(float, cld_coverage, (.535)) _pack(c4.x);
51 | _uniform(float, cld_thick, (125.)) _pack(c4.y);
52 |
53 | _uniform(float, atm_radius, (5000.)) _pack(c4.z);
54 | _uniform(float, atm_ground_y, (4750.)) _pack(c4.w);
55 | _end_ubuffer;
56 | #elif defined(APP_SDF_AO)
57 | _begin_ubuffer(aux_uniform_buffer_t, b1)
58 | _uniform(float, fog_density, (.1)) _pack(c0.x);
59 | _uniform(float, fog_falloff, (.5)) _pack(c0.y);
60 | _end_ubuffer;
61 | #else
62 | _begin_ubuffer(aux_uniform_buffer_t, b1)
63 | _end_ubuffer;
64 | #endif
--------------------------------------------------------------------------------
/src/util.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Various 3D utilities functions
3 | // ----------------------------------------------------------------------------
4 |
5 | ray_t get_primary_ray(
6 | _in(vec3) cam_local_point,
7 | _inout(vec3) cam_origin,
8 | _inout(vec3) cam_look_at
9 | ){
10 | vec3 fwd = normalize(cam_look_at - cam_origin);
11 | vec3 up = vec3(0, 1, 0);
12 | vec3 right = cross(up, fwd);
13 | up = cross(fwd, right);
14 |
15 | ray_t r = _begin(ray_t)
16 | cam_origin,
17 | normalize(fwd + up * cam_local_point.y + right * cam_local_point.x)
18 | _end;
19 | return r;
20 | }
21 |
22 | _constant(mat3) mat3_ident = mat3(1, 0, 0, 0, 1, 0, 0, 0, 1);
23 |
24 | #ifndef HLSL
25 | mat3 transpose(
26 | _in(mat3) m
27 | ){
28 | return mat3(
29 | m[0][0], m[1][0], m[2][0],
30 | m[0][1], m[1][1], m[2][1],
31 | m[0][2], m[1][2], m[2][2]);
32 | }
33 | #endif
34 |
35 | mat2 rotate_2d(
36 | _in(float) angle_degrees
37 | ){
38 | float angle = radians(angle_degrees);
39 | float _sin = sin(angle);
40 | float _cos = cos(angle);
41 | return mat2(_cos, -_sin, _sin, _cos);
42 | }
43 |
44 | mat3 rotate_around_z(
45 | _in(float) angle_degrees
46 | ){
47 | float angle = radians(angle_degrees);
48 | float _sin = sin(angle);
49 | float _cos = cos(angle);
50 | return mat3(_cos, -_sin, 0, _sin, _cos, 0, 0, 0, 1);
51 | }
52 |
53 | mat3 rotate_around_y(
54 | _in(float) angle_degrees
55 | ){
56 | float angle = radians(angle_degrees);
57 | float _sin = sin(angle);
58 | float _cos = cos(angle);
59 | return mat3(_cos, 0, _sin, 0, 1, 0, -_sin, 0, _cos);
60 | }
61 |
62 | mat3 rotate_around_x(
63 | _in(float) angle_degrees
64 | ){
65 | float angle = radians(angle_degrees);
66 | float _sin = sin(angle);
67 | float _cos = cos(angle);
68 | return mat3(1, 0, 0, 0, _cos, -_sin, 0, _sin, _cos);
69 | }
70 |
71 | // http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html
72 | vec3 linear_to_srgb(
73 | _in(vec3) color
74 | ){
75 | const float p = 1. / 2.2;
76 | return vec3(pow(color.r, p), pow(color.g, p), pow(color.b, p));
77 | }
78 | vec3 srgb_to_linear(
79 | _in(vec3) color
80 | ){
81 | const float p = 2.2;
82 | return vec3(pow(color.r, p), pow(color.g, p), pow(color.b, p));
83 | }
84 |
85 | #ifdef __cplusplus
86 | vec3 faceforward(
87 | _in(vec3) N,
88 | _in(vec3) I,
89 | _in(vec3) Nref
90 | ){
91 | return dot(Nref, I) < 0 ? N : -N;
92 | }
93 | #endif
94 |
95 | float checkboard_pattern(
96 | _in(vec2) pos,
97 | _in(float) scale
98 | ){
99 | vec2 pattern = floor(pos * scale);
100 | return mod(pattern.x + pattern.y, 2.0);
101 | }
102 |
103 | float band (
104 | _in(float) start,
105 | _in(float) peak,
106 | _in(float) end,
107 | _in(float) t
108 | ){
109 | return
110 | smoothstep (start, peak, t) *
111 | (1. - smoothstep (peak, end, t));
112 | }
113 |
114 | // from https://www.shadertoy.com/view/4sSSW3
115 | // original http://orbit.dtu.dk/fedora/objects/orbit:113874/datastreams/file_75b66578-222e-4c7d-abdf-f7e255100209/content
116 | void fast_orthonormal_basis(
117 | _in(vec3) n,
118 | _out(vec3) f,
119 | _out(vec3) r
120 | ){
121 | float a = 1. / (1. + n.z);
122 | float b = -n.x*n.y*a;
123 | f = vec3(1. - n.x*n.x*a, b, -n.x);
124 | r = vec3(b, 1. - n.y*n.y*a, -n.y);
125 | }
126 |
127 | float remap(
128 | _in(float) original_value,
129 | _in(float) original_min,
130 | _in(float) original_max,
131 | _in(float) new_min,
132 | _in(float) new_max
133 | ){
134 | return new_min +
135 | (((original_value - original_min) /
136 | (original_max - original_min)) *
137 | (new_max - new_min));
138 | }
139 |
140 |
--------------------------------------------------------------------------------
/src/util_optics.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valentingalea/shaderbox/4d18b45cac9c9ef75de85697fae497c966e9f76f/src/util_optics.h
--------------------------------------------------------------------------------
/src/volumetric.h:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Volumetric utilities
3 | // ----------------------------------------------------------------------------
4 |
5 | float isotropic_phase_func(float mu)
6 | {
7 | return
8 | 1.
9 | / //-------------------
10 | 4. * PI;
11 | }
12 |
13 | float rayleigh_phase_func(float mu)
14 | {
15 | return
16 | 3. * (1. + mu*mu)
17 | / //------------------------
18 | (16. * PI);
19 | }
20 |
21 | // Henyey-Greenstein phase function factor [-1, 1]
22 | // represents the average cosine of the scattered directions
23 | // 0 is isotropic scattering
24 | // > 1 is forward scattering, < 1 is backwards
25 | //#define hg_g
26 |
27 | float henyey_greenstein_phase_func(float mu)
28 | {
29 | return
30 | (1. - hg_g*hg_g)
31 | / //---------------------------------------------
32 | ((4. + PI) * pow(1. + hg_g*hg_g - 2.*hg_g*mu, 1.5));
33 | }
34 |
35 | float schlick_phase_func(float mu)
36 | {
37 | // Schlick Phase Function factor
38 | // Pharr and Humphreys [2004] equivalence to g from Henyey-Greenstein
39 | #define shk_g (1.55*hg_g - 0.55 * (hg_g*hg_g*hg_g))
40 |
41 | return
42 | (1. - shk_g*shk_g)
43 | / //-------------------------------------------
44 | (4. * PI * (1. + shk_g*mu) * (1. + shk_g*mu));
45 | }
46 |
47 | struct volume_sampler_t {
48 | vec3 origin; // start of ray
49 | vec3 pos; // current pos of acccumulation ray
50 | float height; // [0..1] within the volume
51 | float transmittance; // (internal) energy loss by absorption & out-scattering
52 | vec3 radiance; // mainly used as output color
53 | float alpha;
54 | };
55 |
56 | volume_sampler_t construct_volume(
57 | _in(vec3) origin
58 | ){
59 | volume_sampler_t v = _begin(volume_sampler_t)
60 | origin,
61 | origin,
62 | 0.,
63 | 1.,
64 | vec3(0, 0, 0),
65 | 0.
66 | _end;
67 | return v;
68 | }
69 |
70 |
--------------------------------------------------------------------------------
/submodules.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | git submodule update --init --recursive
--------------------------------------------------------------------------------
/ue4/volumetric_clouds/Config/DefaultEditor.ini:
--------------------------------------------------------------------------------
1 | [EditoronlyBP]
2 | bAllowClassAndBlueprintPinMatching=true
3 | bReplaceBlueprintWithClass=true
4 | bDontLoadBlueprintOutsideEditor=true
5 | bBlueprintIsNotBlueprintType=true
6 |
--------------------------------------------------------------------------------
/ue4/volumetric_clouds/Config/DefaultEngine.ini:
--------------------------------------------------------------------------------
1 | [URL]
2 | [/Script/Engine.UserInterfaceSettings]
3 | RenderFocusRule=NavigationOnly
4 | DefaultCursor=None
5 | TextEditBeamCursor=None
6 | CrosshairsCursor=None
7 | GrabHandCursor=None
8 | GrabHandClosedCursor=None
9 | SlashedCircleCursor=None
10 | ApplicationScale=1.000000
11 | UIScaleRule=ShortestSide
12 | CustomScalingRuleClass=None
13 | UIScaleCurve=(EditorCurveData=(PreInfinityExtrap=RCCE_Constant,PostInfinityExtrap=RCCE_Constant,Keys=((Time=480.000000,Value=0.444000),(Time=720.000000,Value=0.666000),(Time=1080.000000,Value=1.000000),(Time=8640.000000,Value=8.000000)),DefaultValue=340282346638528859811704183484516925440.000000),ExternalCurve=None)
14 |
15 | [/Script/Engine.RendererSettings]
16 | r.MobileHDR=True
17 | r.MobileNumDynamicPointLights=4
18 | r.MobileDynamicPointLightsUseStaticBranch=True
19 | r.AllowOcclusionQueries=True
20 | r.MinScreenRadiusForLights=0.030000
21 | r.MinScreenRadiusForDepthPrepass=0.030000
22 | r.PrecomputedVisibilityWarning=False
23 | r.TextureStreaming=True
24 | Compat.UseDXT5NormalMaps=False
25 | r.AllowStaticLighting=True
26 | r.NormalMapsForStaticLighting=False
27 | r.GenerateMeshDistanceFields=False
28 | r.GenerateLandscapeGIData=True
29 | r.TessellationAdaptivePixelsPerTriangle=48.000000
30 | r.SeparateTranslucency=True
31 | r.TranslucentSortPolicy=0
32 | TranslucentSortAxis=(X=0.000000,Y=-1.000000,Z=0.000000)
33 | r.CustomDepth=1
34 | r.DefaultFeature.Bloom=True
35 | r.DefaultFeature.AmbientOcclusion=True
36 | r.DefaultFeature.AmbientOcclusionStaticFraction=True
37 | r.DefaultFeature.AutoExposure=True
38 | r.DefaultFeature.MotionBlur=True
39 | r.DefaultFeature.LensFlare=True
40 | r.DefaultFeature.AntiAliasing=2
41 | r.EarlyZPass=3
42 | r.EarlyZPassMovable=False
43 | r.DBuffer=False
44 | r.ClearSceneMethod=1
45 | r.BasePassOutputsVelocity=False
46 | r.WireframeCullThreshold=5.000000
47 | UIScaleRule=ShortestSide
48 | UIScaleCurve=(EditorCurveData=(PreInfinityExtrap=RCCE_Constant,PostInfinityExtrap=RCCE_Constant,Keys=,DefaultValue=340282346638528859811704183484516925440.000000),ExternalCurve=None)
49 |
50 | [/Script/HardwareTargeting.HardwareTargetingSettings]
51 | TargetedHardwareClass=Desktop
52 | AppliedTargetedHardwareClass=Desktop
53 | DefaultGraphicsPerformance=Maximum
54 | AppliedDefaultGraphicsPerformance=Maximum
55 |
56 | [/Script/EngineSettings.GameMapsSettings]
57 | GameDefaultMap=/Game/Main
58 | EditorStartupMap=/Game/Main
59 |
60 |
--------------------------------------------------------------------------------
/ue4/volumetric_clouds/Config/DefaultGame.ini:
--------------------------------------------------------------------------------
1 | [/Script/EngineSettings.GeneralProjectSettings]
2 | ProjectID=5314FA9346400AA34CF5D290C1484817
3 | ProjectName=Volumetric Clouds Test
4 | CopyrightNotice=none
5 |
6 |
--------------------------------------------------------------------------------
/ue4/volumetric_clouds/Content/Main.umap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valentingalea/shaderbox/4d18b45cac9c9ef75de85697fae497c966e9f76f/ue4/volumetric_clouds/Content/Main.umap
--------------------------------------------------------------------------------
/ue4/volumetric_clouds/Content/clouds_material.uasset:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valentingalea/shaderbox/4d18b45cac9c9ef75de85697fae497c966e9f76f/ue4/volumetric_clouds/Content/clouds_material.uasset
--------------------------------------------------------------------------------
/ue4/volumetric_clouds/Shaders/app_clouds.usf:
--------------------------------------------------------------------------------
1 | #define UE4
2 | #define HLSL
3 |
4 | /**** TWEAK *****************************************************************/
5 | #define COVERAGE .50
6 | #define THICKNESS 15.
7 | #define ABSORPTION 1.030725
8 | #define FUZZINESS 0.035
9 |
10 | #define FBM_FREQ 2.76434
11 | #define NOISE_VALUE
12 | //#define NOISE_WORLEY
13 |
14 | #define WIND_DIR vec3(0, 0, -u_time * .2)
15 | #define SUN_DIR normalize(vec3(0, abs(sin(u_time * .3)), -1))
16 |
17 | #define STEPS 25
18 | /******************************************************************************/
19 |
20 | #ifdef HLSL
21 | #define _in(T) const in T
22 | #define _inout(T) inout T
23 | #define _out(T) out T
24 | #define _begin(type) {
25 | #define _end }
26 | #define _mutable(T) static T
27 | #define _constant(T) static const T
28 | #define vec2 float2
29 | #define vec3 float3
30 | #define vec4 float4
31 | #define mat2 float2x2
32 | #define mat3 float3x3
33 | #define mat4 float4x4
34 | #define mix lerp
35 | #define fract frac
36 | #define mod fmod
37 | #pragma pack_matrix(row_major)
38 | #endif
39 |
40 | #ifdef UE4
41 | _constant(vec2) u_res = vec2(0, 0);
42 | _constant(vec2) u_mouse = vec2(0, 0);
43 | _mutable(float) u_time = 0;
44 | #endif
45 |
46 | #define PI 3.14159265359
47 |
48 | struct ray_t {
49 | vec3 origin;
50 | vec3 direction;
51 | };
52 | #define BIAS 1e-4 // small offset to avoid self-intersections
53 |
54 | struct sphere_t {
55 | vec3 origin;
56 | float radius;
57 | int material;
58 | };
59 |
60 | struct plane_t {
61 | vec3 direction;
62 | float distance;
63 | int material;
64 | };
65 |
66 | struct hit_t {
67 | float t;
68 | int material_id;
69 | vec3 normal;
70 | vec3 origin;
71 | };
72 | #define max_dist 1e8
73 | _constant(hit_t) no_hit = _begin(hit_t)
74 | float(max_dist + 1e1), // 'infinite' distance
75 | -1, // material id
76 | vec3(0., 0., 0.), // normal
77 | vec3(0., 0., 0.) // origin
78 | _end;
79 |
80 |
81 | // ----------------------------------------------------------------------------
82 | // Noise function by iq from https://www.shadertoy.com/view/4sfGzS
83 | // ----------------------------------------------------------------------------
84 |
85 | float hash(
86 | _in(float) n
87 | ){
88 | return fract(sin(n)*753.5453123);
89 | }
90 |
91 | float noise_iq(
92 | _in(vec3) x
93 | ){
94 | vec3 p = floor(x);
95 | vec3 f = fract(x);
96 | f = f*f*(3.0 - 2.0*f);
97 |
98 | #if 1
99 | float n = p.x + p.y*157.0 + 113.0*p.z;
100 | return mix(mix(mix( hash(n+ 0.0), hash(n+ 1.0),f.x),
101 | mix( hash(n+157.0), hash(n+158.0),f.x),f.y),
102 | mix(mix( hash(n+113.0), hash(n+114.0),f.x),
103 | mix( hash(n+270.0), hash(n+271.0),f.x),f.y),f.z);
104 | #else
105 | vec2 uv = (p.xy + vec2(37.0, 17.0)*p.z) + f.xy;
106 | vec2 rg = texture2D(iChannel0, (uv + 0.5) / 256.0, -100.0).yx;
107 | return mix(rg.x, rg.y, f.z);
108 | #endif
109 | }
110 |
111 | #ifdef NOISE_VALUE
112 | #define noise(x) noise_iq(x)
113 | #endif
114 | #ifdef NOISE_WORLEY
115 | #define noise(x) (1. - noise_w(x).r)
116 | //#define noise(x) abs( noise_iq(x / 8.) - (1. - (noise_w(x * 2.).r)))
117 | #endif
118 |
119 | // ----------------------------------------------------------------------------
120 | // Fractal Brownian Motion
121 | // ----------------------------------------------------------------------------
122 |
123 | float fbm(
124 | _in(vec3) pos,
125 | _in(float) lacunarity
126 | ){
127 | vec3 p = pos;
128 | float
129 | t = 0.51749673 * noise(p); p *= lacunarity;
130 | t += 0.25584929 * noise(p); p *= lacunarity;
131 | t += 0.12527603 * noise(p); p *= lacunarity;
132 | t += 0.06255931 * noise(p);
133 |
134 | return t;
135 | }
136 |
137 | #ifdef HLSLTOY
138 | Texture3D u_tex_noise : register(t1);
139 | SamplerState u_sampler0 : register(s0);
140 | #endif
141 |
142 | float noise_func(_in(vec3) x)
143 | {
144 | #if 0
145 | return u_tex_noise.Sample(u_sampler0, x);
146 | #else
147 | return fbm(x, FBM_FREQ);
148 | #endif
149 | }
150 |
151 | vec3 render_sky_color(
152 | _in(vec3) eye_dir,
153 | _in(vec3) sun_dir
154 | ){
155 | _constant(vec3) sun_color = vec3(1., .7, .55);
156 | float sun_amount = max(dot(eye_dir, sun_dir), 0.);
157 |
158 | vec3 sky = mix(vec3(.0, .1, .4), vec3(.3, .6, .8), 1.0 - eye_dir.y);
159 | sky += sun_color * min(pow(sun_amount, 1500.0) * 5.0, 1.0);
160 | sky += sun_color * min(pow(sun_amount, 10.0) * .6, 1.0);
161 |
162 | return sky;
163 | }
164 |
165 | float density_func(
166 | _in(vec3) pos,
167 | _in(vec3) offset,
168 | _in(float) coverage,
169 | _in(float) fuziness
170 | ){
171 | vec3 p = pos * .0212242 + offset;
172 | float dens = noise_func(p);
173 |
174 | //dens *= step(coverage, dens);
175 | //dens -= coverage;
176 | dens *= smoothstep (coverage, coverage + fuziness, dens);
177 |
178 | return clamp(dens, 0., 1.);
179 | }
180 |
181 | vec4 render_clouds(
182 | _in(ray_t) eye,
183 | _in(vec3) sun_dir,
184 | _in(vec3) wind_dir,
185 | _in(float) coverage,
186 | _in(float) thickness,
187 | _in(float) absorbtion,
188 | _in(float) fuzziness
189 | ){
190 | #if 0 // atmosphere 'sphere' intersect
191 | _constant(sphere_t) atmosphere = _begin(sphere_t)
192 | vec3(0, -450, 0), 500., 0
193 | _end;
194 |
195 | hit_t hit = no_hit;
196 | intersect_sphere(eye, atmosphere, hit);
197 |
198 | const int steps = STEPS;
199 | float march_step = thickness / float(steps);
200 | vec3 dir_step = eye.direction * march_step;
201 | vec3 pos = hit.origin;
202 | #else // plane projection
203 | const int steps = STEPS;
204 | float march_step = thickness / float(steps);
205 | vec3 dir_step = eye.direction / eye.direction.y * march_step;
206 | vec3 pos = eye.origin + eye.direction * 100.;
207 | #endif
208 |
209 | float T = 1.;
210 | vec3 C = vec3(0, 0, 0);
211 | float alpha = 0.;
212 |
213 | for (int i = 0; i < steps; i++) {
214 | float h = float(i) / float(steps);
215 | float dens = density_func(pos, wind_dir, coverage, fuzziness);
216 |
217 | float T_i = exp(-absorbtion * dens * march_step);
218 | T *= T_i;
219 | //if (T < .01) break;
220 |
221 | C += T *
222 | (exp(h) / 1.75) * // fake light
223 | dens * march_step;
224 | alpha += (1. - T_i) * (1. - alpha);
225 |
226 | pos += dir_step;
227 | //if (length(pos) > 1e3) break;
228 | }
229 |
230 | return vec4(C, alpha);
231 | }
232 |
233 | #ifdef UE4
234 | vec3 ue4_render_clouds(
235 | _in(vec3) cam_dir,
236 | _in(float) time,
237 | _in(float) coverage,
238 | _in(float) thickness,
239 | _in(float) absorbtion,
240 | _in(float) fuzziness,
241 | _in(vec3) sun_dir,
242 | _in(vec3) wind_dir
243 | ){
244 | ray_t eye_ray = _begin(ray_t)
245 | vec3(0, 0, 0),
246 | cam_dir
247 | _end;
248 | u_time = time;
249 |
250 | vec3 sky = render_sky_color(
251 | eye_ray.direction,
252 | sun_dir
253 | );
254 | vec4 cld = render_clouds(
255 | eye_ray,
256 | sun_dir,
257 | wind_dir,
258 | 1. - coverage,
259 | thickness,
260 | absorbtion,
261 | fuzziness
262 | );
263 | return mix(sky, cld.rgb, cld.a);
264 | }
265 | #endif
266 |
--------------------------------------------------------------------------------
/ue4/volumetric_clouds/volumetric_clouds.uproject:
--------------------------------------------------------------------------------
1 | {
2 | "FileVersion": 3,
3 | "EngineAssociation": "{F79734A3-4E50-17BB-803F-3787E12C4393}",
4 | "Category": "",
5 | "Description": ""
6 | }
--------------------------------------------------------------------------------
/util/ddsvolgen/README.md:
--------------------------------------------------------------------------------
1 | Noise 3D Texture generator
--------------------------------------------------------------------------------
/util/ddsvolgen/prj/ddsvolgen.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 | {204D1B9B-465C-4941-B6A1-39E9E95B8BC2}
15 | Win32Proj
16 | ddsvolgen
17 | 10.0
18 |
19 |
20 |
21 | Application
22 | true
23 | v142
24 | Unicode
25 |
26 |
27 | Application
28 | false
29 | v142
30 | true
31 | Unicode
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | true
45 |
46 |
47 | false
48 | $(SolutionDir)..\bin\
49 |
50 |
51 |
52 |
53 |
54 | Level3
55 | Disabled
56 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
57 | $(SolutionDir)..\lib\vml;%(AdditionalIncludeDirectories)
58 | /permissive- /std:c++17 %(AdditionalOptions)
59 |
60 |
61 | Console
62 | true
63 |
64 |
65 |
66 |
67 | Level3
68 |
69 |
70 | MaxSpeed
71 | true
72 | true
73 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
74 | $(SolutionDir)..\lib\vml;%(AdditionalIncludeDirectories)
75 | Speed
76 | false
77 | StreamingSIMDExtensions2
78 | true
79 | /permissive- /std:c++17 %(AdditionalOptions)
80 |
81 |
82 | Console
83 | true
84 | true
85 | true
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/util/ddsvolgen/prj/ddsvolgen.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
--------------------------------------------------------------------------------
/util/ddsvolgen/src/ddsvolgen.cpp:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Windows / DirectX specific
3 | // ----------------------------------------------------------------------------
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | typedef unsigned long DWORD;
10 | #include "../../../lib/DirectXTex/DirectXTex/DDS.h"
11 | using namespace DirectX;
12 |
13 | struct DDS
14 | {
15 | DWORD dwMagic;
16 | DDS_HEADER header;
17 | DDS_HEADER_DXT10 header10;
18 | };
19 |
20 | // ----------------------------------------------------------------------------
21 | // VML support
22 | // ----------------------------------------------------------------------------
23 | #pragma warning(disable: 4244) // disable return implicit conversion warning
24 | #pragma warning(disable: 4305) // disable truncation warning
25 |
26 | #include
27 | #include
28 | #include
29 |
30 | using vec4 = vml::vector;
31 | using vec3 = vml::vector;
32 | using vec2 = vml::vector;
33 | using _01 = vml::indices_pack<0, 1>;
34 | using _012 = vml::indices_pack<0, 1, 2>;
35 | using _0123 = vml::indices_pack<0, 1, 2, 3>;
36 | using mat2 = vml::matrix;
37 | using mat3 = vml::matrix;
38 | using mat4 = vml::matrix;
39 |
40 | // ----------------------------------------------------------------------------
41 | // GLSL layer
42 | // ----------------------------------------------------------------------------
43 | #include "../../../src/def.h"
44 | #include "../../../src/util.h"
45 | //#include "../../../lib/ashima-noise/src/common.glsl"
46 | //#include "../../../lib/ashima-noise/src/classicnoise3d.glsl"
47 | //#include "../../../lib/ashima-noise/src/noise3d.glsl"
48 | //#include "../../../lib/ashima-noise/src/cellular3d.glsl"
49 | #include "../../../src/noise_worley.h"
50 | #include "../../../src/fbm.h"
51 |
52 | DECL_FBM_FUNC_TILE(fbm_worley_tile, 4, (1. - (noise_w(p, L).r + .25)))
53 | //DECL_FBM_FUNC_TILE(fbm_perlin_tile, 4, abs(pcnoise(p, L)))
54 |
55 | float fbm_dds(vec3 &pos)
56 | {
57 | // float p = fbm_perlin_tile(pos, 2., 1., .5);
58 | // float w = 1. - fbm_worley_tile(pos, 4., 1., .5);
59 | // return remap(p, -w, 1., 0., 1.);
60 | return fbm_worley_tile(pos, 2., 1., .5);
61 | }
62 |
63 | // ----------------------------------------------------------------------------
64 | // Main
65 | // ----------------------------------------------------------------------------
66 | int main(int argc, char* argv[])
67 | {
68 | constexpr size_t size = 128;
69 | constexpr size_t channels = 4;
70 | using FLOAT = float;
71 |
72 | DDS dds = { 0 };
73 |
74 | dds.dwMagic = DDS_MAGIC;
75 |
76 | dds.header.dwSize = sizeof(DDS_HEADER);
77 | dds.header.dwFlags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_VOLUME | DDS_HEADER_FLAGS_PITCH;
78 | dds.header.dwHeight = size;
79 | dds.header.dwWidth = size;
80 | dds.header.dwDepth = size;
81 | dds.header.dwPitchOrLinearSize = (size * (sizeof(FLOAT) * channels) + 7) / 8;
82 | dds.header.dwMipMapCount = 0;
83 | dds.header.ddspf = DDSPF_DX10;
84 | dds.header.dwCaps = DDS_SURFACE_FLAGS_TEXTURE | DDS_SURFACE_FLAGS_CUBEMAP;
85 | dds.header.dwCaps2 = DDS_FLAGS_VOLUME;
86 |
87 | DXGI_FORMAT fmt[] = { DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_UINT, DXGI_FORMAT_R32G32B32A32_FLOAT };
88 | dds.header10.dxgiFormat = fmt[channels - 1];
89 | dds.header10.resourceDimension = DDS_DIMENSION_TEXTURE3D;
90 | dds.header10.arraySize = 1;
91 | dds.header10.miscFlag = 0;
92 | dds.header10.miscFlags2 = 0;
93 |
94 | const size_t total_size = size * size* size * (sizeof(FLOAT) * channels);
95 | std::unique_ptr data;
96 | data.reset(new (std::nothrow) FLOAT[total_size]);
97 | if (!data) {
98 | return 1;
99 | }
100 |
101 | auto worker = [&](size_t start, size_t count) {
102 | for (size_t z = start; z < start + count; z++) {
103 | for (size_t y = 0; y < size; y++) {
104 | auto ptr = data.get() + size*size*channels*z + size*channels*y;
105 |
106 | for (size_t x = 0; x < size; x++) {
107 | vec3 pos = (vec3(x, y, z) + .5f) / FLOAT(size);
108 | *ptr++ = fbm_dds(pos);
109 | *ptr++ = 0.f;
110 | *ptr++ = 0.f;
111 | *ptr++ = 0.f;
112 | }
113 | }
114 | }
115 | printf("...finished [%i..%i]\n", start, start + count);
116 | };
117 |
118 | printf("starting work...\n");
119 | using tclock_t = std::chrono::steady_clock;
120 | using tpoint_t = tclock_t::time_point;
121 | tpoint_t t_start = tclock_t::now();
122 |
123 | constexpr size_t size_quota = size / 4;
124 | std::thread w1{ worker, size_quota * 0, size_quota };
125 | std::thread w2{ worker, size_quota * 1, size_quota };
126 | std::thread w3{ worker, size_quota * 2, size_quota };
127 | std::thread w4{ worker, size_quota * 3, size_quota };
128 | w1.join();
129 | w2.join();
130 | w3.join();
131 | w4.join();
132 |
133 | tpoint_t t_end = tclock_t::now();
134 | using tdiff_t = std::chrono::duration;
135 | auto elapsted = tdiff_t(t_end - t_start).count();
136 | printf("total running time: %f\n", elapsted);
137 |
138 | #if 1
139 | time_t rawtime;
140 | time(&rawtime);
141 | tm timeinfo;
142 | localtime_s(&timeinfo, &rawtime);
143 | constexpr int SZ = 128;
144 | char dds_file[SZ];
145 | strftime(dds_file, SZ, "noise3d-%Y-%m-%d-%H-%M-%S.dds\0", &timeinfo);
146 |
147 | auto file_closer = [](FILE* f) { fclose(f); };
148 | std::unique_ptr file = { fopen(dds_file, "wb+"), file_closer };
149 | if (!file) {
150 | return 2;
151 | }
152 | fwrite(&dds, sizeof(dds), 1, file.get());
153 | fwrite(data.get(), sizeof(FLOAT) * channels, size * size * size, file.get());
154 | #endif
155 |
156 | return 0;
157 | }
--------------------------------------------------------------------------------
/util/hlsltoy/README.md:
--------------------------------------------------------------------------------
1 | Minimal DirectX 11 framework that displays a fragment/compute shader.
--------------------------------------------------------------------------------
/util/hlsltoy/prj/hlsltoy.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valentingalea/shaderbox/4d18b45cac9c9ef75de85697fae497c966e9f76f/util/hlsltoy/prj/hlsltoy.rc
--------------------------------------------------------------------------------
/util/hlsltoy/prj/hlsltoy.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 | {F663DDF3-DF54-4DB7-B7A1-48B6D4E9EA0D}
15 | hlsltoy
16 | 10.0
17 |
18 |
19 |
20 | Application
21 | true
22 | v142
23 | MultiByte
24 |
25 |
26 | Application
27 | false
28 | v142
29 | true
30 | MultiByte
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | $(SolutionDir)..\bin\
46 |
47 |
48 |
49 | Level3
50 | Disabled
51 | true
52 | ..\..\..\lib\imgui
53 |
54 |
55 | true
56 |
57 |
58 | d3d11.lib;D3DCompiler.lib;%(AdditionalDependencies)
59 |
60 |
61 |
62 |
63 | Level3
64 | MaxSpeed
65 | true
66 | true
67 | true
68 | ..\..\..\lib\imgui
69 |
70 |
71 | true
72 | true
73 | true
74 | d3d11.lib;D3DCompiler.lib;%(AdditionalDependencies)
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/util/hlsltoy/prj/hlsltoy.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
11 |
12 |
13 | {eda506de-d838-446b-be7d-8ed0af678881}
14 |
15 |
16 |
17 |
18 | Source Files
19 |
20 |
21 | imgui
22 |
23 |
24 | imgui
25 |
26 |
27 | imgui
28 |
29 |
30 |
31 |
32 | imgui
33 |
34 |
35 | imgui
36 |
37 |
38 | imgui
39 |
40 |
41 | imgui
42 |
43 |
44 | Resource Files
45 |
46 |
47 |
48 |
49 | Resource Files
50 |
51 |
52 |
53 |
54 | Resource Files
55 |
56 |
57 |
58 |
59 | Resource Files
60 |
61 |
62 |
--------------------------------------------------------------------------------
/util/hlsltoy/prj/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valentingalea/shaderbox/4d18b45cac9c9ef75de85697fae497c966e9f76f/util/hlsltoy/prj/icon.ico
--------------------------------------------------------------------------------
/util/hlsltoy/prj/resource.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valentingalea/shaderbox/4d18b45cac9c9ef75de85697fae497c966e9f76f/util/hlsltoy/prj/resource.h
--------------------------------------------------------------------------------
/util/hlsltoy/prj/vertex_shader.hlsl.bin:
--------------------------------------------------------------------------------
1 | // from http://altdevblog.com/2011/08/08/an-interesting-vertex-shader-trick/
2 | float4 main(uint id : SV_VertexID) : SV_Position
3 | {
4 | float2 tex = float2((id << 1) & 2, id & 2);
5 | return float4(tex * float2(2, -2) + float2(-1, 1), 0, 1);
6 | };
--------------------------------------------------------------------------------
/util/inclxpnd/README.md:
--------------------------------------------------------------------------------
1 | Very simple include file expander. Basically a preprocessor that only does #include
--------------------------------------------------------------------------------
/util/inclxpnd/prj/inclxpnd.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 | {4C4B967A-ABE6-4992-8ED3-27828AC8A3E1}
15 | Win32Proj
16 | inclxpnd
17 | 10.0
18 |
19 |
20 |
21 | Application
22 | true
23 | v142
24 | Unicode
25 |
26 |
27 | Application
28 | false
29 | v142
30 | true
31 | Unicode
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | true
45 |
46 |
47 | false
48 | $(SolutionDir)..\bin\
49 |
50 |
51 |
52 |
53 |
54 | Level3
55 | Disabled
56 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
57 |
58 |
59 | Console
60 | true
61 |
62 |
63 |
64 |
65 | Level3
66 |
67 |
68 | MaxSpeed
69 | true
70 | true
71 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
72 |
73 |
74 | Console
75 | true
76 | true
77 | true
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/util/inclxpnd/prj/inclxpnd.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
--------------------------------------------------------------------------------
/util/inclxpnd/src/inclxpnd.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | using namespace std;
7 |
8 | int parse(ifstream &input_file)
9 | {
10 | for (string line; getline (input_file, line); ) {
11 | stringstream tokenizer;
12 | tokenizer << line;
13 |
14 | string token;
15 | tokenizer >> token;
16 |
17 | if (token == "#include") {
18 | tokenizer >> token;
19 | if (token.length() < 2) return 2;
20 |
21 | auto ch = token.front();
22 | if (ch != '"' && ch != '<') return 3;
23 |
24 | ch = token.back();
25 | if (ch != '"' && ch != '>') return 3;
26 |
27 | string filename(token.begin() + 1, token.end() - 1);
28 | ifstream new_input_file(filename);
29 |
30 | if (new_input_file.good()) {
31 | parse(new_input_file);
32 | } else {
33 | cout << "*** error: cannot include file: " << filename << endl;
34 | }
35 | } else {
36 | cout << line << endl;
37 | }
38 | }
39 |
40 | return 0;
41 | }
42 |
43 | int main(int argc, char* argv[])
44 | {
45 | if (argc < 2) {
46 | cout << "Very simple file include expander. Outputs to stdout." << endl;
47 | cout << "Usage:" << endl;
48 | cout << "\tinclxpnd " << endl;
49 | return 1;
50 | }
51 |
52 | ifstream input_file{ string(argv[1]) };
53 | if (!input_file.good()) return 1;
54 |
55 | return parse(input_file);
56 | }
--------------------------------------------------------------------------------