Commit for 2021.05.03.7z
This commit is contained in:
parent
891301fc24
commit
e34f03c3d0
@ -2,25 +2,25 @@
|
||||
#extension GL_EXT_samplerless_texture_functions : require
|
||||
|
||||
#define MULTISAMPLING 1
|
||||
#define UF_DEFERRED_SAMPLING 0
|
||||
#define UF_CAN_DISCARD 1
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define CAN_DISCARD 1
|
||||
|
||||
#if !MULTISAMPLING
|
||||
layout (binding = 1) uniform usampler2D textureId;
|
||||
layout (binding = 2) uniform sampler2D textureNormals;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
layout (binding = 3) uniform sampler2D textureUvs;
|
||||
#else
|
||||
layout (binding = 3) uniform sampler2D textureAlbedo;
|
||||
#endif
|
||||
layout (binding = 3) uniform sampler2D textureAlbedo;
|
||||
#endif
|
||||
#else
|
||||
layout (binding = 1) uniform usampler2DMS textureId;
|
||||
layout (binding = 2) uniform sampler2DMS textureNormals;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
layout (binding = 3) uniform sampler2DMS textureUvs;
|
||||
#else
|
||||
layout (binding = 3) uniform sampler2DMS textureAlbedo;
|
||||
#endif
|
||||
layout (binding = 3) uniform sampler2DMS textureAlbedo;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct Cursor {
|
||||
@ -44,6 +44,7 @@ layout (location = 1) in float inAlpha;
|
||||
layout (location = 2) in Cursor inCursor;
|
||||
|
||||
layout (location = 0) out vec4 outAlbedo;
|
||||
|
||||
void main() {
|
||||
#if !MULTISAMPLING
|
||||
ivec2 screenSize = textureSize(textureId, 0);
|
||||
@ -53,7 +54,7 @@ void main() {
|
||||
ivec2 uv = ivec2(inUv * screenSize);
|
||||
if ( inCursor.radius.x <= 0 || inCursor.radius.y <= 0 ) {
|
||||
#if !MULTISAMPLING
|
||||
outAlbedo = texture(textureAlbedo, uv).rgba;
|
||||
outAlbedo = texture( textureAlbedo, uv ).rgba;
|
||||
#else
|
||||
outAlbedo = resolve( textureAlbedo, uv );
|
||||
#endif
|
||||
@ -62,7 +63,7 @@ void main() {
|
||||
float dist = pow(inUv.x - inCursor.position.x, 2) / pow(inCursor.radius.x, 2) + pow(inUv.y - inCursor.position.y, 2) / pow(inCursor.radius.y, 2);
|
||||
|
||||
#if !MULTISAMPLING
|
||||
outAlbedo = texture(textureAlbedo, inUv);
|
||||
outAlbedo = texture( textureAlbedo, inUv );
|
||||
#else
|
||||
outAlbedo = resolve( textureAlbedo, uv );
|
||||
#endif
|
||||
|
||||
@ -2,14 +2,25 @@
|
||||
#extension GL_EXT_samplerless_texture_functions : require
|
||||
|
||||
#define MULTISAMPLING 1
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define RAY_MARCH_FOG 1
|
||||
#define DEFERRED_SAMPLING 1
|
||||
|
||||
#define VXGI_NDC 1
|
||||
#define VXGI_SHADOWS 0
|
||||
#define VXGI_CASCADES 1
|
||||
|
||||
#define FOG 1
|
||||
#define FOG_RAY_MARCH 1
|
||||
|
||||
#define WHITENOISE 1
|
||||
#define GAMMA_CORRECT 1
|
||||
#define TONE_MAP 1
|
||||
|
||||
#define LAMBERT 0
|
||||
#define PBR 1
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
const float EPSILON = 0.00001;
|
||||
const float SQRT2 = 1.41421356237;
|
||||
|
||||
const float LIGHT_POWER_CUTOFF = 0.005;
|
||||
|
||||
@ -40,13 +51,20 @@ struct Matrices {
|
||||
mat4 iView[2];
|
||||
mat4 iProjection[2];
|
||||
mat4 iProjectionView[2];
|
||||
mat4 ortho;
|
||||
vec4 eyePos[2];
|
||||
mat4 vxgi;
|
||||
};
|
||||
|
||||
struct Ray {
|
||||
vec3 origin;
|
||||
vec3 direction;
|
||||
float distance;
|
||||
};
|
||||
|
||||
struct Space {
|
||||
vec3 eye;
|
||||
vec3 world;
|
||||
} position, normal, view;
|
||||
};
|
||||
|
||||
struct Fog {
|
||||
vec3 color;
|
||||
@ -107,6 +125,7 @@ struct Material {
|
||||
int indexLightmap;
|
||||
int modeAlpha;
|
||||
};
|
||||
|
||||
struct Texture {
|
||||
int index;
|
||||
int samp;
|
||||
@ -115,6 +134,7 @@ struct Texture {
|
||||
|
||||
vec4 lerp;
|
||||
};
|
||||
|
||||
struct DrawCall {
|
||||
int materialIndex;
|
||||
uint materials;
|
||||
@ -122,6 +142,29 @@ struct DrawCall {
|
||||
uint textures;
|
||||
};
|
||||
|
||||
struct SurfaceMaterial {
|
||||
uint id;
|
||||
|
||||
vec4 albedo;
|
||||
vec4 indirect;
|
||||
|
||||
float metallic;
|
||||
float roughness;
|
||||
float occlusion;
|
||||
};
|
||||
|
||||
struct Surface {
|
||||
vec2 uv;
|
||||
Space position;
|
||||
Space normal;
|
||||
|
||||
Ray ray;
|
||||
|
||||
SurfaceMaterial material;
|
||||
|
||||
vec4 fragment;
|
||||
} surface;
|
||||
|
||||
#if !MULTISAMPLING
|
||||
layout (input_attachment_index = 0, binding = 0) uniform usubpassInput samplerId;
|
||||
layout (input_attachment_index = 1, binding = 1) uniform subpassInput samplerNormal;
|
||||
@ -144,7 +187,7 @@ struct DrawCall {
|
||||
|
||||
layout (binding = 4) uniform UBO {
|
||||
Matrices matrices;
|
||||
|
||||
|
||||
Mode mode;
|
||||
Fog fog;
|
||||
|
||||
@ -154,12 +197,12 @@ layout (binding = 4) uniform UBO {
|
||||
uint drawCalls;
|
||||
|
||||
vec3 ambient;
|
||||
float kexp;
|
||||
|
||||
uint msaa;
|
||||
uint poissonSamples;
|
||||
float gamma;
|
||||
|
||||
float exposure;
|
||||
uint msaa;
|
||||
uint shadowSamples;
|
||||
uint padding1;
|
||||
} ubo;
|
||||
|
||||
layout (std140, binding = 5) readonly buffer Lights {
|
||||
@ -179,7 +222,6 @@ layout (binding = 9) uniform sampler3D samplerNoise;
|
||||
layout (binding = 10) uniform samplerCube samplerSkybox;
|
||||
layout (binding = 11) uniform sampler2D samplerTextures[TEXTURES];
|
||||
|
||||
|
||||
layout (location = 0) in vec2 inUv;
|
||||
layout (location = 1) in flat uint inPushConstantPass;
|
||||
|
||||
@ -239,9 +281,9 @@ vec3 gamma( vec3 i ) {
|
||||
return pow(i.rgb, vec3(1.0 / 2.2));
|
||||
}
|
||||
|
||||
vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, vec3 rayO, vec3 rayD ) {
|
||||
const vec3 t0 = (boundsMin - rayO) / rayD;
|
||||
const vec3 t1 = (boundsMax - rayO) / rayD;
|
||||
vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) {
|
||||
const vec3 t0 = (boundsMin - ray.origin) / ray.direction;
|
||||
const vec3 t1 = (boundsMax - ray.origin) / ray.direction;
|
||||
const vec3 tmin = min(t0, t1);
|
||||
const vec3 tmax = max(t0, t1);
|
||||
const float tStart = max(0, max( max(tmin.x, tmin.y), tmin.z ));
|
||||
@ -254,20 +296,20 @@ float sampleDensity( vec3 position ) {
|
||||
return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier;
|
||||
}
|
||||
|
||||
void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) {
|
||||
void fog( in Ray ray, inout vec3 i, float scale ) {
|
||||
if ( ubo.fog.stepScale <= 0 ) return;
|
||||
if ( ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return;
|
||||
|
||||
#if RAY_MARCH_FOG
|
||||
#if FOG_RAY_MARCH
|
||||
const float range = ubo.fog.range.y;
|
||||
const vec3 boundsMin = vec3(-range,-range,-range) + rayO;
|
||||
const vec3 boundsMax = vec3(range,range,range) + rayO;
|
||||
const vec3 boundsMin = vec3(-range,-range,-range) + ray.origin;
|
||||
const vec3 boundsMax = vec3(range,range,range) + ray.origin;
|
||||
const int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale );
|
||||
|
||||
const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD );
|
||||
const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, ray );
|
||||
const float dstToBox = rayBoxInfo.x;
|
||||
const float dstInsideBox = rayBoxInfo.y;
|
||||
const float depth = position.eye.z;
|
||||
const float depth = surface.position.eye.z;
|
||||
|
||||
float lightEnergy = 0;
|
||||
// march
|
||||
@ -278,7 +320,7 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) {
|
||||
float totalDensity = 0;
|
||||
float transmittance = 1;
|
||||
while ( dstTravelled < dstLimit ) {
|
||||
vec3 rayPos = rayO + rayD * (dstToBox + dstTravelled);
|
||||
vec3 rayPos = ray.origin + ray.direction * (dstToBox + dstTravelled);
|
||||
float density = sampleDensity(rayPos);
|
||||
if ( density > 0 ) {
|
||||
transmittance *= exp(-density * stepSize * ubo.fog.absorbtion);
|
||||
@ -293,7 +335,7 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) {
|
||||
const vec3 color = ubo.fog.color.rgb;
|
||||
const float inner = ubo.fog.range.x;
|
||||
const float outer = ubo.fog.range.y * scale;
|
||||
const float distance = length(-position.eye);
|
||||
const float distance = length(-surface.position.eye);
|
||||
const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 );
|
||||
|
||||
i.rgb = mix(i.rgb, color, factor);
|
||||
@ -304,12 +346,6 @@ vec3 decodeNormals( vec2 enc ) {
|
||||
const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) );
|
||||
const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y);
|
||||
return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) );
|
||||
/*
|
||||
vec2 fenc = enc*4-2;
|
||||
float f = dot(fenc,fenc);
|
||||
float g = sqrt(1-f/4);
|
||||
return normalize( vec3(fenc * g, 1 - f / 2) );
|
||||
*/
|
||||
}
|
||||
float wrap( float i ) {
|
||||
return fract(i);
|
||||
@ -347,7 +383,7 @@ uvec4 resolve( usubpassInputMS t ) {
|
||||
float shadowFactor( const Light light, float def ) {
|
||||
if ( !validTextureIndex(light.mapIndex) ) return 1.0;
|
||||
|
||||
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
|
||||
vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0);
|
||||
positionClip.xyz /= positionClip.w;
|
||||
|
||||
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
|
||||
@ -370,21 +406,34 @@ float shadowFactor( const Light light, float def ) {
|
||||
const vec2 uv = positionClip.xy * 0.5 + 0.5;
|
||||
const float bias = light.depthBias;
|
||||
const float eyeDepth = positionClip.z;
|
||||
const int samples = int(ubo.poissonSamples);
|
||||
if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor;
|
||||
const int samples = int(ubo.shadowSamples);
|
||||
if ( samples < 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor;
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
const int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples;
|
||||
const int index = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples;
|
||||
const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r;
|
||||
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
|
||||
}
|
||||
return factor;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 rayO = vec3(0);
|
||||
vec3 rayD = vec3(0);
|
||||
vec3 fragColor = vec3(0);
|
||||
vec4 postProcess() {
|
||||
#if FOG
|
||||
fog( surface.ray, surface.fragment.rgb, surface.fragment.a );
|
||||
#endif
|
||||
#if TONE_MAP
|
||||
surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * ubo.exposure);
|
||||
#endif
|
||||
#if GAMMA_CORRECT
|
||||
surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / ubo.gamma));
|
||||
#endif
|
||||
#if WHITENOISE
|
||||
if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) whitenoise(surface.fragment.rgb);
|
||||
#endif
|
||||
|
||||
return vec4(surface.fragment.rgb,1);
|
||||
}
|
||||
|
||||
void main() {
|
||||
{
|
||||
#if !MULTISAMPLING
|
||||
const float depth = subpassLoad(samplerDepth).r;
|
||||
@ -394,65 +443,79 @@ void main() {
|
||||
|
||||
vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * vec4(inUv * 2.0 - 1.0, depth, 1.0);
|
||||
positionEye /= positionEye.w;
|
||||
position.eye = positionEye.xyz;
|
||||
position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye );
|
||||
surface.position.eye = positionEye.xyz;
|
||||
surface.position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye );
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
const vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
const vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
const vec3 far3 = far4.xyz / far4.w;
|
||||
|
||||
rayO = near3;
|
||||
rayD = normalize( far3 - near3 );
|
||||
surface.ray.origin = near3;
|
||||
surface.ray.direction = normalize( far3 - near3 );
|
||||
}
|
||||
// separate our ray direction due to floating point precision problems
|
||||
if ( false ) {
|
||||
{
|
||||
const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) );
|
||||
const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
const vec3 far3 = far4.xyz / far4.w;
|
||||
|
||||
rayD = normalize( far3 - near3 );
|
||||
surface.ray.direction = normalize( far3 - near3 );
|
||||
}
|
||||
#else
|
||||
{
|
||||
const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) );
|
||||
const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
const vec3 far3 = far4.xyz / far4.w;
|
||||
|
||||
surface.ray.direction = normalize( far3 - near3 );
|
||||
surface.ray.origin = ubo.matrices.eyePos[inPushConstantPass].xyz;
|
||||
}
|
||||
#endif
|
||||
#if !MULTISAMPLING
|
||||
normal.world = decodeNormals( subpassLoad(samplerNormal).xy );
|
||||
surface.normal.world = decodeNormals( subpassLoad(samplerNormal).xy );
|
||||
const uvec2 ID = subpassLoad(samplerId).xy;
|
||||
#else
|
||||
normal.world = decodeNormals( resolve(samplerNormal).xy );
|
||||
surface.normal.world = decodeNormals( resolve(samplerNormal).xy );
|
||||
const uvec2 ID = resolve(samplerId).xy;
|
||||
#endif
|
||||
normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(normal.world, 0.0) );
|
||||
surface.normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(surface.normal.world, 0.0) );
|
||||
|
||||
if ( ID.x == 0 || ID.y == 0 ) {
|
||||
fragColor.rgb = texture( samplerSkybox, rayD ).rgb;
|
||||
fog(rayO, rayD, fragColor, 0.0);
|
||||
outFragColor = vec4(fragColor,1);
|
||||
surface.fragment.rgb = texture( samplerSkybox, surface.ray.direction ).rgb;
|
||||
surface.fragment.a = 0.0;
|
||||
outFragColor = postProcess();
|
||||
return;
|
||||
}
|
||||
const uint drawId = ID.x - 1;
|
||||
const DrawCall drawCall = drawCalls[drawId];
|
||||
const uint materialId = ID.y + drawCall.materialIndex - 1;
|
||||
const Material material = materials[materialId];
|
||||
vec4 A = material.colorBase;
|
||||
surface.material.id = ID.y + drawCall.materialIndex - 1;
|
||||
const Material material = materials[surface.material.id];
|
||||
surface.material.albedo = material.colorBase;
|
||||
surface.fragment = material.colorEmissive;
|
||||
#if DEFERRED_SAMPLING
|
||||
#if !MULTISAMPLING
|
||||
const vec2 uv = subpassLoad(samplerUv).xy;
|
||||
surface.uv = subpassLoad(samplerUv).xy;
|
||||
#else
|
||||
const vec2 uv = resolve(samplerUv).xy;
|
||||
surface.uv = resolve(samplerUv).xy;
|
||||
#endif
|
||||
const float mip = mipLevel(inUv.xy);
|
||||
const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas );
|
||||
Texture textureAtlas;
|
||||
if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas];
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexAtlas ) ) {
|
||||
Texture t = textures[drawCall.textureIndex + material.indexAlbedo];
|
||||
A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexAlbedo ) ) {
|
||||
const Texture t = textures[drawCall.textureIndex + material.indexAlbedo];
|
||||
surface.material.albedo = textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip );
|
||||
}
|
||||
// OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
A.a = 1;
|
||||
surface.material.albedo.a = 1;
|
||||
// BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
|
||||
@ -460,83 +523,72 @@ void main() {
|
||||
} else if ( material.modeAlpha == 2 ) {
|
||||
|
||||
}
|
||||
// Emissive textures
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexEmissive ) ) {
|
||||
const Texture t = textures[drawCall.textureIndex + material.indexEmissive];
|
||||
surface.fragment += textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip );
|
||||
}
|
||||
#else
|
||||
#if !MULTISAMPLING
|
||||
A = subpassLoad(samplerAlbedo);
|
||||
surface.material.albedo = subpassLoad(samplerAlbedo);
|
||||
#else
|
||||
A = resolve(samplerAlbedo);
|
||||
surface.material.albedo = resolve(samplerAlbedo);
|
||||
#endif
|
||||
#endif
|
||||
const float M = material.factorMetallic;
|
||||
const float R = material.factorRoughness;
|
||||
const float AO = 1.0f - material.factorOcclusion;
|
||||
surface.material.metallic = material.factorMetallic;
|
||||
surface.material.roughness = material.factorRoughness;
|
||||
surface.material.occlusion = material.factorOcclusion;
|
||||
|
||||
float litFactor = 1.0;
|
||||
if ( 0 <= material.indexLightmap ) {
|
||||
fragColor = A.rgb + ubo.ambient.rgb * (1 - AO);
|
||||
surface.fragment.rgb += surface.material.albedo.rgb + ubo.ambient.rgb * surface.material.occlusion;
|
||||
} else {
|
||||
fragColor = A.rgb * ubo.ambient.rgb * (1 - AO);
|
||||
surface.fragment.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion;
|
||||
}
|
||||
{
|
||||
const vec3 N = normal.eye;
|
||||
const vec3 F0 = mix(vec3(0.04), A.rgb, M);
|
||||
const vec3 Lo = normalize( -position.eye );
|
||||
const float cosLo = max(0.0, dot(N, Lo));
|
||||
// corrections
|
||||
surface.material.roughness *= 4.0;
|
||||
|
||||
{
|
||||
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
|
||||
const vec3 Lo = normalize( -surface.position.eye );
|
||||
const float cosLo = max(0.0, dot(surface.normal.eye, Lo));
|
||||
|
||||
for ( uint i = 0; i < ubo.lights; ++i ) {
|
||||
const Light light = lights[i];
|
||||
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
|
||||
const vec3 Lp = light.position;
|
||||
const vec3 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - position.eye;
|
||||
const vec3 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - surface.position.eye;
|
||||
const vec3 Li = normalize(Liu);
|
||||
#if VXGI_SHADOWS
|
||||
const float Ls = i < ubo.shadowSamples ? shadowFactor( light, 0.0 ) : 1.0;
|
||||
#else
|
||||
const float Ls = shadowFactor( light, 0.0 );
|
||||
#endif
|
||||
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
|
||||
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
|
||||
|
||||
const float cosLi = max(0.0, dot(N, Li));
|
||||
const float cosLi = max(0.0, dot(surface.normal.eye, Li));
|
||||
const vec3 Lr = light.color.rgb * light.power * La * Ls;
|
||||
#if LAMBERT
|
||||
const vec3 diffuse = A.rgb;
|
||||
const vec3 diffuse = surface.material.albedo.rgb;
|
||||
const vec3 specular = vec3(0);
|
||||
#elif PBR
|
||||
const vec3 Lh = normalize(Li + Lo);
|
||||
const float cosLh = max(0.0, dot(N, Lh));
|
||||
const float cosLh = max(0.0, dot(surface.normal.eye, Lh));
|
||||
|
||||
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
|
||||
const float D = ndfGGX( cosLh, R );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, R);
|
||||
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb;
|
||||
const float D = ndfGGX( cosLh, surface.material.roughness );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness);
|
||||
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
|
||||
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
|
||||
#endif
|
||||
// lightmapped, compute only specular
|
||||
if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specular) * Lr * cosLi;
|
||||
if ( light.type >= 0 && 0 <= material.indexLightmap ) surface.fragment.rgb += (specular) * Lr * cosLi;
|
||||
// point light, compute only diffuse
|
||||
// else if ( abs(light.type) == 1 ) fragColor.rgb += (diffuse) * Lr * cosLi;
|
||||
else fragColor.rgb += (diffuse + specular) * Lr * cosLi;
|
||||
litFactor += light.power * La * Ls;
|
||||
// else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi;
|
||||
else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi;
|
||||
surface.fragment.a += light.power * La * Ls;
|
||||
}
|
||||
}
|
||||
|
||||
fog(rayO, rayD, fragColor, litFactor);
|
||||
|
||||
#if TONE_MAP
|
||||
// fragColor = fragColor / (fragColor + 1.0f);
|
||||
fragColor = vec3(1.0) - exp(-fragColor * ubo.exposure);
|
||||
#endif
|
||||
#if GAMMA_CORRECT
|
||||
fragColor = pow(fragColor, vec3(1.0 / ubo.gama));
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
if ( (ubo.mode.type & (0x1 << 0)) == (0x1 << 0) ) {
|
||||
//dither1(fragColor);
|
||||
fragColor += dither2();
|
||||
}
|
||||
*/
|
||||
if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) {
|
||||
whitenoise(fragColor);
|
||||
}
|
||||
|
||||
outFragColor = vec4(fragColor,1);
|
||||
outFragColor = postProcess();
|
||||
}
|
||||
@ -2,13 +2,15 @@
|
||||
#extension GL_EXT_samplerless_texture_functions : require
|
||||
|
||||
#define MULTISAMPLING 1
|
||||
#define FOG 1
|
||||
#define RAY_MARCH_FOG 1
|
||||
#define WHITENOISE 1
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define SHADOW_CONE_TRACED 0
|
||||
#define VOXEL_TRACE_IN_NDC 1
|
||||
#define DEFERRED_SAMPLING 1
|
||||
|
||||
#define VXGI_NDC 0
|
||||
#define VXGI_SHADOWS 1
|
||||
|
||||
#define FOG 1
|
||||
#define FOG_RAY_MARCH 1
|
||||
|
||||
#define WHITENOISE 1
|
||||
#define GAMMA_CORRECT 1
|
||||
#define TONE_MAP 1
|
||||
|
||||
@ -41,6 +43,7 @@ const vec2 poissonDisk[16] = vec2[](
|
||||
);
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 256;
|
||||
layout (constant_id = 1) const uint CASCADES = 1;
|
||||
|
||||
struct Matrices {
|
||||
mat4 view[2];
|
||||
@ -48,13 +51,22 @@ struct Matrices {
|
||||
mat4 iView[2];
|
||||
mat4 iProjection[2];
|
||||
mat4 iProjectionView[2];
|
||||
mat4 voxel;
|
||||
vec4 eyePos[2];
|
||||
mat4 vxgi;
|
||||
};
|
||||
|
||||
struct Ray {
|
||||
vec3 origin;
|
||||
vec3 direction;
|
||||
|
||||
vec3 position;
|
||||
float distance;
|
||||
};
|
||||
|
||||
struct Space {
|
||||
vec3 eye;
|
||||
vec3 world;
|
||||
} position, normal, view;
|
||||
};
|
||||
|
||||
struct Fog {
|
||||
vec3 color;
|
||||
@ -115,6 +127,7 @@ struct Material {
|
||||
int indexLightmap;
|
||||
int modeAlpha;
|
||||
};
|
||||
|
||||
struct Texture {
|
||||
int index;
|
||||
int samp;
|
||||
@ -123,12 +136,37 @@ struct Texture {
|
||||
|
||||
vec4 lerp;
|
||||
};
|
||||
|
||||
struct DrawCall {
|
||||
int materialIndex;
|
||||
uint materials;
|
||||
int textureIndex;
|
||||
uint textures;
|
||||
};
|
||||
|
||||
struct SurfaceMaterial {
|
||||
uint id;
|
||||
|
||||
vec4 albedo;
|
||||
vec4 indirect;
|
||||
|
||||
float metallic;
|
||||
float roughness;
|
||||
float occlusion;
|
||||
};
|
||||
|
||||
struct Surface {
|
||||
vec2 uv;
|
||||
Space position;
|
||||
Space normal;
|
||||
|
||||
Ray ray;
|
||||
|
||||
SurfaceMaterial material;
|
||||
|
||||
vec4 fragment;
|
||||
} surface;
|
||||
|
||||
struct Voxel {
|
||||
uvec2 id;
|
||||
vec3 position;
|
||||
@ -169,12 +207,12 @@ layout (binding = 4) uniform UBO {
|
||||
uint drawCalls;
|
||||
|
||||
vec3 ambient;
|
||||
float kexp;
|
||||
|
||||
uint msaa;
|
||||
uint poissonSamples;
|
||||
float gamma;
|
||||
|
||||
float exposure;
|
||||
uint msaa;
|
||||
uint shadowSamples;
|
||||
uint padding1;
|
||||
} ubo;
|
||||
|
||||
layout (std140, binding = 5) readonly buffer Lights {
|
||||
@ -190,10 +228,10 @@ layout (std140, binding = 8) readonly buffer DrawCalls {
|
||||
DrawCall drawCalls[];
|
||||
};
|
||||
|
||||
layout (binding = 9) uniform usampler3D voxelId;
|
||||
layout (binding = 10) uniform sampler3D voxelNormal;
|
||||
layout (binding = 11) uniform sampler3D voxelUv;
|
||||
layout (binding = 12) uniform sampler3D voxelAlbedo;
|
||||
layout (binding = 9) uniform usampler3D voxelId[CASCADES];
|
||||
layout (binding = 10) uniform sampler3D voxelUv[CASCADES];
|
||||
layout (binding = 11) uniform sampler3D voxelNormal[CASCADES];
|
||||
layout (binding = 12) uniform sampler3D voxelRadiance[CASCADES];
|
||||
|
||||
layout (binding = 13) uniform sampler3D samplerNoise;
|
||||
layout (binding = 14) uniform samplerCube samplerSkybox;
|
||||
@ -258,9 +296,9 @@ vec3 gamma( vec3 i ) {
|
||||
return pow(i.rgb, vec3(1.0 / 2.2));
|
||||
}
|
||||
|
||||
vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, vec3 rayO, vec3 rayD ) {
|
||||
const vec3 t0 = (boundsMin - rayO) / rayD;
|
||||
const vec3 t1 = (boundsMax - rayO) / rayD;
|
||||
vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) {
|
||||
const vec3 t0 = (boundsMin - ray.origin) / ray.direction;
|
||||
const vec3 t1 = (boundsMax - ray.origin) / ray.direction;
|
||||
const vec3 tmin = min(t0, t1);
|
||||
const vec3 tmax = max(t0, t1);
|
||||
const float tStart = max(0, max( max(tmin.x, tmin.y), tmin.z ));
|
||||
@ -273,20 +311,20 @@ float sampleDensity( vec3 position ) {
|
||||
return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier;
|
||||
}
|
||||
|
||||
void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) {
|
||||
void fog( in Ray ray, inout vec3 i, float scale ) {
|
||||
if ( ubo.fog.stepScale <= 0 ) return;
|
||||
if ( ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return;
|
||||
|
||||
#if RAY_MARCH_FOG
|
||||
#if FOG_RAY_MARCH
|
||||
const float range = ubo.fog.range.y;
|
||||
const vec3 boundsMin = vec3(-range,-range,-range) + rayO;
|
||||
const vec3 boundsMax = vec3(range,range,range) + rayO;
|
||||
const vec3 boundsMin = vec3(-range,-range,-range) + ray.origin;
|
||||
const vec3 boundsMax = vec3(range,range,range) + ray.origin;
|
||||
const int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale );
|
||||
|
||||
const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD );
|
||||
const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, ray );
|
||||
const float dstToBox = rayBoxInfo.x;
|
||||
const float dstInsideBox = rayBoxInfo.y;
|
||||
const float depth = position.eye.z;
|
||||
const float depth = surface.position.eye.z;
|
||||
|
||||
float lightEnergy = 0;
|
||||
// march
|
||||
@ -297,7 +335,7 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) {
|
||||
float totalDensity = 0;
|
||||
float transmittance = 1;
|
||||
while ( dstTravelled < dstLimit ) {
|
||||
vec3 rayPos = rayO + rayD * (dstToBox + dstTravelled);
|
||||
vec3 rayPos = ray.origin + ray.direction * (dstToBox + dstTravelled);
|
||||
float density = sampleDensity(rayPos);
|
||||
if ( density > 0 ) {
|
||||
transmittance *= exp(-density * stepSize * ubo.fog.absorbtion);
|
||||
@ -312,7 +350,7 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) {
|
||||
const vec3 color = ubo.fog.color.rgb;
|
||||
const float inner = ubo.fog.range.x;
|
||||
const float outer = ubo.fog.range.y * scale;
|
||||
const float distance = length(-position.eye);
|
||||
const float distance = length(-surface.position.eye);
|
||||
const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 );
|
||||
|
||||
i.rgb = mix(i.rgb, color, factor);
|
||||
@ -323,12 +361,6 @@ vec3 decodeNormals( vec2 enc ) {
|
||||
const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) );
|
||||
const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y);
|
||||
return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) );
|
||||
/*
|
||||
vec2 fenc = enc*4-2;
|
||||
float f = dot(fenc,fenc);
|
||||
float g = sqrt(1-f/4);
|
||||
return normalize( vec3(fenc * g, 1 - f / 2) );
|
||||
*/
|
||||
}
|
||||
float wrap( float i ) {
|
||||
return fract(i);
|
||||
@ -363,10 +395,11 @@ uvec4 resolve( usubpassInputMS t ) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
#if !VXGI_SHADOWS
|
||||
float shadowFactor( const Light light, float def ) {
|
||||
if ( !validTextureIndex(light.mapIndex) ) return 1.0;
|
||||
|
||||
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
|
||||
vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0);
|
||||
positionClip.xyz /= positionClip.w;
|
||||
|
||||
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
|
||||
@ -389,25 +422,43 @@ float shadowFactor( const Light light, float def ) {
|
||||
const vec2 uv = positionClip.xy * 0.5 + 0.5;
|
||||
const float bias = light.depthBias;
|
||||
const float eyeDepth = positionClip.z;
|
||||
const int samples = int(ubo.poissonSamples);
|
||||
if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor;
|
||||
const int samples = int(ubo.shadowSamples);
|
||||
if ( samples < 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor;
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
const int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples;
|
||||
const int index = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples;
|
||||
const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r;
|
||||
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
|
||||
}
|
||||
return factor;
|
||||
}
|
||||
#endif
|
||||
|
||||
vec4 postProcess() {
|
||||
#if FOG
|
||||
fog( surface.ray, surface.fragment.rgb, surface.fragment.a );
|
||||
#endif
|
||||
#if TONE_MAP
|
||||
surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * ubo.exposure);
|
||||
#endif
|
||||
#if GAMMA_CORRECT
|
||||
surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / ubo.gamma));
|
||||
#endif
|
||||
#if WHITENOISE
|
||||
if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) whitenoise(surface.fragment.rgb);
|
||||
#endif
|
||||
|
||||
return vec4(surface.fragment.rgb,1);
|
||||
}
|
||||
|
||||
Voxel getVoxel( vec3 P ) {
|
||||
const vec3 uvw = vec3( ubo.matrices.voxel * vec4( P, 1.0f ) ) * 0.5f + 0.5f;
|
||||
const vec3 uvw = vec3( ubo.matrices.vxgi * vec4( P, 1.0f ) ) * 0.5f + 0.5f;
|
||||
|
||||
Voxel voxel;
|
||||
voxel.id = uvec2(texture(voxelId, uvw).xy);
|
||||
voxel.id = uvec2(texture(voxelId[0], uvw).xy);
|
||||
voxel.position = P;
|
||||
voxel.normal = decodeNormals( texture(voxelNormal, uvw).xy );
|
||||
voxel.uv = texture(voxelUv, uvw).xy;
|
||||
voxel.color = texture(voxelAlbedo, uvw).rgba;
|
||||
voxel.normal = decodeNormals( texture(voxelNormal[0], uvw).xy );
|
||||
voxel.uv = texture(voxelUv[0], uvw).xy;
|
||||
voxel.color = texture(voxelRadiance[0], uvw).rgba;
|
||||
|
||||
return voxel;
|
||||
}
|
||||
@ -417,76 +468,88 @@ struct VoxelInfo {
|
||||
vec3 max;
|
||||
|
||||
float mipmapLevels;
|
||||
float albedoSize;
|
||||
float radianceSize;
|
||||
float voxelSize;
|
||||
|
||||
float albedoSizeRecip;
|
||||
float radianceSizeRecip;
|
||||
float voxelSizeRecip;
|
||||
};
|
||||
VoxelInfo voxelInfo;
|
||||
} voxelInfo;
|
||||
|
||||
vec4 voxelConeTrace( vec3 rayO, vec3 rayD, float aperture, float maxDistance ) {
|
||||
#if VOXEL_TRACE_IN_NDC
|
||||
rayO = vec3( ubo.matrices.voxel * vec4( rayO, 1.0 ) );
|
||||
rayD = vec3( ubo.matrices.voxel * vec4( rayD, 0.0 ) );
|
||||
const float granularity = 1.0f / 8.0f;
|
||||
const uint maxSteps = uint(voxelInfo.albedoSize * 2);
|
||||
vec4 voxelTrace( inout Ray ray, float aperture, float maxDistance ) {
|
||||
#if VXGI_NDC
|
||||
ray.origin = vec3( ubo.matrices.vxgi * vec4( ray.origin, 1.0 ) );
|
||||
ray.direction = vec3( ubo.matrices.vxgi * vec4( ray.direction, 0.0 ) );
|
||||
const float granularity = 1.0f / 16.0f;
|
||||
const uint maxSteps = uint(voxelInfo.radianceSize * 2);
|
||||
#else
|
||||
const float granularity = 8.0f;
|
||||
const uint maxSteps = uint(voxelInfo.albedoSize * granularity);
|
||||
const float granularity = 10.0f;
|
||||
const uint maxSteps = uint(voxelInfo.radianceSize * granularity);
|
||||
#endif
|
||||
const float granularityRecip = 1.0f / granularity;
|
||||
// box
|
||||
const vec2 rayBoxInfo = rayBoxDst( voxelInfo.min, voxelInfo.max, rayO, rayD );
|
||||
const vec2 rayBoxInfo = rayBoxDst( voxelInfo.min, voxelInfo.max, ray );
|
||||
const float tStart = rayBoxInfo.x;
|
||||
const float tEnd = maxDistance > 0 ? min(maxDistance, rayBoxInfo.y) : rayBoxInfo.y;
|
||||
// steps
|
||||
const float tDelta = voxelInfo.voxelSize * granularityRecip;
|
||||
// marcher
|
||||
float t = tStart + 2.0 * SQRT2;
|
||||
vec3 rayPos = vec3(0);
|
||||
ray.distance = tStart + tDelta * granularity;
|
||||
ray.position = vec3(0);
|
||||
vec4 radiance = vec4(0);
|
||||
vec3 uvw = vec3(0);
|
||||
// cone mipmap shit
|
||||
const float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
||||
float coneDiameter = coneCoefficient * t;
|
||||
float coneDiameter = coneCoefficient * ray.distance;
|
||||
float level = aperture > 0 ? log2( coneDiameter ) : 0;
|
||||
// results
|
||||
vec4 color = vec4(0);
|
||||
float occlusion = 0.0;
|
||||
uint stepCounter = 0;
|
||||
float tD;
|
||||
const float falloff = 256.0f;
|
||||
const float falloff = 32.0f; // maxDistance > 0.0 ? 0.0f : 256.0f;
|
||||
const vec3 voxelBoundsRecip = 1.0f / (voxelInfo.max - voxelInfo.min);
|
||||
// while ( t < tEnd && color.a < 1.0 && occlusion < 1.0 && stepCounter++ < maxSteps ) {
|
||||
while ( t < tEnd && color.a < 1.0 && occlusion < 1.0 ) {
|
||||
t += tDelta * (aperture > 0 ? coneDiameter : 1);
|
||||
rayPos = rayO + rayD * t;
|
||||
#if VOXEL_TRACE_IN_NDC
|
||||
uvw = rayPos * 0.5 + 0.5;
|
||||
// while ( ray.distance < tEnd && color.a < 1.0 && occlusion < 1.0 && stepCounter++ < maxSteps ) {
|
||||
while ( ray.distance < tEnd && color.a < 1.0 && occlusion < 1.0 ) {
|
||||
ray.distance += tDelta * (aperture > 0 ? coneDiameter : 1);
|
||||
ray.position = ray.origin + ray.direction * ray.distance;
|
||||
#if VXGI_NDC
|
||||
uvw = ray.position * 0.5 + 0.5;
|
||||
#else
|
||||
uvw = (rayPos - voxelInfo.min) * voxelBoundsRecip;
|
||||
uvw = (ray.position - voxelInfo.min) * voxelBoundsRecip;
|
||||
#endif
|
||||
if ( abs(uvw.x) > 1.0 || abs(uvw.y) > 1.0 || abs(uvw.z) > 1.0 ) break;
|
||||
coneDiameter = coneCoefficient * t;
|
||||
coneDiameter = coneCoefficient * ray.distance;
|
||||
level = log2( coneDiameter );
|
||||
if ( level >= voxelInfo.mipmapLevels ) break;
|
||||
radiance = texture(voxelAlbedo, uvw, level);
|
||||
radiance = textureLod(voxelRadiance[0], uvw.xzy, level);
|
||||
|
||||
color += (1.0 - color.a) * radiance;
|
||||
occlusion += ((1.0f - occlusion) * radiance.a) / (1.0f + falloff * coneDiameter);
|
||||
}
|
||||
return vec4(color.rgb, occlusion);
|
||||
return maxDistance > 0 ? color : vec4(color.rgb, occlusion);
|
||||
// return vec4(color.rgb, occlusion);
|
||||
}
|
||||
vec4 voxelConeTrace( vec3 rayO, vec3 rayD, float aperture ) {
|
||||
return voxelConeTrace( rayO, rayD, aperture, 0 );
|
||||
vec4 voxelConeTrace( inout Ray ray, float aperture ) {
|
||||
return voxelTrace( ray, aperture, 0 );
|
||||
}
|
||||
vec4 voxelTrace( inout Ray ray, float maxDistance ) {
|
||||
return voxelTrace( ray, 0, maxDistance );
|
||||
}
|
||||
|
||||
#if VXGI_SHADOWS
|
||||
float shadowFactor( const Light light, float def ) {
|
||||
const float SHADOW_APERTURE = 0.2;
|
||||
const float DEPTH_BIAS = 0.0;
|
||||
|
||||
Ray ray;
|
||||
ray.origin = surface.position.world;
|
||||
ray.direction = normalize( light.position - surface.position.world );
|
||||
ray.origin -= ray.direction * 0.5;
|
||||
float z = distance( surface.position.world, light.position ) - DEPTH_BIAS;
|
||||
return 1.0 - voxelTrace( ray, SHADOW_APERTURE, z ).a;
|
||||
}
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
vec3 rayO = vec3(0);
|
||||
vec3 rayD = vec3(0);
|
||||
vec3 fragColor = vec3(0);
|
||||
|
||||
{
|
||||
#if !MULTISAMPLING
|
||||
const float depth = subpassLoad(samplerDepth).r;
|
||||
@ -496,65 +559,79 @@ void main() {
|
||||
|
||||
vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * vec4(inUv * 2.0 - 1.0, depth, 1.0);
|
||||
positionEye /= positionEye.w;
|
||||
position.eye = positionEye.xyz;
|
||||
position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye );
|
||||
surface.position.eye = positionEye.xyz;
|
||||
surface.position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye );
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
const vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
const vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
const vec3 far3 = far4.xyz / far4.w;
|
||||
|
||||
rayO = near3;
|
||||
rayD = normalize( far3 - near3 );
|
||||
surface.ray.origin = near3;
|
||||
surface.ray.direction = normalize( far3 - near3 );
|
||||
}
|
||||
// separate our ray direction due to floating point precision problems
|
||||
if ( true ) {
|
||||
{
|
||||
const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) );
|
||||
const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
const vec3 far3 = far4.xyz / far4.w;
|
||||
|
||||
rayD = normalize( far3 - near3 );
|
||||
surface.ray.direction = normalize( far3 - near3 );
|
||||
}
|
||||
#else
|
||||
{
|
||||
const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) );
|
||||
const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
const vec3 far3 = far4.xyz / far4.w;
|
||||
|
||||
surface.ray.direction = normalize( far3 - near3 );
|
||||
surface.ray.origin = ubo.matrices.eyePos[inPushConstantPass].xyz;
|
||||
}
|
||||
#endif
|
||||
#if !MULTISAMPLING
|
||||
normal.world = decodeNormals( subpassLoad(samplerNormal).xy );
|
||||
surface.normal.world = decodeNormals( subpassLoad(samplerNormal).xy );
|
||||
const uvec2 ID = subpassLoad(samplerId).xy;
|
||||
#else
|
||||
normal.world = decodeNormals( resolve(samplerNormal).xy );
|
||||
surface.normal.world = decodeNormals( resolve(samplerNormal).xy );
|
||||
const uvec2 ID = resolve(samplerId).xy;
|
||||
#endif
|
||||
normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(normal.world, 0.0) );
|
||||
surface.normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(surface.normal.world, 0.0) );
|
||||
|
||||
if ( ID.x == 0 || ID.y == 0 ) {
|
||||
fragColor.rgb = texture( samplerSkybox, rayD ).rgb;
|
||||
fog(rayO, rayD, fragColor, 0.5);
|
||||
outFragColor = vec4(fragColor,1);
|
||||
surface.fragment.rgb = texture( samplerSkybox, surface.ray.direction ).rgb;
|
||||
surface.fragment.a = 0.0;
|
||||
outFragColor = postProcess();
|
||||
return;
|
||||
}
|
||||
const uint drawId = ID.x - 1;
|
||||
const DrawCall drawCall = drawCalls[drawId];
|
||||
const uint materialId = ID.y + drawCall.materialIndex - 1;
|
||||
const Material material = materials[materialId];
|
||||
vec4 A = material.colorBase;
|
||||
surface.material.id = ID.y + drawCall.materialIndex - 1;
|
||||
const Material material = materials[surface.material.id];
|
||||
surface.material.albedo = material.colorBase;
|
||||
surface.fragment = material.colorEmissive;
|
||||
#if DEFERRED_SAMPLING
|
||||
#if !MULTISAMPLING
|
||||
const vec2 uv = subpassLoad(samplerUv).xy;
|
||||
surface.uv = subpassLoad(samplerUv).xy;
|
||||
#else
|
||||
const vec2 uv = resolve(samplerUv).xy;
|
||||
surface.uv = resolve(samplerUv).xy;
|
||||
#endif
|
||||
const float mip = mipLevel(inUv.xy);
|
||||
const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas );
|
||||
Texture textureAtlas;
|
||||
if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas];
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexAtlas ) ) {
|
||||
Texture t = textures[drawCall.textureIndex + material.indexAlbedo];
|
||||
A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexAlbedo ) ) {
|
||||
const Texture t = textures[drawCall.textureIndex + material.indexAlbedo];
|
||||
surface.material.albedo = textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip );
|
||||
}
|
||||
// OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
A.a = 1;
|
||||
surface.material.albedo.a = 1;
|
||||
// BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
|
||||
@ -562,142 +639,177 @@ void main() {
|
||||
} else if ( material.modeAlpha == 2 ) {
|
||||
|
||||
}
|
||||
// Emissive textures
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexEmissive ) ) {
|
||||
const Texture t = textures[drawCall.textureIndex + material.indexEmissive];
|
||||
surface.fragment += textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip );
|
||||
}
|
||||
#else
|
||||
#if !MULTISAMPLING
|
||||
A = subpassLoad(samplerAlbedo);
|
||||
surface.material.albedo = subpassLoad(samplerAlbedo);
|
||||
#else
|
||||
A = resolve(samplerAlbedo);
|
||||
surface.material.albedo = resolve(samplerAlbedo);
|
||||
#endif
|
||||
#endif
|
||||
const float M = material.factorMetallic;
|
||||
const float R = material.factorRoughness;
|
||||
float AO = material.factorOcclusion;
|
||||
|
||||
vec4 indirectLighting = vec4(0);
|
||||
surface.material.metallic = material.factorMetallic;
|
||||
surface.material.roughness = material.factorRoughness;
|
||||
surface.material.occlusion = material.factorOcclusion;
|
||||
// GI
|
||||
{
|
||||
const vec3 P = surface.position.world;
|
||||
const vec3 N = surface.normal.world;
|
||||
|
||||
#if 1
|
||||
const vec3 right = normalize(orthogonal(N));
|
||||
const vec3 up = normalize(cross(right, N));
|
||||
|
||||
const uint CONES_COUNT = 6;
|
||||
const vec3 CONES[] = {
|
||||
N,
|
||||
normalize(N + 0.0f * right + 0.866025f * up),
|
||||
normalize(N + 0.823639f * right + 0.267617f * up),
|
||||
normalize(N + 0.509037f * right + -0.7006629f * up),
|
||||
normalize(N + -0.50937f * right + -0.7006629f * up),
|
||||
normalize(N + -0.823639f * right + 0.267617f * up),
|
||||
};
|
||||
#else
|
||||
const vec3 ortho = normalize(orthogonal(N));
|
||||
const vec3 ortho2 = normalize(cross(ortho, N));
|
||||
|
||||
const vec3 corner = 0.5f * (ortho + ortho2);
|
||||
const vec3 corner2 = 0.5f * (ortho - ortho2);
|
||||
|
||||
const uint CONES_COUNT = 9;
|
||||
const vec3 CONES[] = {
|
||||
N,
|
||||
normalize(mix(N, ortho, 0.5)),
|
||||
normalize(mix(N, -ortho, 0.5)),
|
||||
normalize(mix(N, ortho2, 0.5)),
|
||||
normalize(mix(N, -ortho2, 0.5)),
|
||||
normalize(mix(N, corner, 0.5)),
|
||||
normalize(mix(N, -corner, 0.5)),
|
||||
normalize(mix(N, corner2, 0.5)),
|
||||
normalize(mix(N, -corner2, 0.5)),
|
||||
};
|
||||
#endif
|
||||
|
||||
const float DIFFUSE_CONE_APERTURE = 0.57735f;
|
||||
const float DIFFUSE_INDIRECT_FACTOR = 1.0f / float(CONES_COUNT);
|
||||
|
||||
const float SPECULAR_CONE_APERTURE = clamp(tan(PI * 0.5f * surface.material.roughness), 0.0174533f, PI); // tan( R * PI * 0.5f * 0.1f );
|
||||
const float SPECULAR_INDIRECT_FACTOR = (1.0 - surface.material.metallic) * 0.5; // 1.0f;
|
||||
|
||||
vec4 indirectDiffuse = vec4(0);
|
||||
vec4 indirectSpecular = vec4(0);
|
||||
|
||||
const vec3 P = position.world;
|
||||
const vec3 N = normal.world;
|
||||
|
||||
const float DIFFUSE_CONE_APERTURE = 0.57735f;
|
||||
const float DIFFUSE_INDIRECT_FACTOR = 1.0f / 6.0f; // 1.0f;
|
||||
|
||||
const float SPECULAR_CONE_APERTURE = clamp(tan(PI * 0.5f * R), 0.0174533f, PI); // tan( R * PI * 0.5f * 0.1f );
|
||||
const float SPECULAR_INDIRECT_FACTOR = (1.0 - M) * 0.5; // 1.0f;
|
||||
|
||||
const vec4 CONES[] = {
|
||||
vec4(0.0f, 1.0f, 0.0f, PI / 4.0f),
|
||||
vec4(0.0f, 0.5f, 0.866025f, 3.0f * PI / 20.0f),
|
||||
vec4(0.823639f, 0.5f, 0.267617f, 3.0f * PI / 20.0f),
|
||||
vec4(0.509037f, 0.5f, -0.7006629f, 3.0f * PI / 20.0f),
|
||||
vec4(-0.50937f, 0.5f, -0.7006629f, 3.0f * PI / 20.0f),
|
||||
vec4(-0.823639f, 0.5f, 0.267617f, 3.0f * PI / 20.0f)
|
||||
};
|
||||
{
|
||||
voxelInfo.albedoSize = textureSize( voxelAlbedo, 0 ).x;
|
||||
voxelInfo.albedoSizeRecip = 1.0 / voxelInfo.albedoSize;
|
||||
voxelInfo.mipmapLevels = log2(voxelInfo.albedoSize) + 1; //textureQueryLod( voxelAlbedo, vec3(0) ).x;
|
||||
#if VOXEL_TRACE_IN_NDC
|
||||
voxelInfo.radianceSize = textureSize( voxelRadiance[0], 0 ).x;
|
||||
voxelInfo.radianceSizeRecip = 1.0 / voxelInfo.radianceSize;
|
||||
voxelInfo.mipmapLevels = log2(voxelInfo.radianceSize) + 1;
|
||||
#if VXGI_NDC
|
||||
voxelInfo.min = vec3( -1 );
|
||||
voxelInfo.max = vec3( 1 );
|
||||
voxelInfo.voxelSize = voxelInfo.albedoSizeRecip;
|
||||
voxelInfo.voxelSize = voxelInfo.radianceSizeRecip;
|
||||
#else
|
||||
const mat4 inverseOrtho = inverse( ubo.matrices.voxel );
|
||||
const mat4 inverseOrtho = inverse( ubo.matrices.vxgi );
|
||||
voxelInfo.min = vec3( inverseOrtho * vec4( -1, -1, -1, 1 ) );
|
||||
voxelInfo.max = vec3( inverseOrtho * vec4( 1, 1, 1, 1 ) );
|
||||
voxelInfo.voxelSize = 1;
|
||||
#endif
|
||||
voxelInfo.voxelSizeRecip = 1.0 / voxelInfo.voxelSize;
|
||||
}
|
||||
|
||||
// outFragColor.rgb = voxelConeTrace( rayO, rayD, 0 ).rgb; return;
|
||||
// outFragColor.rgb = voxelConeTrace( surface.ray, 0 ).rgb; return;
|
||||
|
||||
Ray ray;
|
||||
if ( DIFFUSE_INDIRECT_FACTOR > 0.0f ) {
|
||||
vec3 guide = vec3(0.0f, 1.0f, 0.0f);
|
||||
if (abs(dot(N,guide)) == 1.0f) guide = vec3(0.0f, 0.0f, 1.0f);
|
||||
|
||||
const vec3 right = normalize(guide - dot(N, guide) * N);
|
||||
const vec3 up = cross(right, N);
|
||||
for ( uint i = 0; i < 6; ++i ) {
|
||||
const vec3 coneDirection = normalize(N + CONES[i].x * right + CONES[i].z * up);
|
||||
indirectDiffuse += voxelConeTrace(P, coneDirection * ( dot(coneDirection, N) < 0 ? -1 : 1 ), DIFFUSE_CONE_APERTURE ) * CONES[i].w;
|
||||
for ( uint i = 0; i < CONES_COUNT; ++i ) {
|
||||
float weight = i == 0 ? PI * 0.25f : PI * 0.15f;
|
||||
ray.origin = P;
|
||||
ray.direction = CONES[i].xyz;
|
||||
indirectDiffuse += voxelConeTrace( ray, DIFFUSE_CONE_APERTURE ) * weight;
|
||||
}
|
||||
// indirectDiffuse.rgb *= A.rgb;
|
||||
// outFragColor.rgb = indirectDiffuse.rgb; return;
|
||||
AO = indirectDiffuse.a;
|
||||
surface.material.occlusion = 1.0 - clamp(indirectDiffuse.a, 0.0, 1.0);
|
||||
// outFragColor.rgb = indirectDiffuse.rgb; return;
|
||||
// outFragColor.rgb = vec3(surface.material.occlusion); return;
|
||||
}
|
||||
if ( SPECULAR_INDIRECT_FACTOR > 0.0f ) {
|
||||
// const vec3 R = reflect( normalize(P - rayO), N );
|
||||
const vec3 R = reflect( normalize(P - rayO), N );
|
||||
indirectSpecular = voxelConeTrace( P, R, SPECULAR_CONE_APERTURE );
|
||||
// outFragColor.rgb = indirectSpecular.rgb; return;
|
||||
ray.origin = P;
|
||||
ray.direction = reflect( normalize(P - surface.ray.origin), N );
|
||||
indirectSpecular = voxelConeTrace( ray, SPECULAR_CONE_APERTURE );
|
||||
// outFragColor.rgb = indirectSpecular.rgb; return;
|
||||
/*
|
||||
if ( indirectSpecular.a < 1.0 ) {
|
||||
vec4 radiance = texture( samplerSkybox, ray.direction ) * 0.25;
|
||||
indirectSpecular += (1.0 - indirectSpecular.a) * radiance;
|
||||
}
|
||||
*/
|
||||
}
|
||||
indirectLighting = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR;
|
||||
// outFragColor.rgb = indirectLighting.rgb; return;
|
||||
surface.material.indirect = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR;
|
||||
// outFragColor.rgb = surface.material.indirect.rgb; return;
|
||||
}
|
||||
|
||||
float litFactor = 1.0;
|
||||
if ( 0 <= material.indexLightmap ) {
|
||||
fragColor = A.rgb + ubo.ambient.rgb * (1 - AO) + indirectLighting.rgb;
|
||||
surface.fragment.rgb += surface.material.albedo.rgb + ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb;
|
||||
} else {
|
||||
fragColor = A.rgb * ubo.ambient.rgb * (1 - AO) + indirectLighting.rgb;
|
||||
surface.fragment.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb;
|
||||
}
|
||||
#if DEFERRED_SAMPLING
|
||||
// deferred sampling doesn't have a blended albedo buffer
|
||||
// in place we'll just cone trace behind the window
|
||||
if ( surface.material.albedo.a < 1.0 ) {
|
||||
Ray ray;
|
||||
ray.origin = surface.position.world;
|
||||
ray.direction = surface.ray.direction;
|
||||
vec4 radiance = voxelConeTrace( ray, surface.material.albedo.a );
|
||||
surface.fragment.rgb += (1.0 - surface.material.albedo.a) * radiance.rgb;
|
||||
}
|
||||
#endif
|
||||
|
||||
// corrections
|
||||
surface.material.roughness *= 4.0;
|
||||
|
||||
{
|
||||
const float R = material.factorRoughness * 2.0f;
|
||||
const vec3 N = normal.eye;
|
||||
const vec3 F0 = mix(vec3(0.04), A.rgb, M);
|
||||
const vec3 Lo = normalize( -position.eye );
|
||||
const float cosLo = max(0.0, dot(N, Lo));
|
||||
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
|
||||
const vec3 Lo = normalize( -surface.position.eye );
|
||||
const float cosLo = max(0.0, dot(surface.normal.eye, Lo));
|
||||
|
||||
for ( uint i = 0; i < ubo.lights; ++i ) {
|
||||
const Light light = lights[i];
|
||||
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
|
||||
const vec3 Lp = light.position;
|
||||
const vec3 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - position.eye;
|
||||
const vec3 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - surface.position.eye;
|
||||
const vec3 Li = normalize(Liu);
|
||||
#if VXGI_SHADOWS
|
||||
const float Ls = i < ubo.shadowSamples ? shadowFactor( light, 0.0 ) : 1.0;
|
||||
#else
|
||||
const float Ls = shadowFactor( light, 0.0 );
|
||||
#endif
|
||||
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
|
||||
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
|
||||
|
||||
const float cosLi = max(0.0, dot(N, Li));
|
||||
const float cosLi = max(0.0, dot(surface.normal.eye, Li));
|
||||
const vec3 Lr = light.color.rgb * light.power * La * Ls;
|
||||
#if LAMBERT
|
||||
const vec3 diffuse = A.rgb;
|
||||
const vec3 diffuse = surface.material.albedo.rgb;
|
||||
const vec3 specular = vec3(0);
|
||||
#elif PBR
|
||||
const vec3 Lh = normalize(Li + Lo);
|
||||
const float cosLh = max(0.0, dot(N, Lh));
|
||||
const float cosLh = max(0.0, dot(surface.normal.eye, Lh));
|
||||
|
||||
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
|
||||
const float D = ndfGGX( cosLh, R );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, R);
|
||||
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb;
|
||||
const float D = ndfGGX( cosLh, surface.material.roughness );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness);
|
||||
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
|
||||
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
|
||||
#endif
|
||||
// lightmapped, compute only specular
|
||||
if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specular) * Lr * cosLi;
|
||||
if ( light.type >= 0 && 0 <= material.indexLightmap ) surface.fragment.rgb += (specular) * Lr * cosLi;
|
||||
// point light, compute only diffuse
|
||||
// else if ( abs(light.type) == 1 ) fragColor.rgb += (diffuse) * Lr * cosLi;
|
||||
else fragColor.rgb += (diffuse + specular) * Lr * cosLi;
|
||||
litFactor += light.power * La * Ls;
|
||||
// else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi;
|
||||
else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi;
|
||||
surface.fragment.a += light.power * La * Ls;
|
||||
}
|
||||
}
|
||||
|
||||
#if FOG
|
||||
fog(rayO, rayD, fragColor, 1.0 ); //litFactor);
|
||||
#endif
|
||||
#if TONE_MAP
|
||||
fragColor = vec3(1.0) - exp(-fragColor * ubo.exposure);
|
||||
#endif
|
||||
#if GAMMA_CORRECT
|
||||
fragColor = pow(fragColor, vec3(1.0 / ubo.gamma));
|
||||
#endif
|
||||
#if WHITENOISE
|
||||
if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) whitenoise(fragColor);
|
||||
#endif
|
||||
|
||||
outFragColor = vec4(fragColor,1);
|
||||
outFragColor = postProcess();
|
||||
}
|
||||
@ -4,8 +4,7 @@
|
||||
layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
|
||||
|
||||
#define MULTISAMPLING 1
|
||||
#define RAY_MARCH_FOG 1
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define DEFERRED_SAMPLING 1
|
||||
|
||||
#define LAMBERT 1
|
||||
#define PBR 0
|
||||
@ -15,26 +14,8 @@ const float EPSILON = 0.00001;
|
||||
|
||||
const float LIGHT_POWER_CUTOFF = 0.005;
|
||||
|
||||
const vec2 poissonDisk[16] = vec2[](
|
||||
vec2( -0.94201624, -0.39906216 ),
|
||||
vec2( 0.94558609, -0.76890725 ),
|
||||
vec2( -0.094184101, -0.92938870 ),
|
||||
vec2( 0.34495938, 0.29387760 ),
|
||||
vec2( -0.91588581, 0.45771432 ),
|
||||
vec2( -0.81544232, -0.87912464 ),
|
||||
vec2( -0.38277543, 0.27676845 ),
|
||||
vec2( 0.97484398, 0.75648379 ),
|
||||
vec2( 0.44323325, -0.97511554 ),
|
||||
vec2( 0.53742981, -0.47373420 ),
|
||||
vec2( -0.26496911, -0.41893023 ),
|
||||
vec2( 0.79197514, 0.19090188 ),
|
||||
vec2( -0.24188840, 0.99706507 ),
|
||||
vec2( -0.81409955, 0.91437590 ),
|
||||
vec2( 0.19984126, 0.78641367 ),
|
||||
vec2( 0.14383161, -0.14100790 )
|
||||
);
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 256;
|
||||
layout (constant_id = 1) const uint CASCADES = 1;
|
||||
|
||||
struct Matrices {
|
||||
mat4 view[2];
|
||||
@ -42,13 +23,22 @@ struct Matrices {
|
||||
mat4 iView[2];
|
||||
mat4 iProjection[2];
|
||||
mat4 iProjectionView[2];
|
||||
mat4 voxel;
|
||||
vec4 eyePos[2];
|
||||
mat4 vxgi;
|
||||
};
|
||||
|
||||
struct Space {
|
||||
vec3 eye;
|
||||
vec3 world;
|
||||
} position, normal, view;
|
||||
};
|
||||
|
||||
struct Ray {
|
||||
vec3 origin;
|
||||
vec3 direction;
|
||||
|
||||
vec3 position;
|
||||
float distance;
|
||||
};
|
||||
|
||||
struct Fog {
|
||||
vec3 color;
|
||||
@ -109,6 +99,7 @@ struct Material {
|
||||
int indexLightmap;
|
||||
int modeAlpha;
|
||||
};
|
||||
|
||||
struct Texture {
|
||||
int index;
|
||||
int samp;
|
||||
@ -117,6 +108,7 @@ struct Texture {
|
||||
|
||||
vec4 lerp;
|
||||
};
|
||||
|
||||
struct DrawCall {
|
||||
int materialIndex;
|
||||
uint materials;
|
||||
@ -124,6 +116,29 @@ struct DrawCall {
|
||||
uint textures;
|
||||
};
|
||||
|
||||
struct SurfaceMaterial {
|
||||
uint id;
|
||||
|
||||
vec4 albedo;
|
||||
vec4 indirect;
|
||||
|
||||
float metallic;
|
||||
float roughness;
|
||||
float occlusion;
|
||||
};
|
||||
|
||||
struct Surface {
|
||||
vec2 uv;
|
||||
Space position;
|
||||
Space normal;
|
||||
|
||||
Ray ray;
|
||||
|
||||
SurfaceMaterial material;
|
||||
|
||||
vec4 fragment;
|
||||
} surface;
|
||||
|
||||
layout (binding = 4) uniform UBO {
|
||||
Matrices matrices;
|
||||
|
||||
@ -136,12 +151,12 @@ layout (binding = 4) uniform UBO {
|
||||
uint drawCalls;
|
||||
|
||||
vec3 ambient;
|
||||
float kexp;
|
||||
|
||||
uint msaa;
|
||||
uint poissonSamples;
|
||||
float gamma;
|
||||
|
||||
float exposure;
|
||||
uint msaa;
|
||||
uint shadowSamples;
|
||||
uint padding1;
|
||||
} ubo;
|
||||
|
||||
layout (std140, binding = 5) readonly buffer Lights {
|
||||
@ -157,10 +172,10 @@ layout (std140, binding = 8) readonly buffer DrawCalls {
|
||||
DrawCall drawCalls[];
|
||||
};
|
||||
|
||||
layout (binding = 9, rg16ui) uniform volatile coherent uimage3D voxelID;
|
||||
layout (binding = 10, rg16f) uniform volatile coherent image3D voxelNormal;
|
||||
layout (binding = 11, rg16f) uniform volatile coherent image3D voxelUv;
|
||||
layout (binding = 12, rgba8) uniform volatile coherent image3D voxelAlbedo;
|
||||
layout (binding = 9, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES];
|
||||
layout (binding = 10, rg16f) uniform volatile coherent image3D voxelUv[CASCADES];
|
||||
layout (binding = 11, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES];
|
||||
layout (binding = 12, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES];
|
||||
|
||||
layout (binding = 13) uniform sampler3D samplerNoise;
|
||||
layout (binding = 14) uniform samplerCube samplerSkybox;
|
||||
@ -230,7 +245,7 @@ bool validTextureIndex( int textureIndex ) {
|
||||
float shadowFactor( const Light light, float def ) {
|
||||
if ( !validTextureIndex(light.mapIndex) ) return 1.0;
|
||||
|
||||
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
|
||||
vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0);
|
||||
positionClip.xyz /= positionClip.w;
|
||||
|
||||
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
|
||||
@ -253,11 +268,11 @@ float shadowFactor( const Light light, float def ) {
|
||||
const vec2 uv = positionClip.xy * 0.5 + 0.5;
|
||||
const float bias = light.depthBias;
|
||||
const float eyeDepth = positionClip.z;
|
||||
const int samples = int(ubo.poissonSamples);
|
||||
const int samples = int(ubo.shadowSamples);
|
||||
return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor;
|
||||
#if 0
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
const int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples;
|
||||
const int index = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples;
|
||||
const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r;
|
||||
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
|
||||
}
|
||||
@ -266,121 +281,105 @@ float shadowFactor( const Light light, float def ) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 fragColor = vec3(0);
|
||||
const vec3 tUvw = gl_GlobalInvocationID.xzy;
|
||||
for ( uint CASCADE = 0; CASCADE < CASCADES; ++CASCADE ) {
|
||||
surface.normal.world = decodeNormals( vec2(imageLoad(voxelNormal[CASCADE], ivec3(tUvw) ).xy) );
|
||||
surface.normal.eye = vec3( ubo.matrices.vxgi * vec4( surface.normal.world, 0.0f ) );
|
||||
|
||||
const vec3 tUvw = gl_GlobalInvocationID.xyz;
|
||||
{
|
||||
const vec2 N = vec2(imageLoad(voxelNormal, ivec3(tUvw) ).xy);
|
||||
normal.world = decodeNormals( N );
|
||||
normal.eye = vec3( ubo.matrices.voxel * vec4( normal.world, 0.0f ) );
|
||||
|
||||
position.eye = vec3(gl_GlobalInvocationID.xyz) / vec3(imageSize(voxelAlbedo)) * 2.0f - 1.0f;
|
||||
position.world = vec3( inverse(ubo.matrices.voxel) * vec4( position.eye, 1.0f ) );
|
||||
}
|
||||
|
||||
const uvec2 ID = uvec2(imageLoad(voxelID, ivec3(tUvw) ).xy);
|
||||
if ( ID.x == 0 || ID.y == 0 ) {
|
||||
imageStore(voxelAlbedo, ivec3(tUvw), vec4(0));
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
const uvec3 dim = imageSize(voxelAlbedo);
|
||||
float sdf = max(dim.x, max(dim.y, dim.z)) * 2.82842712;
|
||||
|
||||
uvec2 ID;
|
||||
ivec3 coord;
|
||||
for ( uint z = 0; z < dim.z; ++z ) {
|
||||
for ( uint y = 0; y < dim.y; ++y ) {
|
||||
for ( uint x = 0; x < dim.x; ++x ) {
|
||||
coord = ivec3(x,y,z);
|
||||
ID = imageLoad( voxelID, coord ).xy;
|
||||
if ( ID.x == 0 || ID.y == 0 ) continue;
|
||||
sdf = min(distance(tUvw, coord), sdf);
|
||||
surface.position.eye = vec3(gl_GlobalInvocationID.xyz) / (vec3(imageSize(voxelRadiance[CASCADE])) / (CASCADE + 1)) * 2.0f - 1.0f;
|
||||
surface.position.world = vec3( inverse(ubo.matrices.vxgi) * vec4( surface.position.eye, 1.0f ) );
|
||||
|
||||
const uvec2 ID = uvec2(imageLoad(voxelId[CASCADE], ivec3(tUvw) ).xy);
|
||||
if ( ID.x == 0 || ID.y == 0 ) {
|
||||
imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(0));
|
||||
continue;
|
||||
}
|
||||
const uint drawId = ID.x - 1;
|
||||
const DrawCall drawCall = drawCalls[drawId];
|
||||
surface.material.id = ID.y + drawCall.materialIndex - 1;
|
||||
const Material material = materials[surface.material.id];
|
||||
surface.material.albedo = material.colorBase;
|
||||
surface.fragment = material.colorEmissive;
|
||||
|
||||
#if DEFERRED_SAMPLING
|
||||
surface.uv = imageLoad(voxelUv[CASCADE], ivec3(tUvw) ).xy;
|
||||
const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas );
|
||||
Texture textureAtlas;
|
||||
if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas];
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexAlbedo ) ) {
|
||||
const Texture t = textures[drawCall.textureIndex + material.indexAlbedo];
|
||||
surface.material.albedo = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv );
|
||||
}
|
||||
|
||||
// OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
surface.material.albedo.a = 1;
|
||||
// BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
|
||||
// MASK
|
||||
} else if ( material.modeAlpha == 2 ) {
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
const uint drawId = ID.x - 1;
|
||||
const DrawCall drawCall = drawCalls[drawId];
|
||||
const uint materialId = ID.y + drawCall.materialIndex - 1;
|
||||
const Material material = materials[materialId];
|
||||
vec4 A = material.colorBase;
|
||||
|
||||
#if DEFERRED_SAMPLING
|
||||
const vec2 uv = imageLoad(voxelUv, ivec3(tUvw) ).xy;
|
||||
const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas );
|
||||
Texture textureAtlas;
|
||||
if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas];
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexAtlas ) ) {
|
||||
Texture t = textures[drawCall.textureIndex + material.indexAlbedo];
|
||||
A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv );
|
||||
}
|
||||
|
||||
// OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
A.a = 1;
|
||||
// BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
|
||||
// MASK
|
||||
} else if ( material.modeAlpha == 2 ) {
|
||||
|
||||
}
|
||||
#else
|
||||
A = imageLoad(voxelAlbedo, ivec3(tUvw) );
|
||||
#endif
|
||||
const float M = material.factorMetallic;
|
||||
const float R = material.factorRoughness;
|
||||
const float AO = material.factorOcclusion;
|
||||
|
||||
float litFactor = 1.0;
|
||||
if ( 0 <= material.indexLightmap ) {
|
||||
fragColor = A.rgb + ubo.ambient.rgb * (1 - AO);
|
||||
} else {
|
||||
fragColor = A.rgb * ubo.ambient.rgb * (1 - AO);
|
||||
}
|
||||
{
|
||||
const float R = material.factorRoughness * 2.0f;
|
||||
const vec3 N = normal.world;
|
||||
const vec3 F0 = mix(vec3(0.04), A.rgb, M);
|
||||
const vec3 Lo = normalize( position.world );
|
||||
const float cosLo = max(0.0, dot(N, Lo));
|
||||
for ( uint i = 0; i < ubo.lights; ++i ) {
|
||||
const Light light = lights[i];
|
||||
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
|
||||
if ( light.type >= 0 && 0 <= material.indexLightmap ) continue;
|
||||
const vec3 Lp = light.position;
|
||||
const vec3 Liu = light.position - position.world;
|
||||
const vec3 Li = normalize(Liu);
|
||||
const float Ls = shadowFactor( light, 0.0 );
|
||||
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
|
||||
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
|
||||
|
||||
const float cosLi = max(0.0, dot(N, Li));
|
||||
const vec3 Lr = light.color.rgb * light.power * La * Ls;
|
||||
#if LAMBERT
|
||||
const vec3 diffuse = A.rgb;
|
||||
const vec3 specular = vec3(0);
|
||||
#elif PBR
|
||||
const vec3 Lh = normalize(Li + Lo);
|
||||
const float cosLh = max(0.0, dot(N, Lh));
|
||||
|
||||
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
|
||||
const float D = ndfGGX( cosLh, R );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, R);
|
||||
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb;
|
||||
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
|
||||
#endif
|
||||
// lightmapped, compute only specular
|
||||
if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specular) * Lr * cosLi;
|
||||
// point light, compute only diffuse
|
||||
// else if ( abs(light.type) == 1 ) fragColor.rgb += (diffuse) * Lr * cosLi;
|
||||
else fragColor.rgb += (diffuse + specular) * Lr * cosLi;
|
||||
litFactor += light.power * La * Ls;
|
||||
// Emissive textures
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexEmissive ) ) {
|
||||
const Texture t = textures[drawCall.textureIndex + material.indexEmissive];
|
||||
surface.fragment += texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv );
|
||||
}
|
||||
}
|
||||
#else
|
||||
surface.material.albedo = imageLoad(voxelRadiance[CASCADE], ivec3(tUvw) );
|
||||
#endif
|
||||
surface.material.metallic = material.factorMetallic;
|
||||
surface.material.roughness = material.factorRoughness;
|
||||
surface.material.occlusion = material.factorOcclusion;
|
||||
|
||||
imageStore(voxelAlbedo, ivec3(tUvw), vec4(fragColor.rgb, 1));
|
||||
float litFactor = 1.0;
|
||||
if ( 0 <= material.indexLightmap ) {
|
||||
surface.fragment.rgb += surface.material.albedo.rgb + ubo.ambient.rgb * surface.material.occlusion;
|
||||
} else {
|
||||
surface.fragment.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion;
|
||||
}
|
||||
// corrections
|
||||
surface.material.roughness *= 4.0;
|
||||
{
|
||||
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
|
||||
const vec3 Lo = normalize( surface.position.world );
|
||||
const float cosLo = max(0.0, dot(surface.normal.world, Lo));
|
||||
for ( uint i = 0; i < ubo.lights; ++i ) {
|
||||
const Light light = lights[i];
|
||||
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
|
||||
if ( light.type >= 0 && 0 <= material.indexLightmap ) continue;
|
||||
const vec3 Lp = light.position;
|
||||
const vec3 Liu = light.position - surface.position.world;
|
||||
const vec3 Li = normalize(Liu);
|
||||
const float Ls = shadowFactor( light, 0.0 );
|
||||
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
|
||||
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
|
||||
|
||||
const float cosLi = max(0.0, dot(surface.normal.world, Li));
|
||||
const vec3 Lr = light.color.rgb * light.power * La * Ls;
|
||||
#if LAMBERT
|
||||
const vec3 diffuse = surface.material.albedo.rgb;
|
||||
const vec3 specular = vec3(0);
|
||||
#elif PBR
|
||||
const vec3 Lh = normalize(Li + Lo);
|
||||
const float cosLh = max(0.0, dot(surface.normal.world, Lh));
|
||||
|
||||
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
|
||||
const float D = ndfGGX( cosLh, surface.material.roughness );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness);
|
||||
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
|
||||
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
|
||||
#endif
|
||||
// lightmapped, compute only specular
|
||||
if ( light.type >= 0 && 0 <= material.indexLightmap ) surface.fragment.rgb += (specular) * Lr * cosLi;
|
||||
// point light, compute only diffuse
|
||||
// else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi;
|
||||
else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi;
|
||||
surface.fragment.a += light.power * La * Ls;
|
||||
}
|
||||
}
|
||||
|
||||
imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(surface.fragment.rgb, 1));
|
||||
}
|
||||
}
|
||||
@ -50,6 +50,7 @@ struct Material {
|
||||
int indexLightmap;
|
||||
int modeAlpha;
|
||||
};
|
||||
|
||||
struct Texture {
|
||||
int index;
|
||||
int samp;
|
||||
@ -58,6 +59,7 @@ struct Texture {
|
||||
|
||||
vec4 lerp;
|
||||
};
|
||||
|
||||
struct Light {
|
||||
vec3 position;
|
||||
float radius;
|
||||
@ -73,6 +75,43 @@ struct Light {
|
||||
mat4 view;
|
||||
mat4 projection;
|
||||
};
|
||||
|
||||
struct Ray {
|
||||
vec3 origin;
|
||||
vec3 direction;
|
||||
|
||||
vec3 position;
|
||||
float distance;
|
||||
};
|
||||
|
||||
struct Space {
|
||||
vec3 eye;
|
||||
vec3 world;
|
||||
};
|
||||
|
||||
struct SurfaceMaterial {
|
||||
uint id;
|
||||
|
||||
vec4 albedo;
|
||||
vec4 indirect;
|
||||
|
||||
float metallic;
|
||||
float roughness;
|
||||
float occlusion;
|
||||
};
|
||||
|
||||
struct Surface {
|
||||
vec2 uv;
|
||||
Space position;
|
||||
Space normal;
|
||||
|
||||
Ray ray;
|
||||
|
||||
SurfaceMaterial material;
|
||||
|
||||
vec4 fragment;
|
||||
} surface;
|
||||
|
||||
layout (std140, binding = 3) readonly buffer Materials {
|
||||
Material materials[];
|
||||
};
|
||||
@ -160,10 +199,10 @@ bool validTextureIndex( int textureIndex ) {
|
||||
return 0 <= textureIndex; // && textureIndex < ubo.textures;
|
||||
}
|
||||
|
||||
float shadowFactor( const Light light, const vec3 P, float def ) {
|
||||
float shadowFactor( const Light light, float def ) {
|
||||
if ( !validTextureIndex(light.mapIndex) ) return 1.0;
|
||||
|
||||
vec4 positionClip = light.projection * light.view * vec4(P, 1.0);
|
||||
vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0);
|
||||
positionClip.xyz /= positionClip.w;
|
||||
|
||||
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
|
||||
@ -189,7 +228,7 @@ float shadowFactor( const Light light, const vec3 P, float def ) {
|
||||
const int samples = 16; //int(ubo.poissonSamples);
|
||||
if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor;
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
const int index = int( float(samples) * random(floor(P * 1000.0), i)) % samples;
|
||||
const int index = int( float(samples) * random(floor(surface.position.world * 1000.0), i)) % samples;
|
||||
const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r;
|
||||
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
|
||||
}
|
||||
@ -198,16 +237,18 @@ float shadowFactor( const Light light, const vec3 P, float def ) {
|
||||
|
||||
void main() {
|
||||
vec4 A = vec4(1, 1, 1, 1);
|
||||
vec3 N = normalize( inNormal );
|
||||
surface.normal.world = normalize( inNormal );
|
||||
const float mip = mipLevel(inUv.xy);
|
||||
const vec2 uv = wrap(inUv.xy);
|
||||
const vec3 P = inPosition;
|
||||
const int materialId = int(inId.y);
|
||||
const Material material = materials[materialId];
|
||||
surface.uv = wrap(inUv.xy);
|
||||
surface.position.world = inPosition;
|
||||
surface.material.id = int(inId.y);
|
||||
const Material material = materials[surface.material.id];
|
||||
|
||||
const float M = material.factorMetallic;
|
||||
const float R = material.factorRoughness;
|
||||
const float AO = 1.0f - material.factorOcclusion;
|
||||
surface.material.metallic = material.factorMetallic;
|
||||
surface.material.roughness = material.factorRoughness;
|
||||
surface.material.occlusion = 1.0f - material.factorOcclusion;
|
||||
|
||||
surface.fragment = material.colorEmissive;
|
||||
#if 0
|
||||
// sample albedo
|
||||
const bool useAtlas = validTextureIndex( material.indexAtlas );
|
||||
@ -215,66 +256,70 @@ void main() {
|
||||
if ( useAtlas ) textureAtlas = textures[material.indexAtlas];
|
||||
if ( !validTextureIndex( material.indexAlbedo ) ) discard;
|
||||
{
|
||||
Texture t = textures[material.indexAlbedo];
|
||||
A = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
const Texture t = textures[material.indexAlbedo];
|
||||
surface.material.albedo = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
// alpha mode OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
A.a = 1;
|
||||
surface.material.albedo.a = 1;
|
||||
// alpha mode BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
|
||||
// alpha mode MASK
|
||||
} else if ( material.modeAlpha == 2 ) {
|
||||
if ( A.a < abs(material.factorAlphaCutoff) ) discard;
|
||||
A.a = 1;
|
||||
if ( surface.material.albedo.a < abs(material.factorAlphaCutoff) ) discard;
|
||||
surface.material.albedo.a = 1;
|
||||
}
|
||||
if ( A.a == 0 ) discard;
|
||||
if ( surface.material.albedo.a == 0 ) discard;
|
||||
}
|
||||
|
||||
// sample normal
|
||||
if ( validTextureIndex( material.indexNormal ) ) {
|
||||
Texture t = textures[material.indexNormal];
|
||||
N = inTBN * normalize( textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ).xyz * 2.0 - vec3(1.0));
|
||||
const Texture t = textures[material.indexNormal];
|
||||
surfacem.normal.world = inTBN * normalize( textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ).xyz * 2.0 - vec3(1.0));
|
||||
}
|
||||
|
||||
// sample emissive
|
||||
if ( validTextureIndex( material.indexEmissive ) ) {
|
||||
const Texture t = textures[material.indexEmissive];
|
||||
surface.fragment = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
}
|
||||
#else
|
||||
A = vec4(1);
|
||||
surface.material.albedo = vec4(1);
|
||||
#endif
|
||||
|
||||
float litFactor = 1.0;
|
||||
vec3 fragColor = vec3(0);
|
||||
{
|
||||
const vec3 F0 = mix(vec3(0.04), A.rgb, M);
|
||||
const vec3 Lo = normalize( -P );
|
||||
const float cosLo = max(0.0, dot(N, Lo));
|
||||
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
|
||||
const vec3 Lo = normalize( -surface.position.world );
|
||||
const float cosLo = max(0.0, dot(surface.normal.world, Lo));
|
||||
for ( uint i = 0; i < lights.length(); ++i ) {
|
||||
const Light light = lights[i];
|
||||
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
|
||||
const vec3 Lp = light.position;
|
||||
const vec3 Liu = light.position - P;
|
||||
const vec3 Liu = light.position - surface.position.world;
|
||||
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
|
||||
const float Ls = shadowFactor( light, P, 0.0 );
|
||||
const float Ls = shadowFactor( light, 0.0 );
|
||||
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
|
||||
|
||||
const vec3 Li = normalize(Liu);
|
||||
const vec3 Lr = light.color.rgb * light.power * La * Ls;
|
||||
const float cosLi = abs(dot(N, Li));// max(0.0, dot(N, Li));
|
||||
const float cosLi = abs(dot(surface.normal.world, Li));// max(0.0, dot(N, Li));
|
||||
#if LAMBERT
|
||||
const vec3 diffuse = A.rgb;
|
||||
const vec3 diffuse = surface.material.albedo.rgb;
|
||||
const vec3 specular = vec3(0);
|
||||
#elif PBR
|
||||
const vec3 Lh = normalize(Li + Lo);
|
||||
const float cosLh = max(0.0, dot(N, Lh));
|
||||
|
||||
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
|
||||
const float D = ndfGGX( cosLh, R );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, R);
|
||||
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb;
|
||||
const float D = ndfGGX( cosLh, surface.material.roughness );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness);
|
||||
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
|
||||
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
|
||||
#endif
|
||||
fragColor.rgb += (diffuse + specular) * Lr * cosLi;
|
||||
litFactor += light.power * La * Ls;
|
||||
surface.fragment.rgb += (diffuse + specular) * Lr * cosLi;
|
||||
surface.fragment.a += light.power * La * Ls;
|
||||
}
|
||||
}
|
||||
|
||||
outAlbedo = vec4(fragColor, 1);
|
||||
outAlbedo = vec4(surface.fragment.rgb, 1);
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
#version 450
|
||||
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define DEFERRED_SAMPLING 1
|
||||
#define CAN_DISCARD 1
|
||||
#define USE_LIGHTMAP 1
|
||||
|
||||
@ -137,7 +137,7 @@ void main() {
|
||||
// sample metallic/roughness
|
||||
if ( validTextureIndex( material.indexMetallicRoughness ) ) {
|
||||
Texture t = textures[material.indexMetallicRoughness];
|
||||
const vec4 sampled = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
const vec4 sampled = textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
M = sampled.b;
|
||||
R = sampled.g;
|
||||
}
|
||||
@ -145,7 +145,7 @@ void main() {
|
||||
AO = material.factorOcclusion;
|
||||
if ( validTextureIndex( material.indexOcclusion ) ) {
|
||||
Texture t = textures[material.indexOcclusion];
|
||||
AO = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv ).r;
|
||||
AO = textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv ).r;
|
||||
}
|
||||
#endif
|
||||
outAlbedo = A * inColor;
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
#version 450
|
||||
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define DEFERRED_SAMPLING 1
|
||||
#define USE_LIGHTMAP 1
|
||||
|
||||
#define PI 3.1415926536f
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 1;
|
||||
layout (constant_id = 1) const uint CASCADES = 1;
|
||||
|
||||
struct Material {
|
||||
vec4 colorBase;
|
||||
@ -51,10 +52,11 @@ layout (location = 7) in vec3 inPosition;
|
||||
layout (location = 8) flat in ivec4 inId;
|
||||
|
||||
layout (binding = 7) uniform sampler2D samplerTextures[TEXTURES];
|
||||
layout (binding = 8, rg16ui) uniform volatile coherent uimage3D voxelID;
|
||||
layout (binding = 9, rg16f) uniform volatile coherent image3D voxelNormal;
|
||||
layout (binding = 10, rg16f) uniform volatile coherent image3D voxelUv;
|
||||
layout (binding = 11, rgba8) uniform volatile coherent image3D voxelAlbedo;
|
||||
|
||||
layout (binding = 8, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES];
|
||||
layout (binding = 9, rg16f) uniform volatile coherent image3D voxelUv[CASCADES];
|
||||
layout (binding = 10, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES];
|
||||
layout (binding = 11, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES];
|
||||
|
||||
layout (location = 0) out uvec2 outId;
|
||||
layout (location = 1) out vec2 outNormals;
|
||||
@ -84,8 +86,9 @@ bool validTextureIndex( int textureIndex ) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
const vec3 P = inPosition;
|
||||
if ( !(abs(P.x) < 1.0 && abs(P.y) < 1 && abs(P.z) < 1) ) discard;
|
||||
const vec3 P = inPosition.xzy;
|
||||
const uint CASCADE = uint(max( abs(floor(P.x)), max( abs(floor(P.y)), abs(floor(P.z)) ) ));
|
||||
if ( CASCADES <= CASCADE ) discard;
|
||||
|
||||
vec4 A = vec4(0, 0, 0, 0);
|
||||
const vec3 N = inNormal;
|
||||
@ -136,8 +139,8 @@ void main() {
|
||||
const vec2 outNormals = encodeNormals( normalize( N ) );
|
||||
const vec2 outUvs = wrap(inUv.xy);
|
||||
|
||||
imageStore(voxelID, ivec3(P * imageSize(voxelID)), uvec4(outId, 0, 0));
|
||||
imageStore(voxelNormal, ivec3(P * imageSize(voxelNormal)), vec4(outNormals, 0, 0));
|
||||
imageStore(voxelUv, ivec3(P * imageSize(voxelUv)), vec4(outUvs, 0, 0));
|
||||
imageStore(voxelAlbedo, ivec3(P * imageSize(voxelAlbedo)), outAlbedo);
|
||||
imageStore(voxelId[CASCADE], ivec3(P * (1 + CASCADE) * imageSize(voxelId[CASCADE])), uvec4(outId, 0, 0));
|
||||
imageStore(voxelNormal[CASCADE], ivec3(P * (1 + CASCADE) * imageSize(voxelNormal[CASCADE])), vec4(outNormals, 0, 0));
|
||||
imageStore(voxelUv[CASCADE], ivec3(P * (1 + CASCADE) * imageSize(voxelUv[CASCADE])), vec4(outUvs, 0, 0));
|
||||
imageStore(voxelRadiance[CASCADE], ivec3(P * (1 + CASCADE) * imageSize(voxelRadiance[CASCADE])), outAlbedo);
|
||||
}
|
||||
@ -24,39 +24,42 @@ layout (binding = 6) uniform UBO {
|
||||
} ubo;
|
||||
|
||||
void main(){
|
||||
vec3 norm = abs(inNormal[0] + inNormal[1] + inNormal[2]);
|
||||
uint axis = norm.y > norm.x ? 1 : 0;
|
||||
axis = norm.z > norm[axis] ? 2 : axis;
|
||||
const float RENDER_RESOLUTION = 256.0;
|
||||
const float PIXEL_SCALE = 2.0;
|
||||
const float HALF_PIXEL = 1.0 / (RENDER_RESOLUTION * PIXEL_SCALE);
|
||||
const vec3 C = ( inPosition[0] + inPosition[1] + inPosition[2] ) / 3.0;
|
||||
|
||||
mat4 invOrtho = inverse( ubo.voxel );
|
||||
vec3 extentMin = vec3( invOrtho * vec4(-1, -1, -1, 1 ) );
|
||||
vec3 extentMid = vec3( invOrtho * vec4( 0, 0, 0, 1 ) );
|
||||
vec3 extentMax = vec3( invOrtho * vec4( 1, 1, 1, 1 ) );
|
||||
vec3 extentSize = extentMax - extentMin;
|
||||
|
||||
for( uint i = 0; i < 3; ++i ){
|
||||
#if USE_CROSS
|
||||
const vec3 N = abs(cross(inPosition[2] - inPosition[0], inPosition[1] - inPosition[0]));
|
||||
#else
|
||||
const vec3 N = abs(inNormal[0] + inNormal[1] + inNormal[2]);
|
||||
uint A = N.y > N.x ? 1 : 0;
|
||||
A = N.z > N[A] ? 2 : A;
|
||||
#endif
|
||||
for(uint i = 0; i < 3; ++i){
|
||||
outUv = inUv[i];
|
||||
outSt = inSt[i];
|
||||
outColor = inColor[i];
|
||||
outNormal = inNormal[i];
|
||||
outTBN = inTBN[i];
|
||||
outPosition = inPosition[i];
|
||||
outPosition = vec3( ubo.voxel * vec4( inPosition[i], 1 ) ) + normalize( inPosition[i] - C ) * HALF_PIXEL;
|
||||
outId = inId[i];
|
||||
|
||||
outPosition = vec3( ubo.voxel * vec4( outPosition, 1 ) );
|
||||
|
||||
gl_Position = vec4( outPosition.xyz, 1 );
|
||||
if ( axis == 0 ) gl_Position.xyz = gl_Position.zyx;
|
||||
else if ( axis == 1 ) gl_Position.xyz = gl_Position.xzy;
|
||||
|
||||
// outPosition = (inPosition[i] - extentMin) / extentSize;
|
||||
// outPosition = fract(outPosition * 0.5 + 0.5);
|
||||
const vec3 P = fract(outPosition);
|
||||
// const vec3 P = fract(outPosition + normalize( inPosition[i] - C ) * HALF_PIXEL);
|
||||
#if USE_CROSS
|
||||
if ( N.z > N.x && N.z > N.y ) gl_Position = vec4(P.x, P.y, 0, 1);
|
||||
else if ( N.x > N.y && N.x > N.z ) gl_Position = vec4(P.y, P.z, 0, 1);
|
||||
else gl_Position = vec4(P.x, P.z, 0, 1);
|
||||
#else
|
||||
if ( A == 0 ) gl_Position = vec4(P.zy, 1, 1 );
|
||||
else if ( A == 1 ) gl_Position = vec4(P.xz, 1, 1 );
|
||||
else if ( A == 2 ) gl_Position = vec4(P.xy, 1, 1 );
|
||||
#endif
|
||||
|
||||
outPosition = outPosition * 0.5 + 0.5;
|
||||
// gl_Position.xy = fract( gl_Position.xy * 0.5 + 0.5 ) * 2.0 - 1.0;
|
||||
// gl_Position.xy = fract( gl_Position.xy * 0.5 + 0.5 ) * 2.0 - 1.0;
|
||||
gl_Position.z = 1;
|
||||
|
||||
|
||||
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#version 450
|
||||
|
||||
#define UF_DEFERRED_SAMPLING 0
|
||||
#define UF_CAN_DISCARD 1
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define CAN_DISCARD 1
|
||||
|
||||
layout (binding = 1) uniform sampler2D samplerTexture;
|
||||
|
||||
@ -18,12 +18,18 @@ layout (location = 1) in flat Gui inGui;
|
||||
|
||||
layout (location = 0) out uvec2 outId;
|
||||
layout (location = 1) out vec2 outNormals;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
layout (location = 2) out vec2 outUvs;
|
||||
#else
|
||||
layout (location = 2) out vec4 outAlbedo;
|
||||
#endif
|
||||
|
||||
float wrap( float i ) {
|
||||
return fract(i);
|
||||
}
|
||||
vec2 wrap( vec2 uv ) {
|
||||
return vec2( wrap( uv.x ), wrap( uv.y ) );
|
||||
}
|
||||
vec2 encodeNormals( vec3 n ) {
|
||||
float p = sqrt(n.z*8+8);
|
||||
return n.xy/p + 0.5;
|
||||
@ -44,14 +50,14 @@ void main() {
|
||||
vec2 uv = inUv.xy;
|
||||
vec4 C = vec4(1, 1, 1, 1);
|
||||
//vec3 N = inNormal;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
outUvs = wrap(inUv.xy);
|
||||
vec4 outAlbedo = vec4(0,0,0,0);
|
||||
#endif
|
||||
#if !UF_DEFERRED_SAMPLING || UF_CAN_DISCARD
|
||||
#if !DEFERRED_SAMPLING || CAN_DISCARD
|
||||
C = textureLod( samplerTexture, uv, mip );
|
||||
#endif
|
||||
#if !UF_DEFERRED_SAMPLING
|
||||
#if !DEFERRED_SAMPLING
|
||||
if ( inGui.mode == 1 ) {
|
||||
C = inGui.color;
|
||||
} else {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#version 450
|
||||
|
||||
#define UF_DEFERRED_SAMPLING 0
|
||||
#define UF_CAN_DISCARD 1
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define CAN_DISCARD 1
|
||||
|
||||
layout (binding = 1) uniform sampler2D samplerTexture;
|
||||
|
||||
@ -24,7 +24,7 @@ layout (location = 1) in flat Gui inGui;
|
||||
|
||||
layout (location = 0) out uvec2 outId;
|
||||
layout (location = 1) out vec2 outNormals;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
layout (location = 2) out vec2 outUvs;
|
||||
#else
|
||||
layout (location = 2) out vec4 outAlbedo;
|
||||
@ -36,7 +36,7 @@ void main() {
|
||||
if ( inUv.x > inGui.offset.z ) discard;
|
||||
if ( inUv.y > inGui.offset.w ) discard;
|
||||
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
vec4 outAlbedo = vec4(0,0,0,0);
|
||||
#endif
|
||||
|
||||
|
||||
@ -10,10 +10,10 @@ namespace pod {
|
||||
uf::renderer::Texture3D noise;
|
||||
uf::renderer::TextureCube skybox;
|
||||
struct {
|
||||
uf::renderer::Texture3D id;
|
||||
uf::renderer::Texture3D normal;
|
||||
uf::renderer::Texture3D albedo;
|
||||
uf::renderer::Texture3D uv;
|
||||
std::vector<uf::renderer::Texture3D> id;
|
||||
std::vector<uf::renderer::Texture3D> uv;
|
||||
std::vector<uf::renderer::Texture3D> normal;
|
||||
std::vector<uf::renderer::Texture3D> radiance;
|
||||
pod::Matrix4f matrix;
|
||||
} voxels;
|
||||
};
|
||||
|
||||
@ -39,11 +39,7 @@ namespace uf {
|
||||
static bool USE_REVERSE_INFINITE_PROJECTION;
|
||||
|
||||
Camera();
|
||||
/*
|
||||
Camera( const pod::Math::num_t& fov, const pod::Vector2& size, const pod::Vector2& bounds, const pod::Vector3& offset = {0, 0, 0}, const pod::Vector2& tops = {0, 0} );
|
||||
Camera( Camera&& move );
|
||||
Camera( const Camera& copy );
|
||||
*/
|
||||
|
||||
bool modified() const;
|
||||
void setStereoscopic( bool );
|
||||
pod::Transform<>& getTransform();
|
||||
@ -55,8 +51,7 @@ namespace uf {
|
||||
pod::Matrix4& getProjection( size_t = 0 );
|
||||
const pod::Matrix4& getProjection( size_t = 0 ) const;
|
||||
|
||||
// pod::Matrix4& getModel();
|
||||
// const pod::Matrix4& getModel() const;
|
||||
pod::Vector3f getEye( size_t = 0 ) const;
|
||||
|
||||
pod::Math::num_t& getFov();
|
||||
pod::Math::num_t getFov() const;
|
||||
|
||||
1
engine/inc/uf/utils/octree/octree.h
Normal file
1
engine/inc/uf/utils/octree/octree.h
Normal file
@ -0,0 +1 @@
|
||||
#pragma once
|
||||
@ -38,6 +38,7 @@ void uf::GltfBehavior::initialize( uf::Object& self ) {
|
||||
assetLoader.remove<pod::Graph>(filename);
|
||||
|
||||
bool shouldUpdate = false;
|
||||
|
||||
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
|
||||
if ( !ext::json::isNull(graph.metadata["ambient"]) ) {
|
||||
sceneMetadataJson["light"]["ambient"] = graph.metadata["ambient"];
|
||||
@ -48,6 +49,7 @@ void uf::GltfBehavior::initialize( uf::Object& self ) {
|
||||
shouldUpdate = true;
|
||||
}
|
||||
if ( shouldUpdate ) scene.callHook("object:UpdateMetadata.%UID%");
|
||||
|
||||
// deferred shader loading
|
||||
auto& transform = this->getComponent<pod::Transform<>>();
|
||||
graph.root.entity->getComponent<pod::Transform<>>().reference = &transform;
|
||||
@ -75,23 +77,25 @@ void uf::GltfBehavior::destroy( uf::Object& self ) {
|
||||
uf::graph::destroy( graph );
|
||||
}
|
||||
}
|
||||
|
||||
#define UNIFORMS_UPDATE_IN_TICK 1
|
||||
void uf::GltfBehavior::tick( uf::Object& self ) {
|
||||
/* Animation change test */
|
||||
/* Update animations */ if ( this->hasComponent<pod::Graph>() ) {
|
||||
auto& graph = this->getComponent<pod::Graph>();
|
||||
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) uf::graph::update( graph );
|
||||
}
|
||||
/* Update uniforms */
|
||||
|
||||
if ( !this->hasComponent<uf::Graphic>() ) return;
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& metadata = this->getComponent<uf::Serializer>();
|
||||
auto& graphic = this->getComponent<uf::Graphic>();
|
||||
auto& controller = scene.getController();
|
||||
auto& controllerTransform = controller.getComponent<pod::Transform<>>();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
auto& transform = this->getComponent<pod::Transform<>>();
|
||||
|
||||
if ( !graphic.initialized ) return;
|
||||
|
||||
|
||||
auto* objectWithGraph = this;
|
||||
while ( objectWithGraph != &scene ) {
|
||||
if ( objectWithGraph->hasComponent<pod::Graph>() ) break;
|
||||
@ -100,6 +104,7 @@ void uf::GltfBehavior::tick( uf::Object& self ) {
|
||||
if ( !objectWithGraph->hasComponent<pod::Graph>() ) return;
|
||||
auto& graph = objectWithGraph->getComponent<pod::Graph>();
|
||||
|
||||
#if UNIFORMS_UPDATE_IN_TICK
|
||||
#if UF_USE_OPENGL
|
||||
if ( graphic.material.hasShader("vertex") ) {
|
||||
auto& shader = graphic.material.getShader("vertex");
|
||||
@ -119,7 +124,7 @@ void uf::GltfBehavior::tick( uf::Object& self ) {
|
||||
}
|
||||
}
|
||||
#elif UF_USE_VULKAN
|
||||
if ( graphic.material.hasShader("fragment") && !(graph.metadata["flags"]["SEPARATE"].as<bool>()) ) {
|
||||
if ( graphic.material.hasShader("vertex") && !(graph.metadata["flags"]["SEPARATE"].as<bool>()) ) {
|
||||
auto& shader = graphic.material.getShader("vertex");
|
||||
std::vector<pod::Matrix4f> instances( graph.nodes.size() );
|
||||
for ( size_t i = 0; i < graph.nodes.size(); ++i ) {
|
||||
@ -129,31 +134,7 @@ void uf::GltfBehavior::tick( uf::Object& self ) {
|
||||
auto& storageBuffer = *graphic.getStorageBuffer("Models");
|
||||
graphic.updateBuffer( (void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.instanceBufferIndex /*storageBuffer*/ );
|
||||
}
|
||||
if ( graphic.material.hasShader("geometry", "vxgi") ) {
|
||||
auto& shader = graphic.material.getShader("geometry", "vxgi");
|
||||
/*
|
||||
pod::Vector3f min = uf::vector::decode( graph.metadata["extents"]["min"], pod::Vector3f{} );
|
||||
pod::Vector3f max = uf::vector::decode( graph.metadata["extents"]["max"], pod::Vector3f{} );
|
||||
|
||||
min.x += floor(controllerTransform.position.x);
|
||||
min.y -= floor(controllerTransform.position.y);
|
||||
min.z -= floor(controllerTransform.position.z);
|
||||
|
||||
max.x += floor(controllerTransform.position.x);
|
||||
max.y -= floor(controllerTransform.position.y);
|
||||
max.z -= floor(controllerTransform.position.z);
|
||||
// uniforms.matrix = uf::matrix::translate( uf::matrix::identity(), -controllerTransform.position )
|
||||
uniforms.matrix = uf::matrix::ortho<float>( min.x, max.x, min.y, max.y, min.z, max.z );
|
||||
*/
|
||||
auto& sceneTextures = scene.getComponent<pod::SceneTextures>();
|
||||
struct UniformDescriptor {
|
||||
alignas(16) pod::Matrix4f matrix;
|
||||
};
|
||||
auto& uniform = shader.getUniform("UBO");
|
||||
auto& uniforms = uniform.get<UniformDescriptor>();
|
||||
uniforms.matrix = sceneTextures.voxels.matrix;
|
||||
shader.updateUniform( "UBO", uniform );
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -202,24 +183,15 @@ void uf::GltfBehavior::render( uf::Object& self ) {
|
||||
if ( graphic.material.hasShader("vertex") ) {
|
||||
auto& shader = graphic.material.getShader("vertex");
|
||||
auto& uniform = shader.getUniform("UBO");
|
||||
#if UF_UNIFORMS_UPDATE_WITH_JSON
|
||||
if ( !(graph.metadata["flags"]["SEPARATE"].as<bool>()) ) {
|
||||
#if UF_UNIFORMS_UPDATE_WITH_JSON
|
||||
ext::json::Value uniforms;
|
||||
for ( std::size_t i = 0; i < uf::renderer::settings::maxViews; ++i ) {
|
||||
uniforms["view"][i] = uf::matrix::encode( camera.getView( i ) );
|
||||
uniforms["projection"][i] = uf::matrix::encode( camera.getProjection( i ) );
|
||||
}
|
||||
shader.updateUniform("UBO", uniforms );
|
||||
#else
|
||||
auto& uniforms = uniform.get<UniformDescriptor<>>();
|
||||
for ( std::size_t i = 0; i < uf::renderer::settings::maxViews; ++i ) {
|
||||
uniforms.view[i] = camera.getView( i );
|
||||
uniforms.projection[i] = camera.getProjection( i );
|
||||
}
|
||||
shader.updateUniform( "UBO", uniform );
|
||||
#endif
|
||||
} else {
|
||||
#if UF_UNIFORMS_UPDATE_WITH_JSON
|
||||
// auto uniforms = shader.getUniformJson("UBO");
|
||||
ext::json::Value uniforms;
|
||||
uniforms["matrices"]["model"] = uf::matrix::encode( uf::transform::model( transform ) );
|
||||
@ -239,24 +211,61 @@ void uf::GltfBehavior::render( uf::Object& self ) {
|
||||
uniforms["color"][3] = 1.0f;
|
||||
}
|
||||
shader.updateUniform("UBO", uniforms );
|
||||
#else
|
||||
}
|
||||
#else
|
||||
if ( !(graph.metadata["flags"]["SEPARATE"].as<bool>()) ) {
|
||||
auto& uniforms = uniform.get<UniformDescriptor<>>();
|
||||
for ( std::size_t i = 0; i < uf::renderer::settings::maxViews; ++i ) {
|
||||
uniforms.view[i] = camera.getView( i );
|
||||
uniforms.projection[i] = camera.getProjection( i );
|
||||
}
|
||||
shader.updateUniform( "UBO", uniform );
|
||||
} else {
|
||||
auto& uniforms = uniform.get<uf::MeshDescriptor<>>();
|
||||
uniforms.matrices.model = uf::transform::model( transform );
|
||||
for ( std::size_t i = 0; i < uf::renderer::settings::maxViews; ++i ) {
|
||||
uniforms.matrices.view[i] = camera.getView( i );
|
||||
uniforms.matrices.projection[i] = camera.getProjection( i );
|
||||
}
|
||||
if ( ext::json::isArray(metadata["color"]) ) {
|
||||
uniforms.color[0] = metadata["color"][0].as<float>();
|
||||
uniforms.color[1] = metadata["color"][1].as<float>();
|
||||
uniforms.color[2] = metadata["color"][2].as<float>();
|
||||
uniforms.color[3] = metadata["color"][3].as<float>();
|
||||
} else {
|
||||
uniforms.color = { 1, 1, 1, 1 };
|
||||
}
|
||||
uniforms.color = uf::vector::decode( metadata["color"], pod::Vector4f{1,1,1,1} );
|
||||
shader.updateUniform( "UBO", uniform );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !UNIFORMS_UPDATE_IN_TICK
|
||||
if ( uf::renderer::currentRenderMode == uf::renderer::renderModes.front() ) {
|
||||
#if UF_USE_OPENGL
|
||||
if ( graphic.material.hasShader("vertex") ) {
|
||||
auto& shader = graphic.material.getShader("vertex");
|
||||
auto& mesh = this->getComponent<ext::gltf::mesh_t>();
|
||||
|
||||
if ( !(graph.metadata["flags"]["SEPARATE"].as<bool>()) ) {
|
||||
std::vector<pod::Matrix4f> instances( graph.nodes.size() );
|
||||
for ( size_t i = 0; i < graph.nodes.size(); ++i ) {
|
||||
auto& node = graph.nodes[i];
|
||||
instances[i] = node.entity ? uf::transform::model( node.entity->getComponent<pod::Transform<>>() ) : uf::transform::model( node.transform );
|
||||
}
|
||||
|
||||
graphic.updateBuffer( (void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.instanceBufferIndex );
|
||||
shader.execute( graphic, &mesh.vertices[0] );
|
||||
} else if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
|
||||
shader.execute( graphic, &mesh.vertices[0] );
|
||||
}
|
||||
}
|
||||
#elif UF_USE_VULKAN
|
||||
if ( graphic.material.hasShader("vertex") && !(graph.metadata["flags"]["SEPARATE"].as<bool>()) ) {
|
||||
auto& shader = graphic.material.getShader("vertex");
|
||||
std::vector<pod::Matrix4f> instances( graph.nodes.size() );
|
||||
for ( size_t i = 0; i < graph.nodes.size(); ++i ) {
|
||||
auto& node = graph.nodes[i];
|
||||
instances[i] = node.entity ? uf::transform::model( node.entity->getComponent<pod::Transform<>>() ) : uf::transform::model( node.transform );
|
||||
}
|
||||
auto& storageBuffer = *graphic.getStorageBuffer("Models");
|
||||
graphic.updateBuffer( (void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.instanceBufferIndex /*storageBuffer*/ );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -16,8 +16,10 @@ namespace {
|
||||
auto& graphic = entity.getComponent<uf::Graphic>();
|
||||
std::string root = uf::io::directory( graph.name );
|
||||
size_t texture2Ds = 0;
|
||||
size_t texture3Ds = 0;
|
||||
for ( auto& texture : graphic.material.textures ) {
|
||||
if ( texture.width > 1 && texture.height > 1 && texture.depth == 1 && texture.layers == 1 ) ++texture2Ds;
|
||||
else if ( texture.width > 1 && texture.height > 1 && texture.depth > 1 && texture.layers == 1 ) ++texture3Ds;
|
||||
}
|
||||
|
||||
// standard pipeline
|
||||
@ -62,9 +64,14 @@ namespace {
|
||||
ext::json::forEach( shader.metadata["specializationConstants"], [&]( ext::json::Value& sc ){
|
||||
if ( sc["name"].as<std::string>() == "TEXTURES" ) sc["value"] = specializationConstants.textures;
|
||||
});
|
||||
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
|
||||
if ( binding.descriptorCount > 1 ) binding.descriptorCount = specializationConstants.textures;
|
||||
}
|
||||
|
||||
ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){
|
||||
if ( t["name"].as<std::string>() != "samplerTextures" ) return;
|
||||
size_t binding = t["binding"].as<size_t>();
|
||||
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
|
||||
if ( layout.binding == binding ) layout.descriptorCount = specializationConstants.textures;
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -73,15 +80,7 @@ namespace {
|
||||
std::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as<std::string>("/gltf/base.vert.spv");
|
||||
std::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as<std::string>("/gltf/voxelize.geom.spv");
|
||||
std::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as<std::string>("/gltf/voxelize.frag.spv");
|
||||
/*
|
||||
{
|
||||
if ( !graph.metadata["flags"]["SEPARATE"].as<bool>() ) {
|
||||
vertexShaderFilename = graph.metadata["flags"]["SKINNED"].as<bool>() ? "/gltf/skinned.instanced.vert.spv" : "/gltf/instanced.vert.spv";
|
||||
} else if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) vertexShaderFilename = "/gltf/skinned.vert.spv";
|
||||
vertexShaderFilename = entity.grabURI( vertexShaderFilename, root );
|
||||
graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "vxgi");
|
||||
}
|
||||
*/
|
||||
|
||||
if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) {
|
||||
geometryShaderFilename = entity.grabURI( geometryShaderFilename, root );
|
||||
graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY, "vxgi");
|
||||
@ -91,48 +90,32 @@ namespace {
|
||||
graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "vxgi");
|
||||
}
|
||||
#if UF_USE_VULKAN
|
||||
/*
|
||||
{
|
||||
auto& shader = graphic.material.getShader("vertex", "vxgi");
|
||||
struct SpecializationConstant {
|
||||
uint32_t passes = 6;
|
||||
};
|
||||
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
|
||||
specializationConstants.passes = uf::renderer::settings::maxViews;
|
||||
ext::json::forEach( shader.metadata["specializationConstants"], [&]( ext::json::Value& sc ){
|
||||
if ( sc["name"].as<std::string>() == "PASSES" ) sc["value"] = specializationConstants.passes;
|
||||
});
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) {
|
||||
auto& shader = graphic.material.getShader("geometry", "vxgi");
|
||||
pod::Vector3f min = uf::vector::decode( graph.metadata["extents"]["min"], pod::Vector3f{} );
|
||||
pod::Vector3f max = uf::vector::decode( graph.metadata["extents"]["max"], pod::Vector3f{} );
|
||||
|
||||
struct UniformDescriptor {
|
||||
alignas(16) pod::Matrix4f matrix;
|
||||
};
|
||||
|
||||
auto& uniform = shader.getUniform("UBO");
|
||||
auto& uniforms = uniform.get<UniformDescriptor>();
|
||||
uniforms.matrix = uf::matrix::ortho<float>( min.x, max.x, min.y, max.y, max.z, min.z );
|
||||
shader.updateUniform( "UBO", uniform );
|
||||
}
|
||||
*/
|
||||
{
|
||||
auto& shader = graphic.material.getShader("fragment", "vxgi");
|
||||
struct SpecializationConstant {
|
||||
uint32_t textures = 1;
|
||||
uint32_t textures = 256;
|
||||
uint32_t cascades = 2;
|
||||
};
|
||||
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
|
||||
specializationConstants.textures = texture2Ds;
|
||||
specializationConstants.cascades = texture3Ds / 4;
|
||||
ext::json::forEach( shader.metadata["specializationConstants"], [&]( ext::json::Value& sc ){
|
||||
if ( sc["name"].as<std::string>() == "TEXTURES" ) sc["value"] = specializationConstants.textures;
|
||||
std::string name = sc["name"].as<std::string>();
|
||||
if ( name == "TEXTURES" ) sc["value"] = specializationConstants.textures;
|
||||
else if ( name == "CASCADES" ) sc["value"] = specializationConstants.cascades;
|
||||
});
|
||||
ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){
|
||||
size_t binding = t["binding"].as<size_t>();
|
||||
std::string name = t["name"].as<std::string>();
|
||||
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
|
||||
if ( layout.binding != binding ) continue;
|
||||
if ( name == "samplerTextures" ) layout.descriptorCount = specializationConstants.textures;
|
||||
else if ( name == "voxelId" ) layout.descriptorCount = specializationConstants.cascades;
|
||||
else if ( name == "voxelUv" ) layout.descriptorCount = specializationConstants.cascades;
|
||||
else if ( name == "voxelNormal" ) layout.descriptorCount = specializationConstants.cascades;
|
||||
else if ( name == "voxelRadiance" ) layout.descriptorCount = specializationConstants.cascades;
|
||||
}
|
||||
});
|
||||
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
|
||||
if ( binding.descriptorCount > 1 ) binding.descriptorCount = specializationConstants.textures;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -167,10 +150,10 @@ namespace {
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& sceneTextures = scene.getComponent<pod::SceneTextures>();
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.id);
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.normal);
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.uv);
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.albedo);
|
||||
for ( auto& t : sceneTextures.voxels.id ) graphic.material.textures.emplace_back().aliasTexture(t);
|
||||
for ( auto& t : sceneTextures.voxels.uv ) graphic.material.textures.emplace_back().aliasTexture(t);
|
||||
for ( auto& t : sceneTextures.voxels.normal ) graphic.material.textures.emplace_back().aliasTexture(t);
|
||||
for ( auto& t : sceneTextures.voxels.radiance ) graphic.material.textures.emplace_back().aliasTexture(t);
|
||||
}
|
||||
}
|
||||
if ( graph.metadata["flags"]["LOAD"].as<bool>() ) {
|
||||
@ -340,12 +323,14 @@ void uf::graph::process( pod::Graph& graph ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Failsafe
|
||||
if ( graph.materials.empty() ) graph.materials.emplace_back();
|
||||
if ( graph.textures.empty() ) graph.textures.emplace_back();
|
||||
|
||||
// Materials storage buffer
|
||||
std::vector<pod::Material::Storage> materials( graph.materials.size() );
|
||||
for ( size_t i = 0; i < graph.materials.size(); ++i ) {
|
||||
materials[i] = graph.materials[i].storage;
|
||||
if ( graph.metadata["alpha cutoff"].is<float>() )
|
||||
materials[i].factorAlphaCutoff = graph.metadata["alpha cutoff"].as<float>();
|
||||
}
|
||||
graph.root.materialBufferIndex = graphic.initializeBuffer(
|
||||
(void*) materials.data(),
|
||||
@ -1434,7 +1419,7 @@ void uf::graph::save( const pod::Graph& graph, const std::string& filename ) {
|
||||
if ( saveSeparately ) {
|
||||
for ( size_t i = 0; i < graph.images.size(); ++i ) {
|
||||
std::string f = "image."+std::to_string(i)+(compression?".jpg":".png");
|
||||
graph.images[i].save(directory + "/" + f, true);
|
||||
graph.images[i].save(directory + "/" + f);
|
||||
serializer["images"].emplace_back(f);
|
||||
}
|
||||
} else {
|
||||
@ -1523,7 +1508,7 @@ void uf::graph::save( const pod::Graph& graph, const std::string& filename ) {
|
||||
if ( saveSeparately ) {
|
||||
for ( size_t i = 0; i < graph.images.size(); ++i ) {
|
||||
std::string f = "image."+std::to_string(i)+(compression?".jpg":".png");
|
||||
graph.images[i].save(directory + "/" + f, true);
|
||||
graph.images[i].save(directory + "/" + f);
|
||||
serializer["images"].emplace_back(f);
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -62,7 +62,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
/*.blend = */false,
|
||||
/*.samples = */msaa,
|
||||
});
|
||||
if ( ext::vulkan::settings::experimental::deferredMode == "deferredSampling" ) {
|
||||
if ( ext::vulkan::settings::experimental::deferredMode != "" ) {
|
||||
attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{
|
||||
/*.format = */VK_FORMAT_R16G16_UNORM,
|
||||
/*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
@ -131,7 +131,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
/*.samples = */1,
|
||||
});
|
||||
|
||||
if ( ext::vulkan::settings::experimental::deferredMode == "deferredSampling" ) {
|
||||
if ( ext::vulkan::settings::experimental::deferredMode != "" ) {
|
||||
// First pass: fill the G-Buffer
|
||||
{
|
||||
renderTarget.addPass(
|
||||
@ -213,23 +213,56 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
|
||||
auto& shader = blitter.material.shaders.back();
|
||||
struct SpecializationConstant {
|
||||
uint32_t maxTextures = 512;
|
||||
};
|
||||
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
|
||||
size_t maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as<size_t>(256);
|
||||
size_t maxTextures = metadata["system"]["config"]["engine"]["scenes"]["textures"]["max"].as<size_t>(256);
|
||||
|
||||
auto& metadata = scene.getComponent<uf::Serializer>();
|
||||
size_t maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as<size_t>();
|
||||
specializationConstants.maxTextures = metadata["system"]["config"]["engine"]["scenes"]["textures"]["max"].as<size_t>();
|
||||
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
|
||||
if ( binding.descriptorCount > 1 )
|
||||
binding.descriptorCount = specializationConstants.maxTextures;
|
||||
UF_DEBUG_MSG( maxLights << "\t" << maxTextures );
|
||||
|
||||
if ( ext::vulkan::settings::experimental::deferredMode == "vxgi" ) {
|
||||
struct SpecializationConstant {
|
||||
uint32_t maxTextures = 256;
|
||||
uint32_t maxCascades = 2;
|
||||
};
|
||||
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
|
||||
|
||||
auto& metadata = scene.getComponent<uf::Serializer>();
|
||||
specializationConstants.maxTextures = maxTextures;
|
||||
specializationConstants.maxCascades = metadata["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as<size_t>(2);
|
||||
|
||||
ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){
|
||||
size_t binding = t["binding"].as<size_t>();
|
||||
std::string name = t["name"].as<std::string>();
|
||||
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
|
||||
if ( layout.binding != binding ) continue;
|
||||
if ( name == "samplerTextures" ) layout.descriptorCount = specializationConstants.maxTextures;
|
||||
else if ( name == "voxelId" ) layout.descriptorCount = specializationConstants.maxCascades;
|
||||
else if ( name == "voxelUv" ) layout.descriptorCount = specializationConstants.maxCascades;
|
||||
else if ( name == "voxelNormal" ) layout.descriptorCount = specializationConstants.maxCascades;
|
||||
else if ( name == "voxelRadiance" ) layout.descriptorCount = specializationConstants.maxCascades;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
struct SpecializationConstant {
|
||||
uint32_t maxTextures = 256;
|
||||
};
|
||||
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
|
||||
|
||||
auto& metadata = scene.getComponent<uf::Serializer>();
|
||||
specializationConstants.maxTextures = maxTextures;
|
||||
|
||||
ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){
|
||||
if ( t["name"].as<std::string>() != "samplerTextures" ) return;
|
||||
size_t binding = t["binding"].as<size_t>();
|
||||
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
|
||||
if ( layout.binding == binding ) layout.descriptorCount = specializationConstants.maxTextures;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<pod::Light::Storage> lights(maxLights);
|
||||
std::vector<pod::Material::Storage> materials(specializationConstants.maxTextures);
|
||||
std::vector<pod::Texture::Storage> textures(specializationConstants.maxTextures);
|
||||
std::vector<pod::DrawCall::Storage> drawCalls(specializationConstants.maxTextures);
|
||||
std::vector<pod::Material::Storage> materials(maxTextures);
|
||||
std::vector<pod::Texture::Storage> textures(maxTextures);
|
||||
std::vector<pod::DrawCall::Storage> drawCalls(maxTextures);
|
||||
|
||||
for ( auto& material : materials ) material.colorBase = {0,0,0,0};
|
||||
|
||||
|
||||
@ -40,9 +40,10 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderTargetRenderMode::bindGraphicD
|
||||
if ( pass == 0 && type == "vxgi" ) {
|
||||
descriptor.cullMode = VK_CULL_MODE_NONE;
|
||||
descriptor.depth.test = false;
|
||||
descriptor.depth.write = false;
|
||||
descriptor.pipeline = "vxgi";
|
||||
} else if ( type == "depth" ) {
|
||||
descriptor.cullMode = VK_CULL_MODE_NONE;
|
||||
// descriptor.cullMode = VK_CULL_MODE_NONE;
|
||||
}
|
||||
// invalidate
|
||||
if ( target != "" && descriptor.renderMode != this->getName() && descriptor.renderMode != target ) {
|
||||
@ -185,7 +186,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
|
||||
/*.blend = */false,
|
||||
/*.samples = */msaa,
|
||||
});
|
||||
if ( ext::vulkan::settings::experimental::deferredMode == "deferredSampling" ) {
|
||||
if ( false && ext::vulkan::settings::experimental::deferredMode != "" ) {
|
||||
attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{
|
||||
/*.format = */VK_FORMAT_R16G16_UNORM,
|
||||
/*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
@ -216,7 +217,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
|
||||
/*.blend =*/ true,
|
||||
/*.samples =*/ 1,
|
||||
});
|
||||
if ( ext::vulkan::settings::experimental::deferredMode == "deferredSampling" ) {
|
||||
if ( false && ext::vulkan::settings::experimental::deferredMode != "" ) {
|
||||
// First pass: fill the G-Buffer
|
||||
{
|
||||
renderTarget.addPass(
|
||||
@ -347,16 +348,28 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
|
||||
auto& shader = blitter.material.getShader("compute");
|
||||
struct SpecializationConstant {
|
||||
uint32_t maxTextures = 512;
|
||||
uint32_t maxCascades = 1;
|
||||
};
|
||||
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
|
||||
|
||||
auto& metadata = scene.getComponent<uf::Serializer>();
|
||||
size_t maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as<size_t>();
|
||||
specializationConstants.maxTextures = metadata["system"]["config"]["engine"]["scenes"]["textures"]["max"].as<size_t>();
|
||||
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
|
||||
if ( binding.descriptorCount > 1 )
|
||||
binding.descriptorCount = specializationConstants.maxTextures;
|
||||
}
|
||||
size_t maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as<size_t>(256);
|
||||
specializationConstants.maxTextures = metadata["system"]["config"]["engine"]["scenes"]["textures"]["max"].as<size_t>(256);
|
||||
specializationConstants.maxCascades = metadata["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as<size_t>(2);
|
||||
|
||||
|
||||
ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){
|
||||
size_t binding = t["binding"].as<size_t>();
|
||||
std::string name = t["name"].as<std::string>();
|
||||
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
|
||||
if ( layout.binding != binding ) continue;
|
||||
if ( name == "samplerTextures" ) layout.descriptorCount = specializationConstants.maxTextures;
|
||||
else if ( name == "voxelId" ) layout.descriptorCount = specializationConstants.maxCascades;
|
||||
else if ( name == "voxelUv" ) layout.descriptorCount = specializationConstants.maxCascades;
|
||||
else if ( name == "voxelNormal" ) layout.descriptorCount = specializationConstants.maxCascades;
|
||||
else if ( name == "voxelRadiance" ) layout.descriptorCount = specializationConstants.maxCascades;
|
||||
}
|
||||
});
|
||||
|
||||
std::vector<pod::Light::Storage> lights(maxLights);
|
||||
std::vector<pod::Material::Storage> materials(specializationConstants.maxTextures);
|
||||
|
||||
@ -530,12 +530,14 @@ void ext::vulkan::Texture::aliasTexture( const Texture& texture ) {
|
||||
view = texture.view;
|
||||
imageLayout = texture.imageLayout;
|
||||
deviceMemory = texture.deviceMemory;
|
||||
sampler = texture.sampler;
|
||||
width = texture.width;
|
||||
height = texture.height;
|
||||
depth = texture.depth;
|
||||
layers = texture.layers;
|
||||
|
||||
sampler = texture.sampler;
|
||||
sampler.device = NULL;
|
||||
|
||||
this->updateDescriptors();
|
||||
}
|
||||
void ext::vulkan::Texture::aliasAttachment( const RenderTarget::Attachment& attachment, bool createSampler ) {
|
||||
|
||||
@ -16,9 +16,6 @@ uf::Camera::Camera() : m_modified(false) {
|
||||
this->m_settings.offset = {0, 0, 0};
|
||||
this->m_settings.mode = 1;
|
||||
|
||||
// this->setModel(uf::matrix::identity());
|
||||
// this->setView(uf::matrix::identity());
|
||||
// this->setProjection(uf::matrix::identity());
|
||||
this->m_matrices.views.resize(6, uf::matrix::identity());
|
||||
this->m_matrices.projections.resize(6, uf::matrix::identity());
|
||||
|
||||
@ -39,89 +36,30 @@ const pod::Transform<>& uf::Camera::getTransform() const {
|
||||
pod::Matrix4& uf::Camera::getView( size_t eye ) {
|
||||
if ( eye >= this->m_matrices.views.size() ) eye = 0;
|
||||
return this->m_matrices.views[eye];
|
||||
// if ( eye >= this->m_matrices.views.size() ) return uf::matrix::identity();
|
||||
// if ( eye >= this->m_matrices.views.size() ) this->m_matrices.views.resize( uf::matrix::identity() );
|
||||
/*
|
||||
switch ( eye ) {
|
||||
case 0:
|
||||
return this->m_matrices.left.view;
|
||||
break;
|
||||
case 1:
|
||||
return this->m_matrices.right.view;
|
||||
break;
|
||||
default:
|
||||
return this->m_matrices.left.view;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
pod::Matrix4& uf::Camera::getProjection( size_t eye ) {
|
||||
if ( eye >= this->m_matrices.projections.size() ) eye = 0;
|
||||
return this->m_matrices.projections[eye];
|
||||
// if ( eye >= this->m_matrices.projections.size() ) return uf::matrix::identity();
|
||||
// if ( eye >= this->m_matrices.projections.size() ) this->m_matrices.projections.resize( eye, uf::matrix::identity() );
|
||||
/*
|
||||
switch ( eye ) {
|
||||
case 0:
|
||||
return this->m_matrices.left.projection;
|
||||
break;
|
||||
case 1:
|
||||
return this->m_matrices.right.projection;
|
||||
break;
|
||||
default:
|
||||
return this->m_matrices.left.projection;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
/*
|
||||
pod::Matrix4& uf::Camera::getModel() {
|
||||
return this->m_matrices.model;
|
||||
}
|
||||
*/
|
||||
const pod::Matrix4& uf::Camera::getView( size_t eye ) const {
|
||||
if ( eye >= this->m_matrices.views.size() ) eye = 0;
|
||||
return this->m_matrices.views[eye];
|
||||
// if ( eye >= this->m_matrices.views.size() ) return uf::matrix::identity();
|
||||
// if ( eye >= this->m_matrices.views.size() ) this->m_matrices.views.resize( eye, uf::matrix::identity() );
|
||||
/*
|
||||
switch ( eye ) {
|
||||
case 0:
|
||||
return this->m_matrices.left.view;
|
||||
break;
|
||||
case 1:
|
||||
return this->m_matrices.right.view;
|
||||
break;
|
||||
default:
|
||||
return this->m_matrices.left.view;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
const pod::Matrix4& uf::Camera::getProjection( size_t eye ) const {
|
||||
if ( eye >= this->m_matrices.projections.size() ) eye = 0;
|
||||
return this->m_matrices.projections[eye];
|
||||
// if ( eye >= this->m_matrices.projections.size() ) return uf::matrix::identity();
|
||||
// if ( eye >= this->m_matrices.projections.size() ) this->m_matrices.projections.resize( eye, uf::matrix::identity() );
|
||||
/*
|
||||
switch ( eye ) {
|
||||
case 0:
|
||||
return this->m_matrices.left.projection;
|
||||
break;
|
||||
case 1:
|
||||
return this->m_matrices.right.projection;
|
||||
break;
|
||||
default:
|
||||
return this->m_matrices.left.projection;
|
||||
break;
|
||||
}
|
||||
|
||||
pod::Vector3f uf::Camera::getEye( size_t eye ) const {
|
||||
pod::Vector3f position = uf::transform::flatten( this->m_transform ).position;
|
||||
#if UF_USE_OPENVR
|
||||
if ( this->m_settings.stereoscopic && ext::openvr::context ) {
|
||||
position += ext::openvr::hmdPosition( eye == 0 ? vr::Eye_Left : vr::Eye_Right );
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
return position;
|
||||
}
|
||||
/*
|
||||
const pod::Matrix4& uf::Camera::getModel() const {
|
||||
return this->m_matrices.model;
|
||||
}
|
||||
*/
|
||||
|
||||
pod::Math::num_t& uf::Camera::getFov() {
|
||||
return this->m_settings.perspective.fov;
|
||||
}
|
||||
@ -162,20 +100,6 @@ void uf::Camera::setView( const pod::Matrix4& mat, size_t i ) {
|
||||
}
|
||||
if ( i >= this->m_matrices.views.size() ) this->m_matrices.views.resize( i, uf::matrix::identity() );
|
||||
this->m_matrices.views[i] = mat;
|
||||
/*
|
||||
switch ( i ) {
|
||||
case 0:
|
||||
this->m_matrices.left.view = mat;
|
||||
break;
|
||||
case 1:
|
||||
this->m_matrices.right.view = mat;
|
||||
break;
|
||||
default:
|
||||
this->setView( mat, 0 );
|
||||
this->setView( mat, 1 );
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
void uf::Camera::setProjection( const pod::Matrix4& mat, size_t i ) {
|
||||
if ( i >= uf::renderer::settings::maxViews ) {
|
||||
@ -185,26 +109,7 @@ void uf::Camera::setProjection( const pod::Matrix4& mat, size_t i ) {
|
||||
}
|
||||
if ( i >= this->m_matrices.projections.size() ) this->m_matrices.projections.resize( i, uf::matrix::identity() );
|
||||
this->m_matrices.projections[i] = mat;
|
||||
/*
|
||||
switch ( i ) {
|
||||
case 0:
|
||||
this->m_matrices.left.projection = mat;
|
||||
break;
|
||||
case 1:
|
||||
this->m_matrices.right.projection = mat;
|
||||
break;
|
||||
default:
|
||||
this->setProjection( mat, 0 );
|
||||
this->setProjection( mat, 1 );
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
/*
|
||||
void uf::Camera::setModel( const pod::Matrix4& mat ) {
|
||||
this->m_matrices.model = mat;
|
||||
}
|
||||
*/
|
||||
void uf::Camera::setFov( pod::Math::num_t fov ) {
|
||||
this->m_settings.mode = 1;
|
||||
this->m_settings.perspective.fov = fov;
|
||||
|
||||
2
engine/src/utils/octree/octree.cpp
Normal file
2
engine/src/utils/octree/octree.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include <uf/utils/octree/octree.h>
|
||||
|
||||
@ -71,8 +71,9 @@ void ext::PlayerModelBehavior::render( uf::Object& self ){
|
||||
auto& transform = this->getComponent<pod::Transform<>>();
|
||||
|
||||
// auto& renderMode = *uf::renderer::currentRenderMode;
|
||||
// if ( renderMode.getType() == "Deferred" ) {
|
||||
if ( player.getUid() == controller.getUid() && uf::renderer::currentRenderMode->getName() != "RenderTarget" ) {
|
||||
// UF_DEBUG_MSG( uf::renderer::currentRenderMode->getName() << ": " << uf::renderer::currentRenderMode->getType() );
|
||||
if ( uf::renderer::currentRenderMode->getName() == "Gui" ) {
|
||||
// if ( player.getUid() == controller.getUid() && uf::renderer::currentRenderMode->getName() != "RenderTarget" ) {
|
||||
transform.scale = { 0, 0, 0 };
|
||||
} else {
|
||||
transform.scale = metadata.scale;
|
||||
|
||||
@ -210,10 +210,12 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
|
||||
auto& metadata = this->getComponent<ext::ExtSceneBehavior::Metadata>();
|
||||
metadata.serialize = [&]() {
|
||||
metadataJson["light"]["should"] = metadata.light.enabled;
|
||||
|
||||
metadataJson["light"]["ambient"] = uf::vector::encode( metadata.light.ambient );
|
||||
metadataJson["light"]["specular"] = uf::vector::encode( metadata.light.specular );
|
||||
metadataJson["light"]["exposure"] = metadata.light.exposure;
|
||||
metadataJson["light"]["gamma"] = metadata.light.gamma;
|
||||
|
||||
metadataJson["light"]["fog"]["color"] = uf::vector::encode( metadata.fog.color );
|
||||
metadataJson["light"]["fog"]["step scale"] = metadata.fog.stepScale;
|
||||
metadataJson["light"]["fog"]["absorbtion"] = metadata.fog.absorbtion;
|
||||
@ -227,14 +229,17 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
|
||||
metadata.deserialize = [&](){
|
||||
metadata.max.textures = ext::config["engine"]["scenes"]["textures"]["max"].as<size_t>();
|
||||
metadata.max.lights = ext::config["engine"]["scenes"]["lights"]["max"].as<size_t>();
|
||||
|
||||
metadata.light.enabled = ext::config["engine"]["scenes"]["lights"]["enabled"].as<bool>() && metadataJson["light"]["should"].as<bool>();
|
||||
metadata.light.shadowSamples = ext::config["engine"]["scenes"]["lights"]["shadow samples"].as<size_t>();
|
||||
metadata.light.shadowThreshold = ext::config["engine"]["scenes"]["lights"]["shadow threshold"].as<size_t>();
|
||||
metadata.light.updateThreshold = ext::config["engine"]["scenes"]["lights"]["update threshold"].as<size_t>();
|
||||
|
||||
metadata.light.ambient = uf::vector::decode( metadataJson["light"]["ambient"], pod::Vector4f{ 1, 1, 1, 1 } );
|
||||
metadata.light.specular = uf::vector::decode( metadataJson["light"]["specular"], pod::Vector4f{ 1, 1, 1, 1 } );
|
||||
metadata.light.exposure = metadataJson["light"]["exposure"].as<float>(1.0f);
|
||||
metadata.light.gamma = metadataJson["light"]["gamma"].as<float>(2.2f);
|
||||
|
||||
metadata.fog.color = uf::vector::decode( metadataJson["light"]["fog"]["color"], pod::Vector3f{ 1, 1, 1 } );
|
||||
metadata.fog.stepScale = metadataJson["light"]["fog"]["step scale"].as<float>();
|
||||
metadata.fog.absorbtion = metadataJson["light"]["fog"]["absorbtion"].as<float>();
|
||||
@ -244,6 +249,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
|
||||
metadata.fog.density.threshold = metadataJson["light"]["fog"]["density"]["threshold"].as<float>();
|
||||
metadata.fog.density.multiplier = metadataJson["light"]["fog"]["density"]["multiplier"].as<float>();
|
||||
metadata.fog.density.scale = metadataJson["light"]["fog"]["density"]["scale"].as<float>();
|
||||
|
||||
#if UF_USE_OPENGL_FIXED_FUNCTION
|
||||
uf::renderer::states::rebuild = true;
|
||||
#endif
|
||||
@ -364,6 +370,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
#else
|
||||
if ( !metadata.max.textures ) metadata.max.textures = ext::config["engine"]["scenes"]["textures"]["max"].as<size_t>();
|
||||
if ( !metadata.max.lights ) metadata.max.lights = ext::config["engine"]["scenes"]["lights"]["max"].as<size_t>();
|
||||
|
||||
if ( !metadata.light.enabled ) metadata.light.enabled = ext::config["engine"]["scenes"]["lights"]["enabled"].as<bool>() && metadataJson["light"]["should"].as<bool>();
|
||||
if ( !metadata.light.shadowSamples ) metadata.light.shadowSamples = ext::config["engine"]["scenes"]["lights"]["shadow samples"].as<size_t>();
|
||||
if ( !metadata.light.shadowThreshold ) metadata.light.shadowThreshold = ext::config["engine"]["scenes"]["lights"]["shadow threshold"].as<size_t>();
|
||||
@ -371,7 +378,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
if ( !metadata.light.exposure ) metadata.light.exposure = metadataJson["light"]["exposure"].as<float>(1.0f);
|
||||
if ( !metadata.light.gamma ) metadata.light.gamma = metadataJson["light"]["gamma"].as<float>(2.2f);
|
||||
#endif
|
||||
/* Update lights */ if ( metadata.light.enabled ) {
|
||||
/* Update lights */ if ( uf::renderer::settings::experimental::deferredMode != "vxgi" ) {
|
||||
ext::ExtSceneBehavior::bindBuffers( *this );
|
||||
}
|
||||
|
||||
@ -456,7 +463,8 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
alignas(16) pod::Matrix4f iView[2];
|
||||
alignas(16) pod::Matrix4f iProjection[2];
|
||||
alignas(16) pod::Matrix4f iProjectionView[2];
|
||||
alignas(16) pod::Matrix4f ortho;
|
||||
alignas(16) pod::Vector4f eyePos[2];
|
||||
alignas(16) pod::Matrix4f vxgi;
|
||||
} matrices;
|
||||
struct Mode {
|
||||
alignas(8) pod::Vector2ui type;
|
||||
@ -482,12 +490,14 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
alignas(4) uint32_t textures = 0;
|
||||
alignas(4) uint32_t drawCalls = 0;
|
||||
} lengths;
|
||||
alignas(16) pod::Vector4f ambient;
|
||||
|
||||
alignas(4) uint32_t msaa;
|
||||
alignas(4) uint32_t poissonSamples;
|
||||
// alignas(16) pod::Vector4f ambient;
|
||||
pod::Vector3f ambient;
|
||||
alignas(4) float gamma;
|
||||
|
||||
alignas(4) float exposure;
|
||||
alignas(4) uint32_t msaa;
|
||||
alignas(4) uint32_t shadowSamples;
|
||||
alignas(4) uint32_t padding1;
|
||||
};
|
||||
struct SpecializationConstant {
|
||||
uint32_t maxTextures = 512;
|
||||
@ -536,7 +546,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
|
||||
int shadowSamples = metadata.light.shadowSamples;
|
||||
int shadowThreshold = metadata.light.shadowThreshold;
|
||||
if ( shadowSamples <= 0 ) shadowSamples = 16;
|
||||
if ( shadowSamples < 0 ) shadowSamples = 0;
|
||||
if ( shadowThreshold <= 0 ) shadowThreshold = std::numeric_limits<int>::max();
|
||||
{
|
||||
std::vector<LightInfo> scratch;
|
||||
@ -565,14 +575,16 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
uniforms->matrices.iView[i] = uf::matrix::inverse( uniforms->matrices.view[i] );
|
||||
uniforms->matrices.iProjection[i] = uf::matrix::inverse( uniforms->matrices.projection[i] );
|
||||
uniforms->matrices.iProjectionView[i] = uf::matrix::inverse( uniforms->matrices.projection[i] * uniforms->matrices.view[i] );
|
||||
|
||||
uniforms->matrices.eyePos[i] = camera.getEye( i );
|
||||
}
|
||||
|
||||
uniforms->ambient = metadata.light.ambient;
|
||||
uniforms->msaa = ext::vulkan::settings::msaa;
|
||||
uniforms->poissonSamples = shadowSamples;
|
||||
uniforms->shadowSamples = shadowSamples;
|
||||
uniforms->exposure = metadata.light.exposure;
|
||||
uniforms->gamma = metadata.light.gamma;
|
||||
|
||||
|
||||
uniforms->fog.color = metadata.fog.color;
|
||||
uniforms->fog.color.w = metadata.fog.stepScale;
|
||||
|
||||
@ -598,10 +610,10 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
|
||||
graphic.material.textures.clear();
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) {
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.id); //this->getComponent<uf::renderer::Texture3D>());
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.normal); //this->getComponent<uf::renderer::Texture3D>());
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.uv); //this->getComponent<uf::renderer::Texture3D>());
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.albedo); //this->getComponent<uf::renderer::Texture3D>());
|
||||
for ( auto& t : sceneTextures.voxels.id ) graphic.material.textures.emplace_back().aliasTexture(t);
|
||||
for ( auto& t : sceneTextures.voxels.uv ) graphic.material.textures.emplace_back().aliasTexture(t);
|
||||
for ( auto& t : sceneTextures.voxels.normal ) graphic.material.textures.emplace_back().aliasTexture(t);
|
||||
for ( auto& t : sceneTextures.voxels.radiance ) graphic.material.textures.emplace_back().aliasTexture(t);
|
||||
}
|
||||
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.noise); //this->getComponent<uf::renderer::Texture3D>());
|
||||
@ -645,33 +657,8 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
graphic.material.textures.emplace_back().aliasTexture(texture.texture);
|
||||
++textureSlot;
|
||||
}
|
||||
#if 1
|
||||
}
|
||||
uniforms->matrices.ortho = sceneTextures.voxels.matrix;
|
||||
#else
|
||||
// calculate extents
|
||||
pod::Vector3f graphMin = uf::vector::decode( graph.metadata["extents"]["min"], pod::Vector3f{} );
|
||||
pod::Vector3f graphMax = uf::vector::decode( graph.metadata["extents"]["max"], pod::Vector3f{} );
|
||||
|
||||
min.x = std::min( min.x, graphMin.x );
|
||||
min.y = std::min( min.y, graphMin.y );
|
||||
min.z = std::min( min.z, graphMin.z );
|
||||
|
||||
max.x = std::max( max.x, graphMax.x );
|
||||
max.y = std::max( max.y, graphMax.y );
|
||||
max.z = std::max( max.z, graphMax.z );
|
||||
}
|
||||
|
||||
min.x += floor(controllerTransform.position.x );
|
||||
min.y -= floor(controllerTransform.position.y );
|
||||
min.z -= floor(controllerTransform.position.z );
|
||||
|
||||
max.x += floor(controllerTransform.position.x );
|
||||
max.y -= floor(controllerTransform.position.y );
|
||||
max.z -= floor(controllerTransform.position.z );
|
||||
|
||||
uniforms->matrices.ortho = /*uf::matrix::translate( uf::matrix::identity(), controllerTransform.position ) **/ uf::matrix::ortho( min.x, max.x, min.y, max.y, min.z, max.z );
|
||||
#endif
|
||||
uniforms->matrices.vxgi = sceneTextures.voxels.matrix;
|
||||
uniforms->lengths.materials = std::min( materials.size(), maxTextures );
|
||||
uniforms->lengths.textures = std::min( textures.size(), maxTextures );
|
||||
uniforms->lengths.drawCalls = std::min( drawCalls.size(), maxTextures );
|
||||
@ -740,6 +727,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
|
||||
graphic.updatePipelines();
|
||||
}
|
||||
|
||||
shader.updateUniform( "UBO", uniform );
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,8 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) {
|
||||
{
|
||||
const uint32_t DEFAULT_VOXEL_SIZE = ext::config["engine"]["scenes"]["vxgi"]["size"].as<uint32_t>(256);
|
||||
const float DEFAULT_VOXELIZE_LIMITER = ext::config["engine"]["scenes"]["vxgi"]["limiter"].as<float>(0);
|
||||
const uint32_t DEFAULT_DISPATCH_LIMITER = ext::config["engine"]["scenes"]["vxgi"]["dispatch"].as<uint32_t>(8);
|
||||
const uint32_t DEFAULT_DISPATCH_SIZE = ext::config["engine"]["scenes"]["vxgi"]["dispatch"].as<uint32_t>(8);
|
||||
const uint32_t DEFAULT_CASCADES = ext::config["engine"]["scenes"]["vxgi"]["cascades"].as<uint32_t>(8);
|
||||
|
||||
if ( metadata.voxelSize.x == 0 ) metadata.voxelSize.x = DEFAULT_VOXEL_SIZE;
|
||||
if ( metadata.voxelSize.y == 0 ) metadata.voxelSize.y = DEFAULT_VOXEL_SIZE;
|
||||
@ -36,33 +37,42 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) {
|
||||
|
||||
if ( metadata.renderer.limiter == 0 ) metadata.renderer.limiter = DEFAULT_VOXELIZE_LIMITER;
|
||||
|
||||
if ( metadata.dispatchSize.x == 0 ) metadata.dispatchSize.x = DEFAULT_DISPATCH_LIMITER;
|
||||
if ( metadata.dispatchSize.y == 0 ) metadata.dispatchSize.y = DEFAULT_DISPATCH_LIMITER;
|
||||
if ( metadata.dispatchSize.z == 0 ) metadata.dispatchSize.z = DEFAULT_DISPATCH_LIMITER;
|
||||
|
||||
if ( metadata.dispatchSize.x == 0 ) metadata.dispatchSize.x = DEFAULT_DISPATCH_SIZE;
|
||||
if ( metadata.dispatchSize.y == 0 ) metadata.dispatchSize.y = DEFAULT_DISPATCH_SIZE;
|
||||
if ( metadata.dispatchSize.z == 0 ) metadata.dispatchSize.z = DEFAULT_DISPATCH_SIZE;
|
||||
|
||||
if ( metadata.cascades == 0 ) metadata.cascades = DEFAULT_CASCADES;
|
||||
|
||||
metadata.extents.min = uf::vector::decode( ext::config["engine"]["scenes"]["vxgi"]["extents"]["min"], pod::Vector3f{-32, -32, -32} );
|
||||
metadata.extents.max = uf::vector::decode( ext::config["engine"]["scenes"]["vxgi"]["extents"]["max"], pod::Vector3f{ 32, 32, 32} );
|
||||
|
||||
std::vector<uint8_t> empty(metadata.voxelSize.x * metadata.voxelSize.y * metadata.voxelSize.z * sizeof(uint8_t) * 4);
|
||||
|
||||
sceneTextures.voxels.id.sampler.descriptor.filter.min = VK_FILTER_NEAREST;
|
||||
sceneTextures.voxels.id.sampler.descriptor.filter.mag = VK_FILTER_NEAREST;
|
||||
for ( size_t i = 0; i < metadata.cascades; ++i ) {
|
||||
auto& id = sceneTextures.voxels.id.emplace_back();
|
||||
auto& uv = sceneTextures.voxels.uv.emplace_back();
|
||||
auto& normal = sceneTextures.voxels.normal.emplace_back();
|
||||
auto& radiance = sceneTextures.voxels.radiance.emplace_back();
|
||||
|
||||
sceneTextures.voxels.id.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_UINT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
|
||||
sceneTextures.voxels.normal.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_SFLOAT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
|
||||
sceneTextures.voxels.uv.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_SFLOAT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
|
||||
sceneTextures.voxels.albedo.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R8G8B8A8_UNORM, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
|
||||
id.sampler.descriptor.filter.min = VK_FILTER_NEAREST;
|
||||
id.sampler.descriptor.filter.mag = VK_FILTER_NEAREST;
|
||||
|
||||
id.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_UINT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
|
||||
uv.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_SFLOAT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
|
||||
normal.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_SFLOAT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
|
||||
radiance.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R8G8B8A8_UNORM, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
|
||||
}
|
||||
}
|
||||
// initialize render mode
|
||||
{
|
||||
// if ( metadata.fragmentSize.x == 0 ) metadata.fragmentSize.x = metadata.voxelSize.x * 2;
|
||||
// if ( metadata.fragmentSize.y == 0 ) metadata.fragmentSize.y = metadata.voxelSize.y * 2;
|
||||
if ( metadata.fragmentSize.x == 0 ) metadata.fragmentSize.x = metadata.voxelSize.x;
|
||||
if ( metadata.fragmentSize.y == 0 ) metadata.fragmentSize.y = metadata.voxelSize.y;
|
||||
|
||||
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
|
||||
metadata.renderModeName = "VXGI:" + std::to_string((int) this->getUid());
|
||||
uf::renderer::addRenderMode( &renderMode, metadata.renderModeName );
|
||||
renderMode.metadata["type"] = "vxgi";
|
||||
renderMode.metadata["samples"] = 1;
|
||||
renderMode.metadata["samples"] = 2;
|
||||
|
||||
renderMode.blitter.device = &ext::vulkan::device;
|
||||
renderMode.width = metadata.fragmentSize.x;
|
||||
@ -77,12 +87,13 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) {
|
||||
renderMode.blitter.process = false;
|
||||
#endif
|
||||
|
||||
renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.id); //this->getComponent<uf::renderer::Texture3D>());
|
||||
renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.normal); //this->getComponent<uf::renderer::Texture3D>());
|
||||
renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.uv); //this->getComponent<uf::renderer::Texture3D>());
|
||||
renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.albedo); //this->getComponent<uf::renderer::Texture3D>());
|
||||
renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.noise); //this->getComponent<uf::renderer::Texture3D>());
|
||||
renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.skybox); //this->getComponent<uf::renderer::TextureCube>());
|
||||
for ( auto& t : sceneTextures.voxels.id ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t);
|
||||
for ( auto& t : sceneTextures.voxels.uv ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t);
|
||||
for ( auto& t : sceneTextures.voxels.normal ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t);
|
||||
for ( auto& t : sceneTextures.voxels.radiance ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t);
|
||||
|
||||
renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.noise);
|
||||
renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.skybox);
|
||||
|
||||
renderMode.bindCallback( renderMode.CALLBACK_BEGIN, [&]( VkCommandBuffer commandBuffer ){
|
||||
// clear textures
|
||||
@ -94,10 +105,10 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) {
|
||||
subresourceRange.layerCount = 1;
|
||||
|
||||
VkClearColorValue clearColor = { 0.0, 0.0, 0.0, 0.0 };
|
||||
vkCmdClearColorImage( commandBuffer, sceneTextures.voxels.id.image, sceneTextures.voxels.id.imageLayout, &clearColor, 1, &subresourceRange );
|
||||
vkCmdClearColorImage( commandBuffer, sceneTextures.voxels.normal.image, sceneTextures.voxels.normal.imageLayout, &clearColor, 1, &subresourceRange );
|
||||
vkCmdClearColorImage( commandBuffer, sceneTextures.voxels.uv.image, sceneTextures.voxels.uv.imageLayout, &clearColor, 1, &subresourceRange );
|
||||
vkCmdClearColorImage( commandBuffer, sceneTextures.voxels.albedo.image, sceneTextures.voxels.albedo.imageLayout, &clearColor, 1, &subresourceRange );
|
||||
for ( auto& t : sceneTextures.voxels.id ) vkCmdClearColorImage( commandBuffer, t.image, t.imageLayout, &clearColor, 1, &subresourceRange );
|
||||
for ( auto& t : sceneTextures.voxels.normal ) vkCmdClearColorImage( commandBuffer, t.image, t.imageLayout, &clearColor, 1, &subresourceRange );
|
||||
for ( auto& t : sceneTextures.voxels.uv ) vkCmdClearColorImage( commandBuffer, t.image, t.imageLayout, &clearColor, 1, &subresourceRange );
|
||||
for ( auto& t : sceneTextures.voxels.radiance ) vkCmdClearColorImage( commandBuffer, t.image, t.imageLayout, &clearColor, 1, &subresourceRange );
|
||||
});
|
||||
renderMode.bindCallback( renderMode.CALLBACK_END, [&]( VkCommandBuffer commandBuffer ){
|
||||
// parse voxel lighting
|
||||
@ -113,24 +124,25 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) {
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.levelCount = sceneTextures.voxels.albedo.mips;
|
||||
subresourceRange.layerCount = 1;
|
||||
|
||||
sceneTextures.voxels.albedo.setImageLayout(
|
||||
commandBuffer,
|
||||
sceneTextures.voxels.albedo.image,
|
||||
sceneTextures.voxels.albedo.imageLayout,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
subresourceRange
|
||||
);
|
||||
sceneTextures.voxels.albedo.generateMipmaps( commandBuffer, 0 );
|
||||
sceneTextures.voxels.albedo.setImageLayout(
|
||||
commandBuffer,
|
||||
sceneTextures.voxels.albedo.image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
sceneTextures.voxels.albedo.imageLayout,
|
||||
subresourceRange
|
||||
);
|
||||
for ( auto& t : sceneTextures.voxels.radiance ) {
|
||||
subresourceRange.levelCount = t.mips;
|
||||
t.setImageLayout(
|
||||
commandBuffer,
|
||||
t.image,
|
||||
t.imageLayout,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
subresourceRange
|
||||
);
|
||||
t.generateMipmaps( commandBuffer, 0 );
|
||||
t.setImageLayout(
|
||||
commandBuffer,
|
||||
t.image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
t.imageLayout,
|
||||
subresourceRange
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
@ -145,9 +157,10 @@ void ext::VoxelizerBehavior::tick( uf::Object& self ) {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& sceneTextures = scene.getComponent<pod::SceneTextures>();
|
||||
auto& controller = scene.getController();
|
||||
auto& controllerTransform = controller.getComponent<pod::Transform<>>();
|
||||
auto controllerTransform = uf::transform::flatten( controller.getComponent<uf::Camera>().getTransform() );
|
||||
renderMode.setTarget("");
|
||||
if ( renderMode.executed ) {
|
||||
|
||||
if ( renderMode.executed ) {
|
||||
if ( !metadata.initialized ) metadata.initialized = true;
|
||||
|
||||
if ( metadata.renderer.limiter > 0 ) {
|
||||
@ -159,50 +172,42 @@ void ext::VoxelizerBehavior::tick( uf::Object& self ) {
|
||||
renderMode.execute = false;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if ( renderMode.execute ) {
|
||||
pod::Vector3f min = metadata.extents.min;
|
||||
pod::Vector3f max = metadata.extents.max;
|
||||
pod::Vector3f controllerPosition = controllerTransform.position;
|
||||
controllerPosition.x = floor(controllerPosition.x);
|
||||
controllerPosition.y = floor(controllerPosition.y);
|
||||
controllerPosition.z = -floor(controllerPosition.z);
|
||||
|
||||
min.x += floor(controllerTransform.position.x);
|
||||
min.y -= floor(controllerTransform.position.y);
|
||||
min.z -= floor(controllerTransform.position.z);
|
||||
|
||||
max.x += floor(controllerTransform.position.x);
|
||||
max.y -= floor(controllerTransform.position.y);
|
||||
max.z -= floor(controllerTransform.position.z);
|
||||
pod::Vector3f min = metadata.extents.min + controllerPosition;
|
||||
pod::Vector3f max = metadata.extents.max + controllerPosition;
|
||||
sceneTextures.voxels.matrix = uf::matrix::ortho<float>( min.x, max.x, min.y, max.y, min.z, max.z );
|
||||
|
||||
auto graph = uf::scene::generateGraph();
|
||||
for ( auto entity : graph ) {
|
||||
if ( !entity->hasComponent<uf::Graphic>() ) continue;
|
||||
auto& graphic = entity->getComponent<uf::Graphic>();
|
||||
if ( graphic.material.hasShader("geometry", "vxgi") ) {
|
||||
auto& shader = graphic.material.getShader("geometry", "vxgi");
|
||||
|
||||
auto& sceneTextures = scene.getComponent<pod::SceneTextures>();
|
||||
struct UniformDescriptor {
|
||||
alignas(16) pod::Matrix4f matrix;
|
||||
};
|
||||
auto& uniform = shader.getUniform("UBO");
|
||||
auto& uniforms = uniform.get<UniformDescriptor>();
|
||||
uniforms.matrix = sceneTextures.voxels.matrix;
|
||||
shader.updateUniform( "UBO", uniform );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if COMP_SHADER_USED
|
||||
ext::ExtSceneBehavior::bindBuffers( scene, metadata.renderModeName, true );
|
||||
ext::ExtSceneBehavior::bindBuffers( scene );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
void ext::VoxelizerBehavior::render( uf::Object& self ){
|
||||
auto& metadata = this->getComponent<ext::VoxelizerBehavior::Metadata>();
|
||||
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& sceneTextures = scene.getComponent<pod::SceneTextures>();
|
||||
auto& controller = scene.getController();
|
||||
auto& controllerTransform = controller.getComponent<pod::Transform<>>();
|
||||
|
||||
if ( uf::renderer::currentRenderMode->getName() != "RenderTarget" && renderMode.execute ) {
|
||||
pod::Vector3f min = metadata.extents.min;
|
||||
pod::Vector3f max = metadata.extents.max;
|
||||
|
||||
min.x += floor(controllerTransform.position.x);
|
||||
min.y -= floor(controllerTransform.position.y);
|
||||
min.z -= floor(controllerTransform.position.z);
|
||||
|
||||
max.x += floor(controllerTransform.position.x);
|
||||
max.y -= floor(controllerTransform.position.y);
|
||||
max.z -= floor(controllerTransform.position.z);
|
||||
sceneTextures.voxels.matrix = uf::matrix::ortho<float>( min.x, max.x, min.y, max.y, min.z, max.z );
|
||||
}
|
||||
}
|
||||
void ext::VoxelizerBehavior::render( uf::Object& self ){}
|
||||
void ext::VoxelizerBehavior::destroy( uf::Object& self ){
|
||||
#if UF_USE_VULKAN
|
||||
if ( this->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {
|
||||
|
||||
@ -20,6 +20,7 @@ namespace ext {
|
||||
pod::Vector3ui voxelSize = { 0, 0, 0 };
|
||||
pod::Vector3ui dispatchSize = { 0, 0, 0 };
|
||||
std::string renderModeName = "VXGI";
|
||||
size_t cascades = 0;
|
||||
struct {
|
||||
pod::Vector3f min = {};
|
||||
pod::Vector3f max = {};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user