Showing preview only (977K chars total). Download the full file or copy to clipboard to get everything.
Repository: lettier/3d-game-shaders-for-beginners
Branch: master
Commit: 29700852da7b
Files: 121
Total size: 935.1 KB
Directory structure:
gitextract_oegtrd8a/
├── .gitignore
├── README.md
├── demonstration/
│ ├── build-for-linux.sh
│ ├── eggs/
│ │ └── mill-scene/
│ │ ├── banner.bam
│ │ ├── mill-scene.bam
│ │ ├── shutters.bam
│ │ └── weather-vane.bam
│ ├── panda3d-prc-file.prc
│ ├── shaders/
│ │ ├── LICENSE
│ │ ├── fragment/
│ │ │ ├── base-combine.frag
│ │ │ ├── base.frag
│ │ │ ├── bloom.frag
│ │ │ ├── box-blur.frag
│ │ │ ├── chromatic-aberration.frag
│ │ │ ├── depth-of-field.frag
│ │ │ ├── dilation.frag
│ │ │ ├── discard.frag
│ │ │ ├── film-grain.frag
│ │ │ ├── foam-mask.frag
│ │ │ ├── foam.frag
│ │ │ ├── fog.frag
│ │ │ ├── gamma-correction.frag
│ │ │ ├── geometry-buffer-0.frag
│ │ │ ├── geometry-buffer-1.frag
│ │ │ ├── geometry-buffer-2.frag
│ │ │ ├── kuwahara-filter.frag
│ │ │ ├── lookup-table.frag
│ │ │ ├── material-diffuse.frag
│ │ │ ├── material-specular.frag
│ │ │ ├── median-filter.frag
│ │ │ ├── motion-blur.frag
│ │ │ ├── normal.frag
│ │ │ ├── outline.frag
│ │ │ ├── pixelize.frag
│ │ │ ├── position.frag
│ │ │ ├── posterize.frag
│ │ │ ├── reflection-color.frag
│ │ │ ├── reflection.frag
│ │ │ ├── refraction.frag
│ │ │ ├── scene-combine.frag
│ │ │ ├── screen-space-reflection.frag
│ │ │ ├── screen-space-refraction.frag
│ │ │ ├── sharpen.frag
│ │ │ └── ssao.frag
│ │ └── vertex/
│ │ ├── base.vert
│ │ ├── basic.vert
│ │ └── discard.vert
│ ├── sounds/
│ │ ├── water.ogg
│ │ └── wheel.ogg
│ └── src/
│ ├── LICENSE
│ └── main.cxx
├── docs/
│ ├── _build-docs.sh
│ ├── _template.html5
│ ├── blinn-phong.html
│ ├── bloom.html
│ ├── blur.html
│ ├── building-the-demo.html
│ ├── cel-shading.html
│ ├── chromatic-aberration.html
│ ├── deferred-rendering.html
│ ├── depth-of-field.html
│ ├── dilation.html
│ ├── film-grain.html
│ ├── flow-mapping.html
│ ├── foam.html
│ ├── fog.html
│ ├── fresnel-factor.html
│ ├── gamma-correction.html
│ ├── glsl.html
│ ├── index.html
│ ├── lighting.html
│ ├── lookup-table.html
│ ├── motion-blur.html
│ ├── normal-mapping.html
│ ├── outlining.html
│ ├── pixelization.html
│ ├── posterization.html
│ ├── reference-frames.html
│ ├── render-to-texture.html
│ ├── rim-lighting.html
│ ├── running-the-demo.html
│ ├── screen-space-reflection.html
│ ├── screen-space-refraction.html
│ ├── setup.html
│ ├── sharpen.html
│ ├── ssao.html
│ ├── style.css
│ └── texturing.html
└── sections/
├── blinn-phong.md
├── bloom.md
├── blur.md
├── building-the-demo.md
├── cel-shading.md
├── chromatic-aberration.md
├── deferred-rendering.md
├── depth-of-field.md
├── dilation.md
├── film-grain.md
├── flow-mapping.md
├── foam.md
├── fog.md
├── fresnel-factor.md
├── gamma-correction.md
├── glsl.md
├── lighting.md
├── lookup-table.md
├── motion-blur.md
├── normal-mapping.md
├── outlining.md
├── pixelization.md
├── posterization.md
├── reference-frames.md
├── render-to-texture.md
├── rim-lighting.md
├── running-the-demo.md
├── screen-space-reflection.md
├── screen-space-refraction.md
├── setup.md
├── sharpen.md
├── ssao.md
└── texturing.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
images/**
blends/**
*.kra~
*.png~
*main.o*
*3d-game-shaders-for-beginners.o*
*3d-game-shaders-for-beginners*
!blends/*
!blends/mill-scene/mill-scene-low-poly-backup.blend
================================================
FILE: README.md
================================================
<p align="center">
<img src="https://i.imgur.com/x8rtGr4.gif" alt="3D Game Shaders For Beginners" title="3D Game Shaders For Beginners">
</p>
# 3D Game Shaders For Beginners
Interested in adding
textures,
lighting,
shadows,
normal maps,
glowing objects,
ambient occlusion,
reflections,
refractions,
and more to your 3D game?
Great!
Below is a collection of shading techniques that will take your game visuals to new heights.
I've explained each technique in such a way that you can take what you learn here and apply/port it to
whatever stack you use—be it Godot, Unity, Unreal, or something else.
For the glue in between the shaders,
I've chosen the fabulous Panda3D game engine and the OpenGL Shading Language (GLSL).
So if that is your stack, then you'll also get the benefit of learning how to use these
shading techniques with Panda3D and OpenGL specifically.
## Table Of Contents
- [Setup](sections/setup.md)
- [Building The Demo](sections/building-the-demo.md)
- [Running The Demo](sections/running-the-demo.md)
- [Reference Frames](sections/reference-frames.md)
- [GLSL](sections/glsl.md)
- [Render To Texture](sections/render-to-texture.md)
- [Texturing](sections/texturing.md)
- [Lighting](sections/lighting.md)
- [Blinn-Phong](sections/blinn-phong.md)
- [Fresnel Factor](sections/fresnel-factor.md)
- [Rim Lighting](sections/rim-lighting.md)
- [Cel Shading](sections/cel-shading.md)
- [Normal Mapping](sections/normal-mapping.md)
- [Deferred Rendering](sections/deferred-rendering.md)
- [Fog](sections/fog.md)
- [Blur](sections/blur.md)
- [Bloom](sections/bloom.md)
- [SSAO](sections/ssao.md)
- [Motion Blur](sections/motion-blur.md)
- [Chromatic Aberration](sections/chromatic-aberration.md)
- [Screen Space Reflection](sections/screen-space-reflection.md)
- [Screen Space Refraction](sections/screen-space-refraction.md)
- [Foam](sections/foam.md)
- [Flow Mapping](sections/flow-mapping.md)
- [Outlining](sections/outlining.md)
- [Depth Of Field](sections/depth-of-field.md)
- [Posterization](sections/posterization.md)
- [Pixelization](sections/pixelization.md)
- [Sharpen](sections/sharpen.md)
- [Dilation](sections/dilation.md)
- [Film Grain](sections/film-grain.md)
- [Lookup Table (LUT)](sections/lookup-table.md)
- [Gamma Correction](sections/gamma-correction.md)
## License
The included license applies only to the software portion of 3D Game Shaders For Beginners—
specifically the `.cxx`, `.vert`, and `.frag` source code files.
No other portion of 3D Game Shaders For Beginners has been licensed for use.
## Attributions
- [Kiwi Soda Font](https://fontenddev.com/fonts/kiwi-soda/)
## Copyright
(C) 2019 David Lettier
<br>
[lettier.com](https://www.lettier.com)
================================================
FILE: demonstration/build-for-linux.sh
================================================
#!/usr/bin/env bash
SCRIPT_PATH="$(cd "$(dirname "$0")"; pwd -P)"
g++ \
-Wfatal-errors \
-c $SCRIPT_PATH/src/main.cxx \
-o $SCRIPT_PATH/3d-game-shaders-for-beginners.o \
-std=gnu++11 \
-O3 \
-I/usr/include/python3.9/ \
-I$P3D_INCLUDE_PATH
g++ \
$SCRIPT_PATH/3d-game-shaders-for-beginners.o \
-o $SCRIPT_PATH/3d-game-shaders-for-beginners \
-L$P3D_LIB_PATH \
-lp3framework \
-lpanda \
-lpandafx \
-lpandaexpress \
-lpandaphysics \
-lp3dtoolconfig \
-lp3dtool \
-lpthread
================================================
FILE: demonstration/panda3d-prc-file.prc
================================================
load-display pandagl
audio-library-name p3openal_audio
win-origin -2 -2
win-size 1200 900
fullscreen #f
framebuffer-hardware #t
framebuffer-software #f
framebuffer-srgb #f
depth-bits 1
color-bits 1 1 1
alpha-bits 0
stencil-bits 0
multisamples 0
notify-level warning
default-directnotify-level warning
model-path $MAIN_DIR
want-directtools #f
want-tk #f
want-pstats #f
show-frame-rate-meter #f
use-movietexture #t
hardware-animated-vertices #f
model-cache-dir $XDG_CACHE_HOME/panda3d
model-cache-textures #f
basic-shaders-only #f
gl-coordinate-system default
gl-version 3 2
textures-auto-power-2 1
textures-power-2 down
sync-flip #f
sync-video #f
================================================
FILE: demonstration/shaders/LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2019, David Lettier
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: demonstration/shaders/fragment/base-combine.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform sampler2D baseTexture;
uniform sampler2D refractionTexture;
uniform sampler2D foamTexture;
uniform sampler2D reflectionTexture;
uniform sampler2D specularTexture;
out vec4 fragColor;
void main() {
vec2 texSize = textureSize(baseTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 base = texture(baseTexture, texCoord);
vec4 refraction = texture(refractionTexture, texCoord);
vec4 foam = texture(foamTexture, texCoord);
vec4 reflection = texture(reflectionTexture, texCoord);
vec4 specular = texture(specularTexture, texCoord);
fragColor = base;
fragColor.rgb = mix(fragColor.rgb, refraction.rgb, clamp(refraction.a, 0.0, 1.0));
fragColor.rgb = mix(fragColor.rgb, reflection.rgb, clamp(reflection.a, 0.0, 1.0));
fragColor.rgb = mix(fragColor.rgb, foam.rgb, clamp(foam.a, 0.0, 1.0));
fragColor.rgb += (specular.rgb * clamp(specular.a, 0.0, 1.0));
}
================================================
FILE: demonstration/shaders/fragment/base.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
#define NUMBER_OF_LIGHTS 4
#define MAX_SHININESS 127.75
#define MAX_FRESNEL_POWER 5.0
uniform float osg_FrameTime;
uniform vec2 pi;
uniform vec2 gamma;
uniform mat4 trans_world_to_view;
uniform mat4 trans_view_to_world;
uniform sampler2D p3d_Texture0;
uniform sampler2D p3d_Texture1;
uniform sampler2D p3d_Texture2;
uniform sampler2D flowTexture;
uniform sampler2D ssaoBlurTexture;
uniform struct
{ vec4 ambient
; vec4 diffuse
; vec4 emission
; vec3 specular
; float shininess
;
} p3d_Material;
uniform struct
{ vec4 ambient
;
} p3d_LightModel;
uniform struct p3d_LightSourceParameters
{ vec4 color
; vec4 ambient
; vec4 diffuse
; vec4 specular
; vec4 position
; vec3 spotDirection
; float spotExponent
; float spotCutoff
; float spotCosCutoff
; float constantAttenuation
; float linearAttenuation
; float quadraticAttenuation
; vec3 attenuation
; sampler2DShadow shadowMap
; mat4 shadowViewMatrix
;
} p3d_LightSource[NUMBER_OF_LIGHTS];
uniform vec2 normalMapsEnabled;
uniform vec2 fresnelEnabled;
uniform vec2 rimLightEnabled;
uniform vec2 blinnPhongEnabled;
uniform vec2 celShadingEnabled;
uniform vec2 flowMapsEnabled;
uniform vec2 specularOnly;
uniform vec2 isParticle;
uniform vec2 isWater;
uniform vec2 sunPosition;
in vec4 vertexColor;
in vec4 vertexInShadowSpaces[NUMBER_OF_LIGHTS];
in vec4 vertexPosition;
in vec3 vertexNormal;
in vec3 binormal;
in vec3 tangent;
in vec2 diffuseCoord;
in vec2 normalCoord;
out vec4 out0;
out vec4 out1;
void main() {
vec3 shadowColor = pow(vec3(0.149, 0.220, 0.227), vec3(gamma.x));
int shadowSamples = 2;
vec4 diffuseColor;
if (isParticle.x == 1) {
diffuseColor = texture(p3d_Texture0, diffuseCoord) * vertexColor;
} else {
diffuseColor = texture(p3d_Texture0, diffuseCoord);
}
diffuseColor.rgb = pow(diffuseColor.rgb, vec3(gamma.x));
vec3 materialSpecularColor = p3d_Material.specular;
vec2 flow = texture(flowTexture, normalCoord).xy;
flow = (flow - 0.5) * 2.0;
flow.x = abs(flow.x) <= 0.02 ? 0.0 : flow.x;
flow.y = abs(flow.y) <= 0.02 ? 0.0 : flow.y;
vec4 normalTex =
texture
( p3d_Texture1
, vec2
( normalCoord.x + flowMapsEnabled.x * flow.x * osg_FrameTime
, normalCoord.y + flowMapsEnabled.y * flow.y * osg_FrameTime
)
);
vec3 normal;
if (isParticle.x == 1) {
normal = normalize((trans_world_to_view * vec4(0.0, 0.0, 1.0, 0.0)).xyz);
} else if (normalMapsEnabled.x == 1) {
vec3 normalRaw =
normalize
( normalTex.rgb
* 2.0
- 1.0
);
normal =
normalize
( mat3
( tangent
, binormal
, vertexNormal
)
* normalRaw
);
} else {
normal =
normalize(vertexNormal);
}
vec4 specularMap = texture(p3d_Texture2, diffuseCoord);
vec4 diffuse = vec4(0.0, 0.0, 0.0, diffuseColor.a);
vec4 specular = vec4(0.0, 0.0, 0.0, diffuseColor.a);
for (int i = 0; i < p3d_LightSource.length(); ++i) {
vec3 lightDirection =
p3d_LightSource[i].position.xyz
- vertexPosition.xyz
* p3d_LightSource[i].position.w;
vec3 unitLightDirection = normalize(lightDirection);
vec3 eyeDirection = normalize(-vertexPosition.xyz);
vec3 reflectedDirection = normalize(-reflect(unitLightDirection, normal));
vec3 halfwayDirection = normalize(unitLightDirection + eyeDirection);
float lightDistance = length(lightDirection);
float attenuation =
1.0
/ ( p3d_LightSource[i].constantAttenuation
+ p3d_LightSource[i].linearAttenuation
* lightDistance
+ p3d_LightSource[i].quadraticAttenuation
* (lightDistance * lightDistance)
);
if (attenuation <= 0.0) { continue; }
float diffuseIntensity = dot(normal, unitLightDirection);
if (diffuseIntensity < 0.0) { continue; }
diffuseIntensity =
celShadingEnabled.x == 1
? smoothstep(0.1, 0.2, diffuseIntensity)
: diffuseIntensity;
vec4 lightDiffuseColor = p3d_LightSource[i].diffuse;
lightDiffuseColor.rgb = pow(lightDiffuseColor.rgb, vec3(gamma.x));
vec4 diffuseTemp =
vec4
( clamp
( diffuseColor.rgb
* lightDiffuseColor.rgb
* diffuseIntensity
, 0.0
, 1.0
)
, diffuseColor.a
);
float specularIntensity =
( blinnPhongEnabled.x == 1
? clamp(dot(normal, halfwayDirection), 0.0, 1.0)
: clamp(dot(eyeDirection, reflectedDirection), 0.0, 1.0)
);
specularIntensity =
( celShadingEnabled.x == 1
? smoothstep(0.9, 1.0, specularIntensity)
: specularIntensity
);
vec4 lightSpecularColor = p3d_LightSource[i].specular;
lightSpecularColor.rgb = pow(lightSpecularColor.rgb, vec3(gamma.x));
vec4 materialSpecularColor = vec4(vec3(specularMap.r), diffuseColor.a);
if (fresnelEnabled.x == 1) {
float fresnelFactor = dot((blinnPhongEnabled.x == 1 ? halfwayDirection : normal), eyeDirection);
fresnelFactor = max(fresnelFactor, 0.0);
fresnelFactor = 1.0 - fresnelFactor;
fresnelFactor = pow(fresnelFactor, specularMap.b * MAX_FRESNEL_POWER);
materialSpecularColor.rgb = mix(materialSpecularColor.rgb, vec3(1.0), clamp(fresnelFactor, 0.0, 1.0));
}
vec4 specularTemp = vec4(vec3(0.0), diffuseColor.a);
specularTemp.rgb = lightSpecularColor.rgb * pow(specularIntensity, specularMap.g * MAX_SHININESS);
specularTemp.rgb *= materialSpecularColor.rgb;
specularTemp.rgb *= (1 - isParticle.x);
specularTemp.rgb = clamp(specularTemp.rgb, 0.0, 1.0);
float unitLightDirectionDelta =
dot
( normalize(p3d_LightSource[i].spotDirection)
, -unitLightDirection
);
if (unitLightDirectionDelta < p3d_LightSource[i].spotCosCutoff) { continue; }
float spotExponent = p3d_LightSource[i].spotExponent;
diffuseTemp.rgb *= (spotExponent <= 0.0 ? 1.0 : pow(unitLightDirectionDelta, spotExponent));
vec2 shadowMapSize = textureSize(p3d_LightSource[i].shadowMap, 0);
float inShadow = 0.0;
float count = 0.0;
for ( int si = -shadowSamples; si <= shadowSamples; ++si) {
for (int sj = -shadowSamples; sj <= shadowSamples; ++sj) {
inShadow +=
( 1.0
- textureProj
( p3d_LightSource[i].shadowMap
, vertexInShadowSpaces[i] + vec4(vec2(si, sj) / shadowMapSize, vec2(0.0))
)
);
count += 1.0;
}
}
inShadow /= count;
vec3 shadow =
mix
( vec3(1.0)
, shadowColor
, inShadow
);
diffuseTemp.rgb *= mix(shadow, vec3(1.0), isParticle.x);
specularTemp.rgb *= mix(shadow, vec3(1.0), isParticle.x);
diffuseTemp.rgb *= attenuation;
specularTemp.rgb *= attenuation;
diffuse.rgb += diffuseTemp.rgb;
specular.rgb += specularTemp.rgb;
}
vec4 rimLight = vec4(vec3(0.0), diffuseColor.a);
if (rimLightEnabled.x == 1) {
rimLight.rgb =
vec3
( 1.0
- max
( 0.0
, dot(normalize(-vertexPosition.xyz), normalize(normal))
)
);
rimLight.rgb =
( celShadingEnabled.x == 1
? smoothstep(0.3, 0.4, rimLight.rgb)
: pow(rimLight.rgb, vec3(2.0)) * 1.2
);
rimLight.rgb *= diffuse.rgb;
}
vec2 ssaoBlurTexSize = textureSize(ssaoBlurTexture, 0).xy;
vec2 ssaoBlurTexCoord = gl_FragCoord.xy / ssaoBlurTexSize;
vec3 ssao = texture(ssaoBlurTexture, ssaoBlurTexCoord).rgb;
ssao = mix(shadowColor, vec3(1.0), clamp(ssao.r, 0.0, 1.0));
float sunPosition = sin(sunPosition.x * pi.y);
float sunMixFactor = 1.0 - (sunPosition / 2.0 + 0.5);
vec3 ambientCool = pow(vec3(0.302, 0.451, 0.471), vec3(gamma.x)) * max(0.5, sunMixFactor);
vec3 ambientWarm = pow(vec3(0.765, 0.573, 0.400), vec3(gamma.x)) * max(0.5, sunMixFactor);
vec3 skyLight = mix(ambientCool, ambientWarm, sunMixFactor);
vec3 groundLight = mix(ambientWarm, ambientCool, sunMixFactor);
vec3 worldNormal = normalize((trans_view_to_world * vec4(normal, 0.0)).xyz);
vec3 ambientLight =
mix
( groundLight
, skyLight
, 0.5 * (1.0 + dot(worldNormal, vec3(0, 0, 1)))
);
vec3 ambient =
ambientLight.rgb
* diffuseColor.rgb
* ssao;
vec3 emission = p3d_Material.emission.rgb * max(0.1, pow(sunPosition, 0.4));
out0.a = diffuseColor.a;
out0.rgb = ambient.rgb
+ diffuse.rgb
+ rimLight.rgb
+ emission.rgb;
if (isWater.x == 1) { out0.a = 0.0; }
out1.a = diffuseColor.a;
out1.rgb = specular.rgb;
if (isParticle.x == 1) { out1.rgb = vec3(0.0); }
}
================================================
FILE: demonstration/shaders/fragment/bloom.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform sampler2D colorTexture;
uniform vec2 enabled;
out vec4 fragColor;
void main() {
int size = 3;
float separation = 4.0;
float threshold = 0.6;
float amount = 0.6;
if (enabled.x != 1 || size <= 0) { fragColor = vec4(0); return; }
vec2 texSize = textureSize(colorTexture, 0).xy;
vec4 result = vec4(0.0);
vec4 color = vec4(0.0);
float value = 0.0;
float count = 0.0;
for (int i = -size; i <= size; ++i) {
for (int j = -size; j <= size; ++j) {
color =
texture
( colorTexture
, (vec2(i, j) * separation + gl_FragCoord.xy)
/ texSize
);
value = max(color.r, max(color.g, color.b));
if (value < threshold) { color = vec4(0.0); }
result += color;
count += 1.0;
}
}
result /= count;
fragColor = mix(vec4(0.0), result, amount);
}
================================================
FILE: demonstration/shaders/fragment/box-blur.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform sampler2D colorTexture;
uniform vec2 parameters;
out vec4 fragColor;
void main() {
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
fragColor = texture(colorTexture, texCoord);
int size = int(parameters.x);
if (size <= 0) { return; }
float separation = parameters.y;
separation = max(separation, 1);
fragColor.rgb = vec3(0);
float count = 0.0;
for (int i = -size; i <= size; ++i) {
for (int j = -size; j <= size; ++j) {
fragColor.rgb +=
texture
( colorTexture
, ( gl_FragCoord.xy
+ (vec2(i, j) * separation)
)
/ texSize
).rgb;
count += 1.0;
}
}
fragColor.rgb /= count;
}
================================================
FILE: demonstration/shaders/fragment/chromatic-aberration.frag
================================================
/*
(C) 2021 David Lettier
lettier.com
*/
#version 150
uniform sampler2D colorTexture;
uniform vec2 enabled;
uniform vec2 mouseFocusPoint;
out vec4 fragColor;
void main() {
float redOffset = 0.009;
float greenOffset = 0.006;
float blueOffset = -0.006;
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec2 direction = texCoord - mouseFocusPoint;
fragColor = texture(colorTexture, texCoord);
if (enabled.x != 1) { return; }
fragColor.r = texture(colorTexture, texCoord + (direction * vec2(redOffset ))).r;
fragColor.g = texture(colorTexture, texCoord + (direction * vec2(greenOffset))).g;
fragColor.b = texture(colorTexture, texCoord + (direction * vec2(blueOffset ))).b;
}
================================================
FILE: demonstration/shaders/fragment/depth-of-field.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform sampler2D positionTexture;
uniform sampler2D noiseTexture;
uniform sampler2D focusTexture;
uniform sampler2D outOfFocusTexture;
uniform vec2 mouseFocusPoint;
uniform vec2 nearFar;
uniform vec2 enabled;
out vec4 fragColor;
out vec4 fragColor1;
void main() {
float minDistance = 8.0;
float maxDistance = 12.0;
float far = nearFar.y;
vec2 texSize = textureSize(focusTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 focusColor = texture(focusTexture, texCoord);
fragColor = focusColor;
if (enabled.x != 1) { return; }
vec4 position = texture(positionTexture, texCoord);
if (position.a <= 0) { fragColor1 = vec4(1.0); return; }
vec4 outOfFocusColor = texture(outOfFocusTexture, texCoord);
vec4 focusPoint = texture(positionTexture, mouseFocusPoint);
float blur =
smoothstep
( minDistance
, maxDistance
, length(position - focusPoint)
);
fragColor = mix(focusColor, outOfFocusColor, blur);
fragColor1 = vec4(blur);
}
================================================
FILE: demonstration/shaders/fragment/dilation.frag
================================================
/*
(C) 2020 David Lettier
lettier.com
*/
#version 150
uniform sampler2D colorTexture;
uniform vec2 parameters;
out vec4 fragColor;
void main() {
int size = int(parameters.x);
float separation = parameters.y;
float minThreshold = 0.2;
float maxThreshold = 0.5;
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 fragCoord = gl_FragCoord.xy;
fragColor = texture(colorTexture, fragCoord / texSize);
if (size <= 0) { return; }
float mx = 0.0;
vec4 cmx = fragColor;
for (int i = -size; i <= size; ++i) {
for (int j = -size; j <= size; ++j) {
// For a rectangular shape.
//if (false);
// For a diamond shape;
//if (!(abs(i) <= size - abs(j))) { continue; }
// For a circular shape.
if (!(distance(vec2(i, j), vec2(0, 0)) <= size)) { continue; }
vec4 c =
texture
( colorTexture
, ( gl_FragCoord.xy
+ (vec2(i, j) * separation)
)
/ texSize
);
float mxt = dot(c.rgb, vec3(0.3, 0.59, 0.11));
if (mxt > mx) {
mx = mxt;
cmx = c;
}
}
}
fragColor.rgb =
mix
( fragColor.rgb
, cmx.rgb
, smoothstep(minThreshold, maxThreshold, mx)
);
}
================================================
FILE: demonstration/shaders/fragment/discard.frag
================================================
/*
(C) 2020 David Lettier
lettier.com
*/
#version 150
void main() {
discard;
}
================================================
FILE: demonstration/shaders/fragment/film-grain.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform vec2 pi;
uniform float osg_FrameTime;
uniform sampler2D colorTexture;
uniform vec2 enabled;
out vec4 fragColor;
void main() {
float amount = 0.01;
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 color = texture(colorTexture, texCoord);
if (enabled.x == 1) {
float randomIntensity =
fract
( 10000
* sin
(
( gl_FragCoord.x
+ gl_FragCoord.y
* osg_FrameTime
)
* pi.y
)
);
amount *= randomIntensity;
color.rgb += amount;
}
fragColor = color;
}
================================================
FILE: demonstration/shaders/fragment/foam-mask.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform float osg_FrameTime;
uniform sampler2D foamPatternTexture;
uniform sampler2D flowTexture;
uniform vec2 flowMapsEnabled;
in vec2 diffuseCoord;
out vec4 fragColor;
void main() {
vec2 flow = texture(flowTexture, diffuseCoord).xy;
flow = (flow - 0.5) * 2;
flow.x = abs(flow.x) <= 0.02 ? 0 : flow.x;
flow.y = abs(flow.y) <= 0.02 ? 0 : flow.y;
vec4 foamPattern =
texture
( foamPatternTexture
, vec2
( diffuseCoord.x + flowMapsEnabled.x * flow.x * osg_FrameTime
, diffuseCoord.y + flowMapsEnabled.y * flow.y * osg_FrameTime
)
);
fragColor = vec4(vec3(dot(foamPattern.rgb, vec3(1)) / 3), 1);
}
================================================
FILE: demonstration/shaders/fragment/foam.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform vec2 pi;
uniform vec2 gamma;
uniform mat4 viewWorldMat;
uniform sampler2D maskTexture;
uniform sampler2D positionFromTexture;
uniform sampler2D positionToTexture;
uniform vec2 foamDepth;
uniform vec2 sunPosition;
out vec4 fragColor;
void main() {
vec4 foamColor = vec4(0.8, 0.85, 0.92, 0.8);
vec2 texSize = textureSize(positionFromTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 mask = texture(maskTexture, texCoord);
if (mask.r <= 0.0 || foamDepth.x <= 0.0) { fragColor = vec4(0.0); return; }
foamColor.rgb = pow(foamColor.rgb, vec3(gamma.x));
foamColor.rgb *= max(0.4, -1 * sin(sunPosition.x * pi.y));
vec4 positionFrom = texture(positionFromTexture, texCoord);
vec4 positionTo = texture(positionToTexture, texCoord);
positionFrom = viewWorldMat * positionFrom;
positionTo = viewWorldMat * positionTo;
float depth = length(positionTo.xyz - positionFrom.xyz);
float amount = clamp(depth / foamDepth.x, 0.0, 1.0);
amount = 1.0 - amount;
amount *= mask.r;
// Ease in and out.
amount = (amount * amount)
/ (2.0 * (amount * amount - amount) + 1.0);
fragColor = vec4(foamColor.rgb, amount * foamColor.a);
}
================================================
FILE: demonstration/shaders/fragment/fog.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform vec2 pi;
uniform vec2 gamma;
uniform vec4 backgroundColor0;
uniform vec4 backgroundColor1;
uniform sampler2D positionTexture0;
uniform sampler2D positionTexture1;
uniform sampler2D smokeMaskTexture;
uniform vec3 origin;
uniform vec2 nearFar;
uniform vec2 sunPosition;
uniform vec2 enabled;
out vec4 fragColor;
void main() {
float fogMin = 0.00;
float fogMax = 0.97;
if (enabled.x != 1) { fragColor = vec4(0); return; }
vec2 texSize = textureSize(positionTexture0, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 smokeMask = texture(smokeMaskTexture, texCoord);
vec4 position0 = texture(positionTexture0, texCoord);
position0.y -= origin.y;
float near = nearFar.x;
float far = nearFar.y;
vec4 position1 = texture(positionTexture1, texCoord);
position1.y -= origin.y;
if (position1.a <= 0) { position1.y = far; }
vec4 position = position1;
if (position0.a <= 0 && smokeMask.r > 0) {
position.y = mix(far, position1.y, smokeMask.r);
} else if (position0.a > 0 && smokeMask.r > 0) {
position.xyz = mix(position0.xyz, position1.xyz, smokeMask.r);
}
float random =
fract
( 10000
* sin
(
( gl_FragCoord.x
* 104729
+ gl_FragCoord.y
* 7639
)
* pi.y
)
);
vec4 backgroundColor0 = backgroundColor0;
vec4 backgroundColor1 = backgroundColor1;
backgroundColor0.rgb = pow(backgroundColor0.rgb, vec3(gamma.x));
backgroundColor1.rgb = pow(backgroundColor1.rgb, vec3(gamma.x));
vec4 color =
mix
( backgroundColor0
, backgroundColor1
, 1.0 - clamp(random * 0.1 + texCoord.y, 0.0, 1.0)
);
float sunPosition = max(0.2, -1 * sin(sunPosition.x * pi.y));
color.rgb *= sunPosition;
color.b = mix(color.b + 0.05, color.b, sunPosition);
float intensity =
clamp
( (position.y - near)
/ (far - near)
, fogMin
, fogMax
);
fragColor = vec4(color.rgb, intensity);
}
================================================
FILE: demonstration/shaders/fragment/gamma-correction.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform vec2 gamma;
uniform sampler2D colorTexture;
out vec4 fragColor;
void main() {
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
fragColor = texture(colorTexture, texCoord);
fragColor.rgb = pow(fragColor.rgb, vec3(gamma.y));
}
================================================
FILE: demonstration/shaders/fragment/geometry-buffer-0.frag
================================================
/*
(C) 2020 David Lettier
lettier.com
*/
#version 150
uniform sampler2D p3d_Texture1;
uniform vec2 normalMapsEnabled;
in vec4 vertexPosition;
in vec3 vertexNormal;
in vec3 binormal;
in vec3 tangent;
in vec2 normalCoord;
out vec4 positionOut;
out vec4 normalOut;
void main() {
vec4 normalTex =
texture
( p3d_Texture1
, normalCoord
);
vec3 normal;
if (normalMapsEnabled.x == 1) {
normal =
normalize
( normalTex.rgb
* 2.0
- 1.0
);
normal =
normalize
( mat3
( tangent
, binormal
, vertexNormal
)
* normal
);
} else {
normal = normalize(vertexNormal);
}
positionOut = vertexPosition;
normalOut = vec4(normal, 1);
}
================================================
FILE: demonstration/shaders/fragment/geometry-buffer-1.frag
================================================
/*
(C) 2020 David Lettier
lettier.com
*/
#version 150
#define MAX_SHININESS 127.75
uniform float osg_FrameTime;
uniform struct
{ vec3 specular
; float shininess
;
} p3d_Material;
uniform mat4 p3d_ProjectionMatrix;
uniform sampler2D p3d_Texture1;
uniform sampler2D p3d_Texture3;
uniform sampler2D p3d_Texture4;
uniform sampler2D flowTexture;
uniform sampler2D foamPatternTexture;
uniform vec2 normalMapsEnabled;
uniform vec2 flowMapsEnabled;
in vec4 vertexPosition;
in vec4 vertexColor;
in vec3 vertexNormal;
in vec3 binormal;
in vec3 tangent;
in vec2 diffuseCoord;
in vec2 normalCoord;
out vec4 positionOut;
out vec4 normalOut;
out vec4 reflectionMaskOut;
out vec4 refractionMaskOut;
out vec4 foamMaskOut;
void main() {
vec2 flow = texture(flowTexture, normalCoord).xy;
flow = (flow - 0.5) * 2.0;
flow.x = abs(flow.x) <= 0.02 ? 0.0 : flow.x;
flow.y = abs(flow.y) <= 0.02 ? 0.0 : flow.y;
vec3 normal;
if (normalMapsEnabled.x == 1) {
vec4 normalTex =
texture
( p3d_Texture1
, vec2
( normalCoord.x + flowMapsEnabled.x * flow.x * osg_FrameTime
, normalCoord.y + flowMapsEnabled.y * flow.y * osg_FrameTime
)
);
normal =
normalize
( normalTex.rgb
* 2.0
- 1.0
);
normal =
normalize
( mat3
( tangent
, binormal
, vertexNormal
)
* normal
);
} else {
normal = normalize(vertexNormal);
}
vec4 reflectionMask = texture(p3d_Texture3, diffuseCoord);
vec4 refractionMask = texture(p3d_Texture4, diffuseCoord);
vec2 foamPatternTextureSize = textureSize(foamPatternTexture, 0).xy;
vec4 foamUvOffset = p3d_ProjectionMatrix * vec4(normalize(normal), 1.0);
foamUvOffset.xyz /= foamUvOffset.w;
foamUvOffset.xy = foamUvOffset.xy * 0.5 + 0.5;
foamUvOffset.xy /= foamPatternTextureSize;
foamUvOffset.xy *= 0.3;
vec2 foamUv = diffuseCoord.xy + foamUvOffset.xy;
foamUv = foamUv + flowMapsEnabled * flow * 0.5 * osg_FrameTime;
foamUv *= 0.5;
vec4 foamPattern = texture(foamPatternTexture, foamUv);
positionOut = vertexPosition;
normalOut = vec4(normal, 1.0);
reflectionMaskOut = reflectionMask;
refractionMaskOut = refractionMask;
foamMaskOut = foamPattern;
}
================================================
FILE: demonstration/shaders/fragment/geometry-buffer-2.frag
================================================
/*
(C) 2020 David Lettier
lettier.com
*/
#version 150
uniform sampler2D p3d_Texture0;
uniform sampler2D positionTexture;
uniform vec2 isSmoke;
in vec4 vertexPosition;
in vec4 vertexColor;
in vec2 diffuseCoord;
out vec4 positionOut;
out vec4 smokeMaskOut;
void main() {
positionOut = vertexPosition;
smokeMaskOut = vec4(0.0);
if (isSmoke.x == 1) {
vec4 diffuseColor = texture(p3d_Texture0, diffuseCoord) * vertexColor;
vec2 texSize = textureSize(positionTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 position = texture(positionTexture, texCoord);
if (position.a <= 0.0) {
positionOut = diffuseColor.a > 0.0 ? vertexPosition : vec4(0.0);
} else {
positionOut = mix(position, vertexPosition, diffuseColor.a);
}
smokeMaskOut = diffuseColor * vertexColor;
smokeMaskOut.rgb = vec3(dot(smokeMaskOut.rgb, vec3(1.0 / 3.0)));
}
}
================================================
FILE: demonstration/shaders/fragment/kuwahara-filter.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
#define MAX_SIZE 5
#define MAX_KERNEL_SIZE ((MAX_SIZE * 2 + 1) * (MAX_SIZE * 2 + 1))
uniform sampler2D colorTexture;
uniform vec2 parameters;
out vec4 fragColor;
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
int i = 0;
int j = 0;
int count = 0;
vec3 valueRatios = vec3(0.3, 0.59, 0.11);
float values[MAX_KERNEL_SIZE];
vec4 color = vec4(0.0);
vec4 meanTemp = vec4(0.0);
vec4 mean = vec4(0.0);
float valueMean = 0.0;
float variance = 0.0;
float minVariance = -1.0;
void findMean(int i0, int i1, int j0, int j1) {
meanTemp = vec4(0);
count = 0;
for (i = i0; i <= i1; ++i) {
for (j = j0; j <= j1; ++j) {
color =
texture
( colorTexture
, (gl_FragCoord.xy + vec2(i, j))
/ texSize
);
meanTemp += color;
values[count] = dot(color.rgb, valueRatios);
count += 1;
}
}
meanTemp.rgb /= count;
valueMean = dot(meanTemp.rgb, valueRatios);
for (i = 0; i < count; ++i) {
variance += pow(values[i] - valueMean, 2);
}
variance /= count;
if (variance < minVariance || minVariance <= -1) {
mean = meanTemp;
minVariance = variance;
}
}
void main() {
fragColor = texture(colorTexture, texCoord);
int size = int(parameters.x);
if (size <= 0) { return; }
// Lower Left
findMean(-size, 0, -size, 0);
// Upper Right
findMean(0, size, 0, size);
// Upper Left
findMean(-size, 0, 0, size);
// Lower Right
findMean(0, size, -size, 0);
fragColor.rgb = mean.rgb;
}
================================================
FILE: demonstration/shaders/fragment/lookup-table.frag
================================================
/*
(C) 2020 David Lettier
lettier.com
*/
#version 150
uniform vec2 pi;
uniform vec2 gamma;
uniform sampler2D colorTexture;
uniform sampler2D lookupTableTexture0;
uniform sampler2D lookupTableTexture1;
uniform vec2 sunPosition;
uniform vec2 enabled;
out vec4 fragColor;
void main() {
vec2 texSize = textureSize(colorTexture, 0).xy;
vec4 color = texture(colorTexture, gl_FragCoord.xy / texSize);
if (enabled.x != 1) { fragColor = color; return; }
color.rgb = pow(color.rgb, vec3(gamma.y));
float u = floor(color.b * 15.0) / 15.0 * 240.0;
u = (floor(color.r * 15.0) / 15.0 * 15.0) + u;
u /= 255.0;
float v = 1.0 - (floor(color.g * 15.0) / 15.0);
vec3 left0 = texture(lookupTableTexture0, vec2(u, v)).rgb;
vec3 left1 = texture(lookupTableTexture1, vec2(u, v)).rgb;
u = ceil(color.b * 15.0) / 15.0 * 240.0;
u = (ceil(color.r * 15.0) / 15.0 * 15.0) + u;
u /= 255.0;
v = 1.0 - (ceil(color.g * 15.0) / 15.0);
vec3 right0 = texture(lookupTableTexture0, vec2(u, v)).rgb;
vec3 right1 = texture(lookupTableTexture1, vec2(u, v)).rgb;
float sunPosition = sin(sunPosition.x * pi.y);
sunPosition = 0.5 * (sunPosition + 1);
vec3 left = mix(left0, left1, sunPosition);
vec3 right = mix(right0, right1, sunPosition);
color.r = mix(left.r, right.r, fract(color.r * 15.0));
color.g = mix(left.g, right.g, fract(color.g * 15.0));
color.b = mix(left.b, right.b, fract(color.b * 15.0));
color.rgb = pow(color.rgb, vec3(gamma.x));
fragColor = color;
}
================================================
FILE: demonstration/shaders/fragment/material-diffuse.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform struct
{ vec4 diffuse
;
} p3d_Material;
out vec4 fragColor;
void main() {
fragColor = p3d_Material.diffuse;
}
================================================
FILE: demonstration/shaders/fragment/material-specular.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
#define MAX_SHININESS 127.75
uniform struct
{ vec3 specular
; float shininess
;
} p3d_Material;
out vec4 fragColor;
void main() {
fragColor =
vec4
( p3d_Material.specular
, clamp(p3d_Material.shininess / MAX_SHININESS, 0.0, 1.0)
);
}
================================================
FILE: demonstration/shaders/fragment/median-filter.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
#define MAX_SIZE 4
#define MAX_KERNEL_SIZE ((MAX_SIZE * 2 + 1) * (MAX_SIZE * 2 + 1))
#define MAX_BINS_SIZE 10
uniform sampler2D colorTexture;
uniform vec2 parameters;
out vec4 fragColor;
void main() {
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
int size = int(parameters.x);
if (size <= 0) { fragColor = texture(colorTexture, texCoord); return; }
if (size > MAX_SIZE) { size = MAX_SIZE; }
int kernelSize = int(pow(size * 2 + 1, 2));
int binsSize = int(parameters.y);
binsSize = clamp(binsSize, 1, MAX_BINS_SIZE);
int i = 0;
int j = 0;
int count = 0;
int binIndex = 0;
vec4 colors[MAX_KERNEL_SIZE];
float bins[MAX_BINS_SIZE];
int binIndexes[colors.length()];
float total = 0;
float limit = floor(float(kernelSize) / 2) + 1;
float value = 0;
vec3 valueRatios = vec3(0.3, 0.59, 0.11);
for (i = -size; i <= size; ++i) {
for (j = -size; j <= size; ++j) {
colors[count] =
texture
( colorTexture
, ( gl_FragCoord.xy
+ vec2(i, j)
)
/ texSize
);
count += 1;
}
}
for (i = 0; i < binsSize; ++i) {
bins[i] = 0;
}
for (i = 0; i < kernelSize; ++i) {
value = dot(colors[i].rgb, valueRatios);
binIndex = int(floor(value * binsSize));
binIndex = clamp(binIndex, 0, binsSize - 1);
bins[binIndex] += 1;
binIndexes[i] = binIndex;
}
binIndex = 0;
for (i = 0; i < binsSize; ++i) {
total += bins[i];
if (total >= limit) {
binIndex = i;
break;
}
}
fragColor = colors[0];
for (i = 0; i < kernelSize; ++i) {
if (binIndexes[i] == binIndex) {
fragColor = colors[i];
break;
}
}
}
================================================
FILE: demonstration/shaders/fragment/motion-blur.frag
================================================
/*
(C) 2020 David Lettier
lettier.com
*/
#version 150
uniform sampler2D positionTexture;
uniform sampler2D colorTexture;
uniform mat4 previousViewWorldMat;
uniform mat4 worldViewMat;
uniform mat4 lensProjection;
uniform vec2 motionBlurEnabled;
uniform vec2 parameters;
out vec4 fragColor;
void main() {
int size = int(parameters.x);
float separation = parameters.y;
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
fragColor = texture(colorTexture, texCoord);
vec4 position1 = texture(positionTexture, texCoord);
if (size <= 0 || separation <= 0.0 || motionBlurEnabled.x != 1 || position1.a <= 0.0) { return; }
vec4 position0 = worldViewMat * previousViewWorldMat * position1;
position0 = lensProjection * position0;
position0.xyz /= position0.w;
position0.xy = position0.xy * 0.5 + 0.5;
position1 = lensProjection * position1;
position1.xyz /= position1.w;
position1.xy = position1.xy * 0.5 + 0.5;
vec2 direction = position1.xy - position0.xy;
if (length(direction) <= 0.0) { return; }
direction.xy *= separation;
vec2 forward = texCoord;
vec2 backward = texCoord;
float count = 1.0;
for (int i = 0; i < size; ++i) {
forward += direction;
backward -= direction;
fragColor +=
texture
( colorTexture
, forward
);
fragColor +=
texture
( colorTexture
, backward
);
count += 2.0;
}
fragColor /= count;
}
================================================
FILE: demonstration/shaders/fragment/normal.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform float osg_FrameTime;
uniform sampler2D p3d_Texture1;
uniform sampler2D flowTexture;
uniform vec2 normalMapsEnabled;
uniform vec2 flowMapsEnabled;
in vec3 vertexNormal;
in vec3 binormal;
in vec3 tangent;
in vec2 normalCoord;
out vec4 fragColor;
void main() {
vec2 flow = texture(flowTexture, normalCoord).xy;
flow = (flow - 0.5) * 2;
flow.x = abs(flow.x) <= 0.02 ? 0 : flow.x;
flow.y = abs(flow.y) <= 0.02 ? 0 : flow.y;
vec4 normalTex =
texture
( p3d_Texture1
, vec2
( normalCoord.x + flowMapsEnabled.x * flow.x * osg_FrameTime
, normalCoord.y + flowMapsEnabled.y * flow.y * osg_FrameTime
)
);
vec3 normal;
if (normalMapsEnabled.x == 1) {
normal =
normalize
( normalTex.rgb
* 2.0
- 1.0
);
normal =
normalize
( mat3
( tangent
, binormal
, vertexNormal
)
* normal
);
} else {
normal = normalize(vertexNormal);
}
// To convert Panda3D z-up to OpenGL y-up.
// fragColor = vec4(normal.x, normal.z, -normal.y, 1);
fragColor = vec4(normal, 1);
}
================================================
FILE: demonstration/shaders/fragment/outline.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform vec2 gamma;
uniform sampler2D positionTexture;
uniform sampler2D colorTexture;
uniform sampler2D noiseTexture;
uniform sampler2D depthOfFieldTexture;
uniform sampler2D fogTexture;
uniform vec2 nearFar;
uniform vec2 enabled;
out vec4 fragColor;
void main() {
float minSeparation = 1.0;
float maxSeparation = 1.0;
float minDistance = 1.5;
float maxDistance = 2.0;
float noiseScale = 1.0;
int size = 1;
vec3 colorModifier = vec3(0.522, 0.431, 0.349);
colorModifier = pow(colorModifier, vec3(gamma.x));
float near = nearFar.x;
float far = nearFar.y;
vec2 fragCoord = gl_FragCoord.xy;
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 texCoord = fragCoord / texSize;
vec4 color = texture(colorTexture, texCoord);
float depthOfField = texture(depthOfFieldTexture, texCoord).r;
float fog = texture(fogTexture, texCoord).a;
if (enabled.x != 1) { fragColor = color; return; }
fragColor = vec4(0.0);
vec2 noise = texture(noiseTexture, fragCoord / textureSize(noiseTexture, 0).xy).rb;
noise = noise * 2.0 - 1.0;
noise *= noiseScale;
texCoord = (fragCoord - noise) / texSize;
vec4 position = texture(positionTexture, texCoord);
vec4 positionTemp = position;
if (position.a <= 0.0) { position.y = far; }
float depth =
clamp
( 1.0
- ( (far - position.y)
/ (far - near)
)
, 0.0
, 1.0
);
float separation = mix(maxSeparation, minSeparation, depth);
float count = 1.0;
float mx = 0.0;
for (int i = -size; i <= size; ++i) {
for (int j = -size; j <= size; ++j) {
texCoord =
(vec2(i, j) * separation + (fragCoord + noise))
/ texSize;
positionTemp =
texture
( positionTexture
, texCoord
);
if (positionTemp.y <= 0.0) { positionTemp.y = far; }
mx = max(mx, abs(position.y - positionTemp.y));
depthOfField =
max
( texture
( depthOfFieldTexture
, texCoord
).r
, depthOfField
);
fog +=
texture
( fogTexture
, texCoord
).a;
count += 1.0;
}
}
depthOfField = 1.0 - clamp(depthOfField, 0.0, 1.0);
fog = 1.0 - clamp(fog / count, 0.0, 1.0);
float diff = smoothstep(minDistance, maxDistance, mx) * depthOfField * fog;
texCoord = fragCoord / texSize;
vec3 lineColor = texture(colorTexture, texCoord).rgb;
lineColor *= colorModifier;
fragColor.rgb = mix(color.rgb, lineColor, clamp(diff, 0.0, 1.0));
fragColor.a = 1.0;
}
================================================
FILE: demonstration/shaders/fragment/pixelize.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform sampler2D colorTexture;
uniform sampler2D positionTexture;
uniform vec2 parameters;
uniform vec2 enabled;
out vec4 fragColor;
void main() {
// Must be odd.
int pixelSize = int(parameters.x);
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
// Avoid the background.
vec4 position = texture(positionTexture, texCoord);
if (enabled.x != 1 || position.a <= 0.0) {
fragColor = texture(colorTexture, texCoord);
return;
}
float x = int(gl_FragCoord.x) % pixelSize;
float y = int(gl_FragCoord.y) % pixelSize;
x = floor(pixelSize / 2.0) - x;
y = floor(pixelSize / 2.0) - y;
x = gl_FragCoord.x + x;
y = gl_FragCoord.y + y;
vec2 uv = vec2(x, y) / texSize;
fragColor = texture(colorTexture, uv);
}
================================================
FILE: demonstration/shaders/fragment/position.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
in vec4 vertexPosition;
out vec4 fragColor;
void main() {
// To convert Panda3D z-up to OpenGL y-up.
/*
fragColor = vertexPosition.xzyw;
*/
fragColor = vertexPosition;
}
================================================
FILE: demonstration/shaders/fragment/posterize.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform vec2 gamma;
uniform sampler2D colorTexture;
uniform sampler2D positionTexture;
uniform vec2 enabled;
out vec4 fragColor;
void main() {
float levels = 6.0;
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
// Avoid the background.
vec4 position = texture(positionTexture, texCoord);
if (position.a <= 0) { fragColor = vec4(0); return; }
fragColor = texture(colorTexture, texCoord);
if (enabled.x != 1) { return; }
fragColor.rgb = pow(fragColor.rgb, vec3(gamma.y));
float greyscale = max(fragColor.r, max(fragColor.g, fragColor.b));
float lower = floor(greyscale * levels) / levels;
float lowerDiff = abs(greyscale - lower);
float upper = ceil(greyscale * levels) / levels;
float upperDiff = abs(upper - greyscale);
float level = lowerDiff <= upperDiff ? lower : upper;
float adjustment = level / greyscale;
fragColor.rgb = fragColor.rgb * adjustment;
fragColor.rgb = pow(fragColor.rgb, vec3(gamma.x));
}
================================================
FILE: demonstration/shaders/fragment/reflection-color.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform sampler2D uvTexture;
uniform sampler2D colorTexture;
out vec4 fragColor;
void main() {
int size = 6;
float separation = 2.0;
vec2 texSize = textureSize(uvTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 uv = texture(uvTexture, texCoord);
// Removes holes in the UV map.
if (uv.b <= 0.0) {
uv = vec4(0.0);
float count = 0.0;
for (int i = -size; i <= size; ++i) {
for (int j = -size; j <= size; ++j) {
uv += texture
( uvTexture
, ( (vec2(i, j) * separation)
+ gl_FragCoord.xy
)
/ texSize
);
count += 1.0;
}
}
uv.xyz /= count;
}
if (uv.b <= 0.0) { fragColor = vec4(0.0); return;}
vec4 color = texture(colorTexture, uv.xy);
float alpha = clamp(uv.b, 0.0, 1.0);
fragColor = vec4(mix(vec3(0.0), color.rgb, alpha), alpha);
}
================================================
FILE: demonstration/shaders/fragment/reflection.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform sampler2D colorTexture;
uniform sampler2D colorBlurTexture;
uniform sampler2D maskTexture;
out vec4 fragColor;
void main() {
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 mask = texture(maskTexture, texCoord);
vec4 color = texture(colorTexture, texCoord);
vec4 colorBlur = texture(colorBlurTexture, texCoord);
float amount = clamp(mask.r, 0.0, 1.0);
if (amount <= 0.0) { fragColor = vec4(0.0); return; }
float roughness = clamp(mask.g, 0.0, 1.0);
fragColor = mix(color, colorBlur, roughness) * amount;
}
================================================
FILE: demonstration/shaders/fragment/refraction.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform vec2 pi;
uniform vec2 gamma;
uniform sampler2D uvTexture;
uniform sampler2D maskTexture;
uniform sampler2D positionFromTexture;
uniform sampler2D positionToTexture;
uniform sampler2D backgroundColorTexture;
uniform vec2 sunPosition;
out vec4 fragColor;
void main() {
vec4 tintColor = vec4(0.392, 0.537, 0.561, 0.8);
float depthMax = 2.0;
vec2 texSize = textureSize(backgroundColorTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 backgroundColor = texture(backgroundColorTexture, texCoord);
vec4 mask = texture(maskTexture, texCoord);
if (mask.r <= 0) { fragColor = backgroundColor; return; }
vec4 uv = texture(uvTexture, texCoord);
if (uv.b <= 0) { fragColor = backgroundColor; return; }
tintColor.rgb = pow(tintColor.rgb, vec3(gamma.x));
tintColor.rgb *= max(0.2, -1 * sin(sunPosition.x * pi.y));
vec4 positionFrom = texture(positionFromTexture, texCoord);
vec4 positionTo = texture(positionToTexture, uv.xy);
backgroundColor = texture(backgroundColorTexture, uv.xy);
float depth = length(positionTo.xyz - positionFrom.xyz);
float mixture = clamp(depth / depthMax, 0.0, 1.0);
vec3 shallowColor = backgroundColor.rgb;
vec3 deepColor = mix(shallowColor, tintColor.rgb, tintColor.a);
vec3 foregroundColor = mix(shallowColor, deepColor, mixture);
fragColor = mix(vec4(0.0), vec4(foregroundColor, 1.0), uv.b);
}
================================================
FILE: demonstration/shaders/fragment/scene-combine.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform vec2 pi;
uniform vec2 gamma;
uniform sampler2D baseTexture;
uniform sampler2D bloomTexture;
uniform sampler2D fogTexture;
uniform vec4 backgroundColor0;
uniform vec4 backgroundColor1;
uniform vec2 sunPosition;
out vec4 fragColor;
void main() {
vec2 texSize = textureSize(baseTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 backgroundColor0 = backgroundColor0;
vec4 backgroundColor1 = backgroundColor1;
backgroundColor0.rgb = pow(backgroundColor0.rgb, vec3(gamma.x));
backgroundColor1.rgb = pow(backgroundColor1.rgb, vec3(gamma.x));
float random =
fract
( 10000
* sin
(
( gl_FragCoord.x
* 104729
+ gl_FragCoord.y
* 7639
)
* pi.y
)
);
float sunPosition = sin(sunPosition.x * pi.y);
sunPosition = max(0.2, -1 * sunPosition);
vec4 backgroundColor =
mix
( backgroundColor0
, backgroundColor1
, 1.0 - clamp(random * 0.1 + texCoord.y, 0.0, 1.0)
);
backgroundColor.rgb *= sunPosition;
backgroundColor.b = mix(backgroundColor.b + 0.05, backgroundColor.b, sunPosition);
vec4 baseColor = texture(baseTexture, texCoord);
vec4 bloomColor = texture(bloomTexture, texCoord);
vec4 fogColor = texture(fogTexture, texCoord);
fragColor = baseColor;
fragColor = fragColor + bloomColor;
fragColor = mix(fragColor, fogColor, min(fogColor.a, 1));
fragColor =
vec4
( mix
( backgroundColor.rgb
, fragColor.rgb
, min(baseColor.a + fogColor.a, 1)
)
, 1
);
}
================================================
FILE: demonstration/shaders/fragment/screen-space-reflection.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform mat4 lensProjection;
uniform sampler2D positionTexture;
uniform sampler2D normalTexture;
uniform sampler2D maskTexture;
uniform vec2 enabled;
out vec4 fragColor;
void main() {
float maxDistance = 8;
float resolution = 0.3;
int steps = 5;
float thickness = 0.5;
vec2 texSize = textureSize(positionTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 uv = vec4(0.0);
vec4 positionFrom = texture(positionTexture, texCoord);
vec4 mask = texture(maskTexture, texCoord);
if ( positionFrom.w <= 0.0
|| enabled.x != 1.0
|| mask.r <= 0.0
) { fragColor = uv; return; }
vec3 unitPositionFrom = normalize(positionFrom.xyz);
vec3 normal = normalize(texture(normalTexture, texCoord).xyz);
vec3 pivot = normalize(reflect(unitPositionFrom, normal));
vec4 positionTo = positionFrom;
vec4 startView = vec4(positionFrom.xyz + (pivot * 0.0), 1.0);
vec4 endView = vec4(positionFrom.xyz + (pivot * maxDistance), 1.0);
vec4 startFrag = startView;
startFrag = lensProjection * startFrag;
startFrag.xyz /= startFrag.w;
startFrag.xy = startFrag.xy * 0.5 + 0.5;
startFrag.xy *= texSize;
vec4 endFrag = endView;
endFrag = lensProjection * endFrag;
endFrag.xyz /= endFrag.w;
endFrag.xy = endFrag.xy * 0.5 + 0.5;
endFrag.xy *= texSize;
vec2 frag = startFrag.xy;
uv.xy = frag / texSize;
float deltaX = endFrag.x - startFrag.x;
float deltaY = endFrag.y - startFrag.y;
float useX = abs(deltaX) >= abs(deltaY) ? 1.0 : 0.0;
float delta = mix(abs(deltaY), abs(deltaX), useX) * clamp(resolution, 0.0, 1.0);
vec2 increment = vec2(deltaX, deltaY) / max(delta, 0.001);
float search0 = 0;
float search1 = 0;
int hit0 = 0;
int hit1 = 0;
float viewDistance = startView.y;
float depth = thickness;
float i = 0;
for (i = 0; i < int(delta); ++i) {
frag += increment;
uv.xy = frag / texSize;
positionTo = texture(positionTexture, uv.xy);
search1 =
mix
( (frag.y - startFrag.y) / deltaY
, (frag.x - startFrag.x) / deltaX
, useX
);
search1 = clamp(search1, 0.0, 1.0);
viewDistance = (startView.y * endView.y) / mix(endView.y, startView.y, search1);
depth = viewDistance - positionTo.y;
if (depth > 0 && depth < thickness) {
hit0 = 1;
break;
} else {
search0 = search1;
}
}
search1 = search0 + ((search1 - search0) / 2.0);
steps *= hit0;
for (i = 0; i < steps; ++i) {
frag = mix(startFrag.xy, endFrag.xy, search1);
uv.xy = frag / texSize;
positionTo = texture(positionTexture, uv.xy);
viewDistance = (startView.y * endView.y) / mix(endView.y, startView.y, search1);
depth = viewDistance - positionTo.y;
if (depth > 0 && depth < thickness) {
hit1 = 1;
search1 = search0 + ((search1 - search0) / 2);
} else {
float temp = search1;
search1 = search1 + ((search1 - search0) / 2);
search0 = temp;
}
}
float visibility =
hit1
* positionTo.w
* ( 1
- max
( dot(-unitPositionFrom, pivot)
, 0
)
)
* ( 1
- clamp
( depth / thickness
, 0
, 1
)
)
* ( 1
- clamp
( length(positionTo - positionFrom)
/ maxDistance
, 0
, 1
)
)
* (uv.x < 0 || uv.x > 1 ? 0 : 1)
* (uv.y < 0 || uv.y > 1 ? 0 : 1);
visibility = clamp(visibility, 0, 1);
uv.ba = vec2(visibility);
fragColor = uv;
}
================================================
FILE: demonstration/shaders/fragment/screen-space-refraction.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform mat4 lensProjection;
uniform sampler2D positionFromTexture;
uniform sampler2D positionToTexture;
uniform sampler2D normalFromTexture;
uniform vec2 rior;
uniform vec2 enabled;
out vec4 fragColor;
void main() {
float maxDistance = 5;
float resolution = 0.3;
int steps = 5;
float thickness = 0.5;
vec2 texSize = textureSize(positionFromTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 uv = vec4(texCoord.xy, 1, 1);
vec4 positionFrom = texture(positionFromTexture, texCoord);
if (positionFrom.w <= 0 || enabled.x != 1) { fragColor = uv; return; }
vec3 unitPositionFrom = normalize(positionFrom.xyz);
vec3 normalFrom = normalize(texture(normalFromTexture, texCoord).xyz);
vec3 pivot = normalize(refract(unitPositionFrom, normalFrom, rior.x));
vec4 positionTo = positionFrom;
vec4 startView = vec4(positionFrom.xyz + (pivot * 0), 1);
vec4 endView = vec4(positionFrom.xyz + (pivot * maxDistance), 1);
vec4 startFrag = startView;
startFrag = lensProjection * startFrag;
startFrag.xyz /= startFrag.w;
startFrag.xy = startFrag.xy * 0.5 + 0.5;
startFrag.xy *= texSize;
vec4 endFrag = endView;
endFrag = lensProjection * endFrag;
endFrag.xyz /= endFrag.w;
endFrag.xy = endFrag.xy * 0.5 + 0.5;
endFrag.xy *= texSize;
vec2 frag = startFrag.xy;
uv.xy = frag / texSize;
float deltaX = endFrag.x - startFrag.x;
float deltaY = endFrag.y - startFrag.y;
float useX = abs(deltaX) >= abs(deltaY) ? 1 : 0;
float delta = mix(abs(deltaY), abs(deltaX), useX) * clamp(resolution, 0, 1);
vec2 increment = vec2(deltaX, deltaY) / max(delta, 0.001);
float search0 = 0;
float search1 = 0;
int hit0 = 0;
int hit1 = 0;
float viewDistance = startView.y;
float depth = thickness;
float i = 0;
for (i = 0; i < int(delta); ++i) {
frag += increment;
uv.xy = frag / texSize;
positionTo = texture(positionToTexture, uv.xy);
search1 =
mix
( (frag.y - startFrag.y) / deltaY
, (frag.x - startFrag.x) / deltaX
, useX
);
search1 = clamp(search1, 0, 1);
viewDistance = (startView.y * endView.y) / mix(endView.y, startView.y, search1);
depth = viewDistance - positionTo.y;
if (depth > 0 && depth < thickness) {
hit0 = 1;
break;
} else {
search0 = search1;
}
}
search1 = search0 + ((search1 - search0) / 2);
steps *= hit0;
for (i = 0; i < steps; ++i) {
frag = mix(startFrag.xy, endFrag.xy, search1);
uv.xy = frag / texSize;
positionTo = texture(positionToTexture, uv.xy);
viewDistance = (startView.y * endView.y) / mix(endView.y, startView.y, search1);
depth = viewDistance - positionTo.y;
if (depth > 0 && depth < thickness) {
hit1 = 1;
search1 = search0 + ((search1 - search0) / 2);
} else {
float temp = search1;
search1 = search1 + ((search1 - search0) / 2);
search0 = temp;
}
}
float visibility =
hit1
* positionTo.w
* ( 1
- max
( dot(-unitPositionFrom, pivot)
, 0
)
)
* (uv.x < 0 || uv.x > 1 ? 0 : 1)
* (uv.y < 0 || uv.y > 1 ? 0 : 1);
visibility = clamp(visibility, 0, 1);
fragColor = vec4(mix(texCoord.xy, uv.xy, visibility), 1, 1);
}
================================================
FILE: demonstration/shaders/fragment/sharpen.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform sampler2D colorTexture;
uniform vec2 enabled;
out vec4 fragColor;
void main() {
float amount = 0.3;
vec2 texSize = textureSize(colorTexture, 0).xy;
vec2 fragCoord = gl_FragCoord.xy;
vec2 texCoord = fragCoord / texSize;
if (enabled.x != 1) { fragColor = texture(colorTexture, texCoord); return; }
float neighbor = amount * -1.0;
float center = amount * 4.0 + 1.0;
vec3 color =
texture(colorTexture, (fragCoord + vec2( 0, 1)) / texSize).rgb
* neighbor
+ texture(colorTexture, (fragCoord + vec2(-1, 0)) / texSize).rgb
* neighbor
+ texture(colorTexture, (fragCoord + vec2( 0, 0)) / texSize).rgb
* center
+ texture(colorTexture, (fragCoord + vec2( 1, 0)) / texSize).rgb
* neighbor
+ texture(colorTexture, (fragCoord + vec2( 0, -1)) / texSize).rgb
* neighbor
;
fragColor = vec4(color, texture(colorTexture, texCoord).a);
}
================================================
FILE: demonstration/shaders/fragment/ssao.frag
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
#define NUM_SAMPLES 8
#define NUM_NOISE 4
uniform mat4 lensProjection;
uniform vec3 samples[NUM_SAMPLES];
uniform vec3 noise[NUM_NOISE];
uniform sampler2D positionTexture;
uniform sampler2D normalTexture;
uniform vec2 enabled;
out vec4 fragColor;
void main() {
float radius = 0.6;
float bias = 0.005;
float magnitude = 1.1;
float contrast = 1.1;
fragColor = vec4(1);
if (enabled.x != 1) { return; }
vec2 texSize = textureSize(positionTexture, 0).xy;
vec2 texCoord = gl_FragCoord.xy / texSize;
vec4 position = texture(positionTexture, texCoord);
if (position.a <= 0) { return; }
vec3 normal = normalize(texture(normalTexture, texCoord).xyz);
int noiseS = int(sqrt(NUM_NOISE));
int noiseX = int(gl_FragCoord.x - 0.5) % noiseS;
int noiseY = int(gl_FragCoord.y - 0.5) % noiseS;
vec3 random = noise[noiseX + (noiseY * noiseS)];
vec3 tangent = normalize(random - normal * dot(random, normal));
vec3 binormal = cross(normal, tangent);
mat3 tbn = mat3(tangent, binormal, normal);
float occlusion = NUM_SAMPLES;
for (int i = 0; i < NUM_SAMPLES; ++i) {
vec3 samplePosition = tbn * samples[i];
samplePosition = position.xyz + samplePosition * radius;
vec4 offsetUV = vec4(samplePosition, 1.0);
offsetUV = lensProjection * offsetUV;
offsetUV.xyz /= offsetUV.w;
offsetUV.xy = offsetUV.xy * 0.5 + 0.5;
// Config.prc
// gl-coordinate-system default
// textures-auto-power-2 1
// textures-power-2 down
vec4 offsetPosition = texture(positionTexture, offsetUV.xy);
float occluded = 0;
if (samplePosition.y + bias <= offsetPosition.y)
{ occluded = 0; }
else { occluded = 1; }
float intensity =
smoothstep
( 0
, 1
, radius
/ abs(position.y - offsetPosition.y)
);
occluded *= intensity;
occlusion -= occluded;
}
occlusion /= NUM_SAMPLES;
occlusion = pow(occlusion, magnitude);
occlusion = contrast * (occlusion - 0.5) + 0.5;
fragColor = vec4(vec3(occlusion), position.a);
}
================================================
FILE: demonstration/shaders/vertex/base.vert
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
#define NUMBER_OF_LIGHTS 4
uniform mat4 p3d_ModelViewMatrix;
uniform mat4 p3d_ProjectionMatrix;
uniform mat3 p3d_NormalMatrix;
uniform struct p3d_LightSourceParameters
{ vec4 color
; vec4 ambient
; vec4 diffuse
; vec4 specular
; vec4 position
; vec3 spotDirection
; float spotExponent
; float spotCutoff
; float spotCosCutoff
; float constantAttenuation
; float linearAttenuation
; float quadraticAttenuation
; vec3 attenuation
; sampler2DShadow shadowMap
; mat4 shadowViewMatrix
;
} p3d_LightSource[NUMBER_OF_LIGHTS];
in vec4 p3d_Vertex;
in vec3 p3d_Normal;
in vec4 p3d_Color;
in vec2 p3d_MultiTexCoord0;
in vec2 p3d_MultiTexCoord1;
in vec3 p3d_Binormal;
in vec3 p3d_Tangent;
out vec4 vertexPosition;
out vec4 vertexColor;
out vec3 vertexNormal;
out vec3 binormal;
out vec3 tangent;
out vec2 normalCoord;
out vec2 diffuseCoord;
out vec4 vertexInShadowSpaces[NUMBER_OF_LIGHTS];
void main() {
vertexColor = p3d_Color;
vertexPosition = p3d_ModelViewMatrix * p3d_Vertex;
vertexNormal = normalize(p3d_NormalMatrix * p3d_Normal);
binormal = normalize(p3d_NormalMatrix * p3d_Binormal);
tangent = normalize(p3d_NormalMatrix * p3d_Tangent);
normalCoord = p3d_MultiTexCoord0;
diffuseCoord = p3d_MultiTexCoord1;
for (int i = 0; i < p3d_LightSource.length(); ++i) {
vertexInShadowSpaces[i] = p3d_LightSource[i].shadowViewMatrix * vertexPosition;
}
gl_Position = p3d_ProjectionMatrix * vertexPosition;
}
================================================
FILE: demonstration/shaders/vertex/basic.vert
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#version 150
uniform mat4 p3d_ModelViewProjectionMatrix;
in vec4 p3d_Vertex;
void main()
{
gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;
}
================================================
FILE: demonstration/shaders/vertex/discard.vert
================================================
/*
(C) 2020 David Lettier
lettier.com
*/
#version 150
void main()
{
gl_Position = vec4(vec3(2.0), 1.0);
}
================================================
FILE: demonstration/src/LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2019, David Lettier
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: demonstration/src/main.cxx
================================================
/*
(C) 2019 David Lettier
lettier.com
*/
#include <thread>
#include <unistd.h>
#include <random>
#include <string>
#include <chrono>
#include <thread>
#include <algorithm>
#include "pandaFramework.h" // Panda3D 1.10.9
#include "renderBuffer.h"
#include "load_prc_file.h"
#include "pStatClient.h"
#include "pandaSystem.h"
#include "mouseButton.h"
#include "mouseWatcher.h"
#include "buttonRegistry.h"
#include "orthographicLens.h"
#include "ambientLight.h"
#include "directionalLight.h"
#include "pointLight.h"
#include "spotlight.h"
#include "shader.h"
#include "nodePathCollection.h"
#include "auto_bind.h"
#include "animControlCollection.h"
#include "cardMaker.h"
#include "fontPool.h"
#include "texturePool.h"
#include "particleSystemManager.h"
#include "physicsManager.h"
#include "spriteParticleRenderer.h"
#include "pointParticleFactory.h"
#include "pointEmitter.h"
#include "physicalNode.h"
#include "forceNode.h"
#include "linearNoiseForce.h"
#include "linearVectorForce.h"
#include "linearJitterForce.h"
#include "linearCylinderVortexForce.h"
#include "linearEulerIntegrator.h"
#include "audioManager.h"
#include "audioSound.h"
// STRUCTURES
struct FramebufferTexture
{ PT(GraphicsOutput) buffer
; PT(DisplayRegion) bufferRegion
; PT(Camera) camera
; NodePath cameraNP
; NodePath shaderNP
;
};
struct FramebufferTextureArguments
{ PT(WindowFramework) window
; PT(GraphicsOutput) graphicsOutput
; PT(GraphicsEngine) graphicsEngine
; GraphicsOutput::RenderTexturePlane bitplane
; LVecBase4 rgbaBits
; LColor clearColor
; int aux_rgba
; bool setFloatColor
; bool setSrgbColor
; bool setRgbColor
; bool useScene
; std::string name
;
};
// END STRUCTURES
// FUNCTIONS
void generateLights
( NodePath render
, bool showLights
);
void generateWindowLight
( std::string name
, NodePath render
, LVecBase3 position
, bool show
);
float animateLights
( NodePath render
, AnimControlCollection shuttersAnimationCollection
, float delta
, float speed
, bool& closedShutters
, bool middayDown
, bool midnightDown
);
PT(Shader) loadShader
( std::string vert
, std::string frag
);
FramebufferTexture generateFramebufferTexture
( FramebufferTextureArguments framebufferTextureArguments
);
PTA_LVecBase3f generateSsaoSamples
( int numberOfSamples
);
PTA_LVecBase3f generateSsaoNoise
( int numberOfNoise
);
void showBuffer
( NodePath render2d
, NodePath statusNP
, std::tuple<std::string, PT(GraphicsOutput), int> bufferTexture
, bool alpha
);
void hideBuffer
( NodePath render2d
);
int microsecondsSinceEpoch
(
);
bool isButtonDown
( PT(MouseWatcher) mouseWatcher
, std::string character
);
PT(MouseWatcher) getMouseWatcher
( WindowFramework* window
);
void setSoundOff
( PT(AudioSound) sound
);
void setSoundOn
( PT(AudioSound) sound
);
void setSoundState
( PT(AudioSound) sound
, bool on
);
void updateAudoManager
( NodePath sceneRootNP
, NodePath cameraNP
);
LVecBase3f calculateCameraPosition
( double radius
, double phi
, double theta
, LVecBase3 cameraLookAt
);
LVecBase3f calculateCameraLookAt
( double upDownAdjust
, double leftRightAdjust
, double phi
, double theta
, LVecBase3 lookAt
);
NodePath setUpParticles
( NodePath render
, PT(Texture) smokeTexture
);
void squashGeometry
( NodePath environmentNP
);
double microsecondToSecond
( int m
);
double toRadians
( double d
);
LVecBase2f makeEnabledVec
( int t
);
LVecBase2f toggleEnabledVec
( LVecBase2f vec
);
void setTextureToNearestAndClamp
( PT(Texture) texture
);
LColor mixColor
( LColor a
, LColor b
, float amount
);
// END FUNCTIONS
// GLOBALS
const float TO_RAD = M_PI / 180.0;
const LVecBase2f PI_SHADER_INPUT = LVecBase2f(M_PI, TO_RAD);
const float GAMMA = 2.2;
const float GAMMA_REC = 1.0 / GAMMA;
const LVecBase2f GAMMA_SHADER_INPUT = LVecBase2f(GAMMA, GAMMA_REC);
const int BACKGROUND_RENDER_SORT_ORDER = 10;
const int UNSORTED_RENDER_SORT_ORDER = 50;
const int SSAO_SAMPLES = 8;
const int SSAO_NOISE = 4;
const int SHADOW_SIZE = 2048;
LVecBase4f sunlightColor0 =
LVecBase4f
( 0.612
, 0.365
, 0.306
, 1
);
LVecBase4f sunlightColor1 =
LVecBase4f
( 0.765
, 0.573
, 0.400
, 1
);
LVecBase4f moonlightColor0 =
LVecBase4f
( 0.247
, 0.384
, 0.404
, 1
);
LVecBase4f moonlightColor1 =
LVecBase4f
( 0.392
, 0.537
, 0.571
, 1
);
LVecBase4f windowLightColor =
LVecBase4f
( 0.765
, 0.573
, 0.400
, 1
);
std::uniform_real_distribution<float>
randomFloats
( 0.0
, 1.0
);
std::default_random_engine generator;
PT(AsyncTaskManager) taskManager = AsyncTaskManager::get_global_ptr();
PT(AudioManager) audioManager = AudioManager::create_AudioManager();
ParticleSystemManager particleSystemManager = ParticleSystemManager();
PhysicsManager physicsManager = PhysicsManager();
// END GLOBALS
// MAIN
int main
( int argc
, char *argv[]
) {
LColor backgroundColor [] =
{ LColor
( 0.392
, 0.537
, 0.561
, 1
)
, LColor
( 0.953
, 0.733
, 0.525
, 1
)
};
double cameraRotatePhiInitial = 67.5095;
double cameraRotateThetaInitial = 231.721;
double cameraRotateRadiusInitial = 1100.83;
LVecBase3 cameraLookAtInitial = LVecBase3(1.00839, 1.20764, 5.85055);
float cameraFov = 1.0;
int cameraNear = 150;
int cameraFar = 2000;
LVecBase2f cameraNearFar = LVecBase2f(cameraNear, cameraFar);
double cameraRotateRadius = cameraRotateRadiusInitial;
double cameraRotatePhi = cameraRotatePhiInitial;
double cameraRotateTheta = cameraRotateThetaInitial;
LVecBase3 cameraLookAt = cameraLookAtInitial;
float fogNearInitial = 2.0;
float fogFarInitial = 9.0;
float fogNear = fogNearInitial;
float fogFar = fogFarInitial;
float fogAdjust = 0.1;
LVecBase2f foamDepthInitial = LVecBase2f(1.5, 1.5);
float foamDepthAdjust = 0.1;
LVecBase2f foamDepth = foamDepthInitial;
LVecBase2f mouseThen = LVecBase2f(0.0, 0.0);
LVecBase2f mouseNow = mouseThen;
bool mouseWheelDown = false;
bool mouseWheelUp = false;
LVecBase2f riorInitial = LVecBase2f(1.05, 1.05);
float riorAdjust = 0.005;
LVecBase2f rior = riorInitial;
LVecBase2f mouseFocusPointInitial = LVecBase2f(0.509167, 0.598);
LVecBase2f mouseFocusPoint = mouseFocusPointInitial;
float sunlightP = 260;
bool animateSunlight = true;
bool soundEnabled = true;
bool soundStarted = false;
float startSoundAt = 0.5;
bool closedShutters = true;
float statusAlpha = 1.0;
LColor statusColor = LColor(0.9, 0.9, 1.0, statusAlpha);
LColor statusShadowColor = LColor(0.1, 0.1, 0.3, statusAlpha);
float statusFadeRate = 2.0;
std::string statusText = "Ready";
LVecBase2f ssaoEnabled = makeEnabledVec(1);
LVecBase2f blinnPhongEnabled = makeEnabledVec(1);
LVecBase2f fresnelEnabled = makeEnabledVec(1);
LVecBase2f rimLightEnabled = makeEnabledVec(1);
LVecBase2f refractionEnabled = makeEnabledVec(1);
LVecBase2f reflectionEnabled = makeEnabledVec(1);
LVecBase2f fogEnabled = makeEnabledVec(1);
LVecBase2f outlineEnabled = makeEnabledVec(1);
LVecBase2f celShadingEnabled = makeEnabledVec(1);
LVecBase2f normalMapsEnabled = makeEnabledVec(1);
LVecBase2f bloomEnabled = makeEnabledVec(1);
LVecBase2f sharpenEnabled = makeEnabledVec(1);
LVecBase2f depthOfFieldEnabled = makeEnabledVec(1);
LVecBase2f filmGrainEnabled = makeEnabledVec(1);
LVecBase2f flowMapsEnabled = makeEnabledVec(1);
LVecBase2f lookupTableEnabled = makeEnabledVec(1);
LVecBase2f painterlyEnabled = makeEnabledVec(0);
LVecBase2f motionBlurEnabled = makeEnabledVec(0);
LVecBase2f posterizeEnabled = makeEnabledVec(0);
LVecBase2f pixelizeEnabled = makeEnabledVec(0);
LVecBase2f chromaticAberrationEnabled = makeEnabledVec(1);
LVecBase4 rgba8 = ( 8, 8, 8, 8);
LVecBase4 rgba16 = (16, 16, 16, 16);
LVecBase4 rgba32 = (32, 32, 32, 32);
load_prc_file("panda3d-prc-file.prc");
PT(TextFont) font = FontPool::load_font("fonts/font.ttf");
std::vector<PT(AudioSound)> sounds =
{ audioManager->get_sound("sounds/wheel.ogg", true)
, audioManager->get_sound("sounds/water.ogg", true)
};
PT(Texture) blankTexture = TexturePool::load_texture("images/blank.png");
PT(Texture) foamPatternTexture = TexturePool::load_texture("images/foam-pattern.png");
PT(Texture) stillFlowTexture = TexturePool::load_texture("images/still-flow.png");
PT(Texture) upFlowTexture = TexturePool::load_texture("images/up-flow.png");
PT(Texture) colorLookupTableTextureN = TexturePool::load_texture("images/lookup-table-neutral.png");
PT(Texture) colorLookupTableTexture0 = TexturePool::load_texture("images/lookup-table-0.png");
PT(Texture) colorLookupTableTexture1 = TexturePool::load_texture("images/lookup-table-1.png");
PT(Texture) smokeTexture = TexturePool::load_texture("images/smoke.png");
PT(Texture) colorNoiseTexture = TexturePool::load_texture("images/color-noise.png");
setTextureToNearestAndClamp(colorLookupTableTextureN);
setTextureToNearestAndClamp(colorLookupTableTexture0);
setTextureToNearestAndClamp(colorLookupTableTexture1);
PandaFramework framework;
framework.open_framework(argc, argv);
framework.set_window_title("3D Game Shaders For Beginners By David Lettier");
PT(WindowFramework) window = framework.open_window();
PT(GraphicsWindow) graphicsWindow = window->get_graphics_window();
PT(GraphicsOutput) graphicsOutput = window->get_graphics_output();
PT(GraphicsStateGuardian) graphicsStateGuardian = graphicsOutput->get_gsg();
PT(GraphicsEngine) graphicsEngine = graphicsStateGuardian->get_engine();
window->enable_keyboard();
PT(DisplayRegion) displayRegion3d = window->get_display_region_3d();
displayRegion3d->set_clear_color_active(true);
displayRegion3d->set_clear_depth_active(true);
displayRegion3d->set_clear_stencil_active(true);
displayRegion3d->set_clear_color(backgroundColor[1]);
displayRegion3d->set_clear_depth(1.0f);
displayRegion3d->set_clear_stencil(0);
NodePath render = window->get_render();
NodePath render2d = window->get_render_2d();
PT(TextNode) status = new TextNode("status");
status->set_font(font);
status->set_text(statusText);
status->set_text_color(statusColor);
status->set_shadow(0.0, 0.06);
status->set_shadow_color(statusShadowColor);
NodePath statusNP = render2d.attach_new_node(status);
statusNP.set_scale(0.05);
statusNP.set_pos(-0.96, 0, -0.95);
PT(MouseWatcher) mouseWatcher = getMouseWatcher(window);
PT(Camera) mainCamera = window->get_camera(0);
PT(Lens) mainLens = mainCamera->get_lens();
mainLens->set_fov(cameraFov);
mainLens->set_near_far(cameraNear, cameraFar);
NodePath cameraNP = window->get_camera_group();
cameraNP.set_pos
( calculateCameraPosition
( cameraRotateRadius
, cameraRotatePhi
, cameraRotateTheta
, cameraLookAt
)
);
cameraNP.look_at(cameraLookAt);
PT(PandaNode) sceneRootPN = new PandaNode("sceneRoot");
NodePath sceneRootNP = NodePath(sceneRootPN);
sceneRootNP.reparent_to(render);
NodePath environmentNP =
window
->load_model
( framework.get_models()
, "eggs/mill-scene/mill-scene.bam"
);
environmentNP.reparent_to(sceneRootNP);
NodePath shuttersNP =
window
->load_model
( framework.get_models()
, "eggs/mill-scene/shutters.bam"
);
shuttersNP.reparent_to(sceneRootNP);
NodePath weatherVaneNP =
window
->load_model
( framework.get_models()
, "eggs/mill-scene/weather-vane.bam"
);
weatherVaneNP.reparent_to(sceneRootNP);
NodePath bannerNP =
window
->load_model
( framework.get_models()
, "eggs/mill-scene/banner.bam"
);
bannerNP.reparent_to(sceneRootNP);
NodePath wheelNP = environmentNP.find("**/wheel-lp");
NodePath waterNP = environmentNP.find("**/water-lp");
squashGeometry(environmentNP);
NodePath smokeNP = setUpParticles(render, smokeTexture);
waterNP.set_transparency(TransparencyAttrib::M_dual);
waterNP.set_bin("fixed", 0);
AnimControlCollection shuttersAnimationCollection;
AnimControlCollection weatherVaneAnimationCollection;
AnimControlCollection bannerAnimationCollection;
auto_bind
( shuttersNP.node()
, shuttersAnimationCollection
, PartGroup::HMF_ok_wrong_root_name
| PartGroup::HMF_ok_part_extra
| PartGroup::HMF_ok_anim_extra
);
auto_bind
( weatherVaneNP.node()
, weatherVaneAnimationCollection
, PartGroup::HMF_ok_wrong_root_name
| PartGroup::HMF_ok_part_extra
| PartGroup::HMF_ok_anim_extra
);
auto_bind
( bannerNP.node()
, bannerAnimationCollection
, PartGroup::HMF_ok_wrong_root_name
| PartGroup::HMF_ok_part_extra
| PartGroup::HMF_ok_anim_extra
);
generateLights(render, false);
PT(Shader) discardShader = loadShader("discard", "discard");
PT(Shader) baseShader = loadShader("base", "base");
PT(Shader) geometryBufferShader0 = loadShader("base", "geometry-buffer-0");
PT(Shader) geometryBufferShader1 = loadShader("base", "geometry-buffer-1");
PT(Shader) geometryBufferShader2 = loadShader("base", "geometry-buffer-2");
PT(Shader) foamShader = loadShader("basic", "foam");
PT(Shader) fogShader = loadShader("basic", "fog");
PT(Shader) boxBlurShader = loadShader("basic", "box-blur");
PT(Shader) motionBlurShader = loadShader("basic", "motion-blur");
PT(Shader) kuwaharaFilterShader = loadShader("basic", "kuwahara-filter");
PT(Shader) dilationShader = loadShader("basic", "dilation");
PT(Shader) sharpenShader = loadShader("basic", "sharpen");
PT(Shader) outlineShader = loadShader("basic", "outline");
PT(Shader) bloomShader = loadShader("basic", "bloom");
PT(Shader) ssaoShader = loadShader("basic", "ssao");
PT(Shader) screenSpaceRefractionShader = loadShader("basic", "screen-space-refraction");
PT(Shader) screenSpaceReflectionShader = loadShader("basic", "screen-space-reflection");
PT(Shader) refractionShader = loadShader("basic", "refraction");
PT(Shader) reflectionColorShader = loadShader("basic", "reflection-color");
PT(Shader) reflectionShader = loadShader("basic", "reflection");
PT(Shader) baseCombineShader = loadShader("basic", "base-combine");
PT(Shader) sceneCombineShader = loadShader("basic", "scene-combine");
PT(Shader) depthOfFieldShader = loadShader("basic", "depth-of-field");
PT(Shader) posterizeShader = loadShader("basic", "posterize");
PT(Shader) pixelizeShader = loadShader("basic", "pixelize");
PT(Shader) filmGrainShader = loadShader("basic", "film-grain");
PT(Shader) lookupTableShader = loadShader("basic", "lookup-table");
PT(Shader) gammaCorrectionShader = loadShader("basic", "gamma-correction");
PT(Shader) chromaticAberrationShader = loadShader("basic", "chromatic-aberration");
NodePath mainCameraNP = NodePath("mainCamera");
mainCameraNP.set_shader(discardShader);
mainCamera->set_initial_state(mainCameraNP.get_state());
NodePath isWaterNP = NodePath("isWater");
isWaterNP.set_shader_input("isWater", LVecBase2f(1.0, 1.0));
isWaterNP.set_shader_input("flowTexture", upFlowTexture);
isWaterNP.set_shader_input("foamPatternTexture", foamPatternTexture);
NodePath isSmokeNP = NodePath("isSmoke");
isSmokeNP.set_shader_input("isSmoke", LVecBase2f(1.0, 1.0));
isSmokeNP.set_shader_input("isParticle", LVecBase2f(1.0, 1.0));
LMatrix4 currentViewWorldMat = cameraNP.get_transform(render)->get_mat();
LMatrix4 previousViewWorldMat = previousViewWorldMat;
FramebufferTextureArguments framebufferTextureArguments;
framebufferTextureArguments.window = window;
framebufferTextureArguments.graphicsOutput = graphicsOutput;
framebufferTextureArguments.graphicsEngine = graphicsEngine;
framebufferTextureArguments.bitplane = GraphicsOutput::RTP_color;
framebufferTextureArguments.rgbaBits = rgba32;
framebufferTextureArguments.clearColor = LColor(0, 0, 0, 0);
framebufferTextureArguments.aux_rgba = 1;
framebufferTextureArguments.setFloatColor = true;
framebufferTextureArguments.setSrgbColor = false;
framebufferTextureArguments.setRgbColor = true;
framebufferTextureArguments.useScene = true;
framebufferTextureArguments.name = "geometry0";
FramebufferTexture geometryFramebufferTexture0 =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) geometryBuffer0 = geometryFramebufferTexture0.buffer;
PT(Camera) geometryCamera0 = geometryFramebufferTexture0.camera;
NodePath geometryNP0 = geometryFramebufferTexture0.shaderNP;
geometryBuffer0->add_render_texture
( NULL
, GraphicsOutput::RTM_bind_or_copy
, GraphicsOutput::RTP_aux_rgba_0
);
geometryBuffer0->set_clear_active(3, true);
geometryBuffer0->set_clear_value( 3, framebufferTextureArguments.clearColor);
geometryNP0.set_shader(geometryBufferShader0);
geometryNP0.set_shader_input("normalMapsEnabled", normalMapsEnabled);
geometryCamera0->set_initial_state(geometryNP0.get_state());
geometryCamera0->set_camera_mask(BitMask32::bit(1));
PT(Texture) positionTexture0 = geometryBuffer0->get_texture(0);
PT(Texture) normalTexture0 = geometryBuffer0->get_texture(1);
PT(Lens) geometryCameraLens0 = geometryCamera0->get_lens();
waterNP.hide(BitMask32::bit(1));
smokeNP.hide(BitMask32::bit(1));
framebufferTextureArguments.aux_rgba = 4;
framebufferTextureArguments.name = "geometry1";
FramebufferTexture geometryFramebufferTexture1 =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) geometryBuffer1 = geometryFramebufferTexture1.buffer;
PT(Camera) geometryCamera1 = geometryFramebufferTexture1.camera;
NodePath geometryNP1 = geometryFramebufferTexture1.shaderNP;
geometryBuffer1->add_render_texture
( NULL
, GraphicsOutput::RTM_bind_or_copy
, GraphicsOutput::RTP_aux_rgba_0
);
geometryBuffer1->set_clear_active(3, true);
geometryBuffer1->set_clear_value( 3, framebufferTextureArguments.clearColor);
geometryBuffer1->add_render_texture
( NULL
, GraphicsOutput::RTM_bind_or_copy
, GraphicsOutput::RTP_aux_rgba_1
);
geometryBuffer1->set_clear_active(4, true);
geometryBuffer1->set_clear_value( 4, framebufferTextureArguments.clearColor);
geometryBuffer1->add_render_texture
( NULL
, GraphicsOutput::RTM_bind_or_copy
, GraphicsOutput::RTP_aux_rgba_2
);
geometryBuffer1->set_clear_active(5, true);
geometryBuffer1->set_clear_value( 5, framebufferTextureArguments.clearColor);
geometryBuffer1->add_render_texture
( NULL
, GraphicsOutput::RTM_bind_or_copy
, GraphicsOutput::RTP_aux_rgba_3
);
geometryBuffer1->set_clear_active(6, true);
geometryBuffer1->set_clear_value( 6, framebufferTextureArguments.clearColor);
geometryNP1.set_shader(geometryBufferShader1);
geometryNP1.set_shader_input("normalMapsEnabled", normalMapsEnabled);
geometryNP1.set_shader_input("flowTexture", stillFlowTexture);
geometryNP1.set_shader_input("foamPatternTexture", blankTexture);
geometryNP1.set_shader_input("flowMapsEnabled", flowMapsEnabled);
geometryCamera1->set_initial_state(geometryNP1.get_state());
geometryCamera1->set_tag_state_key("geometryBuffer1");
geometryCamera1->set_tag_state("isWater", isWaterNP.get_state());
geometryCamera1->set_camera_mask(BitMask32::bit(2));
PT(Texture) positionTexture1 = geometryBuffer1->get_texture(0);
PT(Texture) normalTexture1 = geometryBuffer1->get_texture(1);
PT(Texture) reflectionMaskTexture = geometryBuffer1->get_texture(2);
PT(Texture) refractionMaskTexture = geometryBuffer1->get_texture(3);
PT(Texture) foamMaskTexture = geometryBuffer1->get_texture(4);
PT(Lens) geometryCameraLens1 = geometryCamera1->get_lens();
waterNP.set_tag("geometryBuffer1", "isWater");
smokeNP.hide(BitMask32::bit(2));
framebufferTextureArguments.aux_rgba = 1;
framebufferTextureArguments.name = "geometry2";
FramebufferTexture geometryFramebufferTexture2 =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) geometryBuffer2 = geometryFramebufferTexture2.buffer;
PT(Camera) geometryCamera2 = geometryFramebufferTexture2.camera;
NodePath geometryNP2 = geometryFramebufferTexture2.shaderNP;
geometryBuffer2->add_render_texture
( NULL
, GraphicsOutput::RTM_bind_or_copy
, GraphicsOutput::RTP_aux_rgba_0
);
geometryBuffer2->set_clear_active(3, true);
geometryBuffer2->set_clear_value( 3, framebufferTextureArguments.clearColor);
geometryBuffer2->set_sort(geometryBuffer1->get_sort() + 1);
geometryNP2.set_shader(geometryBufferShader2);
geometryNP2.set_shader_input("isSmoke", LVecBase2f(0, 0));
geometryNP2.set_shader_input("positionTexture", positionTexture1);
geometryCamera2->set_initial_state(geometryNP2.get_state());
geometryCamera2->set_tag_state_key("geometryBuffer2");
geometryCamera2->set_tag_state("isSmoke", isSmokeNP.get_state());
smokeNP.set_tag("geometryBuffer2", "isSmoke");
PT(Texture) positionTexture2 = geometryBuffer2->get_texture(0);
PT(Texture) smokeMaskTexture = geometryBuffer2->get_texture(1);
PT(Lens) geometryCameraLens2 = geometryCamera2->get_lens();
framebufferTextureArguments.rgbaBits = rgba8;
framebufferTextureArguments.aux_rgba = 0;
framebufferTextureArguments.clearColor = LColor(0, 0, 0, 0);
framebufferTextureArguments.setFloatColor = false;
framebufferTextureArguments.useScene = false;
framebufferTextureArguments.name = "fog";
FramebufferTexture fogFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) fogBuffer = fogFramebufferTexture.buffer;
PT(Camera) fogCamera = fogFramebufferTexture.camera;
NodePath fogNP = fogFramebufferTexture.shaderNP;
fogBuffer->set_sort(geometryBuffer2->get_sort() + 1);
fogNP.set_shader(fogShader);
fogNP.set_shader_input("pi", PI_SHADER_INPUT);
fogNP.set_shader_input("gamma", GAMMA_SHADER_INPUT);
fogNP.set_shader_input("backgroundColor0", backgroundColor[0]);
fogNP.set_shader_input("backgroundColor1", backgroundColor[1]);
fogNP.set_shader_input("positionTexture0", positionTexture1);
fogNP.set_shader_input("positionTexture1", positionTexture2);
fogNP.set_shader_input("smokeMaskTexture", smokeMaskTexture);
fogNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
fogNP.set_shader_input("origin", cameraNP.get_relative_point(render, environmentNP.get_pos()));
fogNP.set_shader_input("nearFar", LVecBase2f(fogNear, fogFar));
fogNP.set_shader_input("enabled", fogEnabled);
fogCamera->set_initial_state(fogNP.get_state());
PT(Texture) fogTexture = fogBuffer->get_texture();
framebufferTextureArguments.clearColor = LColor(1, 1, 1, 0);
framebufferTextureArguments.name = "ssao";
FramebufferTexture ssaoFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) ssaoBuffer = ssaoFramebufferTexture.buffer;
PT(Camera) ssaoCamera = ssaoFramebufferTexture.camera;
NodePath ssaoNP = ssaoFramebufferTexture.shaderNP;
ssaoBuffer->set_sort(geometryBuffer0->get_sort() + 1);
ssaoNP.set_shader(ssaoShader);
ssaoNP.set_shader_input("positionTexture", positionTexture0);
ssaoNP.set_shader_input("normalTexture", normalTexture0);
ssaoNP.set_shader_input("samples", generateSsaoSamples(SSAO_SAMPLES));
ssaoNP.set_shader_input("noise", generateSsaoNoise(SSAO_NOISE));
ssaoNP.set_shader_input("lensProjection", geometryCameraLens0->get_projection_mat());
ssaoNP.set_shader_input("enabled", ssaoEnabled);
ssaoCamera->set_initial_state(ssaoNP.get_state());
framebufferTextureArguments.name = "ssaoBlur";
FramebufferTexture ssaoBlurFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) ssaoBlurBuffer = ssaoBlurFramebufferTexture.buffer;
NodePath ssaoBlurNP = ssaoBlurFramebufferTexture.shaderNP;
ssaoBlurBuffer->set_sort(ssaoBuffer->get_sort() + 1);
ssaoBlurNP.set_shader(kuwaharaFilterShader);
ssaoBlurNP.set_shader_input("colorTexture", ssaoBuffer->get_texture());
ssaoBlurNP.set_shader_input("parameters", LVecBase2f(1, 0));
ssaoBlurFramebufferTexture.camera->set_initial_state(ssaoBlurNP.get_state());
PT(Texture) ssaoBlurTexture = ssaoBlurBuffer->get_texture();
framebufferTextureArguments.rgbaBits = rgba16;
framebufferTextureArguments.clearColor = LColor(0, 0, 0, 0);
framebufferTextureArguments.name = "refractionUv";
FramebufferTexture refractionUvFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) refractionUvBuffer = refractionUvFramebufferTexture.buffer;
PT(Camera) refractionUvCamera = refractionUvFramebufferTexture.camera;
NodePath refractionUvNP = refractionUvFramebufferTexture.shaderNP;
refractionUvBuffer->set_sort(geometryBuffer1->get_sort() + 1);
refractionUvNP.set_shader(screenSpaceRefractionShader);
refractionUvNP.set_shader_input("positionFromTexture", positionTexture1);
refractionUvNP.set_shader_input("positionToTexture", positionTexture0);
refractionUvNP.set_shader_input("normalFromTexture", normalTexture1);
refractionUvNP.set_shader_input("lensProjection", geometryCameraLens0->get_projection_mat());
refractionUvNP.set_shader_input("enabled", refractionEnabled);
refractionUvNP.set_shader_input("rior", rior);
refractionUvCamera->set_initial_state(refractionUvNP.get_state());
PT(Texture) refractionUvTexture = refractionUvBuffer->get_texture();
framebufferTextureArguments.name = "reflectionUv";
FramebufferTexture reflectionUvFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) reflectionUvBuffer = reflectionUvFramebufferTexture.buffer;
PT(Camera) reflectionUvCamera = reflectionUvFramebufferTexture.camera;
NodePath reflectionUvNP = reflectionUvFramebufferTexture.shaderNP;
reflectionUvBuffer->set_sort(geometryBuffer1->get_sort() + 1);
reflectionUvNP.set_shader(screenSpaceReflectionShader);
reflectionUvNP.set_shader_input("positionTexture", positionTexture1);
reflectionUvNP.set_shader_input("normalTexture", normalTexture1);
reflectionUvNP.set_shader_input("maskTexture", reflectionMaskTexture);
reflectionUvNP.set_shader_input("lensProjection", geometryCameraLens0->get_projection_mat());
reflectionUvNP.set_shader_input("enabled", reflectionEnabled);
reflectionUvCamera->set_initial_state(reflectionUvNP.get_state());
PT(Texture) reflectionUvTexture = reflectionUvBuffer->get_texture();
framebufferTextureArguments.rgbaBits = rgba8;
framebufferTextureArguments.aux_rgba = 1;
framebufferTextureArguments.useScene = true;
framebufferTextureArguments.name = "base";
FramebufferTexture baseFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) baseBuffer = baseFramebufferTexture.buffer;
PT(Camera) baseCamera = baseFramebufferTexture.camera;
NodePath baseNP = baseFramebufferTexture.shaderNP;
baseBuffer->add_render_texture
( NULL
, GraphicsOutput::RTM_bind_or_copy
, GraphicsOutput::RTP_aux_rgba_0
);
baseBuffer->set_clear_active(3, true);
baseBuffer->set_clear_value( 3, framebufferTextureArguments.clearColor);
baseBuffer->set_sort
( std::max
( ssaoBlurBuffer->get_sort() + 1
, UNSORTED_RENDER_SORT_ORDER + 1
)
);
baseNP.set_shader(baseShader);
baseNP.set_shader_input("pi", PI_SHADER_INPUT);
baseNP.set_shader_input("gamma", GAMMA_SHADER_INPUT);
baseNP.set_shader_input("ssaoBlurTexture", ssaoBlurTexture);
baseNP.set_shader_input("flowTexture", stillFlowTexture);
baseNP.set_shader_input("normalMapsEnabled", normalMapsEnabled);
baseNP.set_shader_input("blinnPhongEnabled", blinnPhongEnabled);
baseNP.set_shader_input("fresnelEnabled", fresnelEnabled);
baseNP.set_shader_input("rimLightEnabled", rimLightEnabled);
baseNP.set_shader_input("celShadingEnabled", celShadingEnabled);
baseNP.set_shader_input("flowMapsEnabled", flowMapsEnabled);
baseNP.set_shader_input("specularOnly", LVecBase2f(0, 0));
baseNP.set_shader_input("isParticle", LVecBase2f(0, 0));
baseNP.set_shader_input("isWater", LVecBase2f(0, 0));
baseNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
baseCamera->set_initial_state(baseNP.get_state());
baseCamera->set_tag_state_key("baseBuffer");
baseCamera->set_tag_state("isParticle", isSmokeNP.get_state());
baseCamera->set_tag_state("isWater", isWaterNP.get_state());
baseCamera->set_camera_mask(BitMask32::bit(6));
smokeNP.set_tag("baseBuffer", "isParticle");
waterNP.set_tag("baseBuffer", "isWater");
PT(Texture) baseTexture = baseBuffer->get_texture(0);
PT(Texture) specularTexture = baseBuffer->get_texture(1);
framebufferTextureArguments.aux_rgba = 0;
framebufferTextureArguments.useScene = false;
framebufferTextureArguments.name = "refraction";
FramebufferTexture refractionFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) refractionBuffer = refractionFramebufferTexture.buffer;
PT(Camera) refractionCamera = refractionFramebufferTexture.camera;
NodePath refractionNP = refractionFramebufferTexture.shaderNP;
refractionBuffer->set_sort(baseBuffer->get_sort() + 1);
refractionNP.set_shader(refractionShader);
refractionNP.set_shader_input("pi", PI_SHADER_INPUT);
refractionNP.set_shader_input("gamma", GAMMA_SHADER_INPUT);
refractionNP.set_shader_input("uvTexture", refractionUvTexture);
refractionNP.set_shader_input("maskTexture", refractionMaskTexture);
refractionNP.set_shader_input("positionFromTexture", positionTexture1);
refractionNP.set_shader_input("positionToTexture", positionTexture0);
refractionNP.set_shader_input("backgroundColorTexture", baseTexture);
refractionNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
refractionCamera->set_initial_state(refractionNP.get_state());
PT(Texture) refractionTexture = refractionBuffer->get_texture();
framebufferTextureArguments.name = "foam";
FramebufferTexture foamFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) foamBuffer = foamFramebufferTexture.buffer;
PT(Camera) foamCamera = foamFramebufferTexture.camera;
NodePath foamNP = foamFramebufferTexture.shaderNP;
foamBuffer->set_sort(geometryBuffer1->get_sort() + 1);
foamNP.set_shader(foamShader);
foamNP.set_shader_input("pi", PI_SHADER_INPUT);
foamNP.set_shader_input("gamma", GAMMA_SHADER_INPUT);
foamNP.set_shader_input("maskTexture", foamMaskTexture);
foamNP.set_shader_input("foamDepth", foamDepth);
foamNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
foamNP.set_shader_input("viewWorldMat", currentViewWorldMat);
foamNP.set_shader_input("positionFromTexture", positionTexture1);
foamNP.set_shader_input("positionToTexture", positionTexture0);
foamCamera->set_initial_state(foamNP.get_state());
PT(Texture) foamTexture = foamBuffer->get_texture();
framebufferTextureArguments.name = "reflectionColor";
FramebufferTexture reflectionColorFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) reflectionColorBuffer = reflectionColorFramebufferTexture.buffer;
PT(Camera) reflectionColorCamera = reflectionColorFramebufferTexture.camera;
NodePath reflectionColorNP = reflectionColorFramebufferTexture.shaderNP;
reflectionColorBuffer->set_sort(refractionBuffer->get_sort() + 1);
reflectionColorNP.set_shader(reflectionColorShader);
reflectionColorNP.set_shader_input("colorTexture", refractionTexture);
reflectionColorNP.set_shader_input("uvTexture", reflectionUvTexture);
reflectionColorCamera->set_initial_state(reflectionColorNP.get_state());
PT(Texture) reflectionColorTexture = reflectionColorBuffer->get_texture();
framebufferTextureArguments.name = "reflectionColorBlur";
FramebufferTexture reflectionColorBlurFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) reflectionColorBlurBuffer = reflectionColorBlurFramebufferTexture.buffer;
PT(Camera) reflectionColorBlurCamera = reflectionColorBlurFramebufferTexture.camera;
NodePath reflectionColorBlurNP = reflectionColorBlurFramebufferTexture.shaderNP;
reflectionColorBlurBuffer->set_sort(reflectionColorBuffer->get_sort() + 1);
reflectionColorBlurNP.set_shader(boxBlurShader);
reflectionColorBlurNP.set_shader_input("colorTexture", reflectionColorTexture);
reflectionColorBlurNP.set_shader_input("parameters", LVecBase2f(8, 1));
reflectionColorBlurCamera->set_initial_state(reflectionColorBlurNP.get_state());
PT(Texture) reflectionColorBlurTexture = reflectionColorBlurBuffer->get_texture();
framebufferTextureArguments.name = "reflection";
FramebufferTexture reflectionFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) reflectionBuffer = reflectionFramebufferTexture.buffer;
NodePath reflectionNP = reflectionFramebufferTexture.shaderNP;
reflectionBuffer->set_sort(reflectionColorBlurBuffer->get_sort() + 1);
reflectionNP.set_shader(reflectionShader);
reflectionNP.set_shader_input("colorTexture", reflectionColorTexture);
reflectionNP.set_shader_input("colorBlurTexture", reflectionColorBlurTexture);
reflectionNP.set_shader_input("maskTexture", reflectionMaskTexture);
reflectionFramebufferTexture.camera->set_initial_state(reflectionNP.get_state());
PT(Texture) reflectionTexture = reflectionBuffer->get_texture();
framebufferTextureArguments.name = "baseCombine";
FramebufferTexture baseCombineFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) baseCombineBuffer = baseCombineFramebufferTexture.buffer;
PT(Camera) baseCombineCamera = baseCombineFramebufferTexture.camera;
NodePath baseCombineNP = baseCombineFramebufferTexture.shaderNP;
baseCombineBuffer->set_sort(reflectionBuffer->get_sort() + 1);
baseCombineNP.set_shader(baseCombineShader);
baseCombineNP.set_shader_input("baseTexture", baseTexture);
baseCombineNP.set_shader_input("refractionTexture", refractionTexture);
baseCombineNP.set_shader_input("foamTexture", foamTexture);
baseCombineNP.set_shader_input("reflectionTexture", reflectionTexture);
baseCombineNP.set_shader_input("specularTexture", specularTexture);
baseCombineCamera->set_initial_state(baseCombineNP.get_state());
PT(Texture) baseCombineTexture = baseCombineBuffer->get_texture();
framebufferTextureArguments.name = "sharpen";
FramebufferTexture sharpenFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) sharpenBuffer = sharpenFramebufferTexture.buffer;
NodePath sharpenNP = sharpenFramebufferTexture.shaderNP;
sharpenBuffer->set_sort(baseCombineBuffer->get_sort() + 1);
sharpenNP.set_shader(sharpenShader);
sharpenNP.set_shader_input("colorTexture", baseCombineTexture);
sharpenNP.set_shader_input("enabled", sharpenEnabled);
PT(Camera) sharpenCamera = sharpenFramebufferTexture.camera;
sharpenCamera->set_initial_state(sharpenNP.get_state());
PT(Texture) sharpenTexture = sharpenBuffer->get_texture();
framebufferTextureArguments.name = "posterize";
FramebufferTexture posterizeFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) posterizeBuffer = posterizeFramebufferTexture.buffer;
NodePath posterizeNP = posterizeFramebufferTexture.shaderNP;
posterizeBuffer->set_sort(sharpenBuffer->get_sort() + 1);
posterizeNP.set_shader(posterizeShader);
posterizeNP.set_shader_input("gamma", GAMMA_SHADER_INPUT);
posterizeNP.set_shader_input("colorTexture", sharpenTexture);
posterizeNP.set_shader_input("positionTexture", positionTexture2);
posterizeNP.set_shader_input("enabled", posterizeEnabled);
PT(Camera) posterizeCamera = posterizeFramebufferTexture.camera;
posterizeCamera->set_initial_state(posterizeNP.get_state());
PT(Texture) posterizeTexture = posterizeBuffer->get_texture();
framebufferTextureArguments.name = "bloom";
FramebufferTexture bloomFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) bloomBuffer = bloomFramebufferTexture.buffer;
PT(Camera) bloomCamera = bloomFramebufferTexture.camera;
NodePath bloomNP = bloomFramebufferTexture.shaderNP;
bloomBuffer->set_sort(posterizeBuffer->get_sort() + 1);
bloomNP.set_shader(bloomShader);
bloomNP.set_shader_input("colorTexture", posterizeTexture);
bloomNP.set_shader_input("enabled", bloomEnabled);
bloomCamera->set_initial_state(bloomNP.get_state());
PT(Texture) bloomTexture = bloomBuffer->get_texture();
framebufferTextureArguments.name = "sceneCombine";
FramebufferTexture sceneCombineFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) sceneCombineBuffer = sceneCombineFramebufferTexture.buffer;
PT(Camera) sceneCombineCamera = sceneCombineFramebufferTexture.camera;
NodePath sceneCombineNP = sceneCombineFramebufferTexture.shaderNP;
sceneCombineBuffer->set_sort(bloomBuffer->get_sort() + 1);
sceneCombineNP.set_shader(sceneCombineShader);
sceneCombineNP.set_shader_input("pi", PI_SHADER_INPUT);
sceneCombineNP.set_shader_input("gamma", GAMMA_SHADER_INPUT);
sceneCombineNP.set_shader_input("lookupTableTextureN", colorLookupTableTextureN);
sceneCombineNP.set_shader_input("backgroundColor0", backgroundColor[0]);
sceneCombineNP.set_shader_input("backgroundColor1", backgroundColor[1]);
sceneCombineNP.set_shader_input("baseTexture", posterizeTexture);
sceneCombineNP.set_shader_input("bloomTexture", bloomTexture);
sceneCombineNP.set_shader_input("fogTexture", fogTexture);
sceneCombineNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
PT(Texture) sceneCombineTexture = sceneCombineBuffer->get_texture();
sceneCombineCamera->set_initial_state(sceneCombineNP.get_state());
framebufferTextureArguments.clearColor = backgroundColor[1];
framebufferTextureArguments.name = "outOfFocus";
FramebufferTexture outOfFocusFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) outOfFocusBuffer = outOfFocusFramebufferTexture.buffer;
PT(Camera) outOfFocusCamera = outOfFocusFramebufferTexture.camera;
NodePath outOfFocusNP = outOfFocusFramebufferTexture.shaderNP;
outOfFocusBuffer->set_sort(sceneCombineBuffer->get_sort() + 1);
outOfFocusNP.set_shader(boxBlurShader);
outOfFocusNP.set_shader_input("colorTexture", sceneCombineTexture);
outOfFocusNP.set_shader_input("parameters", LVecBase2f(2, 2));
outOfFocusCamera->set_initial_state(outOfFocusNP.get_state());
PT(Texture) outOfFocusTexture = outOfFocusBuffer->get_texture();
framebufferTextureArguments.name = "dilatedOutOfFocus";
FramebufferTexture dilatedOutOfFocusFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) dilatedOutOfFocusBuffer = dilatedOutOfFocusFramebufferTexture.buffer;
PT(Camera) dilatedOutOfFocusCamera = dilatedOutOfFocusFramebufferTexture.camera;
NodePath dilatedOutOfFocusNP = dilatedOutOfFocusFramebufferTexture.shaderNP;
dilatedOutOfFocusBuffer->set_sort(outOfFocusBuffer->get_sort() + 1);
dilatedOutOfFocusNP.set_shader(dilationShader);
dilatedOutOfFocusNP.set_shader_input("colorTexture", outOfFocusTexture);
dilatedOutOfFocusNP.set_shader_input("parameters", LVecBase2f(4, 2));
dilatedOutOfFocusCamera->set_initial_state(dilatedOutOfFocusNP.get_state());
PT(Texture) dilatedOutOfFocusTexture = dilatedOutOfFocusBuffer->get_texture();
framebufferTextureArguments.aux_rgba = 1;
framebufferTextureArguments.name = "depthOfField";
FramebufferTexture depthOfFieldFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) depthOfFieldBuffer = depthOfFieldFramebufferTexture.buffer;
NodePath depthOfFieldNP = depthOfFieldFramebufferTexture.shaderNP;
depthOfFieldBuffer->add_render_texture
( NULL
, GraphicsOutput::RTM_bind_or_copy
, GraphicsOutput::RTP_aux_rgba_0
);
depthOfFieldBuffer->set_clear_active(3, true);
depthOfFieldBuffer->set_clear_value( 3, framebufferTextureArguments.clearColor);
depthOfFieldBuffer->set_sort(dilatedOutOfFocusBuffer->get_sort() + 1);
depthOfFieldNP.set_shader(depthOfFieldShader);
depthOfFieldNP.set_shader_input("positionTexture", positionTexture0);
depthOfFieldNP.set_shader_input("focusTexture", sceneCombineTexture);
depthOfFieldNP.set_shader_input("outOfFocusTexture", dilatedOutOfFocusTexture);
depthOfFieldNP.set_shader_input("mouseFocusPoint", mouseFocusPoint);
depthOfFieldNP.set_shader_input("nearFar", cameraNearFar);
depthOfFieldNP.set_shader_input("enabled", depthOfFieldEnabled);
PT(Camera) depthOfFieldCamera = depthOfFieldFramebufferTexture.camera;
depthOfFieldCamera->set_initial_state(depthOfFieldNP.get_state());
PT(Texture) depthOfFieldTexture0 = depthOfFieldBuffer->get_texture(0);
PT(Texture) depthOfFieldTexture1 = depthOfFieldBuffer->get_texture(1);
framebufferTextureArguments.aux_rgba = 0;
framebufferTextureArguments.name = "outline";
FramebufferTexture outlineFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) outlineBuffer = outlineFramebufferTexture.buffer;
PT(Camera) outlineCamera = outlineFramebufferTexture.camera;
NodePath outlineNP = outlineFramebufferTexture.shaderNP;
outlineBuffer->set_sort(depthOfFieldBuffer->get_sort() + 1);
outlineNP.set_shader(outlineShader);
outlineNP.set_shader_input("gamma", GAMMA_SHADER_INPUT);
outlineNP.set_shader_input("positionTexture", positionTexture0);
outlineNP.set_shader_input("colorTexture", depthOfFieldTexture0);
outlineNP.set_shader_input("noiseTexture", colorNoiseTexture);
outlineNP.set_shader_input("depthOfFieldTexture", depthOfFieldTexture1);
outlineNP.set_shader_input("fogTexture", fogTexture);
outlineNP.set_shader_input("nearFar", cameraNearFar);
outlineNP.set_shader_input("enabled", outlineEnabled);
outlineCamera->set_initial_state(outlineNP.get_state());
PT(Texture) outlineTexture = outlineBuffer->get_texture();
framebufferTextureArguments.name = "painterly";
FramebufferTexture painterlyFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) painterlyBuffer = painterlyFramebufferTexture.buffer;
NodePath painterlyNP = painterlyFramebufferTexture.shaderNP;
painterlyBuffer->set_sort(outlineBuffer->get_sort() + 1);
painterlyNP.set_shader(kuwaharaFilterShader);
painterlyNP.set_shader_input("colorTexture", outlineTexture);
painterlyNP.set_shader_input("parameters", LVecBase2f(0, 0));
PT(Camera) painterlyCamera = painterlyFramebufferTexture.camera;
painterlyCamera->set_initial_state(painterlyNP.get_state());
PT(Texture) painterlyTexture = painterlyBuffer->get_texture();
framebufferTextureArguments.name = "pixelize";
FramebufferTexture pixelizeFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) pixelizeBuffer = pixelizeFramebufferTexture.buffer;
NodePath pixelizeNP = pixelizeFramebufferTexture.shaderNP;
pixelizeBuffer->set_sort(painterlyBuffer->get_sort() + 1);
pixelizeNP.set_shader(pixelizeShader);
pixelizeNP.set_shader_input("colorTexture", painterlyTexture);
pixelizeNP.set_shader_input("positionTexture", positionTexture2);
pixelizeNP.set_shader_input("parameters", LVecBase2f(5, 0));
pixelizeNP.set_shader_input("enabled", pixelizeEnabled);
PT(Camera) pixelizeCamera = pixelizeFramebufferTexture.camera;
pixelizeCamera->set_initial_state(pixelizeNP.get_state());
PT(Texture) pixelizeTexture = pixelizeBuffer->get_texture();
framebufferTextureArguments.name = "motionBlur";
FramebufferTexture motionBlurFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) motionBlurBuffer = motionBlurFramebufferTexture.buffer;
NodePath motionBlurNP = motionBlurFramebufferTexture.shaderNP;
motionBlurBuffer->set_sort(pixelizeBuffer->get_sort() + 1);
motionBlurNP.set_shader(motionBlurShader);
motionBlurNP.set_shader_input("previousViewWorldMat", previousViewWorldMat);
motionBlurNP.set_shader_input("worldViewMat", render.get_transform(cameraNP)->get_mat());
motionBlurNP.set_shader_input("lensProjection", geometryCameraLens2->get_projection_mat());
motionBlurNP.set_shader_input("positionTexture", positionTexture2);
motionBlurNP.set_shader_input("colorTexture", pixelizeTexture);
motionBlurNP.set_shader_input("motionBlurEnabled", motionBlurEnabled);
motionBlurNP.set_shader_input("parameters", LVecBase2f(2, 1.0));
PT(Camera) motionBlurCamera = motionBlurFramebufferTexture.camera;
motionBlurCamera->set_initial_state(motionBlurNP.get_state());
PT(Texture) motionBlurTexture = motionBlurBuffer->get_texture();
framebufferTextureArguments.name = "filmGrain";
FramebufferTexture filmGrainFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) filmGrainBuffer = filmGrainFramebufferTexture.buffer;
NodePath filmGrainNP = filmGrainFramebufferTexture.shaderNP;
filmGrainBuffer->set_sort(motionBlurBuffer->get_sort() + 1);
filmGrainNP.set_shader(filmGrainShader);
filmGrainNP.set_shader_input("pi", PI_SHADER_INPUT);
filmGrainNP.set_shader_input("colorTexture", motionBlurTexture);
filmGrainNP.set_shader_input("enabled", filmGrainEnabled);
PT(Camera) filmGrainCamera = filmGrainFramebufferTexture.camera;
filmGrainCamera->set_initial_state(filmGrainNP.get_state());
PT(Texture) filmGrainTexture = filmGrainBuffer->get_texture();
framebufferTextureArguments.name = "lookupTable";
FramebufferTexture lookupTableFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) lookupTableBuffer = lookupTableFramebufferTexture.buffer;
NodePath lookupTableNP = lookupTableFramebufferTexture.shaderNP;
lookupTableBuffer->set_sort(filmGrainBuffer->get_sort() + 1);
lookupTableNP.set_shader(lookupTableShader);
lookupTableNP.set_shader_input("pi", PI_SHADER_INPUT);
lookupTableNP.set_shader_input("gamma", GAMMA_SHADER_INPUT);
lookupTableNP.set_shader_input("colorTexture", filmGrainTexture);
lookupTableNP.set_shader_input("lookupTableTextureN", colorLookupTableTextureN);
lookupTableNP.set_shader_input("lookupTableTexture0", colorLookupTableTexture0);
lookupTableNP.set_shader_input("lookupTableTexture1", colorLookupTableTexture1);
lookupTableNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
lookupTableNP.set_shader_input("enabled", lookupTableEnabled);
PT(Camera) lookupTableCamera = lookupTableFramebufferTexture.camera;
lookupTableCamera->set_initial_state(lookupTableNP.get_state());
PT(Texture) lookupTableTexture = lookupTableBuffer->get_texture();
framebufferTextureArguments.name = "gammaCorrection";
FramebufferTexture gammaCorrectionFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) gammaCorrectionBuffer = gammaCorrectionFramebufferTexture.buffer;
NodePath gammaCorrectionNP = gammaCorrectionFramebufferTexture.shaderNP;
gammaCorrectionBuffer->set_sort(lookupTableBuffer->get_sort() + 1);
gammaCorrectionNP.set_shader(gammaCorrectionShader);
gammaCorrectionNP.set_shader_input("gamma", GAMMA_SHADER_INPUT);
gammaCorrectionNP.set_shader_input("colorTexture", lookupTableTexture);
PT(Camera) gammaCorrectionCamera = gammaCorrectionFramebufferTexture.camera;
gammaCorrectionCamera->set_initial_state(gammaCorrectionNP.get_state());
PT(Texture) gammaCorrectionTexture = gammaCorrectionBuffer->get_texture();
framebufferTextureArguments.name = "chromaticAberration";
FramebufferTexture chromaticAberrationFramebufferTexture =
generateFramebufferTexture
( framebufferTextureArguments
);
PT(GraphicsOutput) chromaticAberrationBuffer = chromaticAberrationFramebufferTexture.buffer;
NodePath chromaticAberrationNP = chromaticAberrationFramebufferTexture.shaderNP;
chromaticAberrationBuffer->set_sort(gammaCorrectionBuffer->get_sort() + 1);
chromaticAberrationNP.set_shader(chromaticAberrationShader);
chromaticAberrationNP.set_shader_input("mouseFocusPoint", mouseFocusPoint);
chromaticAberrationNP.set_shader_input("colorTexture", gammaCorrectionTexture);
chromaticAberrationNP.set_shader_input("enabled", chromaticAberrationEnabled);
PT(Camera) chromaticAberrationCamera = chromaticAberrationFramebufferTexture.camera;
chromaticAberrationCamera->set_initial_state(chromaticAberrationNP.get_state());
graphicsOutput->set_sort(chromaticAberrationBuffer->get_sort() + 1);
int showBufferIndex = 0;
std::vector<std::tuple<std::string, PT(GraphicsOutput), int>> bufferArray =
{ std::make_tuple("Positions 0", geometryBuffer0, 0)
, std::make_tuple("Normals 0", geometryBuffer0, 1)
, std::make_tuple("Positions 1", geometryBuffer1, 0)
, std::make_tuple("Normals 1", geometryBuffer1, 1)
, std::make_tuple("Reflection Mask", geometryBuffer1, 2)
, std::make_tuple("Refraction Mask", geometryBuffer1, 3)
, std::make_tuple("Foam Mask", geometryBuffer1, 4)
, std::make_tuple("Positions 2", geometryBuffer2, 0)
, std::make_tuple("Smoke Mask", geometryBuffer2, 1)
, std::make_tuple("SSAO", ssaoBuffer, 0)
, std::make_tuple("SSAO Blur", ssaoBlurBuffer, 0)
, std::make_tuple("Refraction UV", refractionUvBuffer, 0)
, std::make_tuple("Refraction", refractionBuffer, 0)
, std::make_tuple("Reflection UV", reflectionUvBuffer, 0)
, std::make_tuple("Reflection Color", reflectionColorBuffer, 0)
, std::make_tuple("Reflection Blur", reflectionColorBlurBuffer, 0)
, std::make_tuple("Reflection", reflectionBuffer, 0)
, std::make_tuple("Foam", foamBuffer, 0)
, std::make_tuple("Base", baseBuffer, 0)
, std::make_tuple("Specular", baseBuffer, 1)
, std::make_tuple("Base Combine", baseCombineBuffer, 0)
, std::make_tuple("Painterly", painterlyBuffer, 0)
, std::make_tuple("Posterize", posterizeBuffer, 0)
, std::make_tuple("Bloom", bloomBuffer, 0)
, std::make_tuple("Outline", outlineBuffer, 0)
, std::make_tuple("Fog", fogBuffer, 0)
, std::make_tuple("Scene Combine", sceneCombineBuffer, 0)
, std::make_tuple("Out of Focus", outOfFocusBuffer, 0)
, std::make_tuple("Dilation", dilatedOutOfFocusBuffer, 0)
, std::make_tuple("Depth of Field Blur", depthOfFieldBuffer, 1)
, std::make_tuple("Depth of Field", depthOfFieldBuffer, 0)
, std::make_tuple("Pixelize", pixelizeBuffer, 0)
, std::make_tuple("Motion Blur", motionBlurBuffer, 0)
, std::make_tuple("Film Grain", filmGrainBuffer, 0)
, std::make_tuple("Lookup Table", lookupTableBuffer, 0)
, std::make_tuple("Gamma Correction", gammaCorrectionBuffer, 0)
, std::make_tuple("Chromatic Aberration", chromaticAberrationBuffer, 0)
};
showBufferIndex = bufferArray.size() - 1;
showBuffer
( render2d
, statusNP
, bufferArray[showBufferIndex]
, false
);
shuttersAnimationCollection.play( "close-shutters" );
weatherVaneAnimationCollection.loop("weather-vane-shake", true);
bannerAnimationCollection.loop( "banner-swing", true);
int then = microsecondsSinceEpoch();
int loopStartedAt = then;
int now = then;
int keyTime = now;
auto beforeFrame =
[&]() -> void {
WindowProperties windowProperties = graphicsWindow->get_properties();
if (windowProperties.get_minimized()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
now = microsecondsSinceEpoch();
// Avoids a loud audio pop.
if (!soundStarted && microsecondToSecond(now - loopStartedAt) >= startSoundAt) {
for_each
( sounds.begin()
, sounds.end()
, [](PT(AudioSound) sound) { sound->set_loop(true); sound->play(); }
);
soundStarted = true;
}
double delta = microsecondToSecond(now - then);
then = now;
double movement = 100 * delta;
double timeSinceKey = microsecondToSecond(now - keyTime);
bool keyDebounced = timeSinceKey >= 0.2;
double cameraUpDownAdjust = 0;
double cameraLeftRightAdjust = 0;
bool shiftDown = isButtonDown(mouseWatcher, "shift");
bool tabDown = isButtonDown(mouseWatcher, "tab");
bool resetDown = isButtonDown(mouseWatcher, "r");
bool fogNearDown = isButtonDown(mouseWatcher, "[");
bool fogFarDown = isButtonDown(mouseWatcher, "]");
bool equalDown = isButtonDown(mouseWatcher, "=");
bool minusDown = isButtonDown(mouseWatcher, "-");
bool deleteDown = isButtonDown(mouseWatcher, "delete");
bool wDown = isButtonDown(mouseWatcher, "w");
bool aDown = isButtonDown(mouseWatcher, "a");
bool dDown = isButtonDown(mouseWatcher, "d");
bool sDown = isButtonDown(mouseWatcher, "s");
bool zDown = isButtonDown(mouseWatcher, "z");
bool xDown = isButtonDown(mouseWatcher, "x");
bool arrowUpDown = isButtonDown(mouseWatcher, "arrow_up");
bool arrowDownDown = isButtonDown(mouseWatcher, "arrow_down");
bool arrowLeftDown = isButtonDown(mouseWatcher, "arrow_left");
bool arrowRightDown = isButtonDown(mouseWatcher, "arrow_right");
bool middayDown = isButtonDown(mouseWatcher, "1");
bool midnightDown = isButtonDown(mouseWatcher, "2");
bool fresnelDown = isButtonDown(mouseWatcher, "3");
bool rimLightDown = isButtonDown(mouseWatcher, "4");
bool particlesDown = isButtonDown(mouseWatcher, "5");
bool motionBlurDown = isButtonDown(mouseWatcher, "6");
bool painterlyDown = isButtonDown(mouseWatcher, "7");
bool celShadingDown = isButtonDown(mouseWatcher, "8");
bool lookupTableDown = isButtonDown(mouseWatcher, "9");
bool blinnPhongDown = isButtonDown(mouseWatcher, "0");
bool ssaoDown = isButtonDown(mouseWatcher, "y");
bool outlineDown = isButtonDown(mouseWatcher, "u");
bool bloomDown = isButtonDown(mouseWatcher, "i");
bool normalMapsDown = isButtonDown(mouseWatcher, "o");
bool fogDown = isButtonDown(mouseWatcher, "p");
bool depthOfFieldDown = isButtonDown(mouseWatcher, "h");
bool posterizeDown = isButtonDown(mouseWatcher, "j");
bool pixelizeDown = isButtonDown(mouseWatcher, "k");
bool sharpenDown = isButtonDown(mouseWatcher, "l");
bool filmGrainDown = isButtonDown(mouseWatcher, "n");
bool reflectionDown = isButtonDown(mouseWatcher, "m");
bool refractionDown = isButtonDown(mouseWatcher, ",");
bool flowMapsDown = isButtonDown(mouseWatcher, ".");
bool sunlightDown = isButtonDown(mouseWatcher, "/");
bool chromaticAberrationDown = isButtonDown(mouseWatcher, "\\");
bool mouseLeftDown = mouseWatcher->is_button_down(MouseButton::one());
bool mouseMiddleDown = mouseWatcher->is_button_down(MouseButton::two());
bool mouseRightDown = mouseWatcher->is_button_down(MouseButton::three());
if (wDown) {
cameraRotatePhi -= movement * 0.5;
}
if (sDown) {
cameraRotatePhi += movement * 0.5;
}
if (aDown) {
cameraRotateTheta += movement * 0.5;
}
if (dDown) {
cameraRotateTheta -= movement * 0.5;
}
if (zDown || mouseWheelUp) {
cameraRotateRadius -= movement * 4 + 50 * mouseWheelUp;
mouseWheelUp = false;
}
if (xDown || mouseWheelDown) {
cameraRotateRadius += movement * 4 + 50 * mouseWheelDown;
mouseWheelDown = false;
}
if (cameraRotatePhi < 1) cameraRotatePhi = 1;
if (cameraRotatePhi > 179) cameraRotatePhi = 179;
if (cameraRotatePhi < 0) cameraRotatePhi = 360 - cameraRotateTheta;
if (cameraRotateTheta > 360) cameraRotateTheta = cameraRotateTheta - 360;
if (cameraRotateTheta < 0) cameraRotateTheta = 360 - cameraRotateTheta;
if (cameraRotateRadius < cameraNear + 5) cameraRotateRadius = cameraNear + 5;
if (cameraRotateRadius > cameraFar - 10) cameraRotateRadius = cameraFar - 10;
if (arrowUpDown) {
cameraUpDownAdjust = -2 * delta;
} else if (arrowDownDown) {
cameraUpDownAdjust = 2 * delta;
}
if (arrowLeftDown) {
cameraLeftRightAdjust = 2 * delta;
} else if (arrowRightDown) {
cameraLeftRightAdjust = -2 * delta;
}
if (mouseWatcher->has_mouse()) {
mouseNow[0] = mouseWatcher->get_mouse_x();
mouseNow[1] = mouseWatcher->get_mouse_y();
if (mouseLeftDown) {
cameraRotateTheta += (mouseThen[0] - mouseNow[0] ) * movement;
cameraRotatePhi += (mouseNow[1] - mouseThen[1]) * movement;
} else if (mouseRightDown) {
cameraLeftRightAdjust = (mouseThen[0] - mouseNow[0]) * movement;
cameraUpDownAdjust = (mouseThen[1] - mouseNow[1]) * movement;
} else if (mouseMiddleDown) {
mouseFocusPoint =
LVecBase2f
( (mouseNow[0] + 1.0) / 2.0
, (mouseNow[1] + 1.0) / 2.0
);
}
if (!mouseLeftDown) {
mouseThen = mouseNow;
}
}
if (shiftDown && fogNearDown) {
fogNear += fogAdjust;
statusAlpha = 1.0;
statusText = "Fog Near " + std::to_string(fogNear);
} else if (fogNearDown) {
fogNear -= fogAdjust;
statusAlpha = 1.0;
statusText = "Fog Near " + std::to_string(fogNear);
}
if (shiftDown && fogFarDown) {
fogFar -= fogAdjust;
statusAlpha = 1.0;
statusText = "Fog Far " + std::to_string(fogFar);
} else if (fogFarDown) {
fogFar += fogAdjust;
statusAlpha = 1.0;
statusText = "Fog Far " + std::to_string(fogFar);
}
if (shiftDown && equalDown) {
rior[0] -= riorAdjust;
statusAlpha = 1.0;
statusText = "Refractive Index " + std::to_string(rior[0]);
} else if (equalDown) {
rior[0] += riorAdjust;
statusAlpha = 1.0;
statusText = "Refractive Index " + std::to_string(rior[0]);
}
rior[1] = rior[0];
if (shiftDown && minusDown) {
foamDepth[0] -= foamDepthAdjust;
if (foamDepth[0] < 0.001) { foamDepth[0] = 0.001; };
statusAlpha = 1.0;
statusText = "Foam Depth " + std::to_string(foamDepth[0]);
} else if (minusDown) {
foamDepth[0] += foamDepthAdjust;
statusAlpha = 1.0;
statusText = "Foam Depth " + std::to_string(foamDepth[0]);
}
foamDepth[1] = foamDepth[0];
if (keyDebounced) {
if (tabDown) {
if (shiftDown) {
showBufferIndex -= 1;
if (showBufferIndex < 0) showBufferIndex = bufferArray.size() - 1;
} else {
showBufferIndex += 1;
if (showBufferIndex >= bufferArray.size()) showBufferIndex = 0;
}
std::string bufferName = std::get<0>(bufferArray[showBufferIndex]);
bool showAlpha =
bufferName == "Outline"
|| bufferName == "Foam"
|| bufferName == "Fog"
;
showBuffer
( render2d
, statusNP
, bufferArray[showBufferIndex]
, showAlpha
);
keyTime = now;
statusAlpha = 1.0;
statusText = bufferName + " Buffer";
}
if (resetDown) {
cameraRotateRadius = cameraRotateRadiusInitial;
cameraRotatePhi = cameraRotatePhiInitial;
cameraRotateTheta = cameraRotateThetaInitial;
cameraLookAt = cameraLookAtInitial;
fogNear = fogNearInitial;
fogFar = fogFarInitial;
foamDepth = foamDepthInitial;
rior = riorInitial;
mouseFocusPoint = mouseFocusPointInitial;
keyTime = now;
statusAlpha = 1.0;
statusText = "Reset";
}
auto toggleStatus =
[&](LVecBase2f enabled, std::string effect) -> void {
statusAlpha = 1.0;
if (enabled[0] == 1) {
statusText = effect + " On";
} else {
statusText = effect + " Off";
}
};
if (ssaoDown) {
ssaoEnabled = toggleEnabledVec(ssaoEnabled);
keyTime = now;
toggleStatus
( ssaoEnabled
, "SSAO"
);
}
if (refractionDown) {
refractionEnabled = toggleEnabledVec(refractionEnabled);
keyTime = now;
toggleStatus
( refractionEnabled
, "Refraction"
);
}
if (reflectionDown) {
reflectionEnabled = toggleEnabledVec(reflectionEnabled);
keyTime = now;
toggleStatus
( reflectionEnabled
, "Reflection"
);
}
if (bloomDown) {
bloomEnabled = toggleEnabledVec(bloomEnabled);
keyTime = now;
toggleStatus
( bloomEnabled
, "Bloom"
);
}
if (normalMapsDown){
normalMapsEnabled = toggleEnabledVec(normalMapsEnabled);
keyTime = now;
toggleStatus
( normalMapsEnabled
, "Normal Maps"
);
}
if (fogDown) {
fogEnabled = toggleEnabledVec(fogEnabled);
keyTime = now;
toggleStatus
( fogEnabled
, "Fog"
);
}
if (outlineDown) {
outlineEnabled = toggleEnabledVec(outlineEnabled);
keyTime = now;
toggleStatus
( outlineEnabled
, "Outline"
);
}
if (celShadingDown) {
celShadingEnabled = toggleEnabledVec(celShadingEnabled);
keyTime = now;
toggleStatus
( celShadingEnabled
, "Cel Shading"
);
}
if (lookupTableDown) {
lookupTableEnabled = toggleEnabledVec(lookupTableEnabled);
keyTime = now;
toggleStatus
( lookupTableEnabled
, "Lookup Table"
);
}
if (fresnelDown) {
fresnelEnabled = toggleEnabledVec(fresnelEnabled);
keyTime = now;
toggleStatus
( fresnelEnabled
, "Fresnel"
);
}
if (rimLightDown) {
rimLightEnabled = toggleEnabledVec(rimLightEnabled);
keyTime = now;
toggleStatus
( rimLightEnabled
, "Rim Light"
);
}
if (blinnPhongDown) {
blinnPhongEnabled = toggleEnabledVec(blinnPhongEnabled);
keyTime = now;
toggleStatus
( blinnPhongEnabled
, "Blinn-Phong"
);
}
if (sharpenDown) {
sharpenEnabled = toggleEnabledVec(sharpenEnabled);
keyTime = now;
toggleStatus
( sharpenEnabled
, "Sharpen"
);
}
if (depthOfFieldDown) {
depthOfFieldEnabled = toggleEnabledVec(depthOfFieldEnabled);
keyTime = now;
toggleStatus
( depthOfFieldEnabled
, "Depth of Field"
);
}
if (painterlyDown) {
painterlyEnabled = toggleEnabledVec(painterlyEnabled);
keyTime = now;
toggleStatus
( painterlyEnabled
, "Painterly"
);
}
if (motionBlurDown) {
motionBlurEnabled = toggleEnabledVec(motionBlurEnabled);
keyTime = now;
toggleStatus
( motionBlurEnabled
, "Motion Blur"
);
}
if (posterizeDown) {
posterizeEnabled = toggleEnabledVec(posterizeEnabled);
keyTime = now;
toggleStatus
( posterizeEnabled
, "Posterize"
);
}
if (pixelizeDown) {
pixelizeEnabled = toggleEnabledVec(pixelizeEnabled);
keyTime = now;
toggleStatus
( pixelizeEnabled
, "Pixelize"
);
}
if (filmGrainDown) {
filmGrainEnabled = toggleEnabledVec(filmGrainEnabled);
keyTime = now;
toggleStatus
( filmGrainEnabled
, "Film Grain"
);
}
if (flowMapsDown) {
flowMapsEnabled = toggleEnabledVec(flowMapsEnabled);
if (flowMapsEnabled[0] == 1 && soundEnabled) {
for_each(sounds.begin(), sounds.end(), setSoundOn);
} else if (flowMapsEnabled[0] != 1) {
for_each(sounds.begin(), sounds.end(), setSoundOff);
}
keyTime = now;
toggleStatus
( flowMapsEnabled
, "Flow Maps"
);
}
if (deleteDown) {
if (soundEnabled) {
for_each(sounds.begin(), sounds.end(), setSoundOff);
soundEnabled = false;
} else {
if (flowMapsEnabled[0] == 1) {
for_each(sounds.begin(), sounds.end(), setSoundOn);
}
soundEnabled = true;
}
keyTime = now;
toggleStatus
( LVecBase2f(soundEnabled ? 1 : 0, 0)
, "Sound"
);
}
if (sunlightDown) {
animateSunlight = animateSunlight ? false : true;
keyTime = now;
toggleStatus
( LVecBase2f(animateSunlight ? 1 : 0, 0)
, "Sun Animation"
);
}
if (particlesDown) {
keyTime = now;
statusAlpha = 1.0;
if (smokeNP.is_hidden()) {
smokeNP.show();
statusText = "Particles On";
} else {
smokeNP.hide();
statusText = "Particles Off";
}
}
if (chromaticAberrationDown) {
chromaticAberrationEnabled = toggleEnabledVec(chromaticAberrationEnabled);
keyTime = now;
toggleStatus
( chromaticAberrationEnabled
, "Chromatic Aberration"
);
}
}
if (flowMapsEnabled[0]) {
float wheelP = wheelNP.get_p();
wheelP += -90.0 * delta;
if (wheelP > 360) wheelP = 0;
if (wheelP < 0) wheelP = 360;
wheelNP.set_p(wheelP);
}
if (animateSunlight || middayDown || midnightDown) {
sunlightP =
animateLights
( render
, shuttersAnimationCollection
, delta
, -360.0 / 64.0
, closedShutters
, middayDown
, midnightDown
);
if (middayDown) {
statusAlpha = 1.0;
statusText = "Midday";
} else if (midnightDown) {
statusAlpha = 1.0;
statusText = "Midnight";
}
}
cameraLookAt =
calculateCameraLookAt
( cameraUpDownAdjust
, cameraLeftRightAdjust
, cameraRotatePhi
, cameraRotateTheta
, cameraLookAt
);
cameraNP.set_pos
( calculateCameraPosition
( cameraRotateRadius
, cameraRotatePhi
, cameraRotateTheta
, cameraLookAt
)
);
cameraNP.look_at(cameraLookAt);
currentViewWorldMat = cameraNP.get_transform(render)->get_mat();
geometryNP0.set_shader_input("normalMapsEnabled", normalMapsEnabled);
geometryNP0.set_shader_input("flowMapsEnabled", flowMapsEnabled);
geometryCamera0->set_initial_state(geometryNP0.get_state());
geometryNP1.set_shader_input("normalMapsEnabled", normalMapsEnabled);
geometryNP1.set_shader_input("flowMapsEnabled", flowMapsEnabled);
geometryCamera1->set_initial_state(geometryNP1.get_state());
fogNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
fogNP.set_shader_input("origin", cameraNP.get_relative_point(render, environmentNP.get_pos()));
fogNP.set_shader_input("nearFar", LVecBase2f(fogNear, fogFar));
fogNP.set_shader_input("enabled", fogEnabled);
fogCamera->set_initial_state(fogNP.get_state());
ssaoNP.set_shader_input("lensProjection", geometryCameraLens0->get_projection_mat());
ssaoNP.set_shader_input("enabled", ssaoEnabled);
ssaoCamera->set_initial_state(ssaoNP.get_state());
refractionUvNP.set_shader_input("lensProjection", geometryCameraLens1->get_projection_mat());
refractionUvNP.set_shader_input("enabled", refractionEnabled);
refractionUvNP.set_shader_input("rior", rior);
refractionUvCamera->set_initial_state(refractionUvNP.get_state());
reflectionUvNP.set_shader_input("lensProjection", geometryCameraLens1->get_projection_mat());
reflectionUvNP.set_shader_input("enabled", reflectionEnabled);
reflectionUvCamera->set_initial_state(reflectionUvNP.get_state());
foamNP.set_shader_input("foamDepth", foamDepth);
foamNP.set_shader_input("viewWorldMat", currentViewWorldMat);
foamNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
foamCamera->set_initial_state(foamNP.get_state());
bloomNP.set_shader_input("enabled", bloomEnabled);
bloomCamera->set_initial_state(bloomNP.get_state());
outlineNP.set_shader_input("enabled", outlineEnabled);
outlineCamera->set_initial_state(outlineNP.get_state());
baseNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
baseNP.set_shader_input("normalMapsEnabled", normalMapsEnabled);
baseNP.set_shader_input("blinnPhongEnabled", blinnPhongEnabled);
baseNP.set_shader_input("fresnelEnabled", fresnelEnabled);
baseNP.set_shader_input("rimLightEnabled", rimLightEnabled);
baseNP.set_shader_input("celShadingEnabled", celShadingEnabled);
baseNP.set_shader_input("flowMapsEnabled", flowMapsEnabled);
baseCamera->set_initial_state(baseNP.get_state());
refractionNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
refractionCamera->set_initial_state(refractionNP.get_state());
sharpenNP.set_shader_input("enabled", sharpenEnabled);
sharpenCamera->set_initial_state(sharpenNP.get_state());
sceneCombineNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
sceneCombineCamera->set_initial_state(sceneCombineNP.get_state());
depthOfFieldNP.set_shader_input("mouseFocusPoint", mouseFocusPoint);
depthOfFieldNP.set_shader_input("enabled", depthOfFieldEnabled);
depthOfFieldCamera->set_initial_state(depthOfFieldNP.get_state());
painterlyNP.set_shader_input("parameters", LVecBase2f(painterlyEnabled[0] == 1 ? 3 : 0, 0));
painterlyCamera->set_initial_state(painterlyNP.get_state());
motionBlurNP.set_shader_input("previousViewWorldMat", previousViewWorldMat);
motionBlurNP.set_shader_input("worldViewMat", render.get_transform(cameraNP)->get_mat());
motionBlurNP.set_shader_input("lensProjection", geometryCameraLens1->get_projection_mat());
motionBlurNP.set_shader_input("motionBlurEnabled", motionBlurEnabled);
motionBlurCamera->set_initial_state(motionBlurNP.get_state());
posterizeNP.set_shader_input("enabled", posterizeEnabled);
posterizeCamera->set_initial_state(posterizeNP.get_state());
pixelizeNP.set_shader_input("enabled", pixelizeEnabled);
pixelizeCamera->set_initial_state(pixelizeNP.get_state());
filmGrainNP.set_shader_input("enabled", filmGrainEnabled);
filmGrainCamera->set_initial_state(filmGrainNP.get_state());
lookupTableNP.set_shader_input("enabled", lookupTableEnabled);
lookupTableNP.set_shader_input("sunPosition", LVecBase2f(sunlightP, 0));
lookupTableCamera->set_initial_state(lookupTableNP.get_state());
chromaticAberrationNP.set_shader_input("mouseFocusPoint", mouseFocusPoint);
chromaticAberrationNP.set_shader_input("enabled", chromaticAberrationEnabled);
chromaticAberrationCamera->set_initial_state(chromaticAberrationNP.get_state());
previousViewWorldMat = currentViewWorldMat;
statusAlpha = statusAlpha - ((1.0 / statusFadeRate) * delta);
statusAlpha = statusAlpha < 0.0 ? 0.0 : statusAlpha;
statusColor[3] = statusAlpha;
statusShadowColor[3] = statusAlpha;
status->set_text_color(statusColor);
status->set_shadow_color(statusShadowColor);
status->set_text(statusText);
updateAudoManager
( sceneRootNP
, cameraNP
);
particleSystemManager.do_particles(delta);
physicsManager.do_physics(delta);
};
auto beforeFrameRunner =
[](GenericAsyncTask* task, void* arg)
-> AsyncTask::DoneStatus {
(*static_cast<decltype(beforeFrame)*>(arg))();
return AsyncTask::DS_cont;
};
taskManager->add
( new GenericAsyncTask
( "beforeFrame"
, beforeFrameRunner
, &beforeFrame
)
);
auto setMouseWheelUp =
[&]() {
mouseWheelUp = true;
};
auto setMouseWheelDown =
[&]() {
mouseWheelDown = true;
};
framework.define_key
( "wheel_up"
, "Mouse Wheel Up"
, [](const Event*, void* arg) {
(*static_cast<decltype(setMouseWheelUp)*>(arg))();
}
, &setMouseWheelUp
);
framework.define_key
( "wheel_down"
, "Mouse Wheel Down"
, [](const Event*, void* arg) {
(*static_cast<decltype(setMouseWheelDown)*>(arg))();
}
, &setMouseWheelDown
);
physicsManager.attach_linear_integrator
( new LinearEulerIntegrator()
);
LVector3f wheelNPRelPos = wheelNP.get_pos(sceneRootNP);
sounds[0]->set_3d_attributes
( wheelNPRelPos[0]
, wheelNPRelPos[1]
, wheelNPRelPos[2]
, 0
, 0
, 0
);
LVector3f waterNPRelPos = waterNP.get_pos(sceneRootNP);
sounds[1]->set_3d_attributes
( waterNPRelPos[0]
, waterNPRelPos[1]
, waterNPRelPos[2]
, 0
, 0
, 0
);
sounds[0]->set_3d_min_distance(60);
sounds[1]->set_3d_min_distance(50);
framework.main_loop();
audioManager->shutdown();
framework.close_framework();
return 0;
}
// END MAIN
void generateLights
( NodePath render
, bool showLights
) {
PT(AmbientLight) ambientLight = new AmbientLight("ambientLight");
ambientLight->set_color
( LVecBase4
( 0.388
, 0.356
, 0.447
, 1
)
);
NodePath ambientLightNP = render.attach_new_node(ambientLight);
render.set_light(ambientLightNP);
PT(DirectionalLight) sunlight = new DirectionalLight("sunlight");
sunlight->set_color(sunlightColor1);
sunlight->set_shadow_caster(true, SHADOW_SIZE, SHADOW_SIZE);
sunlight->get_lens()->set_film_size(35, 35);
sunlight->get_lens()->set_near_far(5.0, 35.0);
if (showLights) sunlight->show_frustum();
NodePath sunlightNP = render.attach_new_node(sunlight);
sunlightNP.set_name("sunlight");
render.set_light(sunlightNP);
PT(DirectionalLight) moonlight = new DirectionalLight("moonlight");
moonlight->set_color(moonlightColor1);
moonlight->set_shadow_caster(true, SHADOW_SIZE, SHADOW_SIZE);
moonlight->get_lens()->set_film_size(35, 35);
moonlight->get_lens()->set_near_far(5.0, 35);
if (showLights) moonlight->show_frustum();
NodePath moonlightNP = render.attach_new_node(moonlight);
moonlightNP.set_name("moonlight");
render.set_light_off(moonlightNP);
NodePath sunlightPivotNP = NodePath("sunlightPivot");
sunlightPivotNP.reparent_to(render);
sunlightPivotNP.set_pos(0, 0.5, 15.0);
sunlightNP.reparent_to(sunlightPivotNP);
sunlightNP.set_pos(0, -17.5, 0);
sunlightPivotNP.set_hpr(135, 340, 0);
NodePath moonlightPivotNP = NodePath("moonlightPivot");
moonlightPivotNP.reparent_to(render);
moonlightPivotNP.set_pos(0, 0.5, 15.0);
moonlightNP.reparent_to(moonlightPivotNP);
moonlightNP.set_pos(0, -17.5, 0);
moonlightPivotNP.set_hpr(135, 160, 0);
generateWindowLight
( "windowLight"
, render
, LVecBase3
( 1.5
, 2.49
, 7.9
)
, showLights
);
generateWindowLight
( "windowLight1"
, render
, LVecBase3
( 3.5
, 2.49
, 7.9
)
, showLights
);
generateWindowLight
( "windowLight2"
, render
, LVecBase3
( 3.5
, 1.49
, 4.5
)
, showLights
);
}
void generateWindowLight
( std::string name
, NodePath render
, LVecBase3 position
, bool show
) {
PT(Spotlight) windowLight = new Spotlight(name);
windowLight->set_color(windowLightColor);
windowLight->set_exponent(5);
windowLight->set_attenuation(LVecBase3(1, 0.008, 0));
windowLight->set_max_distance(37);
PT(PerspectiveLens) windowLightLens = new PerspectiveLens();
windowLightLens->set_near_far(0.5, 12);
windowLightLens->set_fov(140);
windowLight->set_lens(windowLightLens);
if (show) windowLight->show_frustum();
NodePath windowLightNP = render.attach_new_node(windowLight);
windowLightNP.set_name(name);
windowLightNP.set_pos(position);
windowLightNP.set_hpr(180, 0, 0);
render.set_light(windowLightNP);
}
float animateLights
( NodePath render
, AnimControlCollection shuttersAnimationCollection
, float delta
, float speed
, bool& closedShutters
, bool middayDown
, bool midnightDown
) {
auto clamp =
[]
( float a
, float mn
, float mx
) -> float {
if (a > mx) { a = mx; }
if (a < mn) { a = mn; }
return a;
};
NodePath sunlightPivotNP = render.find("**/sunlightPivot");
NodePath moonlightPivotNP = render.find("**/moonlightPivot");
NodePath sunlightNP = render.find("**/sunlight");
NodePath moonlightNP = render.find("**/moonlight");
PT(DirectionalLight) sunlight =
DCAST(DirectionalLight, sunlightNP.node());
PT(DirectionalLight) moonlight =
DCAST(DirectionalLight, moonlightNP.node());
float p = sunlightPivotNP.get_p();
p += speed * delta;
if (p > 360) p = 0;
if (p < 0) p = 360;
if (middayDown) {
p = 270;
} else if (midnightDown) {
p = 90;
}
sunlightPivotNP.set_p( p );
moonlightPivotNP.set_p(p - 180);
float mixFactor = 1.0 - (sin(toRadians(p)) / 2.0 + 0.5);
LColor sunlightColor = mixColor(sunlightColor0, sunlightColor1, mixFactor);
LColor moonlightColor = mixColor(moonlightColor1, sunlightColor0, mixFactor);
LColor lightColor = mixColor(moonlightColor, sunlightColor, mixFactor);
float dayTimeLightMagnitude = clamp(-1 * sin(toRadians(p)), 0.0, 1.0);
float nightTimeLightMagnitude = clamp( sin(toRadians(p)), 0.0, 1.0);
sunlight->set_color( lightColor * dayTimeLightMagnitude);
moonlight->set_color(lightColor * nightTimeLightMagnitude);
if (dayTimeLightMagnitude > 0.0) {
sunlight->set_shadow_caster(true, SHADOW_SIZE, SHADOW_SIZE);
render.set_light(sunlightNP);
} else {
sunlight->set_shadow_caster(false, 0, 0);
render.set_light_off(sunlightNP);
}
if (nightTimeLightMagnitude > 0.0) {
moonlight->set_shadow_caster(true, SHADOW_SIZE, SHADOW_SIZE);
render.set_light(moonlightNP);
} else {
moonlight->set_shadow_caster(false, 0, 0);
render.set_light_off(moonlightNP);
}
auto updateWindowLight =
[&]
( std::string name
) -> void {
NodePath windowLightNP = render.find("**/" + name);
PT(Spotlight) windowLight = DCAST(Spotlight, windowLightNP.node());
float windowLightMagnitude = pow(nightTimeLightMagnitude, 0.4);
windowLight->set_color(windowLightColor * windowLightMagnitude);
if (windowLightMagnitude <= 0.0) {
windowLight->set_shadow_caster(false, 0, 0);
render.set_light_off(windowLightNP);
} else {
windowLight->set_shadow_caster(true, SHADOW_SIZE, SHADOW_SIZE);
render.set_light(windowLightNP);
}
};
updateWindowLight("windowLight");
updateWindowLight("windowLight1");
updateWindowLight("windowLight2");
if (mixFactor >= 0.3 && mixFactor <= 0.35 && closedShutters || midnightDown) {
closedShutters = false;
shuttersAnimationCollection.play("open-shutters");
} else if (mixFactor >= 0.6 && mixFactor <= 0.7 && !closedShutters || middayDown) {
closedShutters = true;
shuttersAnimationCollection.play("close-shutters");
}
return p;
}
PT(Shader) loadShader
( std::string vert
, std::string frag
) {
return Shader::load
( Shader::SL_GLSL
, "shaders/vertex/" + vert + ".vert"
, "shaders/fragment/" + frag + ".frag"
);
}
PTA_LVecBase3f generateSsaoSamples
( int numberOfSamples
) {
auto lerp = [](float a, float b, float f) -> float {
return a + f * (b - a);
};
PTA_LVecBase3f ssaoSamples = PTA_LVecBase3f();
for (int i = 0; i < numberOfSamples; ++i) {
LVecBase3f sample =
LVecBase3f
( randomFloats(generator) * 2.0 - 1.0
, randomFloats(generator) * 2.0 - 1.0
, randomFloats(generator)
).normalized();
float rand = randomFloats(generator);
sample[0] *= rand;
sample[1] *= rand;
sample[2] *= rand;
float scale = (float) i / (float) numberOfSamples;
scale = lerp(0.1, 1.0, scale * scale);
sample[0] *= scale;
sample[1] *= scale;
sample[2] *= scale;
ssaoSamples.push_back(sample);
}
return ssaoSamples;
}
PTA_LVecBase3f generateSsaoNoise
( int numberOfNoise
) {
PTA_LVecBase3f ssaoNoise = PTA_LVecBase3f();
for (int i = 0; i < numberOfNoise; ++i) {
LVecBase3f noise =
LVecBase3f
( randomFloats(generator) * 2.0 - 1.0
, randomFloats(generator) * 2.0 - 1.0
, 0.0
);
ssaoNoise.push_back(noise);
}
return ssaoNoise;
}
FramebufferTexture generateFramebufferTexture
( FramebufferTextureArguments framebufferTextureArguments
) {
PT(WindowFramework) window = framebufferTextureArguments.window;
PT(GraphicsOutput) graphicsOutput = framebufferTextureArguments.graphicsOutput;
PT(GraphicsEngine) graphicsEngine = framebufferTextureArguments.graphicsEngine;
LVecBase4 rgbaBits = framebufferTextureArguments.rgbaBits;
GraphicsOutput::RenderTexturePlane bitplane = framebufferTextureArguments.bitplane;
int aux_rgba = framebufferTextureArguments.aux_rgba;
bool setFloatColor = framebufferTextureArguments.setFloatColor;
bool setSrgbColor = framebufferTextureArguments.setSrgbColor;
bool setRgbColor = framebufferTextureArguments.setRgbColor;
bool useScene = framebufferTextureArguments.useScene;
std::string name = framebufferTextureArguments.name;
LColor clearColor = framebufferTextureArguments.clearColor;
FrameBufferProperties fbp = FrameBufferProperties::get_default();
fbp.set_back_buffers(0);
fbp.set_rgba_bits
( rgbaBits[0]
, rgbaBits[1]
, rgbaBits[2]
, rgbaBits[3]
);
fbp.set_aux_rgba(aux_rgba);
fbp.set_float_color(setFloatColor);
fbp.set_srgb_color (setSrgbColor );
fbp.set_rgb_color (setRgbColor );
PT(GraphicsOutput) buffer =
graphicsEngine
->make_output
( graphicsOutput->get_pipe()
, name + "Buffer"
, BACKGROUND_RENDER_SORT_ORDER - 1
, fbp
, WindowProperties::size(0, 0),
GraphicsPipe::BF_refuse_window
| GraphicsPipe::BF_resizeable
| GraphicsPipe::BF_can_bind_every
| GraphicsPipe::BF_rtt_cumulative
| GraphicsPipe::BF_size_track_host
, graphicsOutput->get_gsg()
, graphicsOutput->get_host()
);
buffer->add_render_texture
( NULL
, GraphicsOutput::RTM_bind_or_copy
, bitplane
);
buffer->set_clear_color(clearColor);
NodePath cameraNP = NodePath("");
PT(Camera) camera = NULL;
if (useScene) {
cameraNP = window->make_camera();
camera = DCAST(Camera, cameraNP.node());
camera->set_lens(window->get_camera(0)->get_lens());
} else {
camera = new Camera(name + "Camera");
PT(OrthographicLens) lens = new OrthographicLens();
lens->set_film_size(2, 2);
lens->set_film_offset(0, 0);
lens->set_near_far(-1, 1);
camera->set_lens(lens);
cameraNP = NodePath(camera);
}
PT(DisplayRegion) bufferRegion =
buffer->make_display_region(0, 1, 0, 1);
bufferRegion->set_camera(cameraNP);
NodePath shaderNP = NodePath(name + "Shader");
if (!useScene) {
NodePath renderNP = NodePath(name + "Render");
renderNP.set_depth_test( false);
renderNP.set_depth_write(false);
cameraNP.reparent_to(renderNP);
CardMaker card = CardMaker(name);
card.set_frame_fullscreen_quad();
card.set_has_uvs(true);
NodePath cardNP = NodePath(card.generate());
cardNP.reparent_to(renderNP);
cardNP.set_pos(0, 0, 0);
cardNP.set_hpr(0, 0, 0);
cameraNP.look_at(cardNP);
}
FramebufferTexture result;
result.buffer = buffer;
result.bufferRegion = bufferRegion;
result.camera = camera;
result.cameraNP = cameraNP;
result.shaderNP = shaderNP;
return result;
}
void showBuffer
( NodePath render2d
, NodePath statusNP
, std::tuple<std::string, PT(GraphicsOutput), int> bufferTexture
, bool alpha
) {
hideBuffer
( render2d
);
std::string bufferName;
PT(GraphicsOutput) buffer;
int texture;
std::tie(bufferName, buffer, texture) = bufferTexture;
NodePath nodePath = buffer->get_texture_card();
nodePath.set_texture(buffer->get_texture(texture));
nodePath.reparent_to(render2d);
nodePath.set_y(0);
if (alpha)
nodePath.set_transparency
( TransparencyAttrib::Mode::M_alpha
);
statusNP.reparent_to(nodePath);
}
void hideBuffer
( NodePath render2d
) {
NodePath nodePath = render2d.find("**/texture card");
if (nodePath)
nodePath.detach_node();
}
int microsecondsSinceEpoch
(
) {
return std::chrono::duration_cast
<std::chrono::microseconds>
( std::chrono::system_clock::now().time_since_epoch()
).count();
}
bool isButtonDown
( PT(MouseWatcher) mouseWatcher
, std::string character
) {
return
mouseWatcher
->is_button_down
( ButtonRegistry::ptr()->find_button(character)
);
}
PT(MouseWatcher) getMouseWatcher
( WindowFramework* window
) {
return DCAST
( MouseWatcher
, window->get_mouse().node()
);
}
void setSoundOff
( PT(AudioSound) sound
) {
setSoundState(sound, false);
}
void setSoundOn
( PT(AudioSound) sound
) {
setSoundState(sound, true);
}
void setSoundState
( PT(AudioSound) sound
, bool on
) {
if (!on && sound->status() == AudioSound::PLAYING) {
sound->stop();
} else if (on && sound->status() != AudioSound::PLAYING) {
sound->play();
}
}
void updateAudoManager
( NodePath sceneRootNP
, NodePath cameraNP
) {
LVector3f f = sceneRootNP.get_relative_vector(cameraNP, LVector3f::forward());
LVector3f u = sceneRootNP.get_relative_vector(cameraNP, LVector3f::up());
LVector3f v = LVector3f(0, 0, 0);
LVector3f p = cameraNP.get_pos(sceneRootNP);
audioManager->audio_3d_set_listener_attributes
( p[0], p[1], p[2]
, v[0], v[1], v[2]
, f[0], f[1], f[2]
, u[0], u[1], u[2]
);
audioManager->update();
}
LVecBase3f calculateCameraPosition
( double radius
, double phi
, double theta
, LVecBase3 lookAt
) {
double x = radius * sin(toRadians(phi)) * cos(toRadians(theta)) + lookAt[0];
double y = radius * sin(toRadians(phi)) * sin(toRadians(theta)) + lookAt[1];
double z = radius * cos(toRadians(phi)) + lookAt[2];
return LVecBase3f(x, y, z);
}
LVecBase3f calculateCameraLookAt
( double upDownAdjust
, double leftRightAdjust
, double phi
, double theta
, LVecBase3 lookAt
) {
lookAt[0] += upDownAdjust * sin(toRadians(-theta - 90)) * cos(toRadians(phi));
lookAt[1] += upDownAdjust * cos(toRadians(-theta - 90)) * cos(toRadians(phi));
lookAt[2] -= -upDownAdjust * sin(toRadians(phi));
lookAt[0] += leftRightAdjust * sin(toRadians(-theta));
lookAt[1] += leftRightAdjust * cos(toRadians(-theta));
return lookAt;
}
NodePath setUpParticles
( NodePath render
, PT(Texture) smokeTexture
) {
PT(ParticleSystem) smokePS = new ParticleSystem();
PT(ForceNode) smokeFN = new ForceNode("smoke");
PT(PhysicalNode) smokePN = new PhysicalNode("smoke");
smokePS->set_pool_size(75);
smokePS->set_birth_rate(0.01);
smokePS->set_litter_size(1);
smokePS->set_litter_spread(2);
smokePS->set_system_lifespan(0.0);
smokePS->set_local_velocity_flag(true);
smokePS->set_system_grows_older_flag(false);
PT(PointParticleFactory) smokePPF = new PointParticleFactory();
smokePPF->set_lifespan_base(0.1);
smokePPF->set_lifespan_spread(3);
smokePPF->set_mass_base(1);
smokePPF->set_mass_spread(0);
smokePPF->set_terminal_velocity_base(400);
smokePPF->set_terminal_velocity_spread(0);
smokePS->set_factory(smokePPF);
PT(SpriteParticleRenderer) smokeSPR = new SpriteParticleRenderer();
smokeSPR->set_alpha_mode(BaseParticleRenderer::PR_ALPHA_OUT);
smokeSPR->set_user_alpha(1.0);
smokeSPR->set_texture(smokeTexture);
smokeSPR->set_color(LColor(1.0, 1.0, 1.0, 1.0));
smokeSPR->set_x_scale_flag(true);
smokeSPR->set_y_scale_flag(true);
smokeSPR->set_anim_angle_flag(true);
smokeSPR->set_initial_x_scale(0.0000001);
smokeSPR->set_final_x_scale( 0.007);
smokeSPR->set_initial_y_scale(0.0000001);
smokeSPR->set_final_y_scale( 0.007);
smokeSPR->set_nonanimated_theta(209.0546);
smokeSPR->set_alpha_blend_method(BaseParticleRenderer::PP_BLEND_CUBIC);
smokeSPR->set_alpha_disable(false);
smokeSPR->get_color_interpolation_manager()->add_linear
( 0.0
, 1.0
, LColor(1.0, 1.0, 1.0, 1.0)
, LColor(0.039, 0.078, 0.156, 1.0)
, true
);
smokePS->set_renderer(smokeSPR);
PT(PointEmitter) smokePE = new PointEmitter();
smokePE->set_emission_type(BaseParticleEmitter::ET_EXPLICIT);
smokePE->set_amplitude(0.0);
smokePE->set_amplitude_spread(1.0);
smokePE->set_offset_force(LVector3f(0.0, 0.0, 2.0));
smokePE->set_explicit_launch_vector(LVector3f(0.0, 0.1, 0.0));
smokePE->set_radiate_origin(LPoint3f(0.0, 0.0, 0.0));
smokePE->set_location(LPoint3f(0.0, 0.0, 0.0));
smokePS->set_emitter(smokePE);
PT(LinearVectorForce) smokeLVF = new LinearVectorForce(LVector3f(3.0, -2.0, 0.0), 1.0, false);
smokeLVF->set_vector_masks(true, true, true);
smokeLVF->set_active(true);
smokeFN->add_force(smokeLVF);
smokePS->add_linear_force(smokeLVF);
PT(LinearJitterForce) smokeLJF = new LinearJitterForce(2.0, false);
smokeLJF->set_vector_masks(true, true, true);
smokeLJF->set_active(true);
smokeFN->add_force(smokeLJF);
smokePS->add_linear_force(smokeLJF);
PT(LinearCylinderVortexForce) smokeLCVF = new LinearCylinderVortexForce(10.0, 1.0, 4.0, 1.0, false);
smokeLCVF->set_vector_masks(true, true, true);
smokeLCVF->set_active(true);
smokeFN->add_force(smokeLCVF);
smokePS->add_linear_force(smokeLCVF);
smokePN->insert_physical(0, smokePS);
smokePS->set_render_parent(smokePN);
NodePath smokeNP = render.attach_new_node(smokePN);
smokeNP.attach_new_node(smokeFN);
particleSystemManager.attach_particlesystem(smokePS);
physicsManager.attach_physical(smokePS);
smokeNP.set_pos(0.47, 4.5, 8.9);
smokeNP.set_transparency(TransparencyAttrib::M_dual);
smokeNP.set_bin("fixed", 0);
return smokeNP;
}
void squashGeometry
( NodePath environmentNP
) {
for (int i = 0; i < 4; ++i) {
std::string index = std::to_string(i);
NodePathCollection treeCollection = environmentNP.find_all_matches("**/tree" + index);
NodePath treesNP = NodePath("treeCollection" + index);
treesNP.reparent_to(environmentNP);
treeCollection.reparent_to(treesNP);
treesNP.flatten_strong();
}
NodePathCollection barrelCollection = environmentNP.find_all_matches("**/barrel-wood*");
NodePath barrelNP = NodePath("barrels");
barrelNP.reparent_to(environmentNP);
barrelCollection.reparent_to(barrelNP);
barrelNP.flatten_strong();
NodePath squashNP = NodePath("squash");
squashNP.reparent_to(environmentNP);
NodePathCollection squashCollection = environmentNP.find_all_matches("**/*");
for (int i = 0; i < squashCollection.size(); ++i) {
if ( squashCollection[i].get_name() == "wheel-lp"
|| squashCollection[i].get_name() == "water-lp"
|| squashCollection[i].get_name() == "squash"
) { continue; }
squashCollection[i].reparent_to(squashNP);
}
squashNP.flatten_strong();
}
double microsecondToSecond
( int m
) {
return m / 1000000.0;
}
double toRadians
( double d
) {
return d * M_PI / 180.0;
}
LVecBase2f makeEnabledVec
( int t
) {
if (t >= 1) { t = 1; } else { t = 0; }
return LVecBase2f(t, t);
}
LVecBase2f toggleEnabledVec
( LVecBase2f vec
) {
int t = vec[0];
if (t >= 1) { t = 0; } else { t = 1; }
vec[0] = t;
vec[1] = t;
return vec;
}
void setTextureToNearestAndClamp
( PT(Texture) texture
) {
texture->set_magfilter(SamplerState::FT_nearest);
texture->set_minfilter(SamplerState::FT_nearest);
texture->set_wrap_u(SamplerState::WM_clamp);
texture->set_wrap_v(SamplerState::WM_clamp);
texture->set_wrap_w(SamplerState::WM_clamp);
}
LColor mixColor
( LColor a
, LColor b
, float factor
) {
return a * (1 - factor) + b * factor;
}
================================================
FILE: docs/_build-docs.sh
================================================
#!/usr/bin/env bash
SCRIPT_PATH="$(cd "$(dirname "$0")"; pwd -P)"
MAIN_TITLE="3D Game Shaders For Beginners"
REPO_URL="https://github.com/lettier/3d-game-shaders-for-beginners"
AUTHOR="David Lettier"
CSS="style.css"
for f in $SCRIPT_PATH/../sections/*
do
echo "$f"
file=$(basename -- "$f")
file_name="${file%.*}"
title=$(echo "$file_name" | sed -r 's/-/ /g' | sed -e 's/\b\(.\)/\u\1/g')
if [ "$title" == "Ssao" ]
then
title="SSAO"
fi
if [ "$title" == "Glsl" ]
then
title="GLSL"
fi
$PANDOC \
-f gfm \
-t html5 \
--highlight-style=breezedark \
--template=$SCRIPT_PATH/_template.html5 \
$f \
--metadata pagetitle="$title | $MAIN_TITLE" \
--metadata author-meta="$AUTHOR" \
--metadata css=$CSS \
-o "$SCRIPT_PATH/$file_name.html"
done
$PANDOC \
-f gfm \
-t html5 \
--highlight-style=breezedark \
--template=$SCRIPT_PATH/_template.html5 \
$SCRIPT_PATH/../README.md \
--metadata pagetitle="$MAIN_TITLE" \
--metadata author-meta="$AUTHOR" \
--metadata css=$CSS \
-o "$SCRIPT_PATH/index.html"
for i in {1..3}
do
for f in $SCRIPT_PATH/*
do
file=$(basename -- "$f")
file_name="${file%.*}"
file_ext="${file##*.}"
if [ "$file_ext" == "html" ]
then
echo $f
sed -i -E 's/href="(sections\/)?([a-z-]+)\.md(.*)"/href="\2\.html\3"/g' $f
sed -i -E 's/href="\.\.\/README.md"/href="index.html"/g' $f
sed -i -E 's+<a href="\.\.\/demonstration\/(.*)">+<a href="'$REPO_URL'\/blob\/master\/demonstration\/\1" target="_blank" rel="noopener noreferrer">+g' $f
fi
done
done
================================================
FILE: docs/_template.html5
================================================
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta property="og:title" content="$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$" />
<meta property="og:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta property="og:image" content="https://i.imgur.com/JIDwVTm.png" />
<meta name="twitter:title" content="$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$" />
<meta name="twitter:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta name="twitter:image" content="https://i.imgur.com/JIDwVTm.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
$for(author-meta)$
<meta name="author" content="$author-meta$" />
$endfor$
$if(date-meta)$
<meta name="dcterms.date" content="$date-meta$" />
$endif$
$if(keywords)$
<meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
$endif$
<title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
$if(quotes)$
q { quotes: "“" "”" "‘" "’"; }
$endif$
</style>
$if(highlighting-css)$
<style>
$highlighting-css$
</style>
$endif$
$if(math)$
$math$
$endif$
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
$for(header-includes)$
$header-includes$
$endfor$
$for(css)$
<link rel="stylesheet" href="$css$" />
$endfor$
</head>
<body>
$for(include-before)$
$include-before$
$endfor$
$if(title)$
<header id="title-block-header">
<h1 class="title">$title$</h1>
$if(subtitle)$
<p class="subtitle">$subtitle$</p>
$endif$
$for(author)$
<p class="author">$author$</p>
$endfor$
$if(date)$
<p class="date">$date$</p>
$endif$
</header>
$endif$
$if(toc)$
<nav id="$idprefix$TOC" role="doc-toc">
$table-of-contents$
</nav>
$endif$
$body$
$for(include-after)$
$include-after$
$endfor$
</body>
</html>
================================================
FILE: docs/blinn-phong.html
================================================
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta property="og:title" content="Blinn Phong | 3D Game Shaders For Beginners" />
<meta property="og:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta property="og:image" content="https://i.imgur.com/JIDwVTm.png" />
<meta name="twitter:title" content="Blinn Phong | 3D Game Shaders For Beginners" />
<meta name="twitter:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta name="twitter:image" content="https://i.imgur.com/JIDwVTm.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<meta name="author" content="David Lettier" />
<title>Blinn Phong | 3D Game Shaders For Beginners</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<style>
code.sourceCode > span { display: inline-block; line-height: 1.25; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
background-color: #232629;
color: #7a7c7d;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #7a7c7d; padding-left: 4px; }
div.sourceCode
{ color: #cfcfc2; background-color: #232629; }
@media screen {
code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span. { color: #cfcfc2; } /* Normal */
code span.al { color: #95da4c; } /* Alert */
code span.an { color: #3f8058; } /* Annotation */
code span.at { color: #2980b9; } /* Attribute */
code span.bn { color: #f67400; } /* BaseN */
code span.bu { color: #7f8c8d; } /* BuiltIn */
code span.cf { color: #fdbc4b; } /* ControlFlow */
code span.ch { color: #3daee9; } /* Char */
code span.cn { color: #27aeae; } /* Constant */
code span.co { color: #7a7c7d; } /* Comment */
code span.cv { color: #7f8c8d; } /* CommentVar */
code span.do { color: #a43340; } /* Documentation */
code span.dt { color: #2980b9; } /* DataType */
code span.dv { color: #f67400; } /* DecVal */
code span.er { color: #da4453; } /* Error */
code span.ex { color: #0099ff; } /* Extension */
code span.fl { color: #f67400; } /* Float */
code span.fu { color: #8e44ad; } /* Function */
code span.im { color: #27ae60; } /* Import */
code span.in { color: #c45b00; } /* Information */
code span.kw { color: #cfcfc2; } /* Keyword */
code span.op { color: #cfcfc2; } /* Operator */
code span.ot { color: #27ae60; } /* Other */
code span.pp { color: #27ae60; } /* Preprocessor */
code span.re { color: #2980b9; } /* RegionMarker */
code span.sc { color: #3daee9; } /* SpecialChar */
code span.ss { color: #da4453; } /* SpecialString */
code span.st { color: #f44f4f; } /* String */
code span.va { color: #27aeae; } /* Variable */
code span.vs { color: #da4453; } /* VerbatimString */
code span.wa { color: #da4453; } /* Warning */
</style>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
<link rel="stylesheet" href="style.css" />
</head>
<body>
<p><a href="lighting.html"><span class="emoji" data-emoji="arrow_backward">◀️</span></a> <a href="index.html"><span class="emoji" data-emoji="arrow_double_up">⏫</span></a> <a href="#"><span class="emoji" data-emoji="arrow_up_small">🔼</span></a> <a href="#copyright"><span class="emoji" data-emoji="arrow_down_small">🔽</span></a> <a href="fresnel-factor.html"><span class="emoji" data-emoji="arrow_forward">▶️</span></a></p>
<h1 id="3d-game-shaders-for-beginners">3D Game Shaders For Beginners</h1>
<h2 id="blinn-phong">Blinn-Phong</h2>
<p align="center">
<img src="https://i.imgur.com/CFWEeGK.gif" alt="Blinn-Phong" title="Blinn-Phong">
</p>
<p>Blinn-Phong is a slight adjustment of the Phong model you saw in the <a href="lighting.html">lighting</a> section. It provides more plausible or realistic specular reflections. You'll notice that Blinn-Phong produces elliptical or elongated specular reflections versus the spherical specular reflections produced by the Phong model. In certain cases, Blinn-Phong can be more efficient to calculate than Phong.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a> <span class="co">// ...</span></span>
<span id="cb1-2"><a href="#cb1-2"></a></span>
<span id="cb1-3"><a href="#cb1-3"></a> vec3 light = normal(lightPosition.xyz - vertexPosition.xyz);</span>
<span id="cb1-4"><a href="#cb1-4"></a> vec3 eye = normalize(-vertexPosition.xyz);</span>
<span id="cb1-5"><a href="#cb1-5"></a> vec3 halfway = normalize(light + eye);</span>
<span id="cb1-6"><a href="#cb1-6"></a></span>
<span id="cb1-7"><a href="#cb1-7"></a> <span class="co">// ...</span></span></code></pre></div>
<p>Instead of computing the reflection vector, compute the halfway or half angle vector. This vector is between the view/camera/eye and light direction vector.</p>
<p align="center">
<img src="https://i.imgur.com/vtqd1Ox.gif" alt="Blinn-Phong vs Phong" title="Blinn-Phong vs Phong">
</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a> <span class="co">// ...</span></span>
<span id="cb2-2"><a href="#cb2-2"></a></span>
<span id="cb2-3"><a href="#cb2-3"></a> <span class="dt">float</span> specularIntensity = dot(normal, halfway);</span>
<span id="cb2-4"><a href="#cb2-4"></a></span>
<span id="cb2-5"><a href="#cb2-5"></a> <span class="co">// ...</span></span></code></pre></div>
<p>The specular intensity is now the dot product of the normal and halfway vector. In the Phong model, it is the dot product of the reflection and view vector.</p>
<p align="center">
<img src="https://i.imgur.com/WZQqxEH.png" alt="Full specular intensity." title="Full specular intensity.">
</p>
<p>The half angle vector (magenta arrow) will point in the same direction as the normal (green arrow) when the view vector (orange arrow) points in the same direction as the reflection vector (magenta arrow). In this case, both the Blinn-Phong and Phong specular intensity will be one.</p>
<p align="center">
<img src="https://i.imgur.com/kiSdJzt.png" alt="Blinn-Phong vs Phong" title="Blinn-Phong vs Phong">
</p>
<p>In other cases, the specular intensity for Blinn-Phong will be greater than zero while the specular intensity for Phong will be zero.</p>
<h3 id="source">Source</h3>
<ul>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/src/main.cxx" target="_blank" rel="noopener noreferrer">main.cxx</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/vertex/base.vert" target="_blank" rel="noopener noreferrer">base.vert</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/fragment/base.frag" target="_blank" rel="noopener noreferrer">base.frag</a></li>
</ul>
<h2 id="copyright">Copyright</h2>
<p>(C) 2020 David Lettier <br> <a href="https://www.lettier.com">lettier.com</a></p>
<p><a href="lighting.html"><span class="emoji" data-emoji="arrow_backward">◀️</span></a> <a href="index.html"><span class="emoji" data-emoji="arrow_double_up">⏫</span></a> <a href="#"><span class="emoji" data-emoji="arrow_up_small">🔼</span></a> <a href="#copyright"><span class="emoji" data-emoji="arrow_down_small">🔽</span></a> <a href="fresnel-factor.html"><span class="emoji" data-emoji="arrow_forward">▶️</span></a></p>
</body>
</html>
================================================
FILE: docs/bloom.html
================================================
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta property="og:title" content="Bloom | 3D Game Shaders For Beginners" />
<meta property="og:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta property="og:image" content="https://i.imgur.com/JIDwVTm.png" />
<meta name="twitter:title" content="Bloom | 3D Game Shaders For Beginners" />
<meta name="twitter:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta name="twitter:image" content="https://i.imgur.com/JIDwVTm.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<meta name="author" content="David Lettier" />
<title>Bloom | 3D Game Shaders For Beginners</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<style>
code.sourceCode > span { display: inline-block; line-height: 1.25; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
background-color: #232629;
color: #7a7c7d;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #7a7c7d; padding-left: 4px; }
div.sourceCode
{ color: #cfcfc2; background-color: #232629; }
@media screen {
code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span. { color: #cfcfc2; } /* Normal */
code span.al { color: #95da4c; } /* Alert */
code span.an { color: #3f8058; } /* Annotation */
code span.at { color: #2980b9; } /* Attribute */
code span.bn { color: #f67400; } /* BaseN */
code span.bu { color: #7f8c8d; } /* BuiltIn */
code span.cf { color: #fdbc4b; } /* ControlFlow */
code span.ch { color: #3daee9; } /* Char */
code span.cn { color: #27aeae; } /* Constant */
code span.co { color: #7a7c7d; } /* Comment */
code span.cv { color: #7f8c8d; } /* CommentVar */
code span.do { color: #a43340; } /* Documentation */
code span.dt { color: #2980b9; } /* DataType */
code span.dv { color: #f67400; } /* DecVal */
code span.er { color: #da4453; } /* Error */
code span.ex { color: #0099ff; } /* Extension */
code span.fl { color: #f67400; } /* Float */
code span.fu { color: #8e44ad; } /* Function */
code span.im { color: #27ae60; } /* Import */
code span.in { color: #c45b00; } /* Information */
code span.kw { color: #cfcfc2; } /* Keyword */
code span.op { color: #cfcfc2; } /* Operator */
code span.ot { color: #27ae60; } /* Other */
code span.pp { color: #27ae60; } /* Preprocessor */
code span.re { color: #2980b9; } /* RegionMarker */
code span.sc { color: #3daee9; } /* SpecialChar */
code span.ss { color: #da4453; } /* SpecialString */
code span.st { color: #f44f4f; } /* String */
code span.va { color: #27aeae; } /* Variable */
code span.vs { color: #da4453; } /* VerbatimString */
code span.wa { color: #da4453; } /* Warning */
</style>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
<link rel="stylesheet" href="style.css" />
</head>
<body>
<p><a href="blur.html"><span class="emoji" data-emoji="arrow_backward">◀️</span></a> <a href="index.html"><span class="emoji" data-emoji="arrow_double_up">⏫</span></a> <a href="#"><span class="emoji" data-emoji="arrow_up_small">🔼</span></a> <a href="#copyright"><span class="emoji" data-emoji="arrow_down_small">🔽</span></a> <a href="ssao.html"><span class="emoji" data-emoji="arrow_forward">▶️</span></a></p>
<h1 id="3d-game-shaders-for-beginners">3D Game Shaders For Beginners</h1>
<h2 id="bloom">Bloom</h2>
<p align="center">
<img src="https://i.imgur.com/UxKRz2r.gif" alt="Bloom" title="Bloom">
</p>
<p>Adding bloom to a scene can really sell the illusion of the lighting model. Light emitting objects are more believable and specular highlights get an extra dose of shimmer.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a> <span class="co">//...</span></span>
<span id="cb1-2"><a href="#cb1-2"></a></span>
<span id="cb1-3"><a href="#cb1-3"></a> <span class="dt">int</span> size = <span class="dv">5</span>;</span>
<span id="cb1-4"><a href="#cb1-4"></a> <span class="dt">float</span> separation = <span class="dv">3</span>;</span>
<span id="cb1-5"><a href="#cb1-5"></a> <span class="dt">float</span> threshold = <span class="fl">0.4</span>;</span>
<span id="cb1-6"><a href="#cb1-6"></a> <span class="dt">float</span> amount = <span class="dv">1</span>;</span>
<span id="cb1-7"><a href="#cb1-7"></a></span>
<span id="cb1-8"><a href="#cb1-8"></a> <span class="co">// ...</span></span></code></pre></div>
<p>These parameters control the look and feel. <code>size</code> determines how blurred the effect is. <code>separation</code> spreads out the blur. <code>threshold</code> controls which fragments are illuminated. And the last parameter, <code>amount</code>, controls how much bloom is outputted.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a> <span class="co">// ...</span></span>
<span id="cb2-2"><a href="#cb2-2"></a></span>
<span id="cb2-3"><a href="#cb2-3"></a> vec2 texSize = textureSize(colorTexture, <span class="dv">0</span>).xy;</span>
<span id="cb2-4"><a href="#cb2-4"></a></span>
<span id="cb2-5"><a href="#cb2-5"></a> <span class="dt">float</span> value = <span class="fl">0.0</span>;</span>
<span id="cb2-6"><a href="#cb2-6"></a> <span class="dt">float</span> count = <span class="fl">0.0</span>;</span>
<span id="cb2-7"><a href="#cb2-7"></a></span>
<span id="cb2-8"><a href="#cb2-8"></a> vec4 result = vec4(<span class="dv">0</span>);</span>
<span id="cb2-9"><a href="#cb2-9"></a> vec4 color = vec4(<span class="dv">0</span>);</span>
<span id="cb2-10"><a href="#cb2-10"></a></span>
<span id="cb2-11"><a href="#cb2-11"></a> <span class="cf">for</span> (<span class="dt">int</span> i = -size; i <= size; ++i) {</span>
<span id="cb2-12"><a href="#cb2-12"></a> <span class="cf">for</span> (<span class="dt">int</span> j = -size; j <= size; ++j) {</span>
<span id="cb2-13"><a href="#cb2-13"></a> <span class="co">// ...</span></span>
<span id="cb2-14"><a href="#cb2-14"></a> }</span>
<span id="cb2-15"><a href="#cb2-15"></a> }</span>
<span id="cb2-16"><a href="#cb2-16"></a></span>
<span id="cb2-17"><a href="#cb2-17"></a> <span class="co">// ...</span></span></code></pre></div>
<p>The technique starts by looping through a kernel/matrix/window centered over the current fragment. This is similar to the window used for <a href="outlining.html">outlining</a>. The size of the window is <code>size * 2 + 1</code> by <code>size * 2 + 1</code>. So for example, with a <code>size</code> setting of two, the window uses <code>(2 * 2 + 1)^2 = 25</code> samples per fragment.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a> <span class="co">// ...</span></span>
<span id="cb3-2"><a href="#cb3-2"></a></span>
<span id="cb3-3"><a href="#cb3-3"></a> color =</span>
<span id="cb3-4"><a href="#cb3-4"></a> texture</span>
<span id="cb3-5"><a href="#cb3-5"></a> ( colorTexture</span>
<span id="cb3-6"><a href="#cb3-6"></a> , ( gl_FragCoord.xy</span>
<span id="cb3-7"><a href="#cb3-7"></a> + (vec2(i, j) * separation)</span>
<span id="cb3-8"><a href="#cb3-8"></a> )</span>
<span id="cb3-9"><a href="#cb3-9"></a> / texSize</span>
<span id="cb3-10"><a href="#cb3-10"></a> );</span>
<span id="cb3-11"><a href="#cb3-11"></a></span>
<span id="cb3-12"><a href="#cb3-12"></a> value = max(color.r, max(color.g, color.b));</span>
<span id="cb3-13"><a href="#cb3-13"></a> <span class="cf">if</span> (value < threshold) { color = vec4(<span class="dv">0</span>); }</span>
<span id="cb3-14"><a href="#cb3-14"></a></span>
<span id="cb3-15"><a href="#cb3-15"></a> result += color;</span>
<span id="cb3-16"><a href="#cb3-16"></a> count += <span class="fl">1.0</span>;</span>
<span id="cb3-17"><a href="#cb3-17"></a></span>
<span id="cb3-18"><a href="#cb3-18"></a> <span class="co">// ...</span></span></code></pre></div>
<p>For each iteration, it retrieves the color from the input texture and turns the red, green, and blue values into a greyscale value. If this greyscale value is less than the threshold, it discards this color by making it solid black. After evaluating the sample's greyscale value, it adds its RGB values to <code>result</code>.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a> <span class="co">// ...</span></span>
<span id="cb4-2"><a href="#cb4-2"></a></span>
<span id="cb4-3"><a href="#cb4-3"></a> result /= count;</span>
<span id="cb4-4"><a href="#cb4-4"></a></span>
<span id="cb4-5"><a href="#cb4-5"></a> fragColor = mix(vec4(<span class="dv">0</span>), result, amount);</span>
<span id="cb4-6"><a href="#cb4-6"></a></span>
<span id="cb4-7"><a href="#cb4-7"></a> <span class="co">// ...</span></span></code></pre></div>
<p>After it's done summing up the samples, it divides the sum of the color samples by the number of samples taken. The result is the average color of itself and its neighbors. By doing this for every fragment, you end up with a blurred image. This form of blurring is known as a <a href="blur.html#box-blur">box blur</a>.</p>
<p align="center">
<img src="https://i.imgur.com/m4yedrM.gif" alt="Bloom progresssion." title="Bloom progresssion.">
</p>
<p>Here you see the progression of the bloom algorithm.</p>
<h3 id="source">Source</h3>
<ul>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/src/main.cxx" target="_blank" rel="noopener noreferrer">main.cxx</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/vertex/basic.vert" target="_blank" rel="noopener noreferrer">basic.vert</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/fragment/outline.frag" target="_blank" rel="noopener noreferrer">bloom.frag</a></li>
</ul>
<h2 id="copyright">Copyright</h2>
<p>(C) 2019 David Lettier <br> <a href="https://www.lettier.com">lettier.com</a></p>
<p><a href="blur.html"><span class="emoji" data-emoji="arrow_backward">◀️</span></a> <a href="index.html"><span class="emoji" data-emoji="arrow_double_up">⏫</span></a> <a href="#"><span class="emoji" data-emoji="arrow_up_small">🔼</span></a> <a href="#copyright"><span class="emoji" data-emoji="arrow_down_small">🔽</span></a> <a href="ssao.html"><span class="emoji" data-emoji="arrow_forward">▶️</span></a></p>
</body>
</html>
================================================
FILE: docs/blur.html
================================================
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta property="og:title" content="Blur | 3D Game Shaders For Beginners" />
<meta property="og:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta property="og:image" content="https://i.imgur.com/JIDwVTm.png" />
<meta name="twitter:title" content="Blur | 3D Game Shaders For Beginners" />
<meta name="twitter:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
<meta name="twitter:image" content="https://i.imgur.com/JIDwVTm.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<meta name="author" content="David Lettier" />
<title>Blur | 3D Game Shaders For Beginners</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<style>
code.sourceCode > span { display: inline-block; line-height: 1.25; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
background-color: #232629;
color: #7a7c7d;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #7a7c7d; padding-left: 4px; }
div.sourceCode
{ color: #cfcfc2; background-color: #232629; }
@media screen {
code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span. { color: #cfcfc2; } /* Normal */
code span.al { color: #95da4c; } /* Alert */
code span.an { color: #3f8058; } /* Annotation */
code span.at { color: #2980b9; } /* Attribute */
code span.bn { color: #f67400; } /* BaseN */
code span.bu { color: #7f8c8d; } /* BuiltIn */
code span.cf { color: #fdbc4b; } /* ControlFlow */
code span.ch { color: #3daee9; } /* Char */
code span.cn { color: #27aeae; } /* Constant */
code span.co { color: #7a7c7d; } /* Comment */
code span.cv { color: #7f8c8d; } /* CommentVar */
code span.do { color: #a43340; } /* Documentation */
code span.dt { color: #2980b9; } /* DataType */
code span.dv { color: #f67400; } /* DecVal */
code span.er { color: #da4453; } /* Error */
code span.ex { color: #0099ff; } /* Extension */
code span.fl { color: #f67400; } /* Float */
code span.fu { color: #8e44ad; } /* Function
gitextract_oegtrd8a/
├── .gitignore
├── README.md
├── demonstration/
│ ├── build-for-linux.sh
│ ├── eggs/
│ │ └── mill-scene/
│ │ ├── banner.bam
│ │ ├── mill-scene.bam
│ │ ├── shutters.bam
│ │ └── weather-vane.bam
│ ├── panda3d-prc-file.prc
│ ├── shaders/
│ │ ├── LICENSE
│ │ ├── fragment/
│ │ │ ├── base-combine.frag
│ │ │ ├── base.frag
│ │ │ ├── bloom.frag
│ │ │ ├── box-blur.frag
│ │ │ ├── chromatic-aberration.frag
│ │ │ ├── depth-of-field.frag
│ │ │ ├── dilation.frag
│ │ │ ├── discard.frag
│ │ │ ├── film-grain.frag
│ │ │ ├── foam-mask.frag
│ │ │ ├── foam.frag
│ │ │ ├── fog.frag
│ │ │ ├── gamma-correction.frag
│ │ │ ├── geometry-buffer-0.frag
│ │ │ ├── geometry-buffer-1.frag
│ │ │ ├── geometry-buffer-2.frag
│ │ │ ├── kuwahara-filter.frag
│ │ │ ├── lookup-table.frag
│ │ │ ├── material-diffuse.frag
│ │ │ ├── material-specular.frag
│ │ │ ├── median-filter.frag
│ │ │ ├── motion-blur.frag
│ │ │ ├── normal.frag
│ │ │ ├── outline.frag
│ │ │ ├── pixelize.frag
│ │ │ ├── position.frag
│ │ │ ├── posterize.frag
│ │ │ ├── reflection-color.frag
│ │ │ ├── reflection.frag
│ │ │ ├── refraction.frag
│ │ │ ├── scene-combine.frag
│ │ │ ├── screen-space-reflection.frag
│ │ │ ├── screen-space-refraction.frag
│ │ │ ├── sharpen.frag
│ │ │ └── ssao.frag
│ │ └── vertex/
│ │ ├── base.vert
│ │ ├── basic.vert
│ │ └── discard.vert
│ ├── sounds/
│ │ ├── water.ogg
│ │ └── wheel.ogg
│ └── src/
│ ├── LICENSE
│ └── main.cxx
├── docs/
│ ├── _build-docs.sh
│ ├── _template.html5
│ ├── blinn-phong.html
│ ├── bloom.html
│ ├── blur.html
│ ├── building-the-demo.html
│ ├── cel-shading.html
│ ├── chromatic-aberration.html
│ ├── deferred-rendering.html
│ ├── depth-of-field.html
│ ├── dilation.html
│ ├── film-grain.html
│ ├── flow-mapping.html
│ ├── foam.html
│ ├── fog.html
│ ├── fresnel-factor.html
│ ├── gamma-correction.html
│ ├── glsl.html
│ ├── index.html
│ ├── lighting.html
│ ├── lookup-table.html
│ ├── motion-blur.html
│ ├── normal-mapping.html
│ ├── outlining.html
│ ├── pixelization.html
│ ├── posterization.html
│ ├── reference-frames.html
│ ├── render-to-texture.html
│ ├── rim-lighting.html
│ ├── running-the-demo.html
│ ├── screen-space-reflection.html
│ ├── screen-space-refraction.html
│ ├── setup.html
│ ├── sharpen.html
│ ├── ssao.html
│ ├── style.css
│ └── texturing.html
└── sections/
├── blinn-phong.md
├── bloom.md
├── blur.md
├── building-the-demo.md
├── cel-shading.md
├── chromatic-aberration.md
├── deferred-rendering.md
├── depth-of-field.md
├── dilation.md
├── film-grain.md
├── flow-mapping.md
├── foam.md
├── fog.md
├── fresnel-factor.md
├── gamma-correction.md
├── glsl.md
├── lighting.md
├── lookup-table.md
├── motion-blur.md
├── normal-mapping.md
├── outlining.md
├── pixelization.md
├── posterization.md
├── reference-frames.md
├── render-to-texture.md
├── rim-lighting.md
├── running-the-demo.md
├── screen-space-reflection.md
├── screen-space-refraction.md
├── setup.md
├── sharpen.md
├── ssao.md
└── texturing.md
SYMBOL INDEX (29 symbols across 1 files) FILE: demonstration/src/main.cxx type FramebufferTexture (line 51) | struct FramebufferTexture type FramebufferTextureArguments (line 60) | struct FramebufferTextureArguments function main (line 282) | int main function generateLights (line 2067) | void generateLights function generateWindowLight (line 2149) | void generateWindowLight function animateLights (line 2175) | float animateLights function loadShader (line 2284) | loadShader function PTA_LVecBase3f (line 2295) | PTA_LVecBase3f generateSsaoSamples function PTA_LVecBase3f (line 2329) | PTA_LVecBase3f generateSsaoNoise function FramebufferTexture (line 2348) | FramebufferTexture generateFramebufferTexture function showBuffer (line 2447) | void showBuffer function hideBuffer (line 2474) | void hideBuffer function microsecondsSinceEpoch (line 2482) | int microsecondsSinceEpoch function isButtonDown (line 2491) | bool isButtonDown function getMouseWatcher (line 2502) | getMouseWatcher function setSoundOff (line 2511) | void setSoundOff function setSoundOn (line 2517) | void setSoundOn function setSoundState (line 2523) | void setSoundState function updateAudoManager (line 2534) | void updateAudoManager function LVecBase3f (line 2553) | LVecBase3f calculateCameraPosition function LVecBase3f (line 2565) | LVecBase3f calculateCameraLookAt function NodePath (line 2581) | NodePath setUpParticles function squashGeometry (line 2673) | void squashGeometry function microsecondToSecond (line 2705) | double microsecondToSecond function toRadians (line 2711) | double toRadians function LVecBase2f (line 2717) | LVecBase2f makeEnabledVec function LVecBase2f (line 2724) | LVecBase2f toggleEnabledVec function setTextureToNearestAndClamp (line 2734) | void setTextureToNearestAndClamp function LColor (line 2744) | LColor mixColor
Condensed preview — 121 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,007K chars).
[
{
"path": ".gitignore",
"chars": 171,
"preview": "images/**\nblends/**\n*.kra~\n*.png~\n*main.o*\n*3d-game-shaders-for-beginners.o*\n*3d-game-shaders-for-beginners*\n!blends/*\n!"
},
{
"path": "README.md",
"chars": 2694,
"preview": "<p align=\"center\">\n<img src=\"https://i.imgur.com/x8rtGr4.gif\" alt=\"3D Game Shaders For Beginners\" title=\"3D Game Shaders"
},
{
"path": "demonstration/build-for-linux.sh",
"chars": 509,
"preview": "#!/usr/bin/env bash\n\nSCRIPT_PATH=\"$(cd \"$(dirname \"$0\")\"; pwd -P)\"\n\ng++ \\\n -Wfatal-errors \\\n -c $SCRIPT_PATH/src/main."
},
{
"path": "demonstration/panda3d-prc-file.prc",
"chars": 1017,
"preview": "load-display pandagl\n\naudio-library-name p3openal_audio\n\nwin-origin -2 -2\nwin-size"
},
{
"path": "demonstration/shaders/LICENSE",
"chars": 1513,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2019, David Lettier\nAll rights reserved.\n\nRedistribution and use in source and binar"
},
{
"path": "demonstration/shaders/fragment/base-combine.frag",
"chars": 1004,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D baseTexture;\nuniform sampler2D refractionT"
},
{
"path": "demonstration/shaders/fragment/base.frag",
"chars": 9079,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\n#define NUMBER_OF_LIGHTS 4\n#define MAX_SHININESS 127."
},
{
"path": "demonstration/shaders/fragment/bloom.frag",
"chars": 930,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D colorTexture;\n\nuniform vec2 enabled;\n\nout "
},
{
"path": "demonstration/shaders/fragment/box-blur.frag",
"chars": 823,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D colorTexture;\n\nuniform vec2 parameters;\n\no"
},
{
"path": "demonstration/shaders/fragment/chromatic-aberration.frag",
"chars": 757,
"preview": "/*\n (C) 2021 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D colorTexture;\n\nuniform vec2 enabled;\nunifo"
},
{
"path": "demonstration/shaders/fragment/depth-of-field.frag",
"chars": 1076,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D positionTexture;\nuniform sampler2D noiseTe"
},
{
"path": "demonstration/shaders/fragment/dilation.frag",
"chars": 1279,
"preview": "/*\n (C) 2020 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D colorTexture;\n\nuniform vec2 parameters;\n\no"
},
{
"path": "demonstration/shaders/fragment/discard.frag",
"chars": 87,
"preview": "/*\n (C) 2020 David Lettier\n lettier.com\n*/\n\n#version 150\n\nvoid main() {\n discard;\n}\n"
},
{
"path": "demonstration/shaders/fragment/film-grain.frag",
"chars": 715,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform vec2 pi;\n\nuniform float osg_FrameTime;\n\nuniform samp"
},
{
"path": "demonstration/shaders/fragment/foam-mask.frag",
"chars": 744,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform float osg_FrameTime;\n\nuniform sampler2D foamPatternT"
},
{
"path": "demonstration/shaders/fragment/foam.frag",
"chars": 1293,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform vec2 pi;\nuniform vec2 gamma;\n\nuniform mat4 viewWorld"
},
{
"path": "demonstration/shaders/fragment/fog.frag",
"chars": 2140,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform vec2 pi;\nuniform vec2 gamma;\n\nuniform vec4 backgroun"
},
{
"path": "demonstration/shaders/fragment/gamma-correction.frag",
"chars": 352,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform vec2 gamma;\n\nuniform sampler2D colorTexture;\n\nout ve"
},
{
"path": "demonstration/shaders/fragment/geometry-buffer-0.frag",
"chars": 790,
"preview": "/*\n (C) 2020 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D p3d_Texture1;\n\nuniform vec2 normalMapsEnab"
},
{
"path": "demonstration/shaders/fragment/geometry-buffer-1.frag",
"chars": 2486,
"preview": "/*\n (C) 2020 David Lettier\n lettier.com\n*/\n\n#version 150\n\n#define MAX_SHININESS 127.75\n\nuniform float osg_FrameTime;\n\n"
},
{
"path": "demonstration/shaders/fragment/geometry-buffer-2.frag",
"chars": 932,
"preview": "/*\n (C) 2020 David Lettier\n lettier.com\n*/\n\n#version 150\n\n\nuniform sampler2D p3d_Texture0;\nuniform sampler2D positionT"
},
{
"path": "demonstration/shaders/fragment/kuwahara-filter.frag",
"chars": 1658,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\n#define MAX_SIZE 5\n#define MAX_KERNEL_SIZE ((MAX_SIZE"
},
{
"path": "demonstration/shaders/fragment/lookup-table.frag",
"chars": 1530,
"preview": "/*\n (C) 2020 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform vec2 pi;\nuniform vec2 gamma;\n\nuniform sampler2D colo"
},
{
"path": "demonstration/shaders/fragment/material-diffuse.frag",
"chars": 188,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform struct\n { vec4 diffuse\n ;\n } p3d_Material;\n\nout v"
},
{
"path": "demonstration/shaders/fragment/material-specular.frag",
"chars": 329,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\n#define MAX_SHININESS 127.75\n\nuniform struct\n { vec3 specul"
},
{
"path": "demonstration/shaders/fragment/median-filter.frag",
"chars": 1872,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\n#define MAX_SIZE 4\n#define MAX_KERNEL_SIZE ((MAX_SIZE"
},
{
"path": "demonstration/shaders/fragment/motion-blur.frag",
"chars": 1530,
"preview": "/*\n (C) 2020 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D positionTexture;\nuniform sampler2D colorTe"
},
{
"path": "demonstration/shaders/fragment/normal.frag",
"chars": 1240,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform float osg_FrameTime;\n\nuniform sampler2D p3d_Texture1"
},
{
"path": "demonstration/shaders/fragment/outline.frag",
"chars": 2769,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform vec2 gamma;\n\nuniform sampler2D positionTexture;\nunif"
},
{
"path": "demonstration/shaders/fragment/pixelize.frag",
"chars": 873,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D colorTexture;\nuniform sampler2D positionTe"
},
{
"path": "demonstration/shaders/fragment/position.frag",
"chars": 243,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nin vec4 vertexPosition;\n\nout vec4 fragColor;\n\nvoid main() {\n"
},
{
"path": "demonstration/shaders/fragment/posterize.frag",
"chars": 1077,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform vec2 gamma;\n\nuniform sampler2D colorTexture;\nuniform"
},
{
"path": "demonstration/shaders/fragment/reflection-color.frag",
"chars": 1019,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D uvTexture;\nuniform sampler2D colorTexture;"
},
{
"path": "demonstration/shaders/fragment/reflection.frag",
"chars": 666,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D colorTexture;\nuniform sampler2D colorBlurT"
},
{
"path": "demonstration/shaders/fragment/refraction.frag",
"chars": 1488,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform vec2 pi;\nuniform vec2 gamma;\n\nuniform sampler2D uvTe"
},
{
"path": "demonstration/shaders/fragment/scene-combine.frag",
"chars": 1717,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform vec2 pi;\nuniform vec2 gamma;\n\nuniform sampler2D base"
},
{
"path": "demonstration/shaders/fragment/screen-space-reflection.frag",
"chars": 3779,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform mat4 lensProjection;\n\nuniform sampler2D positionText"
},
{
"path": "demonstration/shaders/fragment/screen-space-refraction.frag",
"chars": 3494,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform mat4 lensProjection;\n\nuniform sampler2D positionFrom"
},
{
"path": "demonstration/shaders/fragment/sharpen.frag",
"chars": 991,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform sampler2D colorTexture;\n\nuniform vec2 enabled;\n\nout "
},
{
"path": "demonstration/shaders/fragment/ssao.frag",
"chars": 2176,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\n#define NUM_SAMPLES 8\n#define NUM_NOISE 4\n\nuniform mat4 le"
},
{
"path": "demonstration/shaders/vertex/base.vert",
"chars": 1548,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\n#define NUMBER_OF_LIGHTS 4\n\nuniform mat4 p3d_ModelViewMatrix"
},
{
"path": "demonstration/shaders/vertex/basic.vert",
"chars": 202,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#version 150\n\nuniform mat4 p3d_ModelViewProjectionMatrix;\n\nin vec4 p3d_Ver"
},
{
"path": "demonstration/shaders/vertex/discard.vert",
"chars": 114,
"preview": "/*\n (C) 2020 David Lettier\n lettier.com\n*/\n\n#version 150\n\nvoid main()\n{\n gl_Position = vec4(vec3(2.0), 1.0);\n}\n"
},
{
"path": "demonstration/src/LICENSE",
"chars": 1513,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2019, David Lettier\nAll rights reserved.\n\nRedistribution and use in source and binar"
},
{
"path": "demonstration/src/main.cxx",
"chars": 97717,
"preview": "/*\n (C) 2019 David Lettier\n lettier.com\n*/\n\n#include <thread>\n#include <unistd.h>\n#include <random>\n#include <string>\n"
},
{
"path": "docs/_build-docs.sh",
"chars": 1588,
"preview": "#!/usr/bin/env bash\n\nSCRIPT_PATH=\"$(cd \"$(dirname \"$0\")\"; pwd -P)\"\nMAIN_TITLE=\"3D Game Shaders For Beginners\"\nREPO_URL=\""
},
{
"path": "docs/_template.html5",
"chars": 3200,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"$lang$\" xml:lang=\"$lang$\"$if(dir)$ dir=\"$dir$\"$endif$>\n"
},
{
"path": "docs/blinn-phong.html",
"chars": 9952,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/bloom.html",
"chars": 13233,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/blur.html",
"chars": 41338,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/building-the-demo.html",
"chars": 13239,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/cel-shading.html",
"chars": 11986,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/chromatic-aberration.html",
"chars": 11454,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/deferred-rendering.html",
"chars": 6145,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/depth-of-field.html",
"chars": 13694,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/dilation.html",
"chars": 15903,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/film-grain.html",
"chars": 20127,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/flow-mapping.html",
"chars": 13411,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/foam.html",
"chars": 16255,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/fog.html",
"chars": 14668,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/fresnel-factor.html",
"chars": 14306,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/gamma-correction.html",
"chars": 14596,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/glsl.html",
"chars": 10542,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/index.html",
"chars": 5453,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/lighting.html",
"chars": 37162,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/lookup-table.html",
"chars": 17087,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/motion-blur.html",
"chars": 19063,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/normal-mapping.html",
"chars": 17026,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/outlining.html",
"chars": 25208,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/pixelization.html",
"chars": 10141,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/posterization.html",
"chars": 13112,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/reference-frames.html",
"chars": 5504,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/render-to-texture.html",
"chars": 6139,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/rim-lighting.html",
"chars": 12710,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/running-the-demo.html",
"chars": 10660,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/screen-space-reflection.html",
"chars": 66353,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/screen-space-refraction.html",
"chars": 27710,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/setup.html",
"chars": 12288,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/sharpen.html",
"chars": 11266,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/ssao.html",
"chars": 38912,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "docs/style.css",
"chars": 4417,
"preview": "html {\n font-size: 100%;\n overflow-y: scroll;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n}\n\nbody "
},
{
"path": "docs/texturing.html",
"chars": 11384,
"preview": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n <head>\n <meta charset=\"utf-8\" />\n "
},
{
"path": "sections/blinn-phong.md",
"chars": 2515,
"preview": "[:arrow_backward:](lighting.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright)"
},
{
"path": "sections/bloom.md",
"chars": 3111,
"preview": "[:arrow_backward:](blur.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright)\n[:a"
},
{
"path": "sections/blur.md",
"chars": 13164,
"preview": "[:arrow_backward:](fog.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright)\n[:ar"
},
{
"path": "sections/building-the-demo.md",
"chars": 3812,
"preview": "[:arrow_backward:](setup.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright)\n[:"
},
{
"path": "sections/cel-shading.md",
"chars": 3022,
"preview": "[:arrow_backward:](rim-lighting.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyri"
},
{
"path": "sections/chromatic-aberration.md",
"chars": 2570,
"preview": "[:arrow_backward:](motion-blur.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyrig"
},
{
"path": "sections/deferred-rendering.md",
"chars": 3184,
"preview": "[:arrow_backward:](normal-mapping.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copy"
},
{
"path": "sections/depth-of-field.md",
"chars": 4021,
"preview": "[:arrow_backward:](outlining.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright"
},
{
"path": "sections/dilation.md",
"chars": 3944,
"preview": "[:arrow_backward:](sharpen.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright)\n"
},
{
"path": "sections/film-grain.md",
"chars": 5706,
"preview": "[:arrow_backward:](dilation.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright)"
},
{
"path": "sections/flow-mapping.md",
"chars": 3617,
"preview": "[:arrow_backward:](foam.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright)\n[:a"
},
{
"path": "sections/foam.md",
"chars": 4712,
"preview": "[:arrow_backward:](screen-space-refraction.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_smal"
},
{
"path": "sections/fog.md",
"chars": 3579,
"preview": "[:arrow_backward:](deferred-rendering.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#"
},
{
"path": "sections/fresnel-factor.md",
"chars": 4784,
"preview": "[:arrow_backward:](blinn-phong.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyrig"
},
{
"path": "sections/gamma-correction.md",
"chars": 6085,
"preview": "[:arrow_backward:](lookup-table.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyri"
},
{
"path": "sections/glsl.md",
"chars": 2829,
"preview": "[:arrow_backward:](reference-frames.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#co"
},
{
"path": "sections/lighting.md",
"chars": 15345,
"preview": "[:arrow_backward:](texturing.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright"
},
{
"path": "sections/lookup-table.md",
"chars": 6152,
"preview": "[:arrow_backward:](film-grain.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyrigh"
},
{
"path": "sections/motion-blur.md",
"chars": 5552,
"preview": "[:arrow_backward:](ssao.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright)\n[:a"
},
{
"path": "sections/normal-mapping.md",
"chars": 5329,
"preview": "[:arrow_backward:](cel-shading.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyrig"
},
{
"path": "sections/outlining.md",
"chars": 8560,
"preview": "[:arrow_backward:](flow-mapping.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyri"
},
{
"path": "sections/pixelization.md",
"chars": 1952,
"preview": "[:arrow_backward:](posterization.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyr"
},
{
"path": "sections/posterization.md",
"chars": 3401,
"preview": "[:arrow_backward:](depth-of-field.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copy"
},
{
"path": "sections/reference-frames.md",
"chars": 2508,
"preview": "[:arrow_backward:](running-the-demo.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#co"
},
{
"path": "sections/render-to-texture.md",
"chars": 3122,
"preview": "[:arrow_backward:](glsl.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright)\n[:a"
},
{
"path": "sections/rim-lighting.md",
"chars": 3227,
"preview": "[:arrow_backward:](fresnel-factor.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copy"
},
{
"path": "sections/running-the-demo.md",
"chars": 3670,
"preview": "[:arrow_backward:](building-the-demo.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#c"
},
{
"path": "sections/screen-space-reflection.md",
"chars": 32592,
"preview": "[:arrow_backward:](chromatic-aberration.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:]"
},
{
"path": "sections/screen-space-refraction.md",
"chars": 13987,
"preview": "[:arrow_backward:](screen-space-reflection.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_smal"
},
{
"path": "sections/setup.md",
"chars": 4255,
"preview": "[:arrow_backward:](gamma-correction.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#co"
},
{
"path": "sections/sharpen.md",
"chars": 2158,
"preview": "[:arrow_backward:](pixelization.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyri"
},
{
"path": "sections/ssao.md",
"chars": 15100,
"preview": "[:arrow_backward:](bloom.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#copyright)\n[:"
},
{
"path": "sections/texturing.md",
"chars": 2644,
"preview": "[:arrow_backward:](render-to-texture.md)\n[:arrow_double_up:](../README.md)\n[:arrow_up_small:](#)\n[:arrow_down_small:](#c"
}
]
// ... and 6 more files (download for full content)
About this extraction
This page contains the full source code of the lettier/3d-game-shaders-for-beginners GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 121 files (935.1 KB), approximately 281.3k tokens, and a symbol index with 29 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.