This commit is contained in:
luboslenco 2017-02-22 15:50:19 +01:00
parent e883227155
commit 0a51699aff
18 changed files with 283 additions and 371 deletions

View file

@ -14,11 +14,18 @@ precision mediump float;
#ifdef _Irr
#include "../std/shirr.glsl"
#endif
#ifdef _VoxelGI
#include "../std/conetrace.glsl"
#endif
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1;
#ifdef _VoxelGI
//!uniform sampler3D voxels;
#endif
uniform float envmapStrength;
#ifdef _Irr
//!uniform vec4 shirr[7];
@ -54,17 +61,38 @@ void main() {
vec2 metrough = unpackFloat(g0.b);
vec4 g1 = texture(gbuffer1, texCoord); // Basecolor.rgb, occlusion
vec3 albedo = surfaceAlbedo(g1.rgb, metrough.x); // g1.rgb - basecolor
#ifdef _Rad
float depth = texture(gbufferD, texCoord).r * 2.0 - 1.0;
vec3 p = getPos(eye, eyeLook, viewRay, depth);
vec3 v = normalize(eye - p.xyz);
float dotNV = max(dot(n, v), 0.0);
vec3 f0 = surfaceF0(g1.rgb, metrough.x);
vec2 envBRDF = texture(senvmapBrdf, vec2(metrough.y, 1.0 - dotNV)).xy;
#endif
// Indirect
#ifdef _VoxelGI
vec3 indirectDiffuse = indirectDiffuseLight(n, p / voxelgiDimensions.x);
vec3 reflectWorld = reflect(-v, n);
vec3 indirectSpecular = traceSpecularVoxelCone(p / voxelgiDimensions.x, reflectWorld, n, metrough.y * 10.0);
indirectSpecular *= f0 * envBRDF.x + envBRDF.y;
fragColor.rgb = indirectDiffuse * 0.1 * albedo + indirectSpecular;
fragColor.rgb *= texture(ssaotex, texCoord).r;
// if (opacity < 1.0) fragColor.rgb = mix(indirectRefractiveLight(-v), fragColor.rgb); // Transparency
return;
#endif
// Envmap
#ifdef _Irr
vec3 indirect = shIrradiance(n, 2.2) / PI;
fragColor.rgb = shIrradiance(n, 2.2) / PI;
#else
vec3 indirect = vec3(1.0);
fragColor.rgb = vec3(1.0);
#endif
#ifdef _Rad
@ -74,32 +102,22 @@ void main() {
#endif
#ifdef _EnvLDR
indirect = pow(indirect, vec3(2.2));
fragColor.rgb = pow(fragColor.rgb, vec3(2.2));
#ifdef _Rad
prefilteredColor = pow(prefilteredColor, vec3(2.2));
#endif
#endif
vec4 g1 = texture(gbuffer1, texCoord); // Basecolor.rgb, occlusion
vec3 albedo = surfaceAlbedo(g1.rgb, metrough.x); // g1.rgb - basecolor
indirect *= albedo;
fragColor.rgb *= albedo;
#ifdef _Rad
// Indirect specular
float dotNV = max(dot(n, v), 0.0);
vec3 f0 = surfaceF0(g1.rgb, metrough.x);
vec2 envBRDF = texture(senvmapBrdf, vec2(metrough.y, 1.0 - dotNV)).xy;
indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y);
#ifdef _Rad // Indirect specular
fragColor.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y);
#endif
indirect = indirect * envmapStrength;// * lightColor;
indirect = indirect * g1.a; // Occlusion
fragColor.rgb = fragColor.rgb * envmapStrength;// * lightColor;
fragColor.rgb = fragColor.rgb * g1.a; // Occlusion
#ifdef _SSAO
indirect *= texture(ssaotex, texCoord).r; // SSAO
fragColor.rgb *= texture(ssaotex, texCoord).r; // SSAO
#endif
fragColor.rgb = indirect;
}

View file

@ -7,12 +7,12 @@ precision mediump float;
#include "../compiled.glsl"
#include "../std/brdf.glsl"
#include "../std/math.glsl"
// #ifdef _VoxelGI
// #include "../std/conetrace.glsl"
// #endif
// #ifdef _PolyLight
#include "../std/ltc.glsl"
// #endif
#ifdef _VoxelGI
#include "../std/conetrace.glsl"
#endif
#ifndef _NoShadows
#ifdef _PCSS
#include "../std/shadows_pcss.glsl"
@ -26,6 +26,10 @@ precision mediump float;
// octahedronWrap()
// unpackFloat()
// #ifdef _VoxelGI
//-!uniform sampler3D voxels;
// #endif
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1;
@ -38,12 +42,6 @@ uniform sampler2D gbuffer1;
#endif
#endif
#ifdef _VoxelGI
uniform sampler2D ssaotex;
uniform sampler2D senvmapBrdf;
//!uniform sampler3D voxels;
#endif
#ifdef _PolyLight
//!uniform sampler2D sltcMat;
//!uniform sampler2D sltcMag;
@ -185,6 +183,14 @@ void main() {
vec3 albedo = surfaceAlbedo(g1.rgb, metrough.x); // g1.rgb - basecolor
vec3 f0 = surfaceF0(g1.rgb, metrough.x);
float visibility = 1.0;
#ifndef _NoShadows
vec4 lampPos = LWVP * vec4(p, 1.0);
if (lampPos.w > 0.0) {
visibility = shadowTest(lampPos);
}
#endif
// Per-light
vec3 l;
if (lightType == 0) { // Sun
@ -192,6 +198,7 @@ void main() {
}
else { // Point, spot
l = normalize(lightPos - p);
visibility *= attenuate(distance(p, lightPos));
}
vec3 h = normalize(v + l);
@ -201,14 +208,6 @@ void main() {
// float dotLV = dot(l, v);
// float dotLH = dot(l, h);
float visibility = 1.0;
#ifndef _NoShadows
vec4 lampPos = LWVP * vec4(p, 1.0);
if (lampPos.w > 0.0) {
visibility = shadowTest(lampPos);
}
#endif
// Direct
vec3 direct;
@ -283,40 +282,10 @@ void main() {
visibility *= tvis;
#endif
// #ifdef _VoxelGI
// if (dotNL > 0.0) visibility *= traceShadowCone(p / voxelgiResolution.x, l, distance(p, lightPos) / voxelgiResolution.x, n);
// #endif
// Direct
fragColor = vec4(vec3(direct * visibility), 1.0);
// Voxels test..
#ifdef _VoxelGI
vec4 g1a = texture(gbuffer1, texCoord); // Basecolor.rgb, occlusion
vec3 albedoa = surfaceAlbedo(g1a.rgb, metrough.x); // g1a.rgb - basecolor
vec3 tangent = normalize(cross(n, vec3(0.0, 1.0, 0.0)));
if (length(tangent) == 0.0) {
tangent = normalize(cross(n, vec3(0.0, 0.0, 1.0)));
}
vec3 bitangent = normalize(cross(n, tangent));
mat3 tanToWorld = inverse(transpose(mat3(tangent, bitangent, n)));
float diffOcclusion = 0.0;
vec3 indirectDiffusea = coneTraceIndirect(p, tanToWorld, n, diffOcclusion).rgb * 4.0;
indirectDiffusea *= albedoa;
diffOcclusion = min(1.0, 1.5 * diffOcclusion);
vec3 reflectWorld = reflect(-v, n);
float specularOcclusion;
float lodOffset = 0.0;//getMipFromRoughness(roughness, numMips);
vec3 indirectSpecular = coneTrace(p, reflectWorld, n, 0.07 + lodOffset, specularOcclusion).rgb;
if (metrough.y > 0.0) { // Temp..
float dotNVa = max(dot(n, v), 0.0);
vec3 f0a = surfaceF0(g1a.rgb, metrough.x);
vec2 envBRDFa = texture(senvmapBrdf, vec2(metrough.y, 1.0 - dotNVa)).xy;
indirectSpecular *= (f0a * envBRDFa.x + envBRDFa.y);
}
vec3 indirect1 = indirectDiffusea * diffOcclusion + indirectSpecular;
indirect1 *= texture(ssaotex, texCoord).r;
fragColor.rgb += indirect1;
#endif
}

View file

@ -1,56 +0,0 @@
// http://simonstechblog.blogspot.sk/2013/01/implementing-voxel-cone-tracing.html
// http://leifnode.com/2015/05/voxel-cone-traced-global-illumination/
// http://www.seas.upenn.edu/%7Epcozzi/OpenGLInsights/OpenGLInsights-SparseVoxelization.pdf
// https://github.com/Cigg/Voxel-Cone-Tracing
// https://research.nvidia.com/sites/default/files/publications/GIVoxels-pg2011-authors.pdf
#version 450
#extension GL_ARB_shader_image_load_store : enable
in fragData {
#ifdef _Tex
vec2 texuv;
#endif
flat int axis;
vec4 lampPos;
} frag;
uniform layout(RGBA8) image3D voxels;
#ifdef _BaseTex
uniform sampler2D sbase;
#endif
uniform vec4 baseCol;
uniform sampler2D shadowMap;
const int voxelDimensions = 512;
void main() {
#ifdef _BaseTex
vec4 matCol = texture(sbase, frag.texuv);
#else
vec4 matCol = baseCol;
#endif
// vec3 lampPos = frag.lampPos.xyz / frag.lampPos.w;
// lampPos.xy = lampPos.xy * 0.5 + 0.5;
// float distanceFromLight = texture(shadowMap, lampPos.xy).r * 2.0 - 1.0;
// const float shadowsBias = 0.0001;
// float visibility = float(distanceFromLight > lampPos.z - shadowsBias);
float visibility = 1.0;
ivec3 camPos = ivec3(gl_FragCoord.x, gl_FragCoord.y, voxelDimensions * gl_FragCoord.z);
ivec3 texPos;
if (frag.axis == 1) {
texPos.x = voxelDimensions - camPos.z;
texPos.z = camPos.x;
texPos.y = camPos.y;
}
else if (frag.axis == 2) {
texPos.z = camPos.y;
texPos.y = voxelDimensions - camPos.z;
texPos.x = camPos.x;
}
else {
texPos = camPos;
}
texPos.z = voxelDimensions - texPos.z - 1;
imageStore(voxels, texPos, vec4(matCol.rgb * visibility, 1.0));
}

View file

@ -1,56 +0,0 @@
#version 450
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in vertData {
#ifdef _Tex
vec2 texuv;
#endif
vec4 lampPos;
} vertices[];
out fragData {
#ifdef _Tex
vec2 texuv;
#endif
flat int axis;
vec4 lampPos;
} frag;
uniform mat4 PX;
uniform mat4 PY;
uniform mat4 PZ;
void main() {
vec3 p1 = gl_in[1].gl_Position.xyz - gl_in[0].gl_Position.xyz;
vec3 p2 = gl_in[2].gl_Position.xyz - gl_in[0].gl_Position.xyz;
vec3 absnor = abs(normalize(cross(p1, p2)));
mat4 P;
// Dominant axis
if (absnor.x >= absnor.y && absnor.x >= absnor.z) {
frag.axis = 1;
P = PX;
}
else if (absnor.y >= absnor.x && absnor.y >= absnor.z) {
frag.axis = 2;
P = PY;
}
else {
frag.axis = 3;
P = PZ;
}
for (int i = 0; i < gl_in.length(); i++) {
vec3 middlePos = gl_in[0].gl_Position.xyz / 3.0 + gl_in[1].gl_Position.xyz / 3.0 + gl_in[2].gl_Position.xyz / 3.0;
#ifdef _Tex
frag.texuv = vertices[i].texuv;
#endif
frag.lampPos = vertices[i].lampPos;
gl_Position = P * gl_in[i].gl_Position;
EmitVertex();
}
EndPrimitive();
}

View file

@ -1,38 +0,0 @@
#version 450
in vec3 pos;
// in vec3 nor;
#ifdef _Tex
in vec2 tex;
#endif
#ifdef _VCols
in vec3 col;
#endif
#ifdef _NorTex
in vec3 tan;
#endif
#ifdef _Skinning
in vec4 bone;
in vec4 weight;
#endif
#ifdef _Instancing
in vec3 off;
#endif
uniform mat4 LWVP;
uniform mat4 W;
out vertData {
#ifdef _BaseTex
vec2 texuv;
#endif
vec4 lampPos;
} vert;
void main() {
#ifdef _Tex
vert.texuv = tex;
#endif
vert.lampPos = LWVP * vec4(pos, 1.0);
gl_Position = W * vec4(pos, 1.0);
}

View file

@ -1,59 +1,137 @@
// https://github.com/Friduric/voxel-cone-tracing
// https://github.com/Cigg/Voxel-Cone-Tracing
// http://simonstechblog.blogspot.com/2013/01/implementing-voxel-cone-tracing.html
// http://leifnode.com/2015/05/voxel-cone-traced-global-illumination/
// http://www.seas.upenn.edu/%7Epcozzi/OpenGLInsights/OpenGLInsights-SparseVoxelization.pdf
// https://research.nvidia.com/sites/default/files/publications/GIVoxels-pg2011-authors.pdf
uniform sampler3D voxels;
const float voxelGridWorldSize = 150.0;
const int voxelDimensions = 128;
const float maxDist = 30.0;
const float alphaThreshold = 0.95;
const int numCones = 6;
vec3 coneDirections[6] = vec3[](
vec3(0, 1, 0),
vec3(0, 0.5, 0.866025),
vec3(0.823639, 0.5, 0.267617),
vec3(0.509037, 0.5, -0.700629),
vec3(-0.509037, 0.5, -0.700629),
vec3(-0.823639, 0.5, 0.267617));
float coneWeights[6] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
vec4 sampleVoxels(vec3 worldPosition, float lod) {
vec3 offset = vec3(1.0 / voxelDimensions, 1.0 / voxelDimensions, 0);
vec3 texco = worldPosition / (voxelGridWorldSize * 0.5);
texco = texco * 0.5 + 0.5 + offset;
return textureLod(voxels, texco, lod);
const float VOXEL_SIZE = 1.0 / voxelgiResolution.x;
const float MAX_MIPMAP = 5.4;
vec3 orthogonal(const vec3 u) {
// Pass normalized u
const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector.
return abs(dot(u, v)) > 0.99999 ? cross(u, vec3(0.0, 1.0, 0.0)) : cross(u, v);
}
// See https://github.com/Cigg/Voxel-Cone-Tracing
vec4 coneTrace(vec3 posWorld, vec3 direction, vec3 norWorld, float tanHalfAngle, out float occlusion) {
const float voxelWorldSize = voxelGridWorldSize / voxelDimensions;
float dist = voxelWorldSize; // Start one voxel away to avoid self occlusion
vec3 startPos = posWorld + norWorld * voxelWorldSize;
vec3 color = vec3(0.0);
float alpha = 0.0;
occlusion = 0.0;
while (dist < maxDist && alpha < alphaThreshold) {
// Smallest sample diameter possible is the voxel size
float diameter = max(voxelWorldSize, 2.0 * tanHalfAngle * dist);
float lodLevel = log2(diameter / voxelWorldSize);
vec4 voxelColor = sampleVoxels(startPos + dist * direction, lodLevel);
// Front-to-back compositing
float a = (1.0 - alpha);
color += a * voxelColor.rgb;
alpha += a * voxelColor.a;
occlusion += (a * voxelColor.a) / (1.0 + 0.03 * diameter);
dist += diameter * 0.5; // * 2.0
vec3 traceDiffuseVoxelCone(const vec3 from, vec3 direction) {
direction = normalize(direction);
const float CONE_SPREAD = 0.325;
vec4 acc = vec4(0.0);
// Controls bleeding from close surfaces
// Low values look rather bad if using shadow cone tracing
// Might be a better choice to use shadow maps and lower this value
float dist = 0.1953125;
const float SQRT2 = 1.414213;
while (dist < SQRT2 && acc.a < 1) {
vec3 c = vec3(from + dist * direction) * 0.5 + vec3(0.5);
float l = (1.0 + CONE_SPREAD * dist / VOXEL_SIZE);
float level = log2(l);
float ll = (level + 1.0) * (level + 1.0);
vec4 voxel = textureLod(voxels, c, min(MAX_MIPMAP, level));
acc += 0.075 * ll * voxel * pow(1.0 - voxel.a, 2.0);
dist += ll * VOXEL_SIZE * 2.0;
}
return vec4(color, alpha);
return pow(acc.rgb * 2.0, vec3(1.5));
}
vec4 coneTraceIndirect(vec3 posWorld, mat3 tanToWorld, vec3 norWorld, out float occlusion) {
vec4 color = vec4(0.0);
occlusion = 0.0;
vec3 indirectDiffuseLight(const vec3 normal, const vec3 wpos) {
const float ANGLE_MIX = 0.5; // Angle mix (1.0f -> orthogonal direction, 0.0f -> direction of normal)
const float w[3] = { 1.0, 1.0, 1.0 }; // Cone weights
// Find a base for the side cones with the normal as one of its base vectors
const vec3 ortho = normalize(orthogonal(normal));
const vec3 ortho2 = normalize(cross(ortho, normal));
// Find base vectors for the corner cones
const vec3 corner = 0.5 * (ortho + ortho2);
const vec3 corner2 = 0.5 * (ortho - ortho2);
// Find start position of trace (start with a bit of offset)
const float ISQRT2 = 0.707106;
const vec3 N_OFFSET = normal * (1.0 + 4.0 * ISQRT2) * VOXEL_SIZE;
const vec3 C_ORIGIN = wpos + N_OFFSET;
for (int i = 0; i < numCones; i++) {
float coneOcclusion;
const float tanangle = tan(30.0);
color += coneWeights[i] * coneTrace(posWorld, tanToWorld * coneDirections[i], norWorld, tanangle, coneOcclusion);
occlusion += coneWeights[i] * coneOcclusion;
// Accumulate indirect diffuse light
vec3 acc = vec3(0.0);
// We offset forward in normal direction, and backward in cone direction
// Backward in cone direction improves GI, and forward direction removes artifacts
const float CONE_OFFSET = -0.01;
// Trace front cone
acc += w[0] * traceDiffuseVoxelCone(C_ORIGIN + CONE_OFFSET * normal, normal);
// Trace 4 side cones
const vec3 s1 = mix(normal, ortho, ANGLE_MIX);
const vec3 s2 = mix(normal, -ortho, ANGLE_MIX);
const vec3 s3 = mix(normal, ortho2, ANGLE_MIX);
const vec3 s4 = mix(normal, -ortho2, ANGLE_MIX);
acc += w[1] * traceDiffuseVoxelCone(C_ORIGIN + CONE_OFFSET * ortho, s1);
acc += w[1] * traceDiffuseVoxelCone(C_ORIGIN - CONE_OFFSET * ortho, s2);
acc += w[1] * traceDiffuseVoxelCone(C_ORIGIN + CONE_OFFSET * ortho2, s3);
acc += w[1] * traceDiffuseVoxelCone(C_ORIGIN - CONE_OFFSET * ortho2, s4);
// Trace 4 corner cones
const vec3 c1 = mix(normal, corner, ANGLE_MIX);
const vec3 c2 = mix(normal, -corner, ANGLE_MIX);
const vec3 c3 = mix(normal, corner2, ANGLE_MIX);
const vec3 c4 = mix(normal, -corner2, ANGLE_MIX);
acc += w[2] * traceDiffuseVoxelCone(C_ORIGIN + CONE_OFFSET * corner, c1);
acc += w[2] * traceDiffuseVoxelCone(C_ORIGIN - CONE_OFFSET * corner, c2);
acc += w[2] * traceDiffuseVoxelCone(C_ORIGIN + CONE_OFFSET * corner2, c3);
acc += w[2] * traceDiffuseVoxelCone(C_ORIGIN - CONE_OFFSET * corner2, c4);
return acc + vec3(0.001);
}
vec3 traceSpecularVoxelCone(vec3 from, vec3 direction, const vec3 normal, const float specularDiffusion) {
direction = normalize(direction);
float MAX_DISTANCE = distance(vec3(abs(from)), vec3(-1));
const float OFFSET = 8 * VOXEL_SIZE;
const float STEP = VOXEL_SIZE;
from += OFFSET * normal;
vec4 acc = vec4(0.0);
float dist = OFFSET;
while (dist < MAX_DISTANCE && acc.a < 1.0) {
vec3 c = from + dist * direction;
if (!isInsideCube(c)) break;
c = c * 0.5 + vec3(0.5);
float level = 0.1 * specularDiffusion * log2(1.0 + dist / VOXEL_SIZE);
vec4 voxel = textureLod(voxels, c, min(level, MAX_MIPMAP));
float f = 1.0 - acc.a;
acc.rgb += 0.25 * (1.0 + specularDiffusion) * voxel.rgb * voxel.a * f;
acc.a += 0.25 * voxel.a * f;
dist += STEP * (1.0 + 0.125 * level);
}
occlusion = 1.0 - occlusion;
return color;
return 1.0 * pow(specularDiffusion + 1, 0.8) * acc.rgb;
}
// vec3 indirectRefractiveLight(const vec3 v, const vec3 normal){
// float refractiveIndex = 1.2;
// const vec3 refraction = refract(v, normal, 1.0 / refractiveIndex);
// const vec3 cmix = mix(specularColor, 0.5 * (specularColor + vec3(1)), transparency);
// return cmix * traceSpecularVoxelCone(worldPositionFrag, refraction, 0.1);
// }
float traceShadowCone(vec3 from, vec3 direction, float targetDistance, vec3 normal) {
from += normal * 0.0; // Removes artifacts but makes self shadowing for dense meshes meh
float acc = 0.0;
float dist = 3 * VOXEL_SIZE;
// I'm using a pretty big margin here since I use an emissive light ball with a pretty big radius in my demo scenes.
const float STOP = targetDistance - 16.0 * VOXEL_SIZE;
while (dist < STOP && acc < 1.0) {
vec3 c = from + dist * direction;
if (!isInsideCube(c)) break;
c = c * 0.5 + vec3(0.5);
float l = pow(dist, 2.0); // Experimenting with inverse square falloff for shadows.
float s1 = 0.062 * textureLod(voxels, c, 1.0 + 0.75 * l).a;
float s2 = 0.135 * textureLod(voxels, c, 4.5 * l).a;
float s = s1 + s2;
acc += (1.0 - acc) * s;
dist += 0.9 * VOXEL_SIZE * (1.0 + 0.05 * l);
}
return 1.0 - pow(smoothstep(0.0, 1.0, acc * 1.4), 1.0 / 1.4);
}

View file

@ -39,4 +39,8 @@ float attenuate(const float dist) {
// 1.0 / (quadratic * dist * dist);
}
bool isInsideCube(const vec3 p) {
return abs(p.x) < 1 && abs(p.y) < 1 && abs(p.z) < 1;
}
#endif

Binary file not shown.

View file

@ -79,6 +79,18 @@ def make_deferred(cam):
nodes['Begin'].inputs[1].default_value = cam.rp_hdr
nodes['Screen'].inputs[0].default_value = int(cam.rp_supersampling)
if cam.rp_voxelgi:
links.new(nodes['Begin'].outputs[0], nodes['Set Target Voxels'].inputs[0])
links.new(nodes['Generate Mipmaps Voxels'].outputs[0], nodes['Set Target Mesh'].inputs[0])
n = nodes['Image 3D Voxels']
n.inputs[1].default_value = cam.rp_voxelgi_resolution[0]
n.inputs[2].default_value = cam.rp_voxelgi_resolution[1]
n.inputs[3].default_value = cam.rp_voxelgi_resolution[2]
n = nodes['Set Viewport Voxels']
n.inputs[1].default_value = cam.rp_voxelgi_resolution[0]
n.inputs[2].default_value = cam.rp_voxelgi_resolution[1]
links.new(nodes['Image 3D Voxels'].outputs[0], nodes['Deferred Indirect'].inputs[4])
if cam.rp_shadowmap != 'None':
n = nodes['Shadow Map']
n.inputs[1].default_value = n.inputs[2].default_value = int(cam.rp_shadowmap)

View file

@ -312,7 +312,7 @@ def make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices
bind_target_used = False
for i in range(0, len(bind_target_indices)):
index = bind_target_indices[i]
if node.inputs[index].is_linked:
if len(node.inputs) > index and node.inputs[index].is_linked:
bind_target_used = True
if bind_target_constants == None:
constant_name = node.inputs[index + 1].default_value
@ -425,8 +425,7 @@ def make_water_pass(stages, node_group, node):
def make_deferred_light_pass(stages, node_group, node):
# Draw lamp volume - TODO: properly generate stage
# make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2, 3], bind_target_constants=['gbuffer', 'shadowMap'], shader_context='deferred_light/deferred_light/deferred_light')
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2, 3, 4], bind_target_constants=['gbuffer', 'shadowMap', 'voxels'], shader_context='deferred_light/deferred_light/deferred_light')
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2, 3], bind_target_constants=['gbuffer', 'shadowMap'], shader_context='deferred_light/deferred_light/deferred_light')
stages[-1]['command'] = 'draw_lamp_volume'
def make_volumetric_light_pass(stages, node_group, node):
@ -438,9 +437,7 @@ def make_volumetric_light_pass(stages, node_group, node):
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[3, 4], bind_target_constants=['tex', 'gbuffer0'], shader_context='blur_edge_pass/blur_edge_pass/blur_edge_pass_y_blend_add')
def make_deferred_indirect_pass(stages, node_group, node):
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2, 3], bind_target_constants=['gbuffer', 'ssaotex'], shader_context='deferred_indirect/deferred_indirect/deferred_indirect')
# Testing voxels
# make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2, 3, 4], bind_target_constants=['gbuffer', 'ssaotex', 'voxels'], shader_context='deferred_indirect/deferred_indirect/deferred_indirect')
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2, 3, 4], bind_target_constants=['gbuffer', 'ssaotex', 'voxels'], shader_context='deferred_indirect/deferred_indirect/deferred_indirect')
def make_translucent_resolve_pass(stages, node_group, node):
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2], bind_target_constants=['gbuffer'], shader_context='translucent_resolve/translucent_resolve/translucent_resolve')

View file

@ -75,17 +75,20 @@ def build_node_tree(world):
if wrd.diffuse_model == 'Oren Nayar':
wrd.world_defs += '_OrenNayar'
if wrd.voxelgi:
wrd.world_defs += '_VoxelGI'
wrd.world_defs += '_Rad' # Always do radiance for voxels
wrd.world_defs += '_Irr'
# Enable probes
voxelgi = False
for cam in bpy.data.cameras:
if cam.is_probe:
wrd.world_defs += '_Probes'
if cam.rp_shadowmap == 'None':
wrd.world_defs += '_NoShadows'
if cam.rp_voxelgi:
voxelgi = True
if voxelgi:
assets.add_khafile_def('arm_voxelgi')
wrd.world_defs += '_VoxelGI'
wrd.world_defs += '_Rad' # Always do radiance for voxels
wrd.world_defs += '_Irr'
# Area lamps
for lamp in bpy.data.lamps:

View file

@ -1029,7 +1029,9 @@ def parse_value(node, socket):
return '0.0'
elif node.type == 'LIGHT_FALLOFF':
return '0.0'
# Constant, linear, quadratic
# Shaders default to quadratic for now
return '1.0'
elif node.type == 'NORMAL':
nor = parse_vector_input(node.inputs[0])

View file

@ -1,15 +1,9 @@
# http://simonstechblog.blogspot.sk/2013/01/implementing-voxel-cone-tracing.html
# http://leifnode.com/2015/05/voxel-cone-traced-global-illumination/
# http://www.seas.upenn.edu/%7Epcozzi/OpenGLInsights/OpenGLInsights-SparseVoxelization.pdf
# https://github.com/Cigg/Voxel-Cone-Tracing
# https://research.nvidia.com/sites/default/files/publications/GIVoxels-pg2011-authors.pdf
import material.cycles as cycles
import material.mat_state as mat_state
import material.mat_utils as mat_utils
def make(context_id):
con_voxel = mat_state.data.add_context({ 'name': context_id, 'depth_write': False, 'compare_mode': 'always', 'cull_mode': 'none' })
con_voxel = mat_state.data.add_context({ 'name': context_id, 'depth_write': False, 'compare_mode': 'always', 'cull_mode': 'none', 'color_write_red': False, 'color_write_green': False, 'color_write_blue': False, 'color_write_alpha': False })
vert = con_voxel.make_vert()
frag = con_voxel.make_frag()
@ -20,91 +14,69 @@ def make(context_id):
geom.ins = vert.outs
frag.ins = geom.outs
vert.add_uniform('mat4 LWVP', '_lampWorldViewProjectionMatrix')
vert.add_uniform('mat4 W', '_worldMatrix')
vert.add_uniform('mat4 N', '_normalMatrix')
vert.add_out('vec4 lampPos')
# vert.add_out('vec2 texuv')
vert.add_out('vec3 wpositionGeom')
vert.add_out('vec3 wnormalGeom')
# vert.write('texuv = tex;')
vert.write('lampPos = LWVP * vec4(pos, 1.0);')
vert.write('gl_Position = W * vec4(pos, 1.0);')
vert.add_include('../../Shaders/compiled.glsl')
geom.add_uniform('mat4 PX', '_projectionXMatrix')
geom.add_uniform('mat4 PY', '_projectionYMatrix')
geom.add_uniform('mat4 PZ', '_projectionZMatrix')
if mat_state.data.is_elem('tex'):
vert.add_out('vec2 texCoordGeom')
vert.write('texCoordGeom = tex;')
#geom.add_out('vec2 geom_texuv')
geom.add_out('flat int geom_axis')
geom.add_out('vec4 geom_lampPos')
vert.write('wpositionGeom = vec3(W * vec4(pos, 1.0)) / voxelgiDimensions.x;')
vert.write('wnormalGeom = normalize(mat3(N) * nor);')
vert.write('gl_Position = vec4(0.0, 0.0, 0.0, 1.0);')
geom.write('vec3 p1 = gl_in[1].gl_Position.xyz - gl_in[0].gl_Position.xyz;')
geom.write('vec3 p2 = gl_in[2].gl_Position.xyz - gl_in[0].gl_Position.xyz;')
geom.write('vec3 absnor = abs(normalize(cross(p1, p2)));')
geom.write('mat4 P; // Dominant axis')
geom.write('if (absnor.x >= absnor.y && absnor.x >= absnor.z) {')
geom.write(' geom_axis = 1;')
geom.write(' P = PX;')
geom.write('}')
geom.write('else if (absnor.y >= absnor.x && absnor.y >= absnor.z) {')
geom.write(' geom_axis = 2;')
geom.write(' P = PY;')
geom.write('}')
geom.write('else {')
geom.write(' geom_axis = 3;')
geom.write(' P = PZ;')
geom.write('}')
geom.add_out('vec3 wposition')
geom.add_out('vec3 wnormal')
if mat_state.data.is_elem('tex'):
geom.add_out('vec2 texCoord')
geom.write('for (int i = 0; i < gl_in.length(); i++) {')
geom.write(' vec3 middlePos = gl_in[0].gl_Position.xyz / 3.0 + gl_in[1].gl_Position.xyz / 3.0 + gl_in[2].gl_Position.xyz / 3.0;')
#geom.write(' geom_texuv = texuv[i];')
geom.write(' geom_lampPos = lampPos[i];')
geom.write(' gl_Position = P * gl_in[i].gl_Position;')
geom.write('const vec3 p1 = wpositionGeom[1] - wpositionGeom[0];')
geom.write('const vec3 p2 = wpositionGeom[2] - wpositionGeom[0];')
geom.write('const vec3 p = abs(cross(p1, p2));')
geom.write('for (uint i = 0; i < 3; ++i) {')
geom.write(' wposition = wpositionGeom[i];')
geom.write(' wnormal = wnormalGeom[i];')
if mat_state.data.is_elem('tex'):
geom.write(' texCoord = texCoordGeom[i];')
geom.write(' if (p.z > p.x && p.z > p.y) {')
geom.write(' gl_Position = vec4(wposition.x, wposition.y, 0.0, 1.0);')
geom.write(' }')
geom.write(' else if (p.x > p.y && p.x > p.z) {')
geom.write(' gl_Position = vec4(wposition.y, wposition.z, 0.0, 1.0);')
geom.write(' }')
geom.write(' else {')
geom.write(' gl_Position = vec4(wposition.x, wposition.z, 0.0, 1.0);')
geom.write(' }')
geom.write(' EmitVertex();')
geom.write('}')
geom.write('EndPrimitive();')
frag.add_include('../../Shaders/compiled.glsl')
frag.add_include('../../Shaders/std/math.glsl')
frag.write_header('#extension GL_ARB_shader_image_load_store : enable')
frag.add_uniform('layout(RGBA8) image3D voxels')
#frag.add_uniform('sampler2D sbase')
#frag.add_uniform('vec4 baseCol')
#frag.add_uniform('sampler2D shadowMap')
frag.write('const int voxelDimensions = 128;')
frag.add_uniform('vec3 lightPos', '_lampPosition')
frag.add_uniform('vec3 lightColor', '_lampColor')
frag.write('vec3 color = vec3(0.0);')
frag.write('if (!isInsideCube(wposition)) return;')
frag.write('vec3 basecol;')
frag.write('float roughness;')
frag.write('float metallic;')
frag.write('float occlusion;')
frag.write('float roughness;') #
frag.write('float metallic;') #
frag.write('float occlusion;') #
frag.write_pre = True
frag.write('mat3 TBN = mat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);') # TODO: discard, parse basecolor only
frag.write_pre = False
cycles.parse(mat_state.nodes, vert, frag, geom, tesc, tese, parse_opacity=False, parse_displacement=False)
frag.write('vec4 matCol = vec4(basecol, 1.0);')
# vec3 lampPos = geom_lampPos.xyz / geom_lampPos.w;
# lampPos.xy = lampPos.xy * 0.5 + 0.5;
# float distanceFromLight = texture(shadowMap, lampPos.xy).r * 2.0 - 1.0;
# const float shadowsBias = 0.0001;
# float visibility = float(distanceFromLight > lampPos.z - shadowsBias);
frag.write('float visibility = 1.0;')
frag.write('ivec3 camPos = ivec3(gl_FragCoord.x, gl_FragCoord.y, voxelDimensions * gl_FragCoord.z);')
frag.write('ivec3 texPos;')
frag.write('if (geom_axis == 1) {')
frag.write(' texPos.x = voxelDimensions - camPos.z;')
frag.write(' texPos.z = camPos.x;')
frag.write(' texPos.y = camPos.y;')
frag.write('}')
frag.write('else if (geom_axis == 2) {')
frag.write(' texPos.z = camPos.y;')
frag.write(' texPos.y = voxelDimensions - camPos.z;')
frag.write(' texPos.x = camPos.x;')
frag.write('}')
frag.write('else {')
frag.write(' texPos = camPos;')
frag.write('}')
frag.write('texPos.z = voxelDimensions - texPos.z - 1;')
frag.write('imageStore(voxels, texPos, vec4(matCol.rgb * visibility, 1.0));')
frag.write('color = basecol * lightColor * max(dot(wnormal, normalize(lightPos - wposition * voxelgiDimensions.x)), 0.0) * attenuate(distance(wposition * voxelgiDimensions.x, lightPos));')
frag.write('vec3 voxel = wposition * 0.5 + vec3(0.5);')
frag.write('imageStore(voxels, ivec3(voxelgiResolution * voxel), vec4(color, 1.0));') # , alpha
return con_voxel

View file

@ -36,7 +36,7 @@ def get_rpasses(material):
ar.append('mesh')
for con in add_mesh_contexts:
ar.append(con)
if bpy.data.worlds['Arm'].voxelgi:
if bpy.data.cameras[0].rp_voxelgi:
ar.append('voxel')
shadows_enabled = False

View file

@ -295,8 +295,6 @@ class DeferredLightPassNode(Node, CGPipelineTreeNode):
self.inputs.new('NodeSocketShader', "Target")
self.inputs.new('NodeSocketShader', "GBuffer")
self.inputs.new('NodeSocketShader', "Shadow Map")
# Testing voxels
self.inputs.new('NodeSocketShader', "Voxels")
self.outputs.new('NodeSocketShader', "Stage")
@ -311,8 +309,7 @@ class DeferredIndirectPassNode(Node, CGPipelineTreeNode):
self.inputs.new('NodeSocketShader', "Target")
self.inputs.new('NodeSocketShader', "GBuffer")
self.inputs.new('NodeSocketShader', "SSAO")
# Testing voxels
# self.inputs.new('NodeSocketShader', "Voxels")
self.inputs.new('NodeSocketShader', "Voxels")
self.outputs.new('NodeSocketShader', "Stage")

View file

@ -332,6 +332,8 @@ def init_properties():
name="Overlays", description="X-Ray pass", default='Auto', update=update_overlays_state)
bpy.types.Camera.rp_stereo = bpy.props.BoolProperty(name="Stereo", description="Stereo rendering", default=False, update=update_renderpath)
bpy.types.Camera.rp_greasepencil = bpy.props.BoolProperty(name="Grease Pencil", description="Render Grease Pencil data", default=False, update=update_renderpath)
bpy.types.Camera.rp_voxelgi = bpy.props.BoolProperty(name="Voxel GI", description="Voxel-based Global Illumination", default=False, update=update_renderpath)
bpy.types.Camera.rp_voxelgi_resolution = bpy.props.FloatVectorProperty(name="Resolution", description="3D texture resolution", size=3, default=[128, 128, 128], update=update_renderpath)
# For world
bpy.types.World.world_envtex_name = bpy.props.StringProperty(name="Environment Texture", default='')
@ -432,8 +434,7 @@ def init_properties():
items=[('Lambert', 'Lambert', 'Lambert'),
('Oren Nayar', 'Oren Nayar', 'Oren Nayar')],
name="Diffuse", description="Diffuse model", default='Lambert', update=assets.invalidate_shader_cache)
bpy.types.World.voxelgi = bpy.props.BoolProperty(name="Voxel GI", description="Voxel-based Global Illumination", default=False, update=assets.invalidate_shader_cache)
bpy.types.World.voxelgi_dimensions = bpy.props.FloatVectorProperty(name="Dimensions", description="3D texture size", size=3, default=[128, 128, 128], update=assets.invalidate_shader_cache)
bpy.types.World.generate_voxelgi_dimensions = bpy.props.FloatVectorProperty(name="Dimensions", description="Voxelization bounds", size=3, default=[16, 16, 16], update=assets.invalidate_shader_cache)
# For material
bpy.types.Material.is_cached = bpy.props.BoolProperty(name="Material Cached", description="No need to reexport material data", default=False, update=update_mat_cache)
bpy.types.Material.lock_cache = bpy.props.BoolProperty(name="Lock Material Cache", description="Prevent is_cached from updating", default=False)

View file

@ -219,6 +219,9 @@ class GenRPDataPropsPanel(bpy.types.Panel):
layout.prop(dat, "rp_worldnodes")
layout.prop(dat, "rp_stereo")
# layout.prop(dat, "rp_greasepencil")
layout.prop(dat, 'rp_voxelgi')
if dat.rp_voxelgi:
layout.prop(dat, 'rp_voxelgi_resolution')
layout.separator()
layout.prop(dat, "rp_render_to_texture")
@ -261,10 +264,6 @@ class PropsRPDataPropsPanel(bpy.types.Panel):
layout.prop(wrd, 'diffuse_model')
layout.prop(wrd, 'tessellation_enabled')
layout.prop(wrd, 'force_no_culling')
layout.prop(wrd, 'voxelgi')
if wrd.voxelgi:
layout.prop(wrd, 'voxelgi_dimensions')
layout.prop(wrd, 'arm_camera_props_advanced')
if wrd.arm_camera_props_advanced:
@ -318,6 +317,9 @@ class PropsRPDataPropsPanel(bpy.types.Panel):
layout.prop(wrd, 'generate_volumetric_light_air_turbidity')
layout.prop(wrd, 'generate_volumetric_light_air_color')
layout.label('Voxel GI')
layout.prop(wrd, 'generate_voxelgi_dimensions')
def register():
bpy.utils.register_module(__name__)

View file

@ -311,6 +311,12 @@ const vec3 compoFogColor = vec3(""" + str(round(wrd.generate_fog_color[0] * 100)
"""const float compoDOFDistance = """ + str(round(bpy.data.cameras[0].dof_distance * 100) / 100) + """;
const float compoDOFFstop = """ + str(round(bpy.data.cameras[0].gpu_dof.fstop * 100) / 100) + """;
const float compoDOFLength = """ + str(round(bpy.data.cameras[0].lens * 100) / 100) + """;
""")
if bpy.data.cameras[0].rp_voxelgi:
f.write(
"""const vec3 voxelgiResolution = ivec3(""" + str(round(bpy.data.cameras[0].rp_voxelgi_resolution[0])) + """, """ + str(round(bpy.data.cameras[0].rp_voxelgi_resolution[1])) + """, """ + str(round(bpy.data.cameras[0].rp_voxelgi_resolution[2])) + """);
const vec3 voxelgiDimensions = ivec3(""" + str(round(wrd.generate_voxelgi_dimensions[0])) + """, """ + str(round(wrd.generate_voxelgi_dimensions[1])) + """, """ + str(round(wrd.generate_voxelgi_dimensions[2])) + """);
""")
# Skinning
@ -319,7 +325,8 @@ const float compoDOFLength = """ + str(round(bpy.data.cameras[0].lens * 100) / 1
"""const int skinMaxBones = """ + str(wrd.generate_gpu_skin_max_bones) + """;
""")
f.write("""#endif // _COMPILED_GLSL_""")
f.write("""#endif // _COMPILED_GLSL_
""")
def write_traithx(class_name):
wrd = bpy.data.worlds['Arm']