Fix voxel emission
This commit is contained in:
parent
9704a5d294
commit
7b0aa99a2a
|
@ -91,17 +91,11 @@ void main() {
|
|||
#else
|
||||
vec3 wpos = p / voxelgiDimensions;
|
||||
#endif
|
||||
// vec4 indirectDiffuse = indirectDiffuseLight(wpos, n);
|
||||
vec4 indirectDiffuse = traceDiffuse(wpos, n);
|
||||
|
||||
vec3 reflectWorld = reflect(-v, n);
|
||||
vec3 indirectSpecular = traceSpecularVoxelCone(wpos, reflectWorld, n, metrough.y * 12.0 + 3.0);
|
||||
vec3 indirectSpecular = traceSpecular(wpos, n, v, metrough.y);
|
||||
indirectSpecular *= f0 * envBRDF.x + envBRDF.y;
|
||||
|
||||
fragColor.rgb = indirectDiffuse.rgb * voxelgiDiff * g1.rgb + indirectSpecular * voxelgiSpec;
|
||||
float occ = 1.0 - indirectDiffuse.a * 0.2 * voxelgiOcc;
|
||||
// fragColor.rgb *= occ;
|
||||
// float occ = indirectDiffuse.a;
|
||||
|
||||
#ifdef _SSAO
|
||||
fragColor.rgb *= texture(ssaotex, texCoord).r * 0.5 + 0.5;
|
||||
|
@ -158,7 +152,7 @@ void main() {
|
|||
#endif
|
||||
|
||||
#ifdef _VoxelGI
|
||||
fragColor.rgb += envl * voxelgiEnv * occ;
|
||||
fragColor.rgb += envl * voxelgiEnv;
|
||||
#else
|
||||
fragColor.rgb = envl;
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// References
|
||||
// https://github.com/Friduric/voxel-cone-tracing
|
||||
// https://github.com/Cigg/Voxel-Cone-Tracing
|
||||
// https://github.com/GreatBlambo/voxel_cone_tracing/
|
||||
|
@ -5,11 +6,17 @@
|
|||
// 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
|
||||
|
||||
const float MAX_DISTANCE = 1.73205080757;
|
||||
const float VOXEL_SIZE = 1.0 / voxelgiResolution;
|
||||
|
||||
uniform sampler3D voxels;
|
||||
|
||||
const float VOXEL_SIZE = 1.0 / voxelgiResolution;
|
||||
const float MAX_MIPMAP = 5.4;
|
||||
const float VOXEL_RATIO = 128.0 / voxelgiResolution;
|
||||
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);
|
||||
}
|
||||
|
||||
vec3 tangent(const vec3 n) {
|
||||
vec3 t1 = cross(n, vec3(0, 0, 1));
|
||||
|
@ -18,7 +25,7 @@ vec3 tangent(const vec3 n) {
|
|||
else return normalize(t2);
|
||||
}
|
||||
|
||||
// uvec3 face_indices(vec3 dir) {
|
||||
// uvec3 faceIndices(const vec3 dir) {
|
||||
// uvec3 ret;
|
||||
// ret.x = (dir.x < 0.0) ? 0 : 1;
|
||||
// ret.y = (dir.y < 0.0) ? 2 : 3;
|
||||
|
@ -26,185 +33,82 @@ vec3 tangent(const vec3 n) {
|
|||
// return ret;
|
||||
// }
|
||||
|
||||
// vec4 sample_voxel(vec3 pos, vec3 dir, uvec3 indices, float lod) {
|
||||
// vec4 sampleVoxel(const vec3 pos, vec3 dir, const uvec3 indices, const float lod) {
|
||||
// dir = abs(dir);
|
||||
// return dir.x * textureLod(voxels[indices.x], pos, lod) +
|
||||
// dir.y * textureLod(voxels[indices.y], pos, lod) +
|
||||
// dir.z * textureLod(voxels[indices.z], pos, lod);
|
||||
// }
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
vec4 trace_cone(vec3 origin, vec3 dir, float aperture, float max_dist) {
|
||||
vec4 traceCone(const vec3 origin, vec3 dir, float aperture, const float maxDist, const float offset) {
|
||||
dir = normalize(dir);
|
||||
// uvec3 indices = face_indices(dir);
|
||||
vec4 sample_color = vec4(0.0);
|
||||
float dist = 3 * VOXEL_SIZE;
|
||||
// uvec3 indices = faceIndices(dir);
|
||||
vec4 sampleCol = vec4(0.0);
|
||||
float dist = offset;
|
||||
float diam = dist * aperture;
|
||||
vec3 sample_position = dir * dist + origin;
|
||||
vec3 samplePos = dir * dist + origin;
|
||||
// Step until alpha > 1 or out of bounds
|
||||
while (sample_color.a < 1.0 && dist < max_dist) {
|
||||
while (sampleCol.a < 1.0 && dist < maxDist) {
|
||||
// Choose mip level based on the diameter of the cone
|
||||
float mip = max(log2(diam * voxelgiResolution), 0);
|
||||
// vec4 mip_sample = sample_voxel(sample_position, dir, indices, mip);
|
||||
vec4 mip_sample = textureLod(voxels, sample_position * 0.5 + vec3(0.5), mip);
|
||||
// vec4 mipSample = sampleVoxel(samplePos, dir, indices, mip);
|
||||
vec4 mipSample = textureLod(voxels, samplePos * 0.5 + vec3(0.5), mip);
|
||||
#ifdef _Cycles
|
||||
mipSample.rgb = min(mipSample.rgb * 0.9, vec3(0.9)) + max((mipSample.rgb - 0.9) * 200.0, 0.0); // Higher range to allow emission
|
||||
#endif
|
||||
// Blend mip sample with current sample color
|
||||
sample_color += ((1 - sample_color.a) * mip_sample) * (1.0 / max(voxelgiOcc, 0.1));
|
||||
float step_size = max(diam / 2, VOXEL_SIZE);
|
||||
dist += step_size;
|
||||
sampleCol += ((1 - sampleCol.a) * mipSample) * (1.0 / max(voxelgiOcc, 0.1));
|
||||
dist += max(diam / 2, VOXEL_SIZE); // Step size
|
||||
diam = dist * aperture;
|
||||
sample_position = dir * dist + origin;
|
||||
samplePos = dir * dist + origin;
|
||||
}
|
||||
return sample_color;
|
||||
return sampleCol;
|
||||
}
|
||||
|
||||
vec4 traceDiffuse(vec3 origin, vec3 normal) {
|
||||
vec4 traceDiffuse(const vec3 origin, const vec3 normal) {
|
||||
const float TAN_22_5 = 0.55785173935;
|
||||
const float MAX_DISTANCE = 1.73205080757;
|
||||
const float angle_mix = 0.5f;
|
||||
const float angleMix = 0.5f;
|
||||
const float aperture = TAN_22_5;
|
||||
const vec3 o1 = normalize(tangent(normal));
|
||||
const vec3 o2 = normalize(cross(o1, normal));
|
||||
const vec3 c1 = 0.5f * (o1 + o2);
|
||||
const vec3 c2 = 0.5f * (o1 - o2);
|
||||
|
||||
const float offset = 3 * VOXEL_SIZE;
|
||||
// Normal direction
|
||||
vec4 col = trace_cone(origin, normal, aperture, MAX_DISTANCE);
|
||||
|
||||
vec4 col = traceCone(origin, normal, aperture, MAX_DISTANCE, offset);
|
||||
// 4 side cones
|
||||
col += trace_cone(origin, mix(normal, o1, angle_mix), aperture, MAX_DISTANCE);
|
||||
col += trace_cone(origin, mix(normal, -o1, angle_mix), aperture, MAX_DISTANCE);
|
||||
col += trace_cone(origin, mix(normal, o2, angle_mix), aperture, MAX_DISTANCE);
|
||||
col += trace_cone(origin, mix(normal, -o2, angle_mix), aperture, MAX_DISTANCE);
|
||||
|
||||
col += traceCone(origin, mix(normal, o1, angleMix), aperture, MAX_DISTANCE, offset);
|
||||
col += traceCone(origin, mix(normal, -o1, angleMix), aperture, MAX_DISTANCE, offset);
|
||||
col += traceCone(origin, mix(normal, o2, angleMix), aperture, MAX_DISTANCE, offset);
|
||||
col += traceCone(origin, mix(normal, -o2, angleMix), aperture, MAX_DISTANCE, offset);
|
||||
// 4 corners
|
||||
col += trace_cone(origin, mix(normal, c1, angle_mix), aperture, MAX_DISTANCE);
|
||||
col += trace_cone(origin, mix(normal, -c1, angle_mix), aperture, MAX_DISTANCE);
|
||||
col += trace_cone(origin, mix(normal, c2, angle_mix), aperture, MAX_DISTANCE);
|
||||
col += trace_cone(origin, mix(normal, -c2, angle_mix), aperture, MAX_DISTANCE);
|
||||
|
||||
col += traceCone(origin, mix(normal, c1, angleMix), aperture, MAX_DISTANCE, offset);
|
||||
col += traceCone(origin, mix(normal, -c1, angleMix), aperture, MAX_DISTANCE, offset);
|
||||
col += traceCone(origin, mix(normal, c2, angleMix), aperture, MAX_DISTANCE, offset);
|
||||
col += traceCone(origin, mix(normal, -c2, angleMix), aperture, MAX_DISTANCE, offset);
|
||||
return col / 9.0;
|
||||
}
|
||||
|
||||
vec4 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
|
||||
float dist = 0.1953125 / (9.0 * VOXEL_RATIO * voxelgiStep);
|
||||
const float SQRT2 = 1.414213 * voxelgiRange;
|
||||
while (dist < SQRT2 && acc.a < 1.0) {
|
||||
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));
|
||||
|
||||
#ifdef _Cycles
|
||||
voxel.rgb = min(voxel.rgb * 0.9, vec3(0.9)) + max((voxel.rgb - 0.9) * 200.0, 0.0); // Higher range to allow emission
|
||||
#endif
|
||||
|
||||
acc += 0.075 * ll * voxel * pow(1.0 - voxel.a, 2.0);
|
||||
dist += ll * VOXEL_SIZE * 2.0;
|
||||
}
|
||||
return acc;
|
||||
float traceShadow(const vec3 origin, const vec3 dir, const float aperture, const float targetDistance) {
|
||||
const float offset = 3 * VOXEL_SIZE;
|
||||
return traceCone(origin, dir, aperture, targetDistance, offset).a;
|
||||
}
|
||||
|
||||
vec4 indirectDiffuseLight(const vec3 wpos, const vec3 normal) {
|
||||
const float ANGLE_MIX = 0.5; // Angle mix (1.0f -> orthogonal direction, 0.0f -> direction of normal)
|
||||
// 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 vec3 origin = wpos + normal * 3.8 * VOXEL_SIZE;
|
||||
|
||||
// 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
|
||||
vec4 acc = traceDiffuseVoxelCone(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 += traceDiffuseVoxelCone(origin + CONE_OFFSET * ortho, s1);
|
||||
acc += traceDiffuseVoxelCone(origin - CONE_OFFSET * ortho, s2);
|
||||
acc += traceDiffuseVoxelCone(origin + CONE_OFFSET * ortho2, s3);
|
||||
acc += traceDiffuseVoxelCone(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 += traceDiffuseVoxelCone(origin + CONE_OFFSET * corner, c1);
|
||||
acc += traceDiffuseVoxelCone(origin - CONE_OFFSET * corner, c2);
|
||||
acc += traceDiffuseVoxelCone(origin + CONE_OFFSET * corner2, c3);
|
||||
acc += traceDiffuseVoxelCone(origin - CONE_OFFSET * corner2, c4);
|
||||
|
||||
return acc;
|
||||
vec3 traceSpecular(const vec3 pos, const vec3 normal, const vec3 viewDir, const float roughness) {
|
||||
float rough = max(roughness, 0.15);
|
||||
float specularAperture = clamp(tan((3.14159265 / 2) * rough * 0.75), 0.0174533, 3.14159265);
|
||||
vec3 specularDir = normalize(reflect(-viewDir, normal));
|
||||
// Clamp to 1 grad and pi, exponent is angle of cone in radians
|
||||
const float offset = 6 * VOXEL_SIZE;
|
||||
return traceCone(pos, specularDir, specularAperture, MAX_DISTANCE, offset).xyz;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return 1.0 * pow(specularDiffusion + 1, 0.8) * acc.rgb;
|
||||
}
|
||||
|
||||
vec3 indirectRefractiveLight(const vec3 v, const vec3 normal, const vec3 specCol, const float opacity, const vec3 wpos) {
|
||||
const float refractiveIndex = 1.2;
|
||||
vec3 refraction = refract(v, normal, 1.0 / refractiveIndex);
|
||||
vec3 cmix = mix(0.5 * (specCol + vec3(1.0)), specCol, opacity);
|
||||
return cmix * traceSpecularVoxelCone(wpos, refraction, normal, 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);
|
||||
vec3 traceRefraction(const vec3 pos, const vec3 normal, const vec3 viewDir, const float roughness) {
|
||||
const float ior = 1.440;
|
||||
const float transmittance = 1.0;
|
||||
vec3 refraction = refract(viewDir, normal, 1.0 / ior);
|
||||
float rough = max(roughness, 0.15);
|
||||
float specularAperture = clamp(tan((3.14159265 / 2) * rough), 0.0174533, 3.14159265);
|
||||
const float offset = 3 * VOXEL_SIZE;
|
||||
return transmittance * traceCone(pos, refraction, specularAperture, MAX_DISTANCE, offset).xyz;
|
||||
}
|
||||
|
|
|
@ -155,6 +155,7 @@ def parsing_basecolor(b):
|
|||
|
||||
def parse_shader(node, socket):
|
||||
global parsing_basecol
|
||||
global emission_found
|
||||
out_basecol = 'vec3(0.8)'
|
||||
out_roughness = '0.0'
|
||||
out_metallic = '0.0'
|
||||
|
@ -182,7 +183,7 @@ def parse_shader(node, socket):
|
|||
c_state.warn(c_state.mat_name() + ' - Do not use Normal Map node with Armory PBR, connect Image Texture directly')
|
||||
parse_normal_map_color_input(node.inputs[5])
|
||||
# Emission
|
||||
if node.inputs[6].is_linked or node.inputs[6].default_value != 1.0:
|
||||
if node.inputs[6].is_linked or node.inputs[6].default_value != 0.0:
|
||||
out_emission = parse_value_input(node.inputs[6])
|
||||
emission_found = True
|
||||
out_basecol = '({0} + vec3({1} * 100.0))'.format(out_basecol, out_emission)
|
||||
|
|
Loading…
Reference in a new issue