├── .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 | ![snapshot of apps](http://i.imgur.com/JEuXZii.png) 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 | } --------------------------------------------------------------------------------