Initial commit: Final state of the master project
This commit is contained in:
1732
Research/shaders/CombinedStackRaytrace.frag
Normal file
1732
Research/shaders/CombinedStackRaytrace.frag
Normal file
File diff suppressed because it is too large
Load Diff
66
Research/shaders/DepthPeel.frag
Normal file
66
Research/shaders/DepthPeel.frag
Normal file
@@ -0,0 +1,66 @@
|
||||
#version 330 core
|
||||
#define $colorType$
|
||||
|
||||
in vec3 pos;
|
||||
in vec3 normal;
|
||||
#if defined(TEXTURE_COLORS) || defined(TEXTURE_AND_VERTEX_COLORS)
|
||||
in vec2 uv;
|
||||
#endif
|
||||
#if defined(VERTEX_COLORS) || defined(TEXTURE_AND_VERTEX_COLORS)
|
||||
in vec3 vertColor;
|
||||
#endif
|
||||
|
||||
uniform sampler2D textureSampler;
|
||||
uniform sampler2D lastDepthMap;
|
||||
uniform float reflectivity;
|
||||
|
||||
uniform bool firstPass;
|
||||
uniform float depthMargin;
|
||||
uniform vec3 cameraDir;
|
||||
|
||||
|
||||
layout (location = 0) out vec3 color;
|
||||
//layout (location = 1) out float depthOut;
|
||||
layout (location = 1) out float angleOut;
|
||||
layout (location = 2) out vec3 normalOut;
|
||||
layout (location = 3) out float reflectivityOut;
|
||||
|
||||
void main() {
|
||||
#if defined(TEXTURE_COLORS)
|
||||
vec4 fullColor = texture(textureSampler, uv);
|
||||
#endif
|
||||
#if defined(VERTEX_COLORS)
|
||||
vec4 fullColor = vec4(vertColor, 1.0f);
|
||||
#endif
|
||||
#if defined(TEXTURE_AND_VERTEX_COLORS)
|
||||
vec4 fullColor = texture(textureSampler, uv) * vec4(vertColor, 1.0f);
|
||||
#endif
|
||||
#ifdef NO_COLORS
|
||||
vec4 fullColor = vec4(1.0f);
|
||||
#endif
|
||||
|
||||
//Discard transparent fragments
|
||||
if (fullColor.a < 0.5) {
|
||||
discard;
|
||||
}
|
||||
else
|
||||
{
|
||||
float lastDepth = texelFetch(lastDepthMap, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0).r;
|
||||
if (!firstPass && (lastDepth - gl_FragCoord.z) >= -depthMargin)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
color = fullColor.rgb;
|
||||
//vec3 lightDirection = normalize(vec3(0.25, -0.6, -1));
|
||||
//color *= 0.3 + 0.7 * max(dot(-lightDirection, normalize(normal)), 0);
|
||||
// Scale the normal between 0 and 1
|
||||
normalOut = 0.5 + (normal * 0.5);
|
||||
// Calculate the angle of the normal of this position with the camera
|
||||
//angleOut = 1.;
|
||||
if (normal == vec3(0))
|
||||
angleOut = 1;
|
||||
else
|
||||
angleOut = abs(dot(cameraDir, normalize(normal)));
|
||||
}
|
||||
reflectivityOut = reflectivity;
|
||||
}
|
||||
32
Research/shaders/DepthPeel.vert
Normal file
32
Research/shaders/DepthPeel.vert
Normal file
@@ -0,0 +1,32 @@
|
||||
#version 330 core
|
||||
#define $colorType$
|
||||
|
||||
layout (location = $vertexPosition$) in vec3 vertexPosition;
|
||||
layout (location = $vertexNormal$) in vec3 vertexNormal;
|
||||
|
||||
uniform mat4 MVP;
|
||||
|
||||
out vec3 pos;
|
||||
out vec3 normal;
|
||||
|
||||
#if defined(TEXTURE_COLORS) || defined(TEXTURE_AND_VERTEX_COLORS)
|
||||
layout(location = $vertexUV$) in vec2 vertexUV;
|
||||
out vec2 uv;
|
||||
#endif
|
||||
#if defined(VERTEX_COLORS) || defined(TEXTURE_AND_VERTEX_COLORS)
|
||||
layout(location = $vertexColor$) in vec3 vertexColor;
|
||||
out vec3 vertColor;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
pos = vertexPosition;
|
||||
normal = vertexNormal;
|
||||
gl_Position = MVP * vec4(vertexPosition, 1.0f);
|
||||
#if defined(TEXTURE_COLORS) || defined(TEXTURE_AND_VERTEX_COLORS)
|
||||
uv = vertexUV;
|
||||
#endif
|
||||
#if defined(VERTEX_COLORS) || defined(TEXTURE_AND_VERTEX_COLORS)
|
||||
vertColor = vertexColor;
|
||||
#endif
|
||||
|
||||
}
|
||||
45
Research/shaders/GI.frag
Normal file
45
Research/shaders/GI.frag
Normal file
@@ -0,0 +1,45 @@
|
||||
#version 430 core
|
||||
|
||||
in vec2 UV;
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D shadeless;
|
||||
uniform sampler2D direct;
|
||||
uniform sampler2D indirect;
|
||||
|
||||
const int kernelSize = 5;
|
||||
const float[kernelSize][kernelSize] kernel = {
|
||||
{ 2.0, 4.0, 5.0, 4.0, 2.0 },
|
||||
{ 4.0, 9.0, 12.0, 9.0, 4.0 },
|
||||
{ 5.0, 12.0, 15.0, 12.0, 5.0 },
|
||||
{ 4.0, 9.0, 12.0, 9.0, 4.0 },
|
||||
{ 2.0, 4.0, 5.0, 4.0, 2.0 },
|
||||
};
|
||||
const float kernelNormalizer = 1.0 / 115.0;
|
||||
const float lightStrength = 1.0;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
||||
ivec2 screenSize = textureSize(shadeless, 0);
|
||||
|
||||
vec4 smoothIndirect = vec4(0);
|
||||
ivec2 startCoord = ivec2(screenSize * UV) - ((kernelSize - 1) / 2);
|
||||
for (int i = 0; i < kernelSize; i++) {
|
||||
for (int j = 0; j < kernelSize; j++) {
|
||||
ivec2 coord = startCoord + ivec2(i, j);
|
||||
if (coord.x >= 0 && coord.y >= 0)
|
||||
smoothIndirect += kernel[i][j] * texelFetch(indirect, coord, 0);
|
||||
}
|
||||
}
|
||||
smoothIndirect *= kernelNormalizer * lightStrength;
|
||||
|
||||
vec4 shadelessPx = texture(shadeless, UV);
|
||||
vec4 directPx = texture(direct, UV);
|
||||
|
||||
//color = shadelessPx * smoothIndirect;
|
||||
color = shadelessPx * directPx + shadelessPx * smoothIndirect;
|
||||
//color = texture(indirect, UV);
|
||||
|
||||
|
||||
}
|
||||
254
Research/shaders/Raytrace1.frag
Normal file
254
Research/shaders/Raytrace1.frag
Normal file
@@ -0,0 +1,254 @@
|
||||
#version 440 core
|
||||
|
||||
in vec3 pos;
|
||||
in vec2 uv;
|
||||
in vec3 normal;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D textureSampler;
|
||||
uniform usampler3D octreeSampler;
|
||||
|
||||
layout(location = $width$) uniform int width;
|
||||
layout(location = $height$) uniform int height;
|
||||
layout(location = $angle$) uniform float angle;
|
||||
layout(location = $aspect$) uniform float aspect;
|
||||
|
||||
layout(location = $lightDirection$) uniform vec3 lightDirection;
|
||||
layout(location = $cameraPosition$) uniform vec3 cameraPosition;
|
||||
|
||||
ivec3 texSize;
|
||||
|
||||
//************************************
|
||||
// Intersection test between ray and cube, also gives intersection points as p0 + tmin * ray and p0 + tmax * ray
|
||||
//************************************
|
||||
bool rayCube(vec3 p0, vec3 ray, vec3 center, float extent, out float tmin, out float tmax, out uint minFace, out uint maxFace) {
|
||||
|
||||
// Translate ray origin based on cube center
|
||||
p0 -= center;
|
||||
|
||||
// Get t from ray and cube's plane equations and use it to get the intersection coordinates
|
||||
float t1 = -(dot(p0, vec3(1., 0., 0.)) - extent) / dot(ray, vec3(1., 0., 0.)); vec3 test1 = p0 + t1*ray;
|
||||
float t2 = -(dot(p0, vec3(-1., 0., 0.)) - extent) / dot(ray, vec3(-1., 0., 0.)); vec3 test2 = p0 + t2*ray;
|
||||
float t3 = -(dot(p0, vec3(0., 1., 0.)) - extent) / dot(ray, vec3(0., 1., 0.)); vec3 test3 = p0 + t3*ray;
|
||||
float t4 = -(dot(p0, vec3(0., -1., 0.)) - extent) / dot(ray, vec3(0., -1., 0.)); vec3 test4 = p0 + t4*ray;
|
||||
float t5 = -(dot(p0, vec3(0., 0., 1.)) - extent) / dot(ray, vec3(0., 0., 1.)); vec3 test5 = p0 + t5*ray;
|
||||
float t6 = -(dot(p0, vec3(0., 0., -1.)) - extent) / dot(ray, vec3(0., 0., -1.)); vec3 test6 = p0 + t6*ray;
|
||||
|
||||
// Check if t was not negative and that the ray-plane intersection falls within the cube face
|
||||
if (t1 < 0. || any(greaterThan(test1.yz, vec2(extent))) || any(lessThan(test1.yz, vec2(-extent))))
|
||||
t1 = 0.;
|
||||
if (t2 < 0. || any(greaterThan(test2.yz, vec2(extent))) || any(lessThan(test2.yz, vec2(-extent))))
|
||||
t2 = 0.;
|
||||
if (t3 < 0. || any(greaterThan(test3.xz, vec2(extent))) || any(lessThan(test3.xz, vec2(-extent))))
|
||||
t3 = 0.;
|
||||
if (t4 < 0. || any(greaterThan(test4.xz, vec2(extent))) || any(lessThan(test4.xz, vec2(-extent))))
|
||||
t4 = 0.;
|
||||
if (t5 < 0. || any(greaterThan(test5.xy, vec2(extent))) || any(lessThan(test5.xy, vec2(-extent))))
|
||||
t5 = 0.;
|
||||
if (t6 < 0. || any(greaterThan(test6.xy, vec2(extent))) || any(lessThan(test6.xy, vec2(-extent))))
|
||||
t6 = 0.;
|
||||
|
||||
// Initialize tmin and tmax values that define the two intersection points
|
||||
tmin = 9999999999.;
|
||||
tmax = 0.;
|
||||
|
||||
// Use the lowest value of t that is not 0 for tmin
|
||||
if (t1 > 0. && t1 < tmin) { tmin = t1; minFace = 1; }
|
||||
if (t2 > 0. && t2 < tmin) { tmin = t2; minFace = 2; }
|
||||
if (t3 > 0. && t3 < tmin) { tmin = t3; minFace = 3; }
|
||||
if (t4 > 0. && t4 < tmin) { tmin = t4; minFace = 4; }
|
||||
if (t5 > 0. && t5 < tmin) { tmin = t5; minFace = 5; }
|
||||
if (t6 > 0. && t6 < tmin) { tmin = t6; minFace = 6; }
|
||||
|
||||
// Use the highest value of t that is not 0 for tmax
|
||||
if (t1 > 0. && t1 > tmax) { tmax = t1; maxFace = 1; }
|
||||
if (t2 > 0. && t2 > tmax) { tmax = t2; maxFace = 2; }
|
||||
if (t3 > 0. && t3 > tmax) { tmax = t3; maxFace = 3; }
|
||||
if (t4 > 0. && t4 > tmax) { tmax = t4; maxFace = 4; }
|
||||
if (t5 > 0. && t5 > tmax) { tmax = t5; maxFace = 5; }
|
||||
if (t6 > 0. && t6 > tmax) { tmax = t6; maxFace = 6; }
|
||||
|
||||
// If tmin = tmax, the ray origin is within the cube, so set tmin to 0
|
||||
if (tmin == tmax)
|
||||
tmin = 0.;
|
||||
|
||||
// If tmax is not 0, an intersection was found
|
||||
return tmax > 0.;
|
||||
}
|
||||
|
||||
uvec3 getUloc(vec3 p0, vec3 ray, float t, uint hitFace)
|
||||
{
|
||||
vec3 samplePoint = p0 + t * ray;
|
||||
vec3 raySign = clamp(sign(ray), -1, 0);
|
||||
// Calculate the location of the first leaf node that the ray enters
|
||||
uvec3 uLoc = uvec3(floor(samplePoint));
|
||||
// If the ray is moving in a negative direction, then the uLoc will be one position above the desired position.
|
||||
switch(hitFace)
|
||||
{
|
||||
case 1: case 2: uLoc.x = uint(int(round(samplePoint.x + raySign.x))); break;
|
||||
case 3: case 4: uLoc.y = uint(int(round(samplePoint.y + raySign.y))); break;
|
||||
case 5: case 6: uLoc.z = uint(int(round(samplePoint.z + raySign.z))); break;
|
||||
}
|
||||
return uLoc;
|
||||
}
|
||||
|
||||
ivec3 wrapNodePointer(in ivec3 samplePos)
|
||||
{
|
||||
// Make sure that the indices are wrapped if the pointer doesn't fit in the current texture
|
||||
if (samplePos.x >= texSize.x)
|
||||
{
|
||||
samplePos.x = samplePos.x % texSize.x;
|
||||
samplePos.y++;
|
||||
if (samplePos.y >= texSize.y)
|
||||
{
|
||||
samplePos.y = samplePos.y % texSize.y;
|
||||
samplePos.z++;
|
||||
}
|
||||
//return vec4(255, 255, 0, float($max_level$ + 1));
|
||||
}
|
||||
return samplePos;
|
||||
}
|
||||
|
||||
//************************************
|
||||
// Given a pointer to a node, and it's childmask, and some child index
|
||||
// returns the nodePointer to the child at the given index.
|
||||
// Note that if the child doesn't exist, it still returns some pointer as if it would.
|
||||
//************************************
|
||||
uvec3 getNodePointer(uvec3 curNodePointer, uint childMask, uint childIndex)
|
||||
{
|
||||
// Based on the childIndex and the childmask, find out what the index of the childpointer is
|
||||
int childPointerIndex = bitCount(childMask << (31 - childIndex));
|
||||
|
||||
// Find sample position in 3D texture corresponding to current node and locat
|
||||
ivec3 samplePos = ivec3(curNodePointer);
|
||||
samplePos.x += childPointerIndex;
|
||||
|
||||
samplePos = wrapNodePointer(samplePos);
|
||||
|
||||
// Fetch the pointer from the texture
|
||||
return texelFetch(octreeSampler, samplePos, 0).rgb;
|
||||
}
|
||||
|
||||
// Fetches the childmask of the node at curNodePointer (note that this is not a mask for leaf nodes!)
|
||||
uint getChildMask(in uvec3 nodePointer)
|
||||
{
|
||||
return texelFetch(octreeSampler, ivec3(nodePointer), 0).b;
|
||||
}
|
||||
|
||||
bool hasChild(in uint childMask, in uint childIndex)
|
||||
{
|
||||
uint mask = 1 << childIndex;
|
||||
return (childMask & mask) == mask;
|
||||
}
|
||||
|
||||
uint getChildIndex(uvec3 uLoc, uint level)
|
||||
{
|
||||
uint range = 1 << ($max_level$ - level);
|
||||
return ((uLoc.x & range) == range ? 1 : 0)
|
||||
+ ((uLoc.y & range) == range ? 2 : 0)
|
||||
+ ((uLoc.z & range) == range ? 4 : 0);
|
||||
}
|
||||
|
||||
uvec4 sampleOctree(in uvec3 uLoc)
|
||||
{
|
||||
uvec3 result = uvec3(0);
|
||||
uint childMask; uint childIndex;
|
||||
// Traverse octree
|
||||
uint i = 0;
|
||||
for (; i <= $max_level$; ++i) {
|
||||
// Read the childmask (stored in "blue"):
|
||||
childMask = getChildMask(result);
|
||||
|
||||
// Find the index of the child in which the sampleposition is located
|
||||
childIndex = getChildIndex(uLoc, i);
|
||||
|
||||
if (!hasChild(childMask, childIndex))
|
||||
break;
|
||||
|
||||
result = getNodePointer(result, childMask, childIndex);
|
||||
}
|
||||
// Return level reached
|
||||
return uvec4(result, i);
|
||||
}
|
||||
|
||||
uvec3 getColor(uvec3 nodePointer)
|
||||
{
|
||||
return texelFetch(octreeSampler, ivec3(nodePointer), 0).rgb;
|
||||
}
|
||||
|
||||
void main() {
|
||||
uint maxLoop = 300;
|
||||
texSize = textureSize(octreeSampler, 0);
|
||||
|
||||
// Set color using textures
|
||||
color = texture(textureSampler, uv);
|
||||
|
||||
// Scale the grid so that all leaf cells have a width of exactly 1:
|
||||
float extent = $extent$;
|
||||
uint range = 1 << ($max_level$ + 1);
|
||||
float rangeF = float(range);
|
||||
float scale = rangeF / (extent * 2.);
|
||||
float offset = extent + 0.5 / scale;
|
||||
|
||||
// Get ray and sample point
|
||||
vec3 ray = normalize(pos - cameraPosition);
|
||||
uvec3 raySignMask = uvec3(clamp(sign(-ray), 0, 1));
|
||||
vec3 p0 = (cameraPosition + offset) * scale;
|
||||
|
||||
// Calculate the new position of the root
|
||||
vec3 rootCenter = vec3(range) * 0.5;
|
||||
float rootExtent = float(range) * 0.5;
|
||||
|
||||
// Initialize some variables
|
||||
float tmin, tmax, tminRoot, tmaxRoot;
|
||||
uint minFace, maxFace;
|
||||
|
||||
float leafExtent = 0.5;
|
||||
|
||||
// Start the ray at the edge of the root cube:
|
||||
bool collision = rayCube(p0, ray, rootCenter, rootExtent, tminRoot, tmaxRoot, minFace, maxFace);
|
||||
if (!collision) // Ray doesn't intersect with root.
|
||||
{
|
||||
//color.rgb = vec3(0,0,1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find cell through which the ray enters
|
||||
uvec3 uLoc = getUloc(p0, ray, tminRoot, minFace);
|
||||
|
||||
// Keep testing ray box intersection, but prevent endless looping
|
||||
int loop = 0;
|
||||
while (!any(greaterThanEqual(uLoc, uvec3(range))) && !any(lessThan(uLoc, uvec3(0))) && loop < maxLoop) {
|
||||
// Check if the current voxel contains geometry, and if so draw it
|
||||
uvec4 result = sampleOctree(uLoc);
|
||||
if (result.w >= $max_level$ + 1)
|
||||
{
|
||||
//color.rgb = vec3(result) / 255.;
|
||||
color.rgb = vec3(float(loop) / 20.);
|
||||
break;
|
||||
}
|
||||
|
||||
//uint reachedLevelRange = 1 << ($max_level$ - result.w + 1);
|
||||
//float reachedLevelExtent = float(reachedLevelRange) * 0.5;
|
||||
//reachedLevelExtent = 0.5;
|
||||
|
||||
// Otherwise, advance to the next voxel
|
||||
vec3 curCubeCenter = uLoc + leafExtent;
|
||||
if (!rayCube(p0, ray, curCubeCenter, leafExtent, tmin, tmax, minFace, maxFace)) {
|
||||
//color.rgb = vec3(1, float(maxFace) / 6., 0);
|
||||
color.rgb = uLoc / range;
|
||||
break;
|
||||
}
|
||||
|
||||
uLoc = getUloc(p0, ray, tmax, maxFace);
|
||||
|
||||
++loop;
|
||||
}
|
||||
if (loop == maxLoop)
|
||||
color.rgb = vec3(1, 0, 0);
|
||||
|
||||
// Discard pixels that are transparent
|
||||
if (color.a < 0.5)
|
||||
discard;
|
||||
}
|
||||
19
Research/shaders/RenderTexture.frag
Normal file
19
Research/shaders/RenderTexture.frag
Normal file
@@ -0,0 +1,19 @@
|
||||
#version 330 core
|
||||
|
||||
in vec2 UV;
|
||||
|
||||
out vec3 color;
|
||||
|
||||
uniform sampler2D depthTexture;
|
||||
uniform sampler2D renderTexture;
|
||||
uniform bool showDepth = false;
|
||||
|
||||
void main(){
|
||||
if (showDepth)
|
||||
{
|
||||
color = vec3(texture2D( depthTexture, UV ).r ) ;
|
||||
} else
|
||||
{
|
||||
color = texture(renderTexture, UV).xyz;
|
||||
}
|
||||
}
|
||||
12
Research/shaders/RenderTexture.vert
Normal file
12
Research/shaders/RenderTexture.vert
Normal file
@@ -0,0 +1,12 @@
|
||||
#version 330 core
|
||||
|
||||
// Input vertex data, different for all executions of this shader.
|
||||
layout(location = 0) in vec3 vertexPosition_modelspace;
|
||||
|
||||
// Output data ; will be interpolated for each fragment.
|
||||
out vec2 UV;
|
||||
|
||||
void main(){
|
||||
gl_Position = vec4(vertexPosition_modelspace,1);
|
||||
UV = (vertexPosition_modelspace.xy+vec2(1,1))/2.0;
|
||||
}
|
||||
87
Research/shaders/SSAO.frag
Normal file
87
Research/shaders/SSAO.frag
Normal file
@@ -0,0 +1,87 @@
|
||||
#version 430 core
|
||||
in vec2 UV;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D depthTexture;
|
||||
uniform sampler2D renderTexture;
|
||||
|
||||
//layout(location = $MVP$) uniform mat4 MVP;
|
||||
//layout(location = $invMVP$) uniform mat4 invMVP;
|
||||
|
||||
const float total_strength = 1.0;
|
||||
const float base = 0.2;
|
||||
|
||||
const float area = 0.0075;
|
||||
const float falloff = 0.00005;
|
||||
|
||||
const float radius = 0.0002;
|
||||
|
||||
const int sampleCount = 20;
|
||||
const vec3 samples[20] = {
|
||||
vec3(0.576112, -0.307923, 0.273497), vec3(-0.239062, 0.014342, -0.512609),
|
||||
vec3(-0.578527, 0.692620, 0.009409), vec3(-0.496125, 0.306383, -0.508048),
|
||||
vec3(-0.620389, 0.266880, 0.483354), vec3(-0.478377, 0.521577, 0.611179),
|
||||
vec3(0.250791, 0.168587, -0.066709), vec3(0.936988, -0.118714, -0.235831),
|
||||
vec3(0.310220, 0.289636, 0.046191), vec3(-0.604985, 0.514587, 0.180593),
|
||||
vec3(0.253899, 0.730909, 0.587989), vec3(-0.097092, -0.047744, -0.110424),
|
||||
vec3(-0.357070, 0.877361, 0.020189), vec3(0.550173, 0.220257, -0.754331),
|
||||
vec3(0.574418, 0.637574, -0.445669), vec3(0.170666, -0.597387, -0.366459),
|
||||
vec3(0.269777, 0.234300, -0.577843), vec3(-0.702647, -0.090661, -0.628000),
|
||||
vec3(-0.798998, -0.013601, 0.191734),vec3(-0.229475, 0.020532, -0.938973)
|
||||
};
|
||||
|
||||
vec3 normalFromDepth(float depth, vec2 UV) {
|
||||
|
||||
const vec2 offset1 = vec2(0.0, 0.001);
|
||||
const vec2 offset2 = vec2(0.001, 0.0);
|
||||
|
||||
float depth1 = texture(depthTexture, UV + offset1).r;
|
||||
float depth2 = texture(depthTexture, UV + offset2).r;
|
||||
|
||||
vec3 p1 = vec3(offset1, depth1 - depth);
|
||||
vec3 p2 = vec3(offset2, depth2 - depth);
|
||||
|
||||
vec3 normal = cross(p1, p2);
|
||||
normal.z = -normal.z;
|
||||
|
||||
return normalize(normal);
|
||||
}
|
||||
|
||||
float rand(vec2 co){
|
||||
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
float ssao()
|
||||
{
|
||||
// Stolen from: http://theorangeduck.com/page/pure-depth-ssao
|
||||
float depth = texture(depthTexture, UV).r;
|
||||
vec3 random = vec3(rand(UV), rand(vec2(UV.x, UV.y + 1.0)), rand(vec2(UV.x + 1.0, UV.y)));
|
||||
vec3 position = vec3(UV, depth);
|
||||
vec3 normal = normalFromDepth(depth, UV);
|
||||
|
||||
float radius_depth = radius/depth;
|
||||
float occlusion = 0.0;
|
||||
for(int i=0; i < sampleCount; i++) {
|
||||
vec3 ray = radius_depth * reflect(samples[i], random);
|
||||
vec3 hemi_ray = position + sign(dot(ray,normal)) * ray;
|
||||
|
||||
float occ_depth = texture(depthTexture, clamp(hemi_ray.xy, vec2(0.0), vec2(1.0))).r;
|
||||
float difference = depth - occ_depth;
|
||||
|
||||
occlusion += step(falloff, difference) * (1.0-smoothstep(falloff, area, difference));
|
||||
}
|
||||
return 1.0 - total_strength * occlusion * (1.0 / float(sampleCount));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
//color = texture(renderTexture, UV).rgba;
|
||||
float depth = texture(depthTexture, UV).r;
|
||||
color = texture(renderTexture, UV).rgba;
|
||||
if (depth < 0.98)
|
||||
{
|
||||
color *= ssao();
|
||||
}
|
||||
//color = vec4(vec3(depth), 1);
|
||||
}
|
||||
165
Research/shaders/SSAO2.frag
Normal file
165
Research/shaders/SSAO2.frag
Normal file
@@ -0,0 +1,165 @@
|
||||
#version 430 core
|
||||
/*
|
||||
SSAO GLSL shader v1.2
|
||||
assembled by Martins Upitis (martinsh) (devlog-martinsh.blogspot.com)
|
||||
original technique is made by Arkano22 (www.gamedev.net/topic/550699-ssao-no-halo-artifacts/)
|
||||
|
||||
changelog:
|
||||
1.2 - added fog calculation to mask AO. Minor fixes.
|
||||
1.1 - added spiral sampling method from here:
|
||||
(http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere)
|
||||
*/
|
||||
in vec2 UV;
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D depthTexture;
|
||||
uniform sampler2D renderTexture;
|
||||
layout(location = $width$) uniform int renderTextureWidth;
|
||||
layout(location = $height$) uniform int renderTextureHeight;
|
||||
|
||||
#define PI 3.14159265
|
||||
|
||||
float width = renderTextureWidth; //texture width
|
||||
float height = renderTextureHeight; //texture height
|
||||
|
||||
//------------------------------------------
|
||||
//general stuff
|
||||
|
||||
//make sure that these two values are the same for your camera, otherwise distances will be wrong.
|
||||
|
||||
float znear = 100.0; //Z-near
|
||||
float zfar = 1024.0; //Z-far
|
||||
|
||||
//user variables
|
||||
int samples = 32; //ao sample count
|
||||
|
||||
float radius = 2.0; //ao radius
|
||||
float aoclamp = 0.001; //depth clamp - reduces haloing at screen edges
|
||||
bool noise = true; //use noise instead of pattern for sample dithering
|
||||
float noiseamount = 0.0002; //dithering amount
|
||||
|
||||
float diffarea = 0.05; //self-shadowing reduction
|
||||
float gdisplace = 0.05; //gauss bell center
|
||||
|
||||
bool onlyAO = false; //use only ambient occlusion pass?
|
||||
float lumInfluence = 0.2; //how much luminance affects occlusion
|
||||
|
||||
//--------------------------------------------------------
|
||||
|
||||
vec2 rand(vec2 coord) //generating noise/pattern texture for dithering
|
||||
{
|
||||
float noiseX = ((fract(1.0-coord.s*(width/2.0))*0.25)+(fract(coord.t*(height/2.0))*0.75))*2.0-1.0;
|
||||
float noiseY = ((fract(1.0-coord.s*(width/2.0))*0.75)+(fract(coord.t*(height/2.0))*0.25))*2.0-1.0;
|
||||
|
||||
if (noise)
|
||||
{
|
||||
noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0;
|
||||
noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0;
|
||||
}
|
||||
return vec2(noiseX,noiseY)*noiseamount;
|
||||
}
|
||||
|
||||
float readDepth(in vec2 coord)
|
||||
{
|
||||
if (UV.x < 0.0 || UV.y < 0.0) return 1.0;
|
||||
return (2.0 * znear) / (zfar + znear - texture2D(depthTexture, coord).x * (zfar-znear));
|
||||
}
|
||||
|
||||
float compareDepths(in float depth1, in float depth2,inout int far)
|
||||
{
|
||||
float garea = 2.0; //gauss bell width
|
||||
float diff = (depth1 - depth2)*100.0; //depth difference (0-100)
|
||||
//reduce left bell width to avoid self-shadowing
|
||||
if (diff<gdisplace)
|
||||
{
|
||||
garea = diffarea;
|
||||
}else{
|
||||
far = 1;
|
||||
}
|
||||
|
||||
float gauss = pow(2.7182,-2.0*(diff-gdisplace)*(diff-gdisplace)/(garea*garea));
|
||||
return gauss;
|
||||
}
|
||||
|
||||
float calAO(float depth,float dw, float dh)
|
||||
{
|
||||
float dd = (1.0-depth)*radius;
|
||||
|
||||
float temp = 0.0;
|
||||
float temp2 = 0.0;
|
||||
float coordw = UV.x + dw*dd;
|
||||
float coordh = UV.y + dh*dd;
|
||||
float coordw2 = UV.x - dw*dd;
|
||||
float coordh2 = UV.y - dh*dd;
|
||||
|
||||
vec2 coord = vec2(coordw , coordh);
|
||||
vec2 coord2 = vec2(coordw2, coordh2);
|
||||
|
||||
int far = 0;
|
||||
temp = compareDepths(depth, readDepth(coord),far);
|
||||
//DEPTH EXTRAPOLATION:
|
||||
if (far > 0)
|
||||
{
|
||||
temp2 = compareDepths(readDepth(coord2),depth,far);
|
||||
temp += (1.0-temp)*temp2;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec2 noise = rand(UV);
|
||||
float depth = readDepth(UV);
|
||||
//color = vec4(vec3(texture(depthTexture, UV).x), 1);
|
||||
//color = vec4(vec3(depth) * 10.0, 1);
|
||||
//return;
|
||||
|
||||
float w = (1.0 / width)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x));
|
||||
float h = (1.0 / height)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y));
|
||||
|
||||
float pw;
|
||||
float ph;
|
||||
|
||||
float ao = 0;
|
||||
|
||||
float dl = PI*(3.0-sqrt(5.0));
|
||||
float dz = 1.0/float(samples);
|
||||
float l = 0.0;
|
||||
float z = 1.0 - dz/2.0;
|
||||
|
||||
for (int i = 0; i <= samples; i ++)
|
||||
{
|
||||
float r = sqrt(1.0-z);
|
||||
|
||||
pw = cos(l)*r;
|
||||
ph = sin(l)*r;
|
||||
ao += calAO(depth,pw*w,ph*h);
|
||||
z = z - dz;
|
||||
l = l + dl;
|
||||
}
|
||||
|
||||
ao /= float(samples);
|
||||
ao = 1.0-ao;
|
||||
//ao = pow(ao, 2.0);
|
||||
|
||||
//color = vec4(vec3(ao), 1);
|
||||
//return;
|
||||
|
||||
vec3 renderColor = texture(renderTexture, UV).rgb;
|
||||
|
||||
vec3 lumcoeff = vec3(0.299,0.587,0.114);
|
||||
float lum = dot(renderColor, lumcoeff);
|
||||
vec3 luminance = vec3(lum, lum, lum);
|
||||
|
||||
//color = vec4(vec3(lum), 1);
|
||||
//return;
|
||||
|
||||
vec3 final = vec3(renderColor*mix(vec3(ao),vec3(1.0),luminance*lumInfluence));//mix(color*ao, white, luminance)
|
||||
|
||||
if (onlyAO)
|
||||
final = vec3(mix(vec3(ao),vec3(1.0),luminance*lumInfluence)); //ambient occlusion only
|
||||
|
||||
color = vec4(final, 1.0);
|
||||
|
||||
}
|
||||
189
Research/shaders/SSDS.frag
Normal file
189
Research/shaders/SSDS.frag
Normal file
@@ -0,0 +1,189 @@
|
||||
#version 430 core
|
||||
|
||||
#define $Material$
|
||||
#if defined(MT_NORMAL) | defined(MT_COLORNORMAL) | defined(MT_COLORNORMALREFLECTIVITY)
|
||||
const bool SHADE_DIFFUSE = false;
|
||||
#else
|
||||
const bool SHADE_DIFFUSE = true;
|
||||
#endif
|
||||
|
||||
in vec2 UV;
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D depthTexture;
|
||||
uniform sampler2D renderTexture;
|
||||
uniform sampler2D voxelPositionsTexture;
|
||||
layout(location = $width$) uniform int width;
|
||||
layout(location = $height$) uniform int height;
|
||||
layout(location = $MVP$) uniform mat4x4 MVP;
|
||||
|
||||
layout(location = $lightDirection$) uniform vec3 lightDirection;
|
||||
layout(location = $lightType$) uniform int lightType;
|
||||
|
||||
const uint range = 1 << ($max_level$ + 1);
|
||||
const float extent = $extent$;
|
||||
const float rangeF = float(range);
|
||||
const float scale = rangeF / (extent * 2.);
|
||||
const float offset = extent + 0.5 / scale;
|
||||
|
||||
const int SAMPLE_DISTANCE = 3;
|
||||
const float MAX_DISTANCE = 0.02 * rangeF;
|
||||
|
||||
const float ssaoRadius = 2.0;
|
||||
const float ssaoPower = 2.0;
|
||||
|
||||
#define SSAO_KERNEL_SIZE 10
|
||||
|
||||
const vec3[SSAO_KERNEL_SIZE] SSAO_KERNEL = {
|
||||
vec3(-0.013627260795642221, -0.08986502062675834, 0.04169623281496606),
|
||||
vec3(0.1530762079182679, -0.07153954612140453, 0.08688940044738859),
|
||||
vec3(0.07090584436998379, 0.1490828023178984, 0.22615631604538947),
|
||||
vec3(-0.15616336851550036, -0.26564930875054044, 0.20480099388003975),
|
||||
vec3(0.26677241220752623, 0.28676826613128037, 0.2412393865541797),
|
||||
vec3(-0.3475187558492847, -0.15578006191669713, 0.39681643948076967),
|
||||
vec3(0.3887426730563284, 0.02398677725666013, 0.5078422675022826),
|
||||
vec3(0.49626198926704007, -0.21014511667561903, 0.49240538984266874),
|
||||
vec3(-0.5032145340980271, 0.5942213554886051, 0.2570527443031691),
|
||||
vec3(0.5983551080400994, 0.25120169632241235, 0.6379411198904361)
|
||||
};
|
||||
|
||||
#define PI 3.14159265
|
||||
|
||||
//vec3 screenToWorld(vec3 screen) {
|
||||
|
||||
// vec4 homogeniousWorld = invMVP * vec4(screen * 2.0 - 1.0, 1);
|
||||
// homogeniousWorld /= homogeniousWorld.z;
|
||||
// return homogeniousWorld.xyz;
|
||||
//}
|
||||
|
||||
vec3 NormalFromTriangleVertices(vec3 triangleVertices[3])
|
||||
{
|
||||
// now is same as RedBook (OpenGL Programming Guide)
|
||||
vec3 u = triangleVertices[0] - triangleVertices[1];
|
||||
vec3 v = triangleVertices[1] - triangleVertices[2];
|
||||
return normalize(cross(u, v));
|
||||
}
|
||||
|
||||
float getDiffuseLight(vec3 normal, vec3 position)
|
||||
{
|
||||
if (lightType == 0) return 1.0;
|
||||
else if (lightType == 1) return max(dot(-lightDirection, normal), 0);
|
||||
else if (lightType == 2)
|
||||
{
|
||||
vec3 toLight = lightDirection / scale - position;
|
||||
vec3 lightDir = normalize(toLight);
|
||||
return max(dot(lightDir, normal), 0);
|
||||
}
|
||||
}
|
||||
|
||||
float rand(vec2 n)
|
||||
{
|
||||
return 0.5 + 0.5 * fract(sin(dot(n.xy, vec2(12.9898, 78.233)))* 43758.5453);
|
||||
}
|
||||
|
||||
vec3 getTangent(vec3 normal)
|
||||
{
|
||||
vec3 tangent;
|
||||
vec3 c1 = cross(normal, vec3(0.0, 0.0, 1.0));
|
||||
vec3 c2 = cross(normal, vec3(0.0, 1.0, 0.0));
|
||||
|
||||
if (length(c1)>length(c2))
|
||||
tangent = c1;
|
||||
else
|
||||
tangent = c2;
|
||||
|
||||
return normalize(tangent);
|
||||
}
|
||||
|
||||
vec3 voxelGridToWorld(vec3 voxelGridCoord)
|
||||
{
|
||||
return (voxelGridCoord / scale) - offset;
|
||||
}
|
||||
|
||||
vec4 worldToScreen(vec3 sam)
|
||||
{
|
||||
vec4 samUV = vec4(sam , 1.0);
|
||||
samUV = MVP * samUV;
|
||||
samUV.xy /= samUV.w;
|
||||
samUV.xy = samUV.xy * 0.5 + 0.5;
|
||||
return samUV;
|
||||
}
|
||||
|
||||
// Calculates the SSAO occlusion
|
||||
float SSAO(vec3 pos, vec3 normal)
|
||||
{
|
||||
// Rotate our kernel
|
||||
vec3 rvec = vec3(rand(UV), rand(normal.xy), rand(pos.xy));
|
||||
vec3 tangent = normalize(rvec - normal * dot(rvec, normal));
|
||||
vec3 bitangent = cross(normal, tangent);
|
||||
mat3 tbn = mat3(tangent, bitangent, normal);
|
||||
|
||||
float occlusion = 0.0;
|
||||
for (int i = 0; i < SSAO_KERNEL_SIZE; i++) {
|
||||
// get sample position:
|
||||
vec3 sam = tbn * SSAO_KERNEL[i];
|
||||
sam = sam * ssaoRadius + pos;
|
||||
vec3 towardsSam = sam - pos;
|
||||
float samDot = dot(normal, towardsSam);
|
||||
|
||||
|
||||
// project sample position:
|
||||
vec4 samUV = worldToScreen(sam);
|
||||
|
||||
// get sample depth:
|
||||
vec3 sampledPos = voxelGridToWorld(texture(voxelPositionsTexture, samUV.xy).xyz);
|
||||
vec3 towardsSampledPos = sampledPos - pos;
|
||||
float sampledDot = dot(normal, towardsSampledPos);
|
||||
|
||||
//color = vec4(towardsSampledPos, 1);
|
||||
|
||||
//return abs(sampledDot * 1.0) / rangeF;
|
||||
|
||||
// range check & accumulate:
|
||||
float rangeCheck = abs(sampledDot) < ssaoRadius ? 1.0 : 0.0;
|
||||
occlusion += (sampledDot >= samDot ? 1.0 : 0.0) * rangeCheck;
|
||||
}
|
||||
return pow(1.0 - (occlusion / float(SSAO_KERNEL_SIZE)), ssaoPower);
|
||||
}
|
||||
|
||||
|
||||
void main(void)
|
||||
{
|
||||
color = texture(renderTexture, UV);
|
||||
|
||||
// Get the voxel positions in the center, left, right, top bottom:
|
||||
ivec2 screenCoord = ivec2(UV * vec2(width, height));
|
||||
vec3 c = texelFetch(voxelPositionsTexture, screenCoord, 0).xyz;
|
||||
vec3 pos = voxelGridToWorld(c);
|
||||
|
||||
if (c == vec3(0)) return; // If no vertex position is known, don't do further processing
|
||||
vec3 l = texelFetch(voxelPositionsTexture, screenCoord + ivec2(-SAMPLE_DISTANCE, 0), 0).xyz;
|
||||
vec3 r = texelFetch(voxelPositionsTexture, screenCoord + ivec2(+SAMPLE_DISTANCE, 0), 0).xyz;
|
||||
vec3 t = texelFetch(voxelPositionsTexture, screenCoord + ivec2(0, +SAMPLE_DISTANCE), 0).xyz;
|
||||
vec3 b = texelFetch(voxelPositionsTexture, screenCoord + ivec2(0, -SAMPLE_DISTANCE), 0).xyz;
|
||||
|
||||
// Check if we need to dispose any location as they are too far away (in world space);
|
||||
bool ignoreL = length(l - c) > MAX_DISTANCE;
|
||||
bool ignoreR = length(r - c) > MAX_DISTANCE;
|
||||
bool ignoreT = length(t - c) > MAX_DISTANCE;
|
||||
bool ignoreB = length(t - b) > MAX_DISTANCE;
|
||||
|
||||
vec3 normal = vec3(0);
|
||||
|
||||
// Make some triangles and calculate the normal based on those triangles
|
||||
if (!ignoreT && !ignoreR) { vec3 triangle1[3] = { t, c, r }; normal += NormalFromTriangleVertices(triangle1); }
|
||||
if (!ignoreR && !ignoreB) { vec3 triangle2[3] = { r, c, b }; normal += NormalFromTriangleVertices(triangle2); }
|
||||
if (!ignoreB && !ignoreL) { vec3 triangle3[3] = { b, c, l }; normal += NormalFromTriangleVertices(triangle3); }
|
||||
if (!ignoreL && !ignoreT) { vec3 triangle4[3] = { l, c, t }; normal += NormalFromTriangleVertices(triangle4); }
|
||||
|
||||
normal = normalize(normal);
|
||||
//color = vec4(normal == vec3(0) ? 1.0 : 0.0); return;
|
||||
//color = vec4(normal, 1); return;
|
||||
|
||||
if (SHADE_DIFFUSE)
|
||||
color *= (0.4 + 0.6 * getDiffuseLight(normal, pos));
|
||||
|
||||
float occlusion = SSAO(pos, normal);
|
||||
color *= occlusion;
|
||||
|
||||
}
|
||||
234
Research/shaders/Shader.frag
Normal file
234
Research/shaders/Shader.frag
Normal file
@@ -0,0 +1,234 @@
|
||||
#version 440 core
|
||||
|
||||
in vec3 pos;
|
||||
in vec2 uv;
|
||||
in vec3 normal;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D textureSampler;
|
||||
uniform usampler3D octreeSampler;
|
||||
|
||||
layout(location = $width$) uniform int width;
|
||||
layout(location = $height$) uniform int height;
|
||||
layout(location = $angle$) uniform float angle;
|
||||
layout(location = $aspect$) uniform float aspect;
|
||||
|
||||
layout(location = $lightDirection$) uniform vec3 lightDirection;
|
||||
layout(location = $cameraPosition$) uniform vec3 cameraPosition;
|
||||
|
||||
|
||||
//************************************
|
||||
// Intersection test between ray and cube, also gives intersection points as p0 + tmin * ray and p0 + tmax * ray
|
||||
//************************************
|
||||
bool rayCube(vec3 p0, vec3 ray, vec3 center, float extent, out float tmin, out float tmax, out uint minFace, out uint maxFace) {
|
||||
|
||||
// Translate ray origin based on cube center
|
||||
p0 -= center;
|
||||
|
||||
// Get t from ray and cube's plane equations and use it to get the intersection coordinates
|
||||
float t1 = -(dot(p0, vec3(1., 0., 0.)) - extent) / dot(ray, vec3(1., 0., 0.)); vec3 test1 = p0 + t1*ray;
|
||||
float t2 = -(dot(p0, vec3(-1., 0., 0.)) - extent) / dot(ray, vec3(-1., 0., 0.)); vec3 test2 = p0 + t2*ray;
|
||||
float t3 = -(dot(p0, vec3(0., 1., 0.)) - extent) / dot(ray, vec3(0., 1., 0.)); vec3 test3 = p0 + t3*ray;
|
||||
float t4 = -(dot(p0, vec3(0., -1., 0.)) - extent) / dot(ray, vec3(0., -1., 0.)); vec3 test4 = p0 + t4*ray;
|
||||
float t5 = -(dot(p0, vec3(0., 0., 1.)) - extent) / dot(ray, vec3(0., 0., 1.)); vec3 test5 = p0 + t5*ray;
|
||||
float t6 = -(dot(p0, vec3(0., 0., -1.)) - extent) / dot(ray, vec3(0., 0., -1.)); vec3 test6 = p0 + t6*ray;
|
||||
|
||||
// Check if t was not negative and that the ray-plane intersection falls within the cube face
|
||||
if (t1 < 0. || any(greaterThanEqual(test1.yz, vec2(extent))) || any(lessThanEqual(test1.yz, vec2(-extent))))
|
||||
t1 = 0.;
|
||||
if (t2 < 0. || any(greaterThanEqual(test2.yz, vec2(extent))) || any(lessThanEqual(test2.yz, vec2(-extent))))
|
||||
t2 = 0.;
|
||||
if (t3 < 0. || any(greaterThanEqual(test3.xz, vec2(extent))) || any(lessThanEqual(test3.xz, vec2(-extent))))
|
||||
t3 = 0.;
|
||||
if (t4 < 0. || any(greaterThanEqual(test4.xz, vec2(extent))) || any(lessThanEqual(test4.xz, vec2(-extent))))
|
||||
t4 = 0.;
|
||||
if (t5 < 0. || any(greaterThanEqual(test5.xy, vec2(extent))) || any(lessThanEqual(test5.xy, vec2(-extent))))
|
||||
t5 = 0.;
|
||||
if (t6 < 0. || any(greaterThanEqual(test6.xy, vec2(extent))) || any(lessThanEqual(test6.xy, vec2(-extent))))
|
||||
t6 = 0.;
|
||||
|
||||
// Initialize tmin and tmax values that define the two intersection points
|
||||
tmin = 9999999999.;
|
||||
tmax = 0.;
|
||||
|
||||
// Use the lowest value of t that is not 0 for tmin
|
||||
if (t1 > 0. && t1 <= tmin) tmin = t1;
|
||||
if (t2 > 0. && t2 <= tmin) tmin = t2;
|
||||
if (t3 > 0. && t3 <= tmin) tmin = t3;
|
||||
if (t4 > 0. && t4 <= tmin) tmin = t4;
|
||||
if (t5 > 0. && t5 <= tmin) tmin = t5;
|
||||
if (t6 > 0. && t6 <= tmin) tmin = t6;
|
||||
|
||||
// Use the highest value of t that is not 0 for tmax
|
||||
if (t1 > 0. && t1 >= tmax) tmax = t1;
|
||||
if (t2 > 0. && t2 >= tmax) tmax = t2;
|
||||
if (t3 > 0. && t3 >= tmax) tmax = t3;
|
||||
if (t4 > 0. && t4 >= tmax) tmax = t4;
|
||||
if (t5 > 0. && t5 >= tmax) tmax = t5;
|
||||
if (t6 > 0. && t6 >= tmax) tmax = t6;
|
||||
|
||||
// If tmin = tmax, the ray origin is within the cube, so set tmin to 0
|
||||
if (tmin == tmax)
|
||||
tmin = 0.;
|
||||
|
||||
// Figure out which face the ray exits
|
||||
if (t1 == tmin) minFace = 1;
|
||||
if (t2 == tmin) minFace = 2;
|
||||
if (t3 == tmin) minFace = 3;
|
||||
if (t4 == tmin) minFace = 4;
|
||||
if (t5 == tmin) minFace = 5;
|
||||
if (t6 == tmin) minFace = 6;
|
||||
|
||||
if (t1 == tmax) maxFace = 1;
|
||||
if (t2 == tmax) maxFace = 2;
|
||||
if (t3 == tmax) maxFace = 3;
|
||||
if (t4 == tmax) maxFace = 4;
|
||||
if (t5 == tmax) maxFace = 5;
|
||||
if (t6 == tmax) maxFace = 6;
|
||||
|
||||
// If tmax is not 0, an intersection was found
|
||||
return tmax > 0.;
|
||||
}
|
||||
|
||||
//************************************
|
||||
// Sample the octree at a location, return if geometry is present here and return deepest level reached when traversing
|
||||
//************************************
|
||||
uvec4 sampleOctree(vec3 loc) {
|
||||
ivec3 texSize = textureSize(octreeSampler, 0);
|
||||
|
||||
// Set location in range (0,2^$max_level$)
|
||||
uint range = 1 << $max_level$;
|
||||
loc = range + range * loc / $extent$;
|
||||
uvec3 uLoc = uvec3(loc.x, loc.y, loc.z);
|
||||
|
||||
uvec3 result = uvec3(0);
|
||||
|
||||
// Traverse octree
|
||||
uint i = 0;
|
||||
for (; i <= $max_level$; ++i) {
|
||||
|
||||
if (i == $max_level$)
|
||||
{ // Leaf node was reached, fetch the full color:
|
||||
return uvec4(texelFetch(octreeSampler, ivec3(result), 0).rgb, i);
|
||||
}
|
||||
|
||||
// Read the childmask (stored in "blue"):
|
||||
uint childMask = texelFetch(octreeSampler, ivec3(result), 0).b;
|
||||
|
||||
// If the mask is empty, we got a child node
|
||||
if (childMask == 0)
|
||||
break;
|
||||
|
||||
// Find the index of the child in which the sampleposition is located
|
||||
range = 1 << ($max_level$ - i);
|
||||
uint childIndex = ((uLoc.x & range) == range ? 1 : 0)
|
||||
+ ((uLoc.y & range) == range ? 2 : 0)
|
||||
+ ((uLoc.z & range) == range ? 4 : 0);
|
||||
|
||||
uint mask = 1 << childIndex;
|
||||
if ((childMask & mask) == 0) // The child doesn't exist, even though this is not a leaf node
|
||||
break;//return vec4(255, 255, 0, float($max_level$ + 1));
|
||||
// Based on this index and the childmask, find out what the index of the childpointer is
|
||||
uint childPointerIndex = 0;
|
||||
for(int j = 0; j < 8; j++)
|
||||
{
|
||||
uint mask = 1 << j;
|
||||
if ((childMask & mask) == mask)
|
||||
childPointerIndex++;
|
||||
if (j == childIndex)
|
||||
break;
|
||||
}
|
||||
// Find sample position in 3D texture corresponding to current node and location
|
||||
uvec3 samplePos = result;
|
||||
samplePos.x += childPointerIndex;
|
||||
if (samplePos.x >= texSize.x)
|
||||
{
|
||||
samplePos.x = samplePos.x % texSize.x;
|
||||
samplePos.y++;
|
||||
if (samplePos.y >= texSize.y)
|
||||
{
|
||||
samplePos.y = samplePos.y % texSize.y;
|
||||
samplePos.z++;
|
||||
}
|
||||
//return vec4(255, 255, 0, float($max_level$ + 1));
|
||||
}
|
||||
|
||||
result = texelFetch(octreeSampler, ivec3(samplePos), 0).rgb;
|
||||
|
||||
// If not, this is not a leaf node, so result actually contains a pointer to the 3D location of the child
|
||||
// Multiply the location by two to go to next level
|
||||
//loc *= 2.;
|
||||
}
|
||||
// Return level reached, and the pointer found there?
|
||||
return uvec4(result, i);
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
uint maxLoop = 4096;
|
||||
|
||||
// Set color using textures
|
||||
color = texture(textureSampler, uv);
|
||||
|
||||
// Get ray and sample point
|
||||
vec3 ray = normalize(pos - cameraPosition);
|
||||
|
||||
vec3 samplePoint = cameraPosition;
|
||||
float extent = $extent$;
|
||||
float tmin, tmax;
|
||||
uint minFace = 0;
|
||||
uint maxFace;
|
||||
uint crap;
|
||||
|
||||
// Calculate the rayCube intersection with the root:
|
||||
float tmaxRoot, tminRoot;
|
||||
if (!rayCube(cameraPosition, ray, vec3(0.), extent, tminRoot, tmaxRoot, crap, crap))
|
||||
return;
|
||||
float t = tminRoot;
|
||||
|
||||
// Keep testing ray box intersection, but prevent endless looping
|
||||
int loop = 0;
|
||||
while (t < tmaxRoot && loop < maxLoop) {
|
||||
|
||||
samplePoint = cameraPosition + t * ray + 0.001 * ray;
|
||||
|
||||
// Sample octree at sample point and store reached level
|
||||
uvec4 result = sampleOctree(samplePoint);
|
||||
uint reached_level = result.w;
|
||||
|
||||
// If the reached level is max_level + 1, we have reached geometry, so color the pixel and break from loop
|
||||
if (reached_level == $max_level$) {
|
||||
color.rgb = /*(loop / 120.) * (0. + (float(minFace) * 0.16666666)) **/ (vec3(result) / 255.);
|
||||
//color.rgb = samplePoint / $extent$;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set cube center to 0 and current extent to overall extent
|
||||
vec3 cubeCenter = vec3(0.);
|
||||
float currentExtent = extent;
|
||||
// Convert relative sample point to (-1,1) range for easier computations
|
||||
vec3 relativeSamplePoint = samplePoint / extent;
|
||||
|
||||
// Loop through all reached levels
|
||||
for (int j = 0; j <= reached_level; ++j) {
|
||||
// At every level, compute the cube center of the node that was sampled at this level and the sample point relative to this node
|
||||
cubeCenter += sign(relativeSamplePoint) * .5 * currentExtent;
|
||||
relativeSamplePoint = sign(relativeSamplePoint) * (-1. + 2. * abs(relativeSamplePoint));
|
||||
currentExtent *= .5;
|
||||
}
|
||||
|
||||
// Use the obtained cube center to do another ray-box intersection test
|
||||
rayCube(cameraPosition, ray, cubeCenter, currentExtent, tmin, tmax, minFace, maxFace);
|
||||
|
||||
t = tmax;
|
||||
|
||||
++loop;
|
||||
}
|
||||
if (loop == maxLoop)
|
||||
color.rgb = vec3(1, 0,0);
|
||||
|
||||
// Discard pixels that are transparent
|
||||
if (color.a < 0.5)
|
||||
discard;
|
||||
}
|
||||
18
Research/shaders/Shader.vert
Normal file
18
Research/shaders/Shader.vert
Normal file
@@ -0,0 +1,18 @@
|
||||
#version 430 core
|
||||
|
||||
layout(location = $vertexPosition$) in vec3 vertexPosition;
|
||||
layout(location = $vertexUV$) in vec2 vertexUV;
|
||||
layout(location = $vertexNormal$) in vec3 vertexNormal;
|
||||
|
||||
layout(location = $MVP$) uniform mat4 MVP;
|
||||
|
||||
out vec3 pos;
|
||||
out vec2 uv;
|
||||
out vec3 normal;
|
||||
|
||||
void main() {
|
||||
pos = vertexPosition;
|
||||
uv = vertexUV;
|
||||
normal = vertexNormal;
|
||||
gl_Position = MVP * vec4(vertexPosition, 1.0f);
|
||||
}
|
||||
175
Research/shaders/ShaderLoader.cpp
Normal file
175
Research/shaders/ShaderLoader.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
#include "ShaderLoader.h"
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include "../inc/gl/glew.h"
|
||||
#include "../Renderer.h"
|
||||
#include "../PropertyLoader.h"
|
||||
|
||||
|
||||
ShaderLoader* ShaderLoader::mInstance = NULL;
|
||||
|
||||
void ShaderLoader::Create() {
|
||||
if (mInstance == NULL)
|
||||
mInstance = new ShaderLoader();
|
||||
}
|
||||
|
||||
void ShaderLoader::Destroy() {
|
||||
if (mInstance != NULL)
|
||||
delete mInstance;
|
||||
mInstance = NULL;
|
||||
}
|
||||
|
||||
ShaderLoader* ShaderLoader::Instance() {
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
void ShaderLoader::SetShaderPath(std::string shaderPath)
|
||||
{
|
||||
mShaderPath = shaderPath;
|
||||
}
|
||||
|
||||
std::string ShaderLoader::GetShaderPath() {
|
||||
return mShaderPath;
|
||||
}
|
||||
|
||||
// Load shader
|
||||
unsigned ShaderLoader::LoadShader(const char* vertexFileName, const char* fragmentFileName, std::map<std::string, std::string> additionalProperties) {
|
||||
|
||||
// Create the shaders
|
||||
unsigned vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
|
||||
unsigned fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
std::string vertexPath = mShaderPath;
|
||||
std::string fragmentPath = mShaderPath;
|
||||
vertexPath.append(vertexFileName);
|
||||
fragmentPath.append(fragmentFileName);
|
||||
|
||||
// Read the vertex shader code from the file
|
||||
std::string vertexShaderCode;
|
||||
std::ifstream vertexShaderStream(vertexPath, std::ios::in);
|
||||
if (vertexShaderStream.is_open()) {
|
||||
std::string line;
|
||||
while (getline(vertexShaderStream, line)) {
|
||||
ParseProperties(line, '$', additionalProperties);
|
||||
ParseProperties(line, '%', additionalProperties);
|
||||
vertexShaderCode += "\n" + line;
|
||||
}
|
||||
vertexShaderStream.close();
|
||||
}
|
||||
|
||||
// Read the fragment shader code from the file
|
||||
std::string fragmentShaderCode;
|
||||
std::ifstream fragmentShaderStream(fragmentPath, std::ios::in);
|
||||
if (fragmentShaderStream.is_open()) {
|
||||
std::string line = "";
|
||||
while (getline(fragmentShaderStream, line)) {
|
||||
ParseProperties(line, '$', additionalProperties);
|
||||
ParseProperties(line, '%', additionalProperties);
|
||||
fragmentShaderCode += "\n" + line;
|
||||
}
|
||||
fragmentShaderStream.close();
|
||||
}
|
||||
|
||||
int result = GL_FALSE;
|
||||
int infoLogLength;
|
||||
|
||||
// Compile vertex shader
|
||||
if (verbose) printf("Compiling shader : %s\n", vertexFileName);
|
||||
char const* vertexSourcePointer = vertexShaderCode.c_str();
|
||||
glShaderSource(vertexShaderID, 1, &vertexSourcePointer, NULL);
|
||||
glCompileShader(vertexShaderID);
|
||||
|
||||
// Check vertex shader
|
||||
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &result);
|
||||
glGetShaderiv(vertexShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
|
||||
if (infoLogLength > 0)
|
||||
{
|
||||
std::vector<char> vertexShaderErrorMessage(infoLogLength);
|
||||
glGetShaderInfoLog(vertexShaderID, infoLogLength, NULL, &vertexShaderErrorMessage[0]);
|
||||
fprintf(stdout, "%s\n", &vertexShaderErrorMessage[0]);
|
||||
}
|
||||
|
||||
// Compile fragment shader
|
||||
if (verbose) printf("Compiling shader : %s\n", fragmentFileName);
|
||||
char const * fragmentSourcePointer = fragmentShaderCode.c_str();
|
||||
glShaderSource(fragmentShaderID, 1, &fragmentSourcePointer, NULL);
|
||||
glCompileShader(fragmentShaderID);
|
||||
|
||||
// Check fragment shader
|
||||
glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &result);
|
||||
glGetShaderiv(fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
|
||||
if (infoLogLength > 0)
|
||||
{
|
||||
std::vector<char> fragmentShaderErrorMessage(infoLogLength);
|
||||
glGetShaderInfoLog(fragmentShaderID, infoLogLength, NULL, &fragmentShaderErrorMessage[0]);
|
||||
if (fragmentShaderErrorMessage.size() > 1)
|
||||
fprintf(stdout, "%s\n", &fragmentShaderErrorMessage[0]);
|
||||
}
|
||||
|
||||
// Link the program
|
||||
if (verbose) fprintf(stdout, "Linking program\n");
|
||||
unsigned programID = glCreateProgram();
|
||||
glAttachShader(programID, vertexShaderID);
|
||||
glAttachShader(programID, fragmentShaderID);
|
||||
glLinkProgram(programID);
|
||||
|
||||
// Check the program
|
||||
glGetProgramiv(programID, GL_LINK_STATUS, &result);
|
||||
glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength);
|
||||
std::vector<char> programErrorMessage(glm::max(infoLogLength, int(1)));
|
||||
glGetProgramInfoLog(programID, infoLogLength, NULL, &programErrorMessage[0]);
|
||||
if (programErrorMessage.size() > 1)
|
||||
fprintf(stdout, "%s\n", &programErrorMessage[0]);
|
||||
|
||||
glDeleteShader(vertexShaderID);
|
||||
glDeleteShader(fragmentShaderID);
|
||||
|
||||
return programID;
|
||||
}
|
||||
|
||||
ShaderLoader::ShaderLoader() {
|
||||
PropertyLoader::Create();
|
||||
mShaderPath = "../Research/shaders/";
|
||||
}
|
||||
|
||||
ShaderLoader::~ShaderLoader() {
|
||||
|
||||
}
|
||||
|
||||
//************************************
|
||||
// Parse shader properties, i.e. text between delimiters
|
||||
//************************************
|
||||
void ShaderLoader::ParseProperties(std::string &line, char delimiter, std::map<std::string, std::string> additionalProperties) {
|
||||
size_t open = 0, close = 0;
|
||||
bool inProperty = false;
|
||||
size_t i = 0;
|
||||
while(i < line.size()) {
|
||||
// Whenever a delimiter is found, toggle between in and out of property
|
||||
if (line[i] == delimiter)
|
||||
{
|
||||
if (inProperty)
|
||||
{
|
||||
// If we were in a property, this delimiter marks the end of it.
|
||||
// Replace all text between open and close by an additional property
|
||||
close = i;
|
||||
std::string identifier = line.substr(open + 1, close - open - 1);
|
||||
auto addProp = additionalProperties.find(identifier);
|
||||
std::string value;
|
||||
if (addProp != additionalProperties.end())
|
||||
value = addProp->second;
|
||||
else
|
||||
value = PropertyLoader::Instance()->GetProperty("shader_" + identifier);
|
||||
if (value.empty()) return;
|
||||
line.replace(open, close - open + 1, value);
|
||||
i = open + value.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we were NOT in a property, this is the start of one
|
||||
open = i;
|
||||
}
|
||||
inProperty = !inProperty;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
27
Research/shaders/ShaderLoader.h
Normal file
27
Research/shaders/ShaderLoader.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
class ShaderLoader {
|
||||
|
||||
public:
|
||||
static void Create();
|
||||
static void Destroy();
|
||||
static ShaderLoader* Instance();
|
||||
unsigned LoadShader(const char* vertexFileName = "Shader.vert", const char* fragmentFileName = "Shader.frag", const std::map<std::string, std::string> additionalProperties = std::map<std::string, std::string>());
|
||||
|
||||
void SetShaderPath(std::string shaderPath);
|
||||
std::string GetShaderPath();
|
||||
protected:
|
||||
|
||||
private:
|
||||
ShaderLoader();
|
||||
~ShaderLoader();
|
||||
void ParseProperties(std::string &line, char delimiter, const std::map<std::string, std::string> additionalProperties = std::map<std::string, std::string>());
|
||||
|
||||
static ShaderLoader* mInstance;
|
||||
|
||||
std::string mShaderPath;
|
||||
|
||||
bool verbose;
|
||||
};
|
||||
340
Research/shaders/StackRaytrace.frag
Normal file
340
Research/shaders/StackRaytrace.frag
Normal file
@@ -0,0 +1,340 @@
|
||||
#version 440 core
|
||||
|
||||
in vec3 pos;
|
||||
in vec2 uv;
|
||||
in vec3 normal;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D textureSampler;
|
||||
uniform usampler3D octreeSampler;
|
||||
|
||||
layout(location = $width$) uniform int width;
|
||||
layout(location = $height$) uniform int height;
|
||||
layout(location = $angle$) uniform float angle;
|
||||
layout(location = $aspect$) uniform float aspect;
|
||||
|
||||
layout(location = $lightDirection$) uniform vec3 lightDirection;
|
||||
layout(location = $cameraPosition$) uniform vec3 cameraPosition;
|
||||
|
||||
struct Ray
|
||||
{
|
||||
vec3 p0;
|
||||
vec3 dir;
|
||||
vec3 invDir;
|
||||
vec3 dirSign;
|
||||
uvec3 dirSignNegMask;
|
||||
};
|
||||
|
||||
ivec3 texSize;
|
||||
const uint range = 1 << ($max_level$ + 1);
|
||||
const vec3 rootCenter = vec3(range) * 0.5;
|
||||
const float rootExtent = float(range) * 0.5;
|
||||
|
||||
// Initialize the stack
|
||||
uvec3 pointerStack[$max_level$ + 1];
|
||||
vec3 positionStack[$max_level$ + 1];
|
||||
float extentStack[$max_level$ + 1];
|
||||
|
||||
uint stackPos;
|
||||
|
||||
Ray getRay(vec3 p0, vec3 dir)
|
||||
{
|
||||
dir = normalize(dir);
|
||||
vec3 dirSign = sign(dir);
|
||||
return Ray(
|
||||
p0,
|
||||
dir,
|
||||
1 / dir,
|
||||
dirSign,
|
||||
uvec3(-clamp(sign(dir), -1, 0)));
|
||||
}
|
||||
|
||||
vec3 sampleRay(Ray ray, float time)
|
||||
{
|
||||
return ray.dir * time + ray.p0;
|
||||
}
|
||||
|
||||
//************************************
|
||||
// Intersection test between ray and cube, also gives intersection points as p0 + tmin * ray and p0 + tmax * ray
|
||||
//************************************
|
||||
bool rayCube(in Ray ray, in vec3 center, in float extent, out float tmin, out float tmax, out vec3 minAxis, out vec3 maxAxis) {
|
||||
|
||||
// Translate ray origin based on cube center
|
||||
vec3 p0 = ray.p0 - center;
|
||||
|
||||
// Get t from ray and cube's plane equations and use it to get the intersection coordinates
|
||||
float t1 = -(dot(p0, vec3(1., 0., 0.)) - extent) / dot(ray.dir, vec3(1., 0., 0.)); vec3 test1 = p0 + t1*ray.dir;
|
||||
float t2 = -(dot(p0, vec3(-1., 0., 0.)) - extent) / dot(ray.dir, vec3(-1., 0., 0.)); vec3 test2 = p0 + t2*ray.dir;
|
||||
float t3 = -(dot(p0, vec3(0., 1., 0.)) - extent) / dot(ray.dir, vec3(0., 1., 0.)); vec3 test3 = p0 + t3*ray.dir;
|
||||
float t4 = -(dot(p0, vec3(0., -1., 0.)) - extent) / dot(ray.dir, vec3(0., -1., 0.)); vec3 test4 = p0 + t4*ray.dir;
|
||||
float t5 = -(dot(p0, vec3(0., 0., 1.)) - extent) / dot(ray.dir, vec3(0., 0., 1.)); vec3 test5 = p0 + t5*ray.dir;
|
||||
float t6 = -(dot(p0, vec3(0., 0., -1.)) - extent) / dot(ray.dir, vec3(0., 0., -1.)); vec3 test6 = p0 + t6*ray.dir;
|
||||
|
||||
// Check if t was not negative and that the ray-plane intersection falls within the cube face
|
||||
if (t1 < 0. || any(greaterThan(test1.yz, vec2(extent))) || any(lessThan(test1.yz, vec2(-extent))))
|
||||
t1 = 0.;
|
||||
if (t2 < 0. || any(greaterThan(test2.yz, vec2(extent))) || any(lessThan(test2.yz, vec2(-extent))))
|
||||
t2 = 0.;
|
||||
if (t3 < 0. || any(greaterThan(test3.xz, vec2(extent))) || any(lessThan(test3.xz, vec2(-extent))))
|
||||
t3 = 0.;
|
||||
if (t4 < 0. || any(greaterThan(test4.xz, vec2(extent))) || any(lessThan(test4.xz, vec2(-extent))))
|
||||
t4 = 0.;
|
||||
if (t5 < 0. || any(greaterThan(test5.xy, vec2(extent))) || any(lessThan(test5.xy, vec2(-extent))))
|
||||
t5 = 0.;
|
||||
if (t6 < 0. || any(greaterThan(test6.xy, vec2(extent))) || any(lessThan(test6.xy, vec2(-extent))))
|
||||
t6 = 0.;
|
||||
|
||||
// Initialize tmin and tmax values that define the two intersection points
|
||||
tmin = 9999999999.;
|
||||
tmax = 0.;
|
||||
|
||||
// Use the lowest value of t that is not 0 for tmin
|
||||
if (t1 > 0. && t1 < tmin) { tmin = t1; minAxis = vec3(1, 0, 0); }
|
||||
if (t2 > 0. && t2 < tmin) { tmin = t2; minAxis = vec3(1, 0, 0); }
|
||||
if (t3 > 0. && t3 < tmin) { tmin = t3; minAxis = vec3(0, 1, 0); }
|
||||
if (t4 > 0. && t4 < tmin) { tmin = t4; minAxis = vec3(0, 1, 0); }
|
||||
if (t5 > 0. && t5 < tmin) { tmin = t5; minAxis = vec3(0, 0, 1); }
|
||||
if (t6 > 0. && t6 < tmin) { tmin = t6; minAxis = vec3(0, 0, 1); }
|
||||
|
||||
// Use the highest value of t that is not 0 for tmax
|
||||
if (t1 > 0. && t1 > tmax) { tmax = t1; maxAxis = vec3(1, 0, 0); }
|
||||
if (t2 > 0. && t2 > tmax) { tmax = t2; maxAxis = vec3(1, 0, 0); }
|
||||
if (t3 > 0. && t3 > tmax) { tmax = t3; maxAxis = vec3(0, 1, 0); }
|
||||
if (t4 > 0. && t4 > tmax) { tmax = t4; maxAxis = vec3(0, 1, 0); }
|
||||
if (t5 > 0. && t5 > tmax) { tmax = t5; maxAxis = vec3(0, 0, 1); }
|
||||
if (t6 > 0. && t6 > tmax) { tmax = t6; maxAxis = vec3(0, 0, 1); }
|
||||
|
||||
// If tmin = tmax, the ray origin is within the cube, so set tmin to 0
|
||||
if (tmin == tmax)
|
||||
tmin = 0.;
|
||||
|
||||
// If tmax is not 0, an intersection was found
|
||||
return tmax > 0.;
|
||||
}
|
||||
|
||||
// Assuming the ray hits the given cube, calculates the time at which it hits it
|
||||
void rayCubeExit(in Ray ray, in vec3 center, in float extent, out float t, out vec3 axis)
|
||||
{
|
||||
// Edges taking into account the direction of the ray
|
||||
vec3 voxelEdges = center + (extent * ray.dirSign);
|
||||
// Calculate the times at which the planes that span on the edges of the cubes are hit
|
||||
vec3 axisTimes = (voxelEdges - ray.p0) * ray.invDir;
|
||||
|
||||
// The smallest of these times is side of the cube the ray hits (assuming it hits the cube)
|
||||
t = min(min(axisTimes.x, axisTimes.y), axisTimes.z);
|
||||
if (axisTimes.x == t) axis = vec3(1, 0, 0);
|
||||
else if (axisTimes.y == t) axis = vec3(0, 1, 0);
|
||||
else axis = vec3(0, 0, 1);
|
||||
}
|
||||
|
||||
ivec3 wrapNodePointer(in ivec3 samplePos)
|
||||
{
|
||||
// Make sure that the indices are wrapped if the pointer doesn't fit in the current texture
|
||||
if (samplePos.x >= texSize.x)
|
||||
{
|
||||
samplePos.x = samplePos.x % texSize.x;
|
||||
samplePos.y++;
|
||||
if (samplePos.y >= texSize.y)
|
||||
{
|
||||
samplePos.y = samplePos.y % texSize.y;
|
||||
samplePos.z++;
|
||||
}
|
||||
//return vec4(255, 255, 0, float($max_level$ + 1));
|
||||
}
|
||||
return samplePos;
|
||||
}
|
||||
|
||||
//************************************
|
||||
// Given a pointer to a node, and it's childmask, and some child index
|
||||
// returns the nodePointer to the child at the given index.
|
||||
// Note that if the child doesn't exist, it still returns some pointer as if it would.
|
||||
//************************************
|
||||
uvec3 getNodePointer(uvec3 curNodePointer, uint childMask, uint childIndex)
|
||||
{
|
||||
// Based on the childIndex and the childmask, find out what the index of the childpointer is
|
||||
int childPointerIndex = bitCount(childMask << (31 - childIndex));
|
||||
|
||||
// Find sample position in 3D texture corresponding to current node and locat
|
||||
ivec3 samplePos = ivec3(curNodePointer);
|
||||
samplePos.x += childPointerIndex;
|
||||
// Make sure that the indices are wrapped if the pointer doesn't fit in the current texture
|
||||
samplePos = wrapNodePointer(samplePos);
|
||||
|
||||
// Fetch the pointer from the texture
|
||||
return texelFetch(octreeSampler, samplePos, 0).rgb;
|
||||
}
|
||||
|
||||
// Fetches the childmask of the node at curNodePointer (note that this is not a mask for leaf nodes!)
|
||||
uint getChildMask(in uvec3 nodePointer)
|
||||
{
|
||||
return texelFetch(octreeSampler, ivec3(nodePointer), 0).b;
|
||||
}
|
||||
|
||||
uvec3 getColor(in uvec3 nodePointer)
|
||||
{
|
||||
return texelFetch(octreeSampler, ivec3(nodePointer), 0).rgb;
|
||||
}
|
||||
|
||||
bool hasChild(in uint childMask, in uint childIndex)
|
||||
{
|
||||
uint mask = 1 << childIndex;
|
||||
return (childMask & mask) == mask;
|
||||
}
|
||||
|
||||
ivec3 getNextULoc(in Ray ray, in float t, in ivec3 lastULoc, in vec3 hitAxis)
|
||||
{
|
||||
vec3 samplePoint = ray.p0 + t * ray.dir/* + 0.005 * ray.dirSign*/;
|
||||
vec3 hitDirMask = ray.dirSign * hitAxis;
|
||||
// Calculate the location of the first leaf node that the ray enters
|
||||
// HACK: Cast to int, and then to uint, because casting int to uint gets uint.maxValue if the value == -1,
|
||||
// but float to uint directly rounds and gives 0, meaning you will never get out of the cube!
|
||||
ivec3 nextULoc = ivec3(floor(samplePoint + hitDirMask));
|
||||
return ivec3(ray.dirSign) * max(ivec3(ray.dirSign) * nextULoc, ivec3(ray.dirSign) * lastULoc);
|
||||
}
|
||||
|
||||
uint getChildIndex(uvec3 uLoc, uint level)
|
||||
{
|
||||
uint range = 1 << ($max_level$ - level);
|
||||
return int((uLoc.x & range) == range) * 1
|
||||
+ int((uLoc.y & range) == range) * 2
|
||||
+ int((uLoc.z & range) == range) * 4;
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// Gets the position and scale (extent) of the child voxel at the given index
|
||||
//****************************************
|
||||
vec3 getChildPosition(vec3 parentPos, float childExtent, uint childIndex)
|
||||
{
|
||||
vec3 childOffset = vec3(
|
||||
((childIndex & 1) == 1) ? childExtent : -childExtent,
|
||||
((childIndex & 2) == 2) ? childExtent : -childExtent,
|
||||
((childIndex & 4) == 4) ? childExtent : -childExtent);
|
||||
|
||||
return parentPos + childOffset;
|
||||
}
|
||||
|
||||
//***********************************************
|
||||
// Casts a ray against the octree structure, which is assumed to be located at rootcenter, with leaf voxels a size of 1, 1, 1
|
||||
// Returns 0 if no intersection, 1 if intersection, and -1 if it is unknown if there was an intersection due to the maximum loop being reached
|
||||
//***********************************************
|
||||
int castRay(in Ray ray, in uint maxLoop, out float t, out uvec3 hitNodePointer, out vec3 hitAxis)
|
||||
{
|
||||
// Initialize out values
|
||||
t = 0;
|
||||
hitNodePointer = uvec3(0);
|
||||
hitAxis = vec3(0);
|
||||
|
||||
// Initialize the stack
|
||||
stackPos = 0;
|
||||
for (int i = 0; i <= $max_level$; i++)
|
||||
{
|
||||
pointerStack[i] = uvec3(0); // The root node is always at position 0, 0, 0 in the texture
|
||||
positionStack[i] = rootCenter;
|
||||
extentStack[i] = float(1 << ($max_level$ - i + 1)) * 0.5;
|
||||
}
|
||||
|
||||
// Find out if the ray intersects with the root node
|
||||
float tminRoot, tmaxRoot;
|
||||
vec3 minAxis, maxAxis;
|
||||
bool collision = rayCube(ray, rootCenter, rootExtent, tminRoot, tmaxRoot, minAxis, maxAxis);
|
||||
if (!collision) // Ray doesn't intersect with root.
|
||||
return 0;
|
||||
|
||||
// Calculate the location of the first leaf node that the ray enters
|
||||
ivec3 uLoc = getNextULoc(ray, tminRoot, ivec3(ray.p0), minAxis);
|
||||
|
||||
// Keep testing ray box intersection, but prevent endless looping
|
||||
int loop = 0;
|
||||
uvec3 rangeU = uvec3(range);
|
||||
while (stackPos < $max_level$ && loop < maxLoop) {
|
||||
uint preferredChild = getChildIndex(uLoc, stackPos);
|
||||
float preferredChildExtent = extentStack[stackPos + 1];
|
||||
vec3 preferredChildPosition = getChildPosition(positionStack[stackPos], preferredChildExtent, preferredChild);
|
||||
uint childMask = getChildMask(pointerStack[stackPos]);
|
||||
//************************************
|
||||
// PUSH
|
||||
// If we have the preferred child, explore it
|
||||
//************************************
|
||||
if (hasChild(childMask, preferredChild))
|
||||
{
|
||||
pointerStack[stackPos + 1] = getNodePointer(pointerStack[stackPos], childMask, preferredChild);
|
||||
positionStack[stackPos + 1] = preferredChildPosition;
|
||||
stackPos++;
|
||||
}
|
||||
//*************************************
|
||||
// ADVANCE/POP
|
||||
// If we didn't have the preferred child, find the next preferred child.
|
||||
//*************************************
|
||||
else
|
||||
{
|
||||
// Find the first child that the ray enters after it exits the current preferred child
|
||||
rayCubeExit(ray, preferredChildPosition, preferredChildExtent, t, maxAxis);
|
||||
|
||||
ivec3 lastULoc = uLoc;
|
||||
uLoc = getNextULoc(ray, t - 0.05, lastULoc, maxAxis);
|
||||
if (any(lessThan(uLoc, uvec3(0))) || any(greaterThanEqual(uLoc, rangeU)))
|
||||
return 0;
|
||||
|
||||
// Count the number of bits that were the same in the last uLoc (until they start not being the same)
|
||||
// Since lastULoc is in the current node, we know that this number of bits is the last common parent, so we pop up to that level.
|
||||
// Note that this level is indeed one higher, but we need that to advance to the next cell?
|
||||
ivec3 equalBits = $max_level$ - findMSB(lastULoc ^ uLoc);
|
||||
stackPos = min(min(equalBits.x, equalBits.y), equalBits.z);
|
||||
}
|
||||
++loop;
|
||||
}
|
||||
hitAxis = maxAxis;
|
||||
hitNodePointer = pointerStack[stackPos];
|
||||
|
||||
// Check if the current node is a leaf node. If so, draw it:
|
||||
if (stackPos >= $max_level$)
|
||||
return 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
uint maxLoop = 4096;
|
||||
|
||||
texSize = textureSize(octreeSampler, 0);
|
||||
|
||||
// Set color using textures
|
||||
color = texture(textureSampler, uv);
|
||||
|
||||
// Scale the grid so that all leaf cells have a width of exactly 1:
|
||||
float extent = $extent$;
|
||||
float rangeF = float(range);
|
||||
float scale = rangeF / (extent * 2.);
|
||||
float offset = extent + 0.5 / scale;
|
||||
|
||||
// Get ray and sample point
|
||||
vec3 p0 = (cameraPosition + offset) * scale;
|
||||
vec3 rayDir = normalize(pos - cameraPosition);
|
||||
Ray ray = getRay(p0, rayDir);
|
||||
|
||||
// Cast the primary ray
|
||||
float time;
|
||||
vec3 hitAxis;
|
||||
uvec3 hitNodePointer;
|
||||
int primaryRayHit = castRay(ray, maxLoop, time, hitNodePointer, hitAxis);
|
||||
if (primaryRayHit == 1)
|
||||
{
|
||||
color.rgb = vec3(getColor(hitNodePointer)) / 255.;
|
||||
|
||||
// Cast one shadow ray
|
||||
if (lightDirection != vec3(0))
|
||||
{
|
||||
Ray lightRay = getRay(ray.dir * time + p0 - ray.dir * 0.01, -lightDirection);
|
||||
int shadowResult = castRay(lightRay, max(range / 1024, 1000), time, hitNodePointer, hitAxis);
|
||||
if (shadowResult == 1 || shadowResult == -1)
|
||||
color.rgb *= 0.5 + (0.5 - float(abs(shadowResult)) * 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
// Discard pixels that are transparent
|
||||
if (color.a < 0.5)
|
||||
discard;
|
||||
|
||||
}
|
||||
22
Research/shaders/shader_properties.txt
Normal file
22
Research/shaders/shader_properties.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
shader_vertexPosition 0
|
||||
shader_vertexUV 1
|
||||
shader_vertexNormal 2
|
||||
shader_vertexColor 3
|
||||
|
||||
shader_MVP 0
|
||||
shader_width 1
|
||||
shader_height 2
|
||||
shader_angle 3
|
||||
shader_aspect 4
|
||||
shader_lightDirection 5
|
||||
shader_lightType 6
|
||||
shader_cameraPosition 7
|
||||
shader_reflections 8
|
||||
shader_pixelHalfConeAngle 9
|
||||
shader_bitsPerChannel 10
|
||||
shader_bitsPerTree 11
|
||||
shader_invMVP 12
|
||||
|
||||
shader_textColor 0
|
||||
shader_max_level 12
|
||||
shader_extent 600.0
|
||||
Reference in New Issue
Block a user