Commit for 2021.04.15.7z

This commit is contained in:
mrq 2021-04-15 00:00:00 -05:00
parent 7cae094543
commit 7794e730aa
33 changed files with 2587 additions and 741 deletions

View File

@ -13,6 +13,7 @@ struct Matrices {
mat4 iView[2];
mat4 iProjection[2];
mat4 iProjectionView[2];
mat4 ortho;
};
struct Space {
@ -113,11 +114,8 @@ struct DrawCall {
#endif
layout (input_attachment_index = 3, binding = 3) uniform subpassInputMS samplerDepth;
#endif
layout (binding = 4) uniform sampler3D samplerNoise;
layout (binding = 5) uniform samplerCube samplerSkybox;
layout (binding = 6) uniform sampler2D samplerTextures[TEXTURES];
layout (binding = 7) uniform UBO {
layout (binding = 4) uniform UBO {
Matrices matrices;
Mode mode;
@ -137,19 +135,23 @@ layout (binding = 7) uniform UBO {
uint padding2;
} ubo;
layout (std140, binding = 8) readonly buffer Lights {
layout (std140, binding = 5) readonly buffer Lights {
Light lights[];
};
layout (std140, binding = 9) readonly buffer Materials {
layout (std140, binding = 6) readonly buffer Materials {
Material materials[];
};
layout (std140, binding = 10) readonly buffer Textures {
layout (std140, binding = 7) readonly buffer Textures {
Texture textures[];
};
layout (std140, binding = 11) readonly buffer DrawCalls {
layout (std140, binding = 8) readonly buffer DrawCalls {
DrawCall drawCalls[];
};
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;
@ -208,7 +210,35 @@ void phong( Light light, vec4 albedoSpecular, inout vec3 i ) {
i += Id + Is;
}
void phongSpecular( Light light, vec4 albedoSpecular, inout vec3 i ) {
vec3 Ls = vec3(1.0, 1.0, 1.0); // light specular
vec3 Ld = light.color; // light color
vec3 La = vec3(1.0, 1.0, 1.0);
vec3 Ks = vec3(albedoSpecular.a); // material specular
vec3 Kd = albedoSpecular.rgb; // material diffuse
vec3 Ka = vec3(1.0, 1.0, 1.0);
float Kexp = ubo.kexp;
vec3 V = position.eye;
vec3 N = normal.eye;
vec3 L = light.position.xyz - V;
float dist = length(L);
vec3 D = normalize(L);
vec3 R = reflect( -D, N );
vec3 S = normalize(-V);
float s_factor = pow( max(dot( R, S ), 0.0), Kexp );
if ( Kexp < 0.0001 ) s_factor = 0;
float radiance = light.power / (dist * dist);
vec3 Ia = La * Ka;
vec3 Is = Ls * Ks * s_factor * radiance;
i += Is;
}
const float PI = 3.14159265359;
float DistributionGGX(vec3 N, vec3 H, float roughness) {
float a = roughness*roughness;
@ -493,7 +523,38 @@ void pbr( Light light, vec3 albedo, float metallic, float roughness, vec3 lightP
// add to outgoing radiance Lo
i += (kD * albedo / PI + specular) * radiance * NdotL;
}
void pbrSpecular( Light light, vec3 albedo, float metallic, float roughness, inout vec3 i ) {
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic);
vec3 N = normalize(normal.eye);
vec3 L = light.position.xyz - position.eye;
float dist = length(L);
L = normalize(L);
vec3 V = normalize(-position.eye);
vec3 H = normalize(V + L);
float NdotL = max(dot(N, L), 0.0);
float NdotV = max(dot(N, V), 0.0);
float attenuation = light.power / (dist * dist);
vec3 radiance = light.color.rgb * attenuation;
// cook-torrance brdf
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
vec3 kD = vec3(1.0) - F;
kD *= 1.0 - metallic;
vec3 numerator = NDF * G * F;
float denominator = 4.0 * NdotV * NdotL;
vec3 specular = numerator / max(denominator, 0.001);
// add to outgoing radiance Lo
i += specular * radiance * NdotL;
}
vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, vec3 rayO, vec3 rayD ) {
vec3 t0 = (boundsMin - rayO) / rayD;
vec3 t1 = (boundsMax - rayO) / rayD;
@ -558,13 +619,17 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) {
}
vec3 decodeNormals( vec2 enc ) {
#define kPI 3.1415926536f
vec2 ang = enc*2-1;
vec2 scth = vec2( sin(ang.x * kPI), cos(ang.x * kPI) );
vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y);
return 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);
vec3 n;
n.xy = fenc*g;
n.z = 1-f/2;
return normalize(n);
return normalize( vec3(fenc * g, 1 - f / 2) );
*/
}
float wrap( float i ) {
return fract(i);
@ -637,12 +702,14 @@ void main() {
rayD = normalize( far3 - near3 );
}
#if !MULTISAMPLING
normal.eye = decodeNormals( subpassLoad(samplerNormal).xy );
normal.world = decodeNormals( subpassLoad(samplerNormal).xy );
uvec2 ID = subpassLoad(samplerId).xy;
#else
normal.eye = decodeNormals( resolve(samplerNormal).xy );
normal.world = decodeNormals( resolve(samplerNormal).xy );
uvec2 ID = resolve(samplerId).xy;
#endif
normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(normal.world, 0.0) );
uint drawId = ID.x;
uint materialId = ID.y;
if ( drawId == 0 || materialId == 0 ) {
@ -666,7 +733,8 @@ void main() {
vec2 uv = resolve(samplerUv).xy;
#endif
bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas );
Texture textureAtlas = ( useAtlas ) ? textures[drawCall.textureIndex + material.indexAtlas] : textures[0];
Texture textureAtlas;
if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas];
if ( validTextureIndex( drawCall.textureIndex + material.indexAtlas ) ) {
Texture t = textures[drawCall.textureIndex + material.indexAlbedo];
C = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
@ -698,6 +766,20 @@ void main() {
bool useLightmap = 0 <= material.indexLightmap;
if ( useLightmap ) {
fragColor = C.rgb + ubo.ambient.rgb;
for ( uint i = 0; i < ubo.lights; ++i ) {
Light light = lights[i];
if ( light.power <= 0.001 ) continue;
light.position.xyz = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1));
if ( validTextureIndex(light.mapIndex) ) {
float factor = shadowFactor( light, light.mapIndex, 0.0 );
light.power *= factor;
litFactor += light.power;
}
if ( light.power <= 0.0001 ) continue;
if ( usePbr ) pbrSpecular( light, C.rgb, M, R, fragColor ); else phongSpecular( light, C, fragColor );
}
/*
float totalShadows = 0.0;
float totalLights = 0.0;

View File

@ -0,0 +1,687 @@
#version 450
#extension GL_EXT_samplerless_texture_functions : require
#define MULTISAMPLING 1
#define RAY_MARCH_FOG 1
#define UF_DEFERRED_SAMPLING 0
layout (constant_id = 0) const uint TEXTURES = 256;
struct Matrices {
mat4 view[2];
mat4 projection[2];
mat4 iView[2];
mat4 iProjection[2];
mat4 iProjectionView[2];
mat4 voxel;
};
struct Space {
vec3 eye;
vec3 world;
} position, normal, view;
struct Fog {
vec3 color;
float stepScale;
vec3 offset;
float densityScale;
float densityThreshold;
float densityMultiplier;
float absorbtion;
float padding1;
vec2 range;
float padding2;
float padding3;
};
struct Mode {
uint type;
uint scalar;
vec2 padding;
vec4 parameters;
};
struct Light {
vec3 position;
float radius;
vec3 color;
float power;
int type;
int mapIndex;
float depthBias;
float padding;
mat4 view;
mat4 projection;
};
struct Material {
vec4 colorBase;
vec4 colorEmissive;
float factorMetallic;
float factorRoughness;
float factorOcclusion;
float factorAlphaCutoff;
int indexAlbedo;
int indexNormal;
int indexEmissive;
int indexOcclusion;
int indexMetallicRoughness;
int indexAtlas;
int indexLightmap;
int modeAlpha;
};
struct Texture {
int index;
int samp;
int remap;
float blend;
vec4 lerp;
};
struct DrawCall {
int materialIndex;
uint materials;
int textureIndex;
uint textures;
};
struct Voxel {
uvec2 id;
vec3 position;
vec3 normal;
vec2 uv;
vec4 color;
};
#if !MULTISAMPLING
layout (input_attachment_index = 0, binding = 0) uniform usubpassInput samplerId;
layout (input_attachment_index = 1, binding = 1) uniform subpassInput samplerNormal;
#if UF_DEFERRED_SAMPLING
layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerUv;
#else
layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerAlbedo;
#endif
layout (input_attachment_index = 3, binding = 3) uniform subpassInput samplerDepth;
#else
layout (input_attachment_index = 0, binding = 0) uniform usubpassInputMS samplerId;
layout (input_attachment_index = 1, binding = 1) uniform subpassInputMS samplerNormal;
#if UF_DEFERRED_SAMPLING
layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerUv;
#else
layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerAlbedo;
#endif
layout (input_attachment_index = 3, binding = 3) uniform subpassInputMS samplerDepth;
#endif
layout (binding = 4) uniform UBO {
Matrices matrices;
Mode mode;
Fog fog;
uint lights;
uint materials;
uint textures;
uint drawCalls;
vec3 ambient;
float kexp;
uint msaa;
uint poissonSamples;
uint padding1;
uint padding2;
} ubo;
layout (std140, binding = 5) readonly buffer Lights {
Light lights[];
};
layout (std140, binding = 6) readonly buffer Materials {
Material materials[];
};
layout (std140, binding = 7) readonly buffer Textures {
Texture textures[];
};
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 = 13) uniform sampler3D samplerNoise;
layout (binding = 14) uniform samplerCube samplerSkybox;
layout (binding = 15) uniform sampler2D samplerTextures[TEXTURES];
layout (location = 0) in vec2 inUv;
layout (location = 1) in flat uint inPushConstantPass;
layout (location = 0) out vec4 outFragColor;
layout (location = 1) out vec4 outDebugValue;
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 )
);
const float PI = 3.14159265359;
const float EPSILON = 0.00001;
// GGX/Towbridge-Reitz normal distribution function.
// Uses Disney's reparametrization of alpha = roughness^2.
float ndfGGX(float cosLh, float roughness) {
float alpha = roughness * roughness;
float alphaSq = alpha * alpha;
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
return alphaSq / (PI * denom * denom);
}
// Single term for separable Schlick-GGX below.
float gaSchlickG1(float cosTheta, float k) {
return cosTheta / (cosTheta * (1.0 - k) + k);
}
// Schlick-GGX approximation of geometric attenuation function using Smith's method.
float gaSchlickGGX(float cosLi, float cosLo, float roughness) {
float r = roughness + 1.0;
float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights.
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k);
}
vec3 fresnelSchlick(vec3 F0, float cosTheta) {
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
float random(vec3 seed, int i){
vec4 seed4 = vec4(seed,i);
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
return fract(sin(dot_product) * 43758.5453);
}
float shadowFactor( Light light, uint shadowMap, float def ) {
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
positionClip.xyz /= positionClip.w;
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0;
if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0;
float factor = 1.0;
// spot light
if ( light.type == 1 || light.type == 2 ) {
float dist = length( positionClip.xy );
if ( dist > 0.5 ) return def; //0.0;
// spot light with attenuation
if ( light.type == 2 ) {
factor = 1.0 - (pow(dist * 2,2.0));
}
}
vec2 uv = positionClip.xy * 0.5 + 0.5;
float bias = light.depthBias;
float eyeDepth = positionClip.z;
int samples = int(ubo.poissonSamples);
if ( samples <= 1 ) {
return eyeDepth < texture(samplerTextures[shadowMap], uv).r - bias ? 0.0 : factor;
}
for ( int i = 0; i < samples; ++i ) {
// int index = i;
// int index = int( float(samples) * random(gl_FragCoord.xyy, i) ) % samples;
int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples;
float lightDepth = texture(samplerTextures[shadowMap], uv + poissonDisk[index] / 700.0 ).r;
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
}
return factor;
}
// Returns a vector that is orthogonal to u.
vec3 orthogonal(vec3 u){
u = normalize(u);
vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector.
return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v);
}
float rand2(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453);
}
float rand3(vec3 co){
return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453);
}
void whitenoise(inout vec3 color) {
float flicker = ubo.mode.parameters.x;
float pieces = ubo.mode.parameters.y;
float blend = ubo.mode.parameters.z;
float time = ubo.mode.parameters.w;
if ( blend < 0.0001 ) return;
float freq = sin(pow(mod(time, flicker) + flicker, 1.9));
// float whiteNoise = rand3( floor(position.world / pieces) + floor(time * 2) );
float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) );
color = mix( color, vec3(whiteNoise), blend );
}
vec3 gamma( vec3 i ) {
return pow(i.rgb, vec3(1.0 / 2.2));
}
vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, vec3 rayO, vec3 rayD ) {
vec3 t0 = (boundsMin - rayO) / rayD;
vec3 t1 = (boundsMax - rayO) / rayD;
vec3 tmin = min(t0, t1);
vec3 tmax = max(t0, t1);
float dstA = max( max(tmin.x, tmin.y), tmin.z );
float dstB = min( tmax.x, min(tmax.y, tmax.z) );
float tStart = max(0, dstA);
float tEnd = max(0, dstB - tStart);
return vec2(tStart, tEnd);
}
float sampleDensity( vec3 position ) {
vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01;
return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier;
}
void fog( vec3 rayO, vec3 rayD, 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
float range = ubo.fog.range.y;
vec3 boundsMin = vec3(-range,-range,-range) + rayO;
vec3 boundsMax = vec3(range,range,range) + rayO;
int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale );
vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD );
float dstToBox = rayBoxInfo.x;
float dstInsideBox = rayBoxInfo.y;
float depth = position.eye.z;
float lightEnergy = 0;
// march
if ( 0 <= dstInsideBox && dstToBox <= depth ) {
float dstTravelled = 0;
float stepSize = dstInsideBox / numSteps;
float dstLimit = min( depth - dstToBox, dstInsideBox );
float totalDensity = 0;
float transmittance = 1;
while ( dstTravelled < dstLimit ) {
vec3 rayPos = rayO + rayD * (dstToBox + dstTravelled);
float density = sampleDensity(rayPos);
if ( density > 0 ) {
transmittance *= exp(-density * stepSize * ubo.fog.absorbtion);
if ( transmittance < 0.01 ) break;
}
dstTravelled += stepSize;
}
i.rgb = mix(ubo.fog.color.rgb, i.rgb, transmittance);
}
#endif
vec3 color = ubo.fog.color.rgb;
float inner = ubo.fog.range.x;
float outer = ubo.fog.range.y * scale;
float distance = length(-position.eye);
float factor = (distance - inner) / (outer - inner);
factor = clamp( factor, 0.0, 1.0 );
i.rgb = mix(i.rgb, color, factor);
}
vec3 decodeNormals( vec2 enc ) {
#define kPI 3.1415926536f
vec2 ang = enc*2-1;
vec2 scth = vec2( sin(ang.x * kPI), cos(ang.x * kPI) );
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);
}
vec2 wrap( vec2 uv ) {
return vec2( wrap( uv.x ), wrap( uv.y ) );
}
float mipLevel( in vec2 uv ) {
vec2 dx_vtc = dFdx(uv);
vec2 dy_vtc = dFdy(uv);
return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)));
}
bool validTextureIndex( int textureIndex ) {
return 0 <= textureIndex; // && textureIndex < ubo.textures;
}
vec4 resolve( subpassInputMS t ) {
int samples = int(ubo.msaa);
vec4 resolved = vec4(0);
for ( int i = 0; i < samples; ++i ) {
resolved += subpassLoad(t, i);
}
resolved /= vec4(samples);
return resolved;
}
uvec4 resolve( usubpassInputMS t ) {
int samples = int(ubo.msaa);
uvec4 resolved = uvec4(0);
for ( int i = 0; i < samples; ++i ) {
resolved += subpassLoad(t, i);
}
resolved /= uvec4(samples);
return resolved;
}
Voxel getVoxel( vec3 P ) {
vec3 uvw = vec3( ubo.matrices.voxel * vec4( P, 1.0f ) ) * 0.5f + 0.5f;
Voxel voxel;
voxel.id = uvec2(texture(voxelId, uvw).xy);
voxel.position = P;
voxel.normal = decodeNormals( texture(voxelNormal, uvw).xy );
voxel.uv = texture(voxelUv, uvw).xy;
voxel.color = texture(voxelAlbedo, uvw).rgba;
return voxel;
}
#define VOXEL_TRACE_IN_NDC 0
vec4 voxelConeTrace( vec3 rayO, vec3 rayD, float aperture ) {
// bounds
float albedoSize = textureSize( voxelAlbedo, 0 ).x;
float mipmapLevels = textureQueryLod( voxelAlbedo, vec3(0) ).x;
#if VOXEL_TRACE_IN_NDC
rayO = vec3( ubo.matrices.voxel * vec4( rayO, 1.0 ) );
rayD = vec3( ubo.matrices.voxel * vec4( rayD, 0.0 ) );
vec3 boundsMin = vec3( -1 );
vec3 boundsMax = vec3( 1 );
float voxelSize = 1.0 / albedoSize;
#else
mat4 inverseOrtho = inverse( ubo.matrices.voxel );
vec3 boundsMin = vec3( inverseOrtho * vec4( -1, -1, -1, 1 ) );
vec3 boundsMax = vec3( inverseOrtho * vec4( 1, 1, 1, 1 ) );
float voxelSize = 1;
#endif
float granularity = 1.0 / 6.0; // (2.0 * sqrt(2.0) );
// box
vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD );
float tStart = rayBoxInfo.x;
float tEnd = rayBoxInfo.y;
// steps
float tDelta = voxelSize * granularity;
uint maxSteps = uint(albedoSize / granularity);
// marcher
float t = tStart + tDelta * 2.0;
vec3 rayPos = vec3(0);
vec4 radiance = vec4(0);
vec3 uvw = vec3(0);
// cone mipmap shit
float coneCoefficient = 2.0 * tan(aperture * 0.5);
float coneDiameter = coneCoefficient * t;
float level = aperture > 0 ? log2( coneDiameter / albedoSize ) : 0;
// results
vec4 color = vec4(0);
float occlusion = 0.0;
// do
uint stepCounter = 0;
while ( t < tEnd && occlusion < 1.0 && stepCounter++ < maxSteps ) {
t += tDelta;
rayPos = rayO + rayD * t;
#if VOXEL_TRACE_IN_NDC
uvw = rayPos * 0.5 + 0.5;
#else
uvw = (rayPos - boundsMin) / (boundsMax - boundsMin); // vec3( ubo.matrices.voxel * vec4( rayPos, 1 ) ) * 0.5 + 0.5;
#endif
if ( abs(uvw.x) > 1.0 || abs(uvw.y) > 1.0 || abs(uvw.z) > 1.0 ) break;
coneDiameter = coneCoefficient * t;
level = log2( coneDiameter / albedoSize );
radiance = texture(voxelAlbedo, uvw, level) * granularity;
occlusion += radiance.a;
color.rgb += (1.0 - occlusion) * radiance.rgb;
}
return vec4(color.rgb, occlusion);
}
void main() {
vec3 rayO = vec3(0);
vec3 rayD = vec3(0);
vec3 fragColor = vec3(0);
{
#if !MULTISAMPLING
float depth = subpassLoad(samplerDepth).r;
#else
float depth = resolve( samplerDepth ).r;
#endif
vec4 positionClip = vec4(inUv * 2.0 - 1.0, depth, 1.0);
vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * positionClip;
positionEye /= positionEye.w;
position.eye = positionEye.xyz;
vec4 positionWorld = ubo.matrices.iView[inPushConstantPass] * positionEye;
position.world = positionWorld.xyz;
}
{
vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
vec3 near3 = near4.xyz / near4.w;
vec3 far3 = far4.xyz / far4.w;
rayO = near3;
}
{
mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) );
vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
vec3 near3 = near4.xyz / near4.w;
vec3 far3 = far4.xyz / far4.w;
rayD = normalize( far3 - near3 );
}
#if !MULTISAMPLING
normal.world = decodeNormals( subpassLoad(samplerNormal).xy );
uvec2 ID = subpassLoad(samplerId).xy;
#else
normal.world = decodeNormals( resolve(samplerNormal).xy );
uvec2 ID = resolve(samplerId).xy;
#endif
normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(normal.world, 0.0) );
uint drawId = ID.x;
uint materialId = ID.y;
if ( drawId == 0 || materialId == 0 ) {
fragColor.rgb = texture( samplerSkybox, rayD ).rgb;
fog(rayO, rayD, fragColor, 0.0);
outFragColor = vec4(fragColor,1);
return;
}
--drawId;
--materialId;
DrawCall drawCall = drawCalls[drawId];
materialId += drawCall.materialIndex;
Material material = materials[materialId];
vec4 C = material.colorBase;
#if UF_DEFERRED_SAMPLING
#if !MULTISAMPLING
vec2 uv = subpassLoad(samplerUv).xy;
#else
vec2 uv = resolve(samplerUv).xy;
#endif
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];
C = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
}
// OPAQUE
if ( material.modeAlpha == 0 ) {
C.a = 1;
// BLEND
} else if ( material.modeAlpha == 1 ) {
// MASK
} else if ( material.modeAlpha == 2 ) {
}
#else
#if !MULTISAMPLING
C = subpassLoad(samplerAlbedo);
#else
C = resolve(samplerAlbedo);
#endif
#endif
float M = material.factorMetallic;
float R = material.factorRoughness;
float AO = material.factorOcclusion;
vec4 indirectLighting = vec4(0);
// GI
{
vec3 P = position.world;
vec3 N = normal.world;
// outFragColor = voxelConeTrace(rayO, rayD, 0 );
// return;
const float ROUGHNESS_SCALE = clamp(sqrt( 0.111111f / ( R * R + 0.111111f ) ), 0.0, 1.0);
const float ANGLE_MIX = 0.5f;
const float DIFFUSE_CONE_APERTURE = 0.325;
const float DIFFUSE_INDIRECT_FACTOR = ROUGHNESS_SCALE; //0.11111f * 0.111111f;
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 vec3 CONES[9] = {
N,
mix(N, ortho, ANGLE_MIX),
mix(N, -ortho, ANGLE_MIX),
mix(N, ortho2, ANGLE_MIX),
mix(N, -ortho2, ANGLE_MIX),
mix(N, corner, ANGLE_MIX),
mix(N, -corner, ANGLE_MIX),
mix(N, corner2, ANGLE_MIX),
mix(N, -corner2, ANGLE_MIX),
};
vec4 indirectDiffuse = vec4(0);
vec4 indirectSpecular = vec4(0);
// indirectDiffuse += voxelConeTrace( P, N, 0.325 );
for ( uint i = 0; i < 1; ++i ) {
indirectDiffuse += voxelConeTrace(P, CONES[i], DIFFUSE_CONE_APERTURE );
}
const float SPECULAR_CONE_APERTURE = acos( ROUGHNESS_SCALE );
const float SPECULAR_INDIRECT_FACTOR = ROUGHNESS_SCALE; // 0.1;
vec3 R = reflect( normalize(P - rayO), N );
indirectSpecular = voxelConeTrace( P, R, SPECULAR_CONE_APERTURE );
indirectLighting = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR;
// AO = 1.0 - clamp(indirectDiffuse.a, 0.0, 1.0);
// outFragColor.rgb = vec3(AO);
// return;
// outFragColor.rgb = indirectLighting.rgb;
// outFragColor.rgb = indirectDiffuse.rgb;
// outFragColor.rgb = indirectSpecular.rgb;
// return;
}
R *= 2.0f;
bool usePbr = true;
bool gammaCorrect = false;
float litFactor = 1.0;
bool useLightmap = 0 <= material.indexLightmap;
if ( useLightmap ) {
fragColor = C.rgb + ubo.ambient.rgb + indirectLighting.rgb;
} else {
fragColor = C.rgb * ubo.ambient.rgb * (1 - AO) + indirectLighting.rgb;
}
{
const float LIGHT_POWER_CUTOFF = 0.0001;
vec3 N = normal.eye;
vec3 F0 = mix(vec3(0.04), C.rgb, M);
for ( uint i = 0; i < ubo.lights; ++i ) {
Light light = lights[i];
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
light.position = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1));
if ( validTextureIndex(light.mapIndex) ) {
float factor = shadowFactor( light, light.mapIndex, 0.0 );
light.power *= factor;
litFactor += light.power;
}
vec3 Li = light.position - position.eye;
light.power *= 1.0 / (PI * pow(length(Li), 2.0));
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
Li = normalize(Li);
vec3 Lo = normalize( -position.eye );
vec3 Lh = normalize(Li + Lo);
vec3 Lradiance = light.color.rgb * light.power;
vec3 albedo = C.rgb;
float cosLi = max(0.0, dot(N, Li));
float cosLo = max(0.0, dot(N, Lo));
float cosLh = max(0.0, dot(N, Lh));
vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
float D = ndfGGX( cosLh, R );
float G = gaSchlickGGX(cosLi, cosLo, R);
vec3 Kd = mix( vec3(1.0) - F, vec3(0.0), M );
vec3 diffuseBRDF = Kd * albedo;
vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
if ( useLightmap ) {
fragColor.rgb += (specularBRDF) * Lradiance * cosLi;
} else {
fragColor.rgb += (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
}
}
}
if ( gammaCorrect ) fragColor = gamma( fragColor );
fog(rayO, rayD, fragColor, litFactor);
if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) {
whitenoise(fragColor);
}
outFragColor = vec4(fragColor,1);
}

View File

@ -0,0 +1,371 @@
#version 450
#extension GL_EXT_samplerless_texture_functions : require
layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
#define MULTISAMPLING 1
#define RAY_MARCH_FOG 1
#define UF_DEFERRED_SAMPLING 0
layout (constant_id = 0) const uint TEXTURES = 256;
struct Matrices {
mat4 view[2];
mat4 projection[2];
mat4 iView[2];
mat4 iProjection[2];
mat4 iProjectionView[2];
mat4 voxel;
};
struct Space {
vec3 eye;
vec3 world;
} position, normal, view;
struct Fog {
vec3 color;
float stepScale;
vec3 offset;
float densityScale;
float densityThreshold;
float densityMultiplier;
float absorbtion;
float padding1;
vec2 range;
float padding2;
float padding3;
};
struct Mode {
uint type;
uint scalar;
vec2 padding;
vec4 parameters;
};
struct Light {
vec3 position;
float radius;
vec3 color;
float power;
int type;
int mapIndex;
float depthBias;
float padding;
mat4 view;
mat4 projection;
};
struct Material {
vec4 colorBase;
vec4 colorEmissive;
float factorMetallic;
float factorRoughness;
float factorOcclusion;
float factorAlphaCutoff;
int indexAlbedo;
int indexNormal;
int indexEmissive;
int indexOcclusion;
int indexMetallicRoughness;
int indexAtlas;
int indexLightmap;
int modeAlpha;
};
struct Texture {
int index;
int samp;
int remap;
float blend;
vec4 lerp;
};
struct DrawCall {
int materialIndex;
uint materials;
int textureIndex;
uint textures;
};
layout (binding = 4) uniform UBO {
Matrices matrices;
Mode mode;
Fog fog;
uint lights;
uint materials;
uint textures;
uint drawCalls;
vec3 ambient;
float kexp;
uint msaa;
uint poissonSamples;
uint padding1;
uint padding2;
} ubo;
layout (std140, binding = 5) readonly buffer Lights {
Light lights[];
};
layout (std140, binding = 6) readonly buffer Materials {
Material materials[];
};
layout (std140, binding = 7) readonly buffer Textures {
Texture textures[];
};
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 = 13) uniform sampler3D samplerNoise;
layout (binding = 14) uniform samplerCube samplerSkybox;
layout (binding = 15) uniform sampler2D samplerTextures[TEXTURES];
const float PI = 3.14159265359;
const float EPSILON = 0.00001;
// GGX/Towbridge-Reitz normal distribution function.
// Uses Disney's reparametrization of alpha = roughness^2.
float ndfGGX(float cosLh, float roughness) {
float alpha = roughness * roughness;
float alphaSq = alpha * alpha;
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
return alphaSq / (PI * denom * denom);
}
// Single term for separable Schlick-GGX below.
float gaSchlickG1(float cosTheta, float k) {
return cosTheta / (cosTheta * (1.0 - k) + k);
}
// Schlick-GGX approximation of geometric attenuation function using Smith's method.
float gaSchlickGGX(float cosLi, float cosLo, float roughness) {
float r = roughness + 1.0;
float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights.
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k);
}
vec3 fresnelSchlick(vec3 F0, float cosTheta) {
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
float random(vec3 seed, int i){
vec4 seed4 = vec4(seed,i);
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
return fract(sin(dot_product) * 43758.5453);
}
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 )
);
float shadowFactor( Light light, uint shadowMap, float def ) {
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
positionClip.xyz /= positionClip.w;
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0;
if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0;
float factor = 1.0;
// spot light
if ( light.type == 1 || light.type == 2 ) {
float dist = length( positionClip.xy );
if ( dist > 0.5 ) return def; //0.0;
// spot light with attenuation
if ( light.type == 2 ) {
factor = 1.0 - (pow(dist * 2,2.0));
}
}
vec2 uv = positionClip.xy * 0.5 + 0.5;
float bias = light.depthBias;
/*
if ( true ) {
float cosTheta = clamp(dot(normal.eye, normalize(light.position.xyz - position.eye)), 0, 1);
bias = clamp(bias * tan(acos(cosTheta)), 0, 0.01);
} else if ( true ) {
bias = max(bias * 10 * (1.0 - dot(normal.eye, normalize(light.position.xyz - position.eye))), bias);
}
*/
float eyeDepth = positionClip.z;
int samples = int(ubo.poissonSamples);
if ( samples <= 1 ) {
return eyeDepth < texture(samplerTextures[shadowMap], uv).r - bias ? 0.0 : factor;
}
for ( int i = 0; i < samples; ++i ) {
// int index = i;
// int index = int( float(samples) * random(gl_FragCoord.xyy, i) ) % samples;
int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples;
float lightDepth = texture(samplerTextures[shadowMap], uv + poissonDisk[index] / 700.0 ).r;
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
}
return factor;
}
vec3 decodeNormals( vec2 enc ) {
#define kPI 3.1415926536f
vec2 ang = enc*2-1;
vec2 scth = vec2( sin(ang.x * kPI), cos(ang.x * kPI) );
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);
}
vec2 wrap( vec2 uv ) {
return vec2( wrap( uv.x ), wrap( uv.y ) );
}
bool validTextureIndex( int textureIndex ) {
return 0 <= textureIndex; // && textureIndex < ubo.textures;
}
void main() {
vec3 tUvw = gl_GlobalInvocationID.xyz;
uvec2 ID = uvec2(imageLoad(voxelID, ivec3(tUvw) ).xy);
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 ) );
vec2 uv = imageLoad(voxelUv, ivec3(tUvw) ).xy;
uint drawId = ID.x;
uint materialId = ID.y;
if ( drawId == 0 || materialId == 0 ) {
imageStore(voxelAlbedo, ivec3(tUvw), vec4(0));
return;
}
--drawId;
--materialId;
DrawCall drawCall = drawCalls[drawId];
materialId += drawCall.materialIndex;
Material material = materials[materialId];
vec4 C = material.colorBase;
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];
C = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv );
}
// OPAQUE
if ( material.modeAlpha == 0 ) {
C.a = 1;
// BLEND
} else if ( material.modeAlpha == 1 ) {
// MASK
} else if ( material.modeAlpha == 2 ) {
}
float M = material.factorMetallic;
float R = material.factorRoughness * 4.0;
float AO = material.factorOcclusion;
bool usePbr = true;
bool gammaCorrect = false;
float litFactor = 1.0;
bool useLightmap = 0 <= material.indexLightmap;
vec3 fragColor = vec3(0.0);
if ( useLightmap ) {
fragColor = C.rgb + ubo.ambient.rgb;
} else {
fragColor = C.rgb * ubo.ambient.rgb * (1 - AO);
}
{
const float LIGHT_POWER_CUTOFF = 0.005;
vec3 N = normal.world;
vec3 F0 = mix(vec3(0.04), C.rgb, M);
for ( uint i = 0; i < ubo.lights; ++i ) {
Light light = lights[i];
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
if ( validTextureIndex(light.mapIndex) ) {
float factor = shadowFactor( light, light.mapIndex, 0.0 );
light.power *= factor;
litFactor += light.power;
}
vec3 Li = light.position - position.world;
light.power *= 1.0 / (PI * pow(length(Li), 2.0));
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
Li = normalize(Li);
vec3 Lo = normalize( -position.world );
vec3 Lh = normalize(Li + Lo);
vec3 Lradiance = light.color.rgb * light.power;
vec3 albedo = C.rgb;
float cosLi = max(0.0, dot(N, Li));
float cosLo = max(0.0, dot(N, Lo));
float cosLh = max(0.0, dot(N, Lh));
vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
float D = ndfGGX( cosLh, R );
float G = gaSchlickGGX(cosLi, cosLo, R);
vec3 Kd = mix( vec3(1.0) - F, vec3(0.0), M );
vec3 diffuseBRDF = Kd * albedo;
vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
if ( useLightmap ) {
fragColor.rgb += (specularBRDF) * Lradiance * cosLi;
} else {
fragColor.rgb += (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
}
}
}
imageStore(voxelAlbedo, ivec3(tUvw), vec4(fragColor.rgb, 1));
}

View File

@ -57,8 +57,9 @@ layout (location = 1) out vec2 outNormals;
#endif
vec2 encodeNormals( vec3 n ) {
float p = sqrt(n.z*8+8);
return n.xy/p + 0.5;
// return n.xy / sqrt(n.z*8+8) + 0.5;
#define kPI 3.1415926536f
return (vec2(atan(n.y,n.x)/kPI, n.z)+1.0)*0.5;
}
float wrap( float i ) {

View File

@ -172,7 +172,7 @@ float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
void pbr( Light light, vec3 albedo, float metallic, float roughness, vec3 lightPositionWorld, vec3 normal, vec3 position, inout vec3 i ) {
void pbr( Light light, vec3 albedo, float metallic, float roughness, vec3 normal, vec3 position, inout vec3 i ) {
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic);
@ -202,7 +202,8 @@ void pbr( Light light, vec3 albedo, float metallic, float roughness, vec3 lightP
vec3 specular = numerator / max(denominator, 0.001);
// add to outgoing radiance Lo
i += (kD * albedo / PI + specular) * radiance * NdotL;
// ignore specular
i += (kD * albedo / PI ) * radiance * NdotL;
}
void main() {
@ -210,7 +211,7 @@ void main() {
vec2 uv = wrap(inUv.xy);
vec4 C = vec4(1, 1, 1, 1);
vec3 P = inPosition;
vec3 N = inNormal;
vec3 N = normalize( inNormal );
int materialId = int(inId.y);
Material material = materials[materialId];
@ -248,6 +249,7 @@ void main() {
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));
}
#endif
C = vec4(1);
bool lit = false;
vec3 fragColor = vec3(0);
@ -259,18 +261,7 @@ void main() {
light.power *= factor;
}
if ( light.power <= 0.0001 ) continue;
pbr( light, C.rgb, M, R, light.position.xyz, N, P, fragColor );
// if ( usePbr ) pbr( light, C.rgb, M, R, lightPositionWorld, fragColor ); else phong( light, C, fragColor );
/*
Light light = lights[i];
if ( validTextureIndex(light.mapIndex) ) {
light.power *= shadowFactor( P, light, light.mapIndex, 0.0 );
}
if ( light.power < 0.001 ) continue;
pbr( light, C.rgb, M, R, light.position.xyz, N, P, fragColor );
lit = true;
*/
pbr( light, C.rgb, M, R, N, P, fragColor );
}
// if ( !lit ) fragColor = C.rgb;
outAlbedo = vec4(fragColor, 1);
}

View File

@ -57,8 +57,9 @@ layout (location = 1) out vec2 outNormals;
#endif
vec2 encodeNormals( vec3 n ) {
float p = sqrt(n.z*8+8);
return n.xy/p + 0.5;
// return n.xy / sqrt(n.z*8+8) + 0.5;
#define kPI 3.1415926536f
return (vec2(atan(n.y,n.x)/kPI, n.z)+1.0)*0.5;
}
float wrap( float i ) {
return fract(i);
@ -81,7 +82,6 @@ void main() {
vec3 P = inPosition;
vec3 N = inNormal;
#if UF_DEFERRED_SAMPLING
outUvs = wrap(inUv.xy);
vec4 outAlbedo = vec4(0,0,0,0);
#endif
#if !UF_DEFERRED_SAMPLING || UF_CAN_DISCARD
@ -145,6 +145,8 @@ void main() {
}
#endif
outAlbedo = C * inColor;
#else
outUvs = wrap(inUv.xy);
#endif
outNormals = encodeNormals( N );
outId = ivec2(inId.w+1, inId.y+1);

View File

@ -32,10 +32,6 @@ layout (location = 4) out mat3 outTBN;
layout (location = 7) out vec3 outPosition;
layout (location = 8) out ivec4 outId;
out gl_PerVertex {
vec4 gl_Position;
};
vec4 snap(vec4 vertex, vec2 resolution) {
vec4 snappedPos = vertex;
snappedPos.xyz = vertex.xyz / vertex.w;
@ -50,8 +46,12 @@ void main() {
outColor = ubo.color;
outId = ivec4(inId, PushConstant.pass, PushConstant.draw);
outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
outNormal = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0));
// outPosition = vec3(ubo.matrices.projection[PushConstant.pass] * ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
// outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0));
outPosition = vec3(ubo.matrices.model * vec4(inPos.xyz, 1.0));
// outNormal = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0));
outNormal = vec3(ubo.matrices.model * vec4(inNormal.xyz, 0.0));
outNormal = normalize(outNormal);

View File

@ -30,10 +30,6 @@ layout (location = 4) out mat3 outTBN;
layout (location = 7) out vec3 outPosition;
layout (location = 8) out ivec4 outId;
out gl_PerVertex {
vec4 gl_Position;
};
vec4 snap(vec4 vertex, vec2 resolution) {
vec4 snappedPos = vertex;
snappedPos.xyz = vertex.xyz / vertex.w;
@ -49,8 +45,12 @@ void main() {
outId = ivec4(inId, PushConstant.pass, PushConstant.draw);
mat4 model = models.length() <= 0 ? mat4(1.0) : models[int(inId.x)];
outPosition = vec3(ubo.view[PushConstant.pass] * model * vec4(inPos.xyz, 1.0));
outNormal = vec3(ubo.view[PushConstant.pass] * model * vec4(inNormal.xyz, 0.0));
// outPosition = vec3(ubo.projection[PushConstant.pass] * ubo.view[PushConstant.pass] * model * vec4(inPos.xyz, 1.0));
// outPosition = vec3(ubo.view[PushConstant.pass] * model * vec4(inPos.xyz, 1.0));
outPosition = vec3(model * vec4(inPos.xyz, 1.0));
// outNormal = vec3(ubo.view[PushConstant.pass] * model * vec4(inNormal.xyz, 0.0));
outNormal = vec3(model * vec4(inNormal.xyz, 0.0));
outNormal = normalize(outNormal);
{

View File

@ -36,10 +36,6 @@ layout (location = 4) out mat3 outTBN;
layout (location = 7) out vec3 outPosition;
layout (location = 8) out ivec4 outId;
out gl_PerVertex {
vec4 gl_Position;
};
vec4 snap(vec4 vertex, vec2 resolution) {
vec4 snappedPos = vertex;
snappedPos.xyz = vertex.xyz / vertex.w;
@ -61,8 +57,12 @@ void main() {
inWeights.z * joints[int(inJoints.z)] +
inWeights.w * joints[int(inJoints.w)];
outPosition = vec3(ubo.view[PushConstant.pass] * model * skinnedMatrix * vec4(inPos.xyz, 1.0));
outNormal = vec3(ubo.view[PushConstant.pass] * model * vec4(inNormal.xyz, 0.0));
// outPosition = vec3(ubo.projection[PushConstant.pass] * ubo.view[PushConstant.pass] * model * skinnedMatrix * vec4(inPos.xyz, 1.0));
// outPosition = vec3(ubo.view[PushConstant.pass] * model * skinnedMatrix * vec4(inPos.xyz, 1.0));
outPosition = vec3(model * skinnedMatrix * vec4(inPos.xyz, 1.0));
// outNormal = vec3(ubo.view[PushConstant.pass] * model * vec4(inNormal.xyz, 0.0));
outNormal = vec3(model * vec4(inNormal.xyz, 0.0));
outNormal = normalize(outNormal);

View File

@ -38,10 +38,6 @@ layout (location = 4) out mat3 outTBN;
layout (location = 7) out vec3 outPosition;
layout (location = 8) out ivec4 outId;
out gl_PerVertex {
vec4 gl_Position;
};
vec4 snap(vec4 vertex, vec2 resolution) {
vec4 snappedPos = vertex;
snappedPos.xyz = vertex.xyz / vertex.w;
@ -62,8 +58,12 @@ void main() {
inWeights.z * joints[int(inJoints.z)] +
inWeights.w * joints[int(inJoints.w)];
outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * skinnedMatrix * vec4(inPos.xyz, 1.0));
outNormal = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0));
// outPosition = vec3(ubo.matrices.projection[PushConstant.pass] * ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * skinnedMatrix * vec4(inPos.xyz, 1.0));
// outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * skinnedMatrix * vec4(inPos.xyz, 1.0));
outPosition = vec3(ubo.matrices.model * skinnedMatrix * vec4(inPos.xyz, 1.0));
// outNormal = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0));
outNormal = vec3(ubo.matrices.model * vec4(inNormal.xyz, 0.0));
outNormal = normalize(outNormal);

View File

@ -0,0 +1,136 @@
#version 450
#define UF_DEFERRED_SAMPLING 0
#define UF_CAN_DISCARD 1
layout (constant_id = 0) const uint TEXTURES = 1;
struct Material {
vec4 colorBase;
vec4 colorEmissive;
float factorMetallic;
float factorRoughness;
float factorOcclusion;
float factorAlphaCutoff;
int indexAlbedo;
int indexNormal;
int indexEmissive;
int indexOcclusion;
int indexMetallicRoughness;
int indexAtlas;
int indexLightmap;
int modeAlpha;
};
struct Texture {
int index;
int samp;
int remap;
float blend;
vec4 lerp;
};
layout (std140, binding = 0) readonly buffer Materials {
Material materials[];
};
layout (std140, binding = 1) readonly buffer Textures {
Texture textures[];
};
layout (location = 0) in vec2 inUv;
layout (location = 1) in vec2 inSt;
layout (location = 2) in vec4 inColor;
layout (location = 3) in vec3 inNormal;
layout (location = 4) in mat3 inTBN;
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 (location = 0) out uvec2 outId;
layout (location = 1) out vec2 outNormals;
#if UF_DEFERRED_SAMPLING
layout (location = 2) out vec2 outUvs;
#else
layout (location = 2) out vec4 outAlbedo;
#endif
vec2 encodeNormals( vec3 n ) {
// return n.xy / sqrt(n.z*8+8) + 0.5;
#define kPI 3.1415926536f
return (vec2(atan(n.y,n.x)/kPI, n.z)+1.0)*0.5;
}
float wrap( float i ) {
return fract(i);
}
vec2 wrap( vec2 uv ) {
return vec2( wrap( uv.x ), wrap( uv.y ) );
}
float mipLevel( in vec2 uv ) {
vec2 dx_vtc = dFdx(uv);
vec2 dy_vtc = dFdy(uv);
return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)));
}
bool validTextureIndex( int textureIndex ) {
return 0 <= textureIndex && textureIndex < textures.length();
}
void main() {
vec3 P = inPosition;
if ( !(abs(P.x) < 1.0 && abs(P.y) < 1 && abs(P.z) < 1) ) discard;
vec4 C = vec4(0, 0, 0, 0);
vec3 N = inNormal;
vec2 uv = wrap(inUv.xy);
float mip = mipLevel(inUv.xy);
int materialId = int(inId.y);
Material material = materials[materialId];
float M = material.factorMetallic;
float R = material.factorRoughness;
float AO = material.factorOcclusion;
// sample albedo
bool useAtlas = validTextureIndex( material.indexAtlas );
Texture textureAtlas;
if ( useAtlas ) textureAtlas = textures[material.indexAtlas];
if ( !validTextureIndex( material.indexAlbedo ) ) discard; {
Texture t = textures[material.indexAlbedo];
C = 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 ) {
C.a = 1;
// alpha mode BLEND
} else if ( material.modeAlpha == 1 ) {
// alpha mode MASK
} else if ( material.modeAlpha == 2 ) {
if ( C.a < abs(material.factorAlphaCutoff) ) discard;
C.a = 1;
}
if ( C.a == 0 ) discard;
}
#if UF_DEFERRED_SAMPLING
vec4 outAlbedo;
#else
vec2 outUvs;
#endif
/*vec4*/ outAlbedo = C * inColor;
/*uvec2*/ outId = uvec2(inId.w+1, inId.y+1);
/*vec2*/ outNormals = encodeNormals( normalize( N ) );
/*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);
}

View File

@ -0,0 +1,63 @@
#version 450
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
layout (location = 0) in vec2 inUv[];
layout (location = 1) in vec2 inSt[];
layout (location = 2) in vec4 inColor[];
layout (location = 3) in vec3 inNormal[];
layout (location = 4) in mat3 inTBN[];
layout (location = 7) in vec3 inPosition[];
layout (location = 8) flat in ivec4 inId[];
layout (location = 0) out vec2 outUv;
layout (location = 1) out vec2 outSt;
layout (location = 2) out vec4 outColor;
layout (location = 3) out vec3 outNormal;
layout (location = 4) out mat3 outTBN;
layout (location = 7) out vec3 outPosition;
layout (location = 8) flat out ivec4 outId;
layout (binding = 6) uniform UBO {
mat4 voxel;
} 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;
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 ){
outUv = inUv[i];
outSt = inSt[i];
outColor = inColor[i];
outNormal = inNormal[i];
outTBN = inTBN[i];
outPosition = inPosition[i];
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);
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();
}

View File

@ -86,25 +86,9 @@ namespace pod {
namespace uf {
namespace graph {
/*
pod::Node& UF_API node();
pod::Node* UF_API find( const pod::Node& node, int32_t index );
pod::Node* UF_API find( pod::Node* node, int32_t index );
pod::Node* UF_API find( const pod::Graph& graph, int32_t index );
pod::Node* UF_API find( const pod::Node& node, const std::string& name );
pod::Node* UF_API find( pod::Node* node, const std::string& name );
pod::Node* UF_API find( const pod::Graph& graph, const std::string& name );
pod::Matrix4f UF_API local( const pod::Node& node );
pod::Matrix4f UF_API matrix( const pod::Node& node );
*/
pod::Node* UF_API find( pod::Graph& graph, int32_t index );
pod::Node* UF_API find( pod::Graph& graph, const std::string& name );
// pod::Matrix4f UF_API local( const pod::Node& node );
// pod::Matrix4f UF_API matrix( pod::Graph&, const pod::Node& node );
pod::Matrix4f UF_API local( pod::Graph&, int32_t );
pod::Matrix4f UF_API matrix( pod::Graph&, int32_t );
@ -112,6 +96,7 @@ namespace uf {
void UF_API process( pod::Graph& graph );
void UF_API process( pod::Graph& graph, int32_t, uf::Object& parent );
void UF_API cleanup( pod::Graph& graph );
void UF_API initialize( pod::Graph& graph );
void UF_API override( pod::Graph& );
void UF_API animate( pod::Graph&, const std::string&, float = 1, bool = true );

View File

@ -6,6 +6,17 @@
#include <uf/utils/math/transform.h>
namespace pod {
struct UF_API SceneTextures {
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;
} voxels;
};
struct UF_API DrawCall {
struct Storage {
alignas(4) int32_t materialIndex = -1;

View File

@ -97,12 +97,18 @@ template<> inline bool ext::json::Value::is<std::string>(bool strict) const { re
template<> inline bool ext::json::Value::is<unsigned int>(bool strict) const { return strict ? is_number_unsigned() : is_number(); }
#endif
template<typename T> inline T ext::json::Value::as() const {
return !is<T>() ? T() : get<T>();
/*
if ( !is<T>() ) return T();
return get<T>();
*/
}
template<typename T> inline T ext::json::Value::as( const T& fallback ) const {
return !is<T>() ? fallback : get<T>();
/*
if ( !is<T>() ) return fallback;
return get<T>();
*/
}
template<> inline bool ext::json::Value::as<bool>() const {
// explicitly a bool

View File

@ -34,11 +34,6 @@ namespace ext {
VkSpecializationInfo specializationInfo;
uf::Serializer metadata;
/*
std::vector<uint8_t> specializationConstants;
std::vector<ext::vulkan::userdata_t> pushConstants;
std::vector<ext::vulkan::userdata_t> uniforms;
*/
ext::vulkan::userdata_t specializationConstants;
std::vector<ext::vulkan::userdata_t> pushConstants;
@ -75,12 +70,16 @@ namespace ext {
VkDescriptorSet descriptorSet;
GraphicDescriptor descriptor;
uf::Serializer metadata;
void initialize( Graphic& graphic );
void initialize( Graphic& graphic, GraphicDescriptor& descriptor );
void update( Graphic& graphic );
void update( Graphic& graphic, GraphicDescriptor& descriptor );
void record( Graphic& graphic, VkCommandBuffer, size_t = 0, size_t = 0 );
void destroy();
std::vector<Shader*> getShaders( std::vector<Shader>& );
};
struct UF_API Material {
bool aliased = false;
@ -94,11 +93,11 @@ namespace ext {
void initialize( Device& device );
void destroy();
void attachShader( const std::string&, VkShaderStageFlagBits );
void initializeShaders( const std::vector<std::pair<std::string, VkShaderStageFlagBits>>& );
void attachShader( const std::string&, VkShaderStageFlagBits, const std::string& pipeline = "" );
void initializeShaders( const std::vector<std::pair<std::string, VkShaderStageFlagBits>>&, const std::string& pipeline = "" );
bool hasShader( const std::string& type );
Shader& getShader( const std::string& type );
bool hasShader( const std::string& type, const std::string& pipeline = "" );
Shader& getShader( const std::string& type, const std::string& pipeline = "" );
bool validate();
};

View File

@ -13,6 +13,8 @@ namespace ext {
virtual const size_t blitters() const;
virtual ext::vulkan::Graphic* getBlitter(size_t = 0);
virtual std::vector<ext::vulkan::Graphic*> getBlitters();
virtual GraphicDescriptor bindGraphicDescriptor( const GraphicDescriptor&, size_t = 0 );
virtual void createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics );
virtual void initialize( Device& device );

View File

@ -6,11 +6,20 @@
namespace ext {
namespace vulkan {
struct UF_API RenderTargetRenderMode : public ext::vulkan::RenderMode {
ext::vulkan::Graphic blitter;
ext::vulkan::Graphic blitter;
typedef std::function<void(VkCommandBuffer)> callback_t;
std::unordered_map<int32_t, callback_t> commandBufferCallbacks;
//
const std::string getTarget() const;
void setTarget( const std::string& );
void bindCallback( int32_t, const callback_t& );
constexpr static int32_t CALLBACK_BEGIN = -1;
constexpr static int32_t CALLBACK_END = -2;
// RAII
virtual const std::string getType() const;
virtual const size_t blitters() const;

View File

@ -51,6 +51,8 @@ namespace ext {
namespace RENDERER {
struct UF_API GraphicDescriptor {
std::string renderMode = "";
std::string pipeline = "";
uint32_t renderTarget = 0;
uint32_t subpass = 0;

View File

@ -48,6 +48,15 @@ pod::Matrix4t<T> /*UF_API*/ uf::matrix::identity() {
}
template<typename T>
pod::Matrix4t<T> /*UF_API*/ uf::matrix::ortho( T l, T r, T b, T t, T f, T n ) {
pod::Matrix4t<T> m = uf::matrix::identity();
m[0*4+0] = 2 / (r - l);
m[1*4+1] = 2 / (t - b);
m[2*4+2] = - 2 / (f - n);
m[3*4+0] = - (r + l) / (r - l);
m[3*4+1] = - (t + b) / (t - b);
m[3*4+2] = - (f + n) / (f - n);
return m;
/*
std::vector<T> m = {
2 / (r - l), 0, 0, 0,
0, 2 / (t - b), 0, 0,
@ -55,6 +64,7 @@ pod::Matrix4t<T> /*UF_API*/ uf::matrix::ortho( T l, T r, T b, T t, T f, T n ) {
-(r + l) / (r - l), -(t + b) / (t - b), -(f + n) / (f - n), 1,
};
return uf::matrix::initialize(m);
*/
}
template<typename T>
pod::Matrix4t<T> /*UF_API*/ uf::matrix::ortho( T l, T r, T b, T t ) {

View File

@ -36,127 +36,34 @@ void uf::GltfBehavior::initialize( uf::Object& self ) {
auto& graph = this->getComponent<pod::Graph>();
graph = std::move( *graphPointer );
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"];
shouldUpdate = true;
}
if ( !ext::json::isNull(graph.metadata["fog"]) ) {
sceneMetadataJson["light"]["fog"] = graph.metadata["fog"];
shouldUpdate = true;
}
if ( shouldUpdate ) {
scene.callHook("object:UpdateMetadata.%UID%");
}
bool shouldUpdate = false;
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
if ( !ext::json::isNull(graph.metadata["ambient"]) ) {
sceneMetadataJson["light"]["ambient"] = graph.metadata["ambient"];
shouldUpdate = true;
}
if ( !ext::json::isNull(graph.metadata["fog"]) ) {
sceneMetadataJson["light"]["fog"] = graph.metadata["fog"];
shouldUpdate = true;
}
if ( shouldUpdate ) scene.callHook("object:UpdateMetadata.%UID%");
// deferred shader loading
graph.root.entity->process([&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Graphic>() ) return;
auto& graphic = entity->getComponent<uf::Graphic>();
if ( !(graph.metadata["flags"]["LOAD"].as<bool>()) ) {
if ( graph.metadata["flags"]["SEPARATE"].as<bool>() ) {
{
std::string filename = "/gltf/base.vert.spv";
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
filename = "/gltf/skinned.vert.spv";
}
if ( metadata["system"]["renderer"]["shaders"]["vertex"].is<std::string>() )
filename = metadata["system"]["renderer"]["shaders"]["vertex"].as<std::string>();
filename = this->grabURI( filename, metadata["system"]["root"].as<std::string>() );
graphic.material.attachShader(filename, uf::renderer::enums::Shader::VERTEX);
}
{
std::string filename = "/gltf/base.frag.spv";
if ( metadata["system"]["renderer"]["shaders"]["fragment"].is<std::string>() )
filename = metadata["system"]["renderer"]["shaders"]["fragment"].as<std::string>();
filename = this->grabURI( filename, metadata["system"]["root"].as<std::string>() );
graphic.material.attachShader(filename, uf::renderer::enums::Shader::FRAGMENT);
}
} else {
{
std::string filename = "/gltf/instanced.vert.spv";
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
filename = "/gltf/skinned.instanced.vert.spv";
}
if ( metadata["system"]["renderer"]["shaders"]["vertex"].is<std::string>() )
filename = metadata["system"]["renderer"]["shaders"]["vertex"].as<std::string>();
filename = this->grabURI( filename, metadata["system"]["root"].as<std::string>() );
graphic.material.attachShader(filename, uf::renderer::enums::Shader::VERTEX);
}
{
std::string filename = "/gltf/base.frag.spv";
if ( metadata["system"]["renderer"]["shaders"]["fragment"].is<std::string>() )
filename = metadata["system"]["renderer"]["shaders"]["fragment"].as<std::string>();
filename = this->grabURI( filename, metadata["system"]["root"].as<std::string>() );
graphic.material.attachShader(filename, uf::renderer::enums::Shader::FRAGMENT);
}
}
}
#if UF_USE_VULKAN
{
auto& shader = graphic.material.getShader("vertex");
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 ){
std::string name = sc["name"].as<std::string>();
if ( name == "PASSES" ) {
sc["value"] = specializationConstants.passes;
}
});
}
{
auto& shader = graphic.material.getShader("fragment");
struct SpecializationConstant {
uint32_t textures = 1;
};
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
specializationConstants.textures = graphic.material.textures.size();
ext::json::forEach( shader.metadata["specializationConstants"], [&]( ext::json::Value& sc ){
std::string name = sc["name"].as<std::string>();
if ( name == "TEXTURES" ) {
sc["value"] = specializationConstants.textures;
}
});
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
if ( binding.descriptorCount > 1 )
binding.descriptorCount = specializationConstants.textures;
}
}
#endif
graphic.process = true;
});
auto& transform = this->getComponent<pod::Transform<>>();
graph.root.entity->getComponent<pod::Transform<>>().reference = &transform;
graph.root.entity->initialize();
graph.root.entity->process([&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Graphic>() ) {
if ( entity->getUid() == 0 ) entity->initialize();
return;
}
uf::instantiator::bind( "GltfBehavior", *entity );
uf::instantiator::unbind( "RenderBehavior", *entity );
if ( entity->getUid() == 0 ) entity->initialize();
});
uf::graph::initialize( graph );
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
if ( metadata["model"]["animation"].is<std::string>() ) {
uf::graph::animate( graph, metadata["model"]["animation"].as<std::string>() );
}
/*
if ( metadata["model"]["print animations"].as<bool>() ) {
uf::Serializer json = ext::json::array();
for ( auto pair : graph.animations ) json.emplace_back( pair.first );
}
*/
}
this->addChild(graph.root.entity->as<uf::Entity>());
@ -174,26 +81,28 @@ void uf::GltfBehavior::tick( uf::Object& self ) {
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>();
if ( !graphic.initialized ) return;
auto* objectWithGraph = this;
while ( objectWithGraph != &scene ) {
if ( objectWithGraph->hasComponent<pod::Graph>() ) break;
objectWithGraph = &objectWithGraph->getParent().as<uf::Object>();
}
if ( !objectWithGraph->hasComponent<pod::Graph>() ) return;
auto& graph = objectWithGraph->getComponent<pod::Graph>();
#if UF_USE_OPENGL
/* Update uniforms */ if ( this->hasComponent<uf::Graphic>() ) {
auto& scene = uf::scene::getCurrentScene();
auto& metadata = this->getComponent<uf::Serializer>();
auto& graphic = this->getComponent<uf::Graphic>();
auto& controller = scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
if ( !graphic.initialized ) return;
if ( !graphic.material.hasShader("vertex") ) return;
auto* objectWithGraph = this;
while ( objectWithGraph != &scene ) {
if ( objectWithGraph->hasComponent<pod::Graph>() ) break;
objectWithGraph = &objectWithGraph->getParent().as<uf::Object>();
}
if ( !objectWithGraph->hasComponent<pod::Graph>() ) return;
if ( graphic.material.hasShader("vertex") ) {
auto& shader = graphic.material.getShader("vertex");
auto& graph = objectWithGraph->getComponent<pod::Graph>();
auto& mesh = this->getComponent<ext::gltf::mesh_t>();
if ( !(graph.metadata["flags"]["SEPARATE"].as<bool>()) ) {
@ -210,34 +119,36 @@ void uf::GltfBehavior::tick( uf::Object& self ) {
}
}
#elif UF_USE_VULKAN
/* Update uniforms */ if ( this->hasComponent<uf::Graphic>() ) {
auto& scene = uf::scene::getCurrentScene();
auto& metadata = this->getComponent<uf::Serializer>();
auto& graphic = this->getComponent<uf::Graphic>();
auto& controller = scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
if ( !graphic.initialized ) return;
if ( !graphic.material.hasShader("fragment") ) return;
auto* objectWithGraph = this;
while ( objectWithGraph != &scene ) {
if ( objectWithGraph->hasComponent<pod::Graph>() ) break;
objectWithGraph = &objectWithGraph->getParent().as<uf::Object>();
if ( graphic.material.hasShader("fragment") && !(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 );
}
if ( !objectWithGraph->hasComponent<pod::Graph>() ) return;
auto& storageBuffer = *graphic.getStorageBuffer("Models");
graphic.updateBuffer( (void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.instanceBufferIndex /*storageBuffer*/ );
}
if ( graphic.material.hasShader("geometry", "svogi") ) {
auto& shader = graphic.material.getShader("geometry", "svogi");
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);
auto& graph = objectWithGraph->getComponent<pod::Graph>();
if ( !(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*/ );
}
max.x += floor(controllerTransform.position.x);
max.y -= floor(controllerTransform.position.y);
max.z -= floor(controllerTransform.position.z);
struct UniformDescriptor {
alignas(16) pod::Matrix4f matrix;
};
auto& uniform = shader.getUniform("UBO");
auto& uniforms = uniform.get<UniformDescriptor>();
uniforms.matrix = /*uf::matrix::translate( uf::matrix::identity(), -controllerTransform.position ) **/ uf::matrix::ortho<float>( min.x, max.x, min.y, max.y, min.z, max.z );
shader.updateUniform( "UBO", uniform );
}
#endif
}
@ -251,25 +162,28 @@ namespace {
}
void uf::GltfBehavior::render( uf::Object& self ) {
/* Update uniforms */ if ( this->hasComponent<uf::Graphic>() ) {
auto& scene = uf::scene::getCurrentScene();
auto& metadata = this->getComponent<uf::Serializer>();
auto& graphic = this->getComponent<uf::Graphic>();
auto& controller = scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
auto& transform = this->getComponent<pod::Transform<>>();
/* Update uniforms */
if ( !this->hasComponent<uf::Graphic>() ) return;
if ( !graphic.initialized ) return;
auto& scene = uf::scene::getCurrentScene();
auto& metadata = this->getComponent<uf::Serializer>();
auto& graphic = this->getComponent<uf::Graphic>();
auto& controller = scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
auto& transform = this->getComponent<pod::Transform<>>();
auto* objectWithGraph = this;
while ( objectWithGraph != &scene ) {
if ( objectWithGraph->hasComponent<pod::Graph>() ) break;
objectWithGraph = &objectWithGraph->getParent().as<uf::Object>();
}
if ( !objectWithGraph->hasComponent<pod::Graph>() ) return;
auto& graph = objectWithGraph->getComponent<pod::Graph>();
if ( !graphic.initialized ) return;
auto* objectWithGraph = this;
while ( objectWithGraph != &scene ) {
if ( objectWithGraph->hasComponent<pod::Graph>() ) break;
objectWithGraph = &objectWithGraph->getParent().as<uf::Object>();
}
if ( !objectWithGraph->hasComponent<pod::Graph>() ) return;
auto& graph = objectWithGraph->getComponent<pod::Graph>();
#if UF_USE_OPENGL
if ( graphic.material.hasShader("vertex") ) {
auto uniformBuffer = graphic.getUniform();
pod::Uniform& uniform = *((pod::Uniform*) graphic.device->getBuffer(uniformBuffer.buffer));
uniform.projection = camera.getProjection();
@ -279,16 +193,13 @@ void uf::GltfBehavior::render( uf::Object& self ) {
uniform.modelView = camera.getView() * uf::transform::model( transform );
}
graphic.updateUniform( (void*) &uniform, sizeof(uniform) );
}
#elif UF_USE_VULKAN
if ( !graphic.material.hasShader("fragment") ) return;
if ( !graphic.hasStorage("Materials") ) return;
// std::cout << "START" << std::endl;
if ( graphic.material.hasShader("vertex") ) {
auto& shader = graphic.material.getShader("vertex");
auto& uniform = shader.getUniform("UBO");
if ( !(graph.metadata["flags"]["SEPARATE"].as<bool>()) ) {
#if UF_UNIFORMS_UPDATE_WITH_JSON
// auto uniforms = shader.getUniformJson("UBO");
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 ) );
@ -342,7 +253,7 @@ void uf::GltfBehavior::render( uf::Object& self ) {
shader.updateUniform( "UBO", uniform );
#endif
}
#endif
}
#endif
}
#undef this

View File

@ -54,6 +54,9 @@ uf::Scene& uf::scene::loadScene( const std::string& name, const std::string& fil
*/
target = uf::string::lowercase( target );
scene->load(filename != "" ? filename : "./scenes/" + target + "/scene.json");
if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) {
uf::instantiator::bind( "VoxelizerBehavior", *scene );
}
scene->initialize();
return *scene;
}
@ -61,6 +64,9 @@ uf::Scene& uf::scene::loadScene( const std::string& name, const uf::Serializer&
uf::Scene* scene = uf::instantiator::objects->has( name ) ? (uf::Scene*) &uf::instantiator::instantiate( name ) : new uf::Scene;
uf::scene::scenes.emplace_back( scene );
if ( data != "" ) scene->load(data);
if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) {
uf::instantiator::bind( "VoxelizerBehavior", *scene );
}
scene->initialize();
return *scene;
}

View File

@ -12,6 +12,132 @@
#endif
namespace {
void initializeShaders( pod::Graph& graph, uf::Object& entity ) {
auto& graphic = entity.getComponent<uf::Graphic>();
std::string root = uf::io::directory( graph.name );
size_t texture2Ds = 0;
for ( auto& texture : graphic.material.textures ) {
if ( texture.width > 1 && texture.height > 1 && texture.depth == 1 && texture.layers == 1 ) ++texture2Ds;
}
// standard pipeline
{
std::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as<std::string>("/gltf/base.vert.spv");
std::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as<std::string>("");
std::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as<std::string>("/gltf/base.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);
}
if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) {
geometryShaderFilename = entity.grabURI( geometryShaderFilename, root );
graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY);
}
{
fragmentShaderFilename = entity.grabURI( fragmentShaderFilename, root );
graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT);
}
#if UF_USE_VULKAN
{
auto& shader = graphic.material.getShader("vertex");
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;
});
}
{
auto& shader = graphic.material.getShader("fragment");
struct SpecializationConstant {
uint32_t textures = 1;
};
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
specializationConstants.textures = texture2Ds;
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;
}
}
#endif
}
// svogi pipeline
if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) {
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, "svogi");
}
*/
if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) {
geometryShaderFilename = entity.grabURI( geometryShaderFilename, root );
graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY, "svogi");
}
{
fragmentShaderFilename = entity.grabURI( fragmentShaderFilename, root );
graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "svogi");
}
#if UF_USE_VULKAN
/*
{
auto& shader = graphic.material.getShader("vertex", "svogi");
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", "svogi");
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", "svogi");
struct SpecializationConstant {
uint32_t textures = 1;
};
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
specializationConstants.textures = texture2Ds;
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;
}
}
#endif
}
graphic.process = true;
}
void initializeGraphics( pod::Graph& graph, uf::Object& entity ) {
auto& graphic = entity.getComponent<uf::Graphic>();
graphic.device = &uf::renderer::device;
@ -37,44 +163,18 @@ namespace {
for ( auto& sampler : graph.samplers ) {
graphic.material.samplers.emplace_back( sampler );
}
// bind scene's voxel texture
if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) {
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);
}
}
if ( graph.metadata["flags"]["LOAD"].as<bool>() ) {
if ( graph.metadata["flags"]["SEPARATE"].as<bool>() ) {
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
graphic.material.attachShader(uf::io::root + "/shaders/gltf/skinned.vert.spv", uf::renderer::enums::Shader::VERTEX);
} else {
graphic.material.attachShader(uf::io::root + "/shaders/gltf/base.vert.spv", uf::renderer::enums::Shader::VERTEX);
}
} else {
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
graphic.material.attachShader(uf::io::root + "/shaders/gltf/skinned.instanced.vert.spv", uf::renderer::enums::Shader::VERTEX);
} else {
graphic.material.attachShader(uf::io::root + "/shaders/gltf/instanced.vert.spv", uf::renderer::enums::Shader::VERTEX);
}
}
graphic.material.attachShader(uf::io::root + "/shaders/gltf/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT);
#if UF_USE_VULKAN
{
auto& shader = graphic.material.getShader("vertex");
struct SpecializationConstant {
uint32_t passes = 6;
};
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
specializationConstants.passes = uf::renderer::settings::maxViews;
}
{
auto& shader = graphic.material.getShader("fragment");
struct SpecializationConstant {
uint32_t textures = 1;
};
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
specializationConstants.textures = graphic.material.textures.size();
for ( auto& binding : shader.descriptorSetLayoutBindings ) {
if ( binding.descriptorCount > 1 )
binding.descriptorCount = specializationConstants.textures;
}
}
#endif
initializeShaders( graph, entity );
} else {
graphic.process = false;
}
@ -148,16 +248,10 @@ void uf::graph::process( pod::Graph& graph ) {
// invalidate our ST's if we're in OpenGL
} else {
#if UF_USE_OPENGL
for ( auto& mesh : graph.meshes ) {
for ( auto& v : mesh.vertices ) {
v.st = pod::Vector2f{0,0};
}
}
for ( auto& mesh : graph.meshes ) for ( auto& v : mesh.vertices ) v.st = pod::Vector2f{0,0};
#endif
}
if ( graph.metadata["flags"]["ATLAS"].as<bool>() && graph.atlas.generated() ) {
// for ( auto& texture : graph.textures ) if ( 0 <= texture.storage.index ) ++texture.storage.index;
auto& image = *graph.images.emplace(graph.images.begin(), graph.atlas.getAtlas());
auto& texture = *graph.textures.emplace(graph.textures.begin());
texture.name = "atlas";
@ -213,16 +307,6 @@ void uf::graph::process( pod::Graph& graph ) {
texture.texture.loadFromImage( image );
}
}
/*
{
size_t textureSlot = 0;
for ( auto& texture : graph.textures ) {
texture.storage.index = -1;
if ( !texture.bind ) continue;
texture.storage.index = textureSlot++;
}
}
*/
if ( !graph.root.entity ) graph.root.entity = new uf::Object;
for ( auto index : graph.root.children ) process( graph, index, *graph.root.entity );
@ -272,8 +356,6 @@ void uf::graph::process( pod::Graph& graph ) {
std::vector<pod::Texture::Storage> textures( graph.textures.size() );
for ( size_t i = 0; i < graph.textures.size(); ++i ) {
textures[i] = graph.textures[i].storage;
// textures[i].index = i;
// textures[i].remap = -1;
}
graph.root.textureBufferIndex = graphic.initializeBuffer(
(void*) textures.data(),
@ -282,12 +364,43 @@ void uf::graph::process( pod::Graph& graph ) {
);
}
// calculate extents
pod::Vector3f extentMin = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
pod::Vector3f extentMax = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
graph.root.entity->process([&]( uf::Entity* entity ) {
if ( !entity->hasComponent<ext::gltf::mesh_t>() ) return;
auto& transform = entity->getComponent<pod::Transform<>>();
auto& mesh = entity->getComponent<ext::gltf::mesh_t>();
auto& metadata = entity->getComponent<uf::Serializer>();
std::string nodeName = metadata["system"]["graph"]["name"].as<std::string>();
pod::Vector3f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
pod::Vector3f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
auto model = uf::transform::model( transform );
for ( auto& vertex : mesh.vertices ) {
// auto position = uf::matrix::multiply<float>( model, vertex.position, 1.0f );
min.x = std::min( min.x, vertex.position.x );
min.y = std::min( min.y, vertex.position.y );
min.z = std::min( min.z, vertex.position.z );
max.x = std::max( max.x, vertex.position.x );
max.y = std::max( max.y, vertex.position.y );
max.z = std::max( max.z, vertex.position.z );
}
min = uf::matrix::multiply<float>( model, min, 1.0f );
max = uf::matrix::multiply<float>( model, max, 1.0f );
extentMin.x = std::min( min.x, extentMin.x );
extentMin.y = std::min( min.y, extentMin.y );
extentMin.z = std::min( min.z, extentMin.z );
extentMax.x = std::max( max.x, extentMax.x );
extentMax.y = std::max( max.y, extentMax.y );
extentMax.z = std::max( max.z, extentMax.z );
#if 1
if ( graph.metadata["flags"]["NORMALS"].as<bool>() ) {
// bool invert = false;
@ -391,6 +504,9 @@ void uf::graph::process( pod::Graph& graph ) {
}
}
});
if ( ext::json::isNull( graph.metadata["extents"]["min"] ) ) graph.metadata["extents"]["min"] = uf::vector::encode( extentMin * graph.metadata["extents"]["scale"].as<float>(1.0f) );
if ( ext::json::isNull( graph.metadata["extents"]["max"] ) ) graph.metadata["extents"]["max"] = uf::vector::encode( extentMax * graph.metadata["extents"]["scale"].as<float>(1.0f) );
}
void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) {
auto& node = graph.nodes[index];
@ -603,6 +719,20 @@ void uf::graph::override( pod::Graph& graph ) {
}
}
void uf::graph::initialize( pod::Graph& graph ) {
graph.root.entity->initialize();
graph.root.entity->process([&]( uf::Entity* entity ) {
if ( !entity->hasComponent<uf::Graphic>() ) {
if ( entity->getUid() == 0 ) entity->initialize();
return;
}
if ( !graph.metadata["flags"]["LOAD"].as<bool>() ) initializeShaders( graph, entity->as<uf::Object>() );
uf::instantiator::bind( "GltfBehavior", *entity );
uf::instantiator::unbind( "RenderBehavior", *entity );
if ( entity->getUid() == 0 ) entity->initialize();
});
}
void uf::graph::animate( pod::Graph& graph, const std::string& name, float speed, bool immediate ) {
if ( !(graph.metadata["flags"]["SKINNED"].as<bool>()) ) return;
if ( graph.animations.count( name ) > 0 ) {

View File

@ -4,6 +4,7 @@
#include <uf/ext/vulkan/initializers.h>
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/openvr/openvr.h>
#include <uf/utils/camera/camera.h>
#include <spirv_cross/spirv_cross.hpp>
#include <spirv_cross/spirv_glsl.hpp>
@ -798,9 +799,11 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des
this->device = graphic.device;
//this->descriptor = descriptor;
Device& device = *graphic.device;
metadata["name"] = descriptor.pipeline;
// VK_VALIDATION_MESSAGE(&graphic << ": Shaders: " << graphic.material.shaders.size() << " Textures: " << graphic.material.textures.size());
assert( graphic.material.shaders.size() > 0 );
auto shaders = getShaders( graphic.material.shaders );
assert( shaders.size() > 0 );
RenderMode& renderMode = ext::vulkan::getRenderMode( descriptor.renderMode, true);
auto& renderTarget = renderMode.getRenderTarget( descriptor.renderTarget );
@ -810,7 +813,9 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des
std::vector<VkDescriptorPoolSize> poolSizes;
std::unordered_map<VkDescriptorType, uint32_t> descriptorTypes;
for ( auto& shader : graphic.material.shaders ) {
// for ( auto& shader : graphic.material.shaders ) {
for ( auto* shaderPointer : shaders ) {
auto& shader = *shaderPointer;
descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() );
std::size_t offset = 0;
@ -868,7 +873,8 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout));
}
// Compute
for ( auto& shader : graphic.material.shaders ) {
for ( auto* shaderPointer : shaders ) {
auto& shader = *shaderPointer;
if ( shader.descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue;
// Create compute shader pipelines
@ -1002,7 +1008,9 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des
vertexInputState.pVertexAttributeDescriptions = vertexAttributeDescriptions.data();
std::vector<VkPipelineShaderStageCreateInfo> shaderDescriptors;
for ( auto& shader : graphic.material.shaders ) {
for ( auto* shaderPointer : shaders ) {
auto& shader = *shaderPointer;
void* s = (void*) shader.specializationConstants;
size_t len = shader.specializationConstants.data().len;
for ( size_t i = 0; i < len / 4; ++i ) {
@ -1081,7 +1089,10 @@ PIPELINE_INITIALIZATION_INVALID:
}
void ext::vulkan::Pipeline::record( Graphic& graphic, VkCommandBuffer commandBuffer, size_t pass, size_t draw ) {
auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
for ( auto& shader : graphic.material.shaders ) {
auto shaders = getShaders( graphic.material.shaders );
for ( auto* shaderPointer : shaders ) {
auto& shader = *shaderPointer;
if ( shader.descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) {
bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
}
@ -1122,7 +1133,9 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip
auto& renderTarget = renderMode.getRenderTarget(descriptor.renderTarget );
std::vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings;
for ( auto& shader : graphic.material.shaders ) {
auto shaders = getShaders( graphic.material.shaders );
for ( auto* shaderPointer : shaders ) {
auto& shader = *shaderPointer;
descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() );
}
@ -1155,7 +1168,9 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip
}
ext::json::Value bindingMapping;
for ( auto& shader : graphic.material.shaders ) {
for ( auto* shaderPointer : shaders ) {
auto& shader = *shaderPointer;
#define PARSE_BUFFER( buffers ) for ( auto& buffer : buffers ) {\
if ( buffer.usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) {\
infos.uniform.emplace_back(buffer.descriptor);\
@ -1180,7 +1195,9 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip
consumes += layout.descriptorCount;
std::string imageType = "";
std::string binding = std::to_string(layout.binding);
for ( auto& shader : graphic.material.shaders ) {
for ( auto* shaderPointer : shaders ) {
auto& shader = *shaderPointer;
auto& info = shader.metadata["definitions"]["textures"][binding];
if ( ext::json::isNull(info) ) continue;
imageType = info["type"].as<std::string>();
@ -1211,11 +1228,12 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip
#define BREAK_ASSERT(condition, ...) if ( condition ) { VK_VALIDATION_MESSAGE(#condition << "\t" << __VA_ARGS__); break; }
std::vector<VkWriteDescriptorSet> writeDescriptorSets;
for ( auto& shader : graphic.material.shaders ) {
// std::cout << shader.filename << ": " << std::endl;
// std::cout << "\tAVAILABLE UNIFORM BUFFERS: " << infos.uniform.size() << std::endl;
// std::cout << "\tAVAILABLE STORAGE BUFFERS: " << infos.storage.size() << std::endl;
// std::cout << "\tCONSUMING : " << shader.descriptorSetLayoutBindings.size() << std::endl;
for ( auto* shaderPointer : shaders ) {
auto& shader = *shaderPointer;
// UF_DEBUG_MSG(shader.filename << ": ");
// UF_DEBUG_MSG("\tAVAILABLE UNIFORM BUFFERS: " << infos.uniform.size());
// UF_DEBUG_MSG("\tAVAILABLE STORAGE BUFFERS: " << infos.storage.size());
// UF_DEBUG_MSG("\tCONSUMING : " << shader.descriptorSetLayoutBindings.size());
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
// VK_VALIDATION_MESSAGE(shader.filename << "\tType: " << layout.descriptorType << "\tConsuming: " << layout.descriptorCount);
@ -1224,7 +1242,14 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
// std::cout << "\tINSERTING IMAGE" << std::endl;
// UF_DEBUG_MSG("\t["<< layout.binding << "] INSERTING " << layout.descriptorCount << " IMAGE");
// if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ) UF_DEBUG_MSG("\t\tCOMBINED_IMAGE_SAMPLER");
// if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ) UF_DEBUG_MSG("\t\tSAMPLED_IMAGE");
// if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ) UF_DEBUG_MSG("\t\tSTORAGE_IMAGE");
if ( layout.descriptorCount == 1 ) {
VkDescriptorImageInfo i = (*imageInfo);
// UF_DEBUG_MSG(i.imageView << "\t" << i.imageLayout);
}
BREAK_ASSERT( imageInfo == infos.image.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount )
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
@ -1236,7 +1261,7 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip
imageInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
// std::cout << "\tINSERTING INPUT_ATTACHMENT" << std::endl;
// UF_DEBUG_MSG("\t["<< layout.binding << "] INSERTING " << layout.descriptorCount << " INPUT_ATTACHMENT");
BREAK_ASSERT( inputInfo == infos.input.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount )
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
@ -1248,7 +1273,7 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip
inputInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_SAMPLER: {
// std::cout << "\tINSERTING SAMPLER" << std::endl;
// UF_DEBUG_MSG("\t["<< layout.binding << "] INSERTING " << layout.descriptorCount << " SAMPLER");
BREAK_ASSERT( samplerInfo == infos.sampler.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount )
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
@ -1260,7 +1285,7 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip
samplerInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
// std::cout << "\tINSERTING UNIFORM_BUFFER" << std::endl;
// UF_DEBUG_MSG("\t["<< layout.binding << "] INSERTING " << layout.descriptorCount << " UNIFORM_BUFFER");
BREAK_ASSERT( uniformBufferInfo == infos.uniform.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount )
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
@ -1272,7 +1297,7 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip
uniformBufferInfo += layout.descriptorCount;
} break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
// std::cout << "\tINSERTING STORAGE_BUFFER" << std::endl;
// UF_DEBUG_MSG("\t["<< layout.binding << "] INSERTING " << layout.descriptorCount << " STORAGE_BUFFER");
BREAK_ASSERT( storageBufferInfo == infos.storage.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount )
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
@ -1306,7 +1331,9 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip
auto pointer = const_cast<VkDescriptorImageInfo*>(&descriptor.pImageInfo[i]);
std::string binding = std::to_string(descriptor.dstBinding);
std::string imageType = "";
for ( auto& shader : graphic.material.shaders ) {
for ( auto* shaderPointer : shaders ) {
auto& shader = *shaderPointer;
auto& info = shader.metadata["definitions"]["textures"][binding];
if ( ext::json::isNull(info) ) continue;
imageType = info["type"].as<std::string>();
@ -1379,6 +1406,45 @@ void ext::vulkan::Pipeline::destroy() {
descriptorSetLayout = VK_NULL_HANDLE;
}
}
std::vector<ext::vulkan::Shader*> ext::vulkan::Pipeline::getShaders( std::vector<ext::vulkan::Shader>& shaders ) {
std::string pipelineName = metadata["name"].as<std::string>();
std::unordered_map<std::string, ext::vulkan::Shader*> map;
std::vector<ext::vulkan::Shader*> res;
for ( auto& shader : shaders ) {
std::string target = shader.metadata["pipeline"].as<std::string>();
std::string type = shader.metadata["type"].as<std::string>();
if ( target != "" && target != pipelineName ) continue;
map[type] = &shader;
}
for ( auto pair : map ) {
res.insert( res.begin(), pair.second);
}
/*
std::string pipelineName = metadata["name"].as<std::string>();
std::vector<ext::vulkan::Shader*> res;
std::unordered_map<std::string, size_t> map;
// first push base pipeline
for ( auto& shader : shaders ) {
if ( shader.metadata["pipeline"].as<std::string>() != "" ) continue;
map[shader.metadata["type"].as<std::string>()] = res.size();
res.emplace_back(&shader);
}
// then add requested ones
if ( pipelineName != "" ) for ( auto& shader : shaders ) {
if ( shader.metadata["pipeline"].as<std::string>() != pipelineName ) continue;
if ( map.count(shader.metadata["type"].as<std::string>()) == 0 ) {
res.emplace_back(&shader);
} else {
size_t index = map.at(shader.metadata["type"].as<std::string>());
res[index] = &shader;
}
}
*/
return res;
}
void ext::vulkan::Material::initialize( Device& device ) {
this->device = &device;
@ -1394,7 +1460,7 @@ void ext::vulkan::Material::destroy() {
textures.clear();
samplers.clear();
}
void ext::vulkan::Material::attachShader( const std::string& filename, VkShaderStageFlagBits stage ) {
void ext::vulkan::Material::attachShader( const std::string& filename, VkShaderStageFlagBits stage, const std::string& pipeline ) {
auto& shader = shaders.emplace_back();
shader.initialize( *device, filename, stage );
@ -1422,24 +1488,27 @@ void ext::vulkan::Material::attachShader( const std::string& filename, VkShaderS
case VK_SHADER_STAGE_INTERSECTION_BIT_KHR: type = "intersection"; break;
case VK_SHADER_STAGE_CALLABLE_BIT_KHR: type = "callable"; break;
}
metadata["shaders"][type]["index"] = shaders.size() - 1;
metadata["shaders"][type]["filename"] = filename;
shader.metadata["pipeline"] = pipeline;
shader.metadata["type"] = type;
metadata["shaders"][pipeline][type]["index"] = shaders.size() - 1;
metadata["shaders"][pipeline][type]["filename"] = filename;
}
void ext::vulkan::Material::initializeShaders( const std::vector<std::pair<std::string, VkShaderStageFlagBits>>& layout ) {
void ext::vulkan::Material::initializeShaders( const std::vector<std::pair<std::string, VkShaderStageFlagBits>>& layout, const std::string& pipeline ) {
shaders.clear(); shaders.reserve( layout.size() );
for ( auto& request : layout ) {
attachShader( request.first, request.second );
attachShader( request.first, request.second, pipeline );
}
}
bool ext::vulkan::Material::hasShader( const std::string& type ) {
return !ext::json::isNull( metadata["shaders"][type] );
bool ext::vulkan::Material::hasShader( const std::string& type, const std::string& pipeline ) {
return !ext::json::isNull( metadata["shaders"][pipeline][type] );
}
ext::vulkan::Shader& ext::vulkan::Material::getShader( const std::string& type ) {
if ( !hasShader(type) ) {
ext::vulkan::Shader& ext::vulkan::Material::getShader( const std::string& type, const std::string& pipeline ) {
if ( !hasShader(type, pipeline) ) {
static ext::vulkan::Shader null;
return null;
}
size_t index = metadata["shaders"][type]["index"].as<size_t>();
size_t index = metadata["shaders"][pipeline][type]["index"].as<size_t>();
return shaders.at(index);
}
bool ext::vulkan::Material::validate() {
@ -1455,6 +1524,10 @@ ext::vulkan::Graphic::~Graphic() {
void ext::vulkan::Graphic::initialize( const std::string& renderModeName ) {
RenderMode& renderMode = ext::vulkan::getRenderMode(renderModeName, true);
// if ( !uf::Camera::USE_REVERSE_INFINITE_PROJECTION && descriptor.depth.operation == ext::vulkan::enums::Compare::GREATER_OR_EQUAL ) {
// descriptor.depth.operation = ext::vulkan::enums::Compare::LESS_OR_EQUAL;
// }
this->descriptor.renderMode = renderModeName;
auto* device = renderMode.device;
if ( !device ) device = &ext::vulkan::device;

View File

@ -253,6 +253,12 @@ void ext::vulkan::RenderMode::bindPipelines( const std::vector<ext::vulkan::Grap
if ( descriptor.invalidated ) continue;
// ignore if pipeline exists for this render mode
if ( graphic.hasPipeline( descriptor ) ) continue;
// if pipeline name is specified for the rendermode, check if we have shaders for it
size_t shaders = 0;
for ( auto& shader : graphic.material.shaders ) {
if ( shader.metadata["pipeline"].as<std::string>() == descriptor.pipeline ) ++shaders;
}
if ( shaders == 0 ) continue;
graphic.initializePipeline( descriptor );
}
}

View File

@ -44,7 +44,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
size_t eyes = metadata["eyes"].as<size_t>();
for ( size_t eye = 0; eye < eyes; ++eye ) {
struct {
size_t id, normals, uvs, albedo, depth, output;
size_t id, normals, uvs, albedo, depth, output, debug;
} attachments;
size_t msaa = ext::vulkan::settings::msaa;
@ -122,6 +122,15 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
});
}
metadata["outputs"].emplace_back(attachments.output);
attachments.debug = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format = */VK_FORMAT_R16G16B16A16_SFLOAT,
/*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
/*.blend = */false,
/*.samples = */1,
});
if ( ext::vulkan::settings::experimental::deferredMode == "deferredSampling" ) {
// First pass: fill the G-Buffer
{
@ -138,7 +147,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
{
renderTarget.addPass(
/*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
/*.colors =*/ { attachments.output },
/*.colors =*/ { attachments.output, attachments.debug },
/*.inputs =*/ { attachments.id, attachments.normals, attachments.uvs, attachments.depth },
/*.resolve =*/ {},
/*.depth = */ attachments.depth,
@ -161,7 +170,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
{
renderTarget.addPass(
/*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
/*.colors =*/ { attachments.output },
/*.colors =*/ { attachments.output, attachments.debug },
/*.inputs =*/ { attachments.id, attachments.normals, attachments.albedo, attachments.depth },
/*.resolve =*/ {},
/*.depth = */ attachments.depth,
@ -189,11 +198,17 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
blitter.initialize( this->getName() );
blitter.initializeMesh( mesh );
blitter.material.initializeShaders({
{uf::io::root+"/shaders/display/subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{uf::io::root+"/shaders/display/subpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
if ( ext::vulkan::settings::experimental::deferredMode == "svogi" ) {
blitter.material.initializeShaders({
{uf::io::root+"/shaders/display/subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{uf::io::root+"/shaders/display/subpass.svogi.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
} else {
blitter.material.initializeShaders({
{uf::io::root+"/shaders/display/subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{uf::io::root+"/shaders/display/subpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
}
{
auto& scene = uf::scene::getCurrentScene();
@ -266,6 +281,11 @@ void ext::vulkan::DeferredRenderMode::destroy() {
ext::vulkan::RenderMode::destroy();
blitter.destroy();
}
ext::vulkan::GraphicDescriptor ext::vulkan::DeferredRenderMode::bindGraphicDescriptor( const ext::vulkan::GraphicDescriptor& reference, size_t pass ) {
ext::vulkan::GraphicDescriptor descriptor = ext::vulkan::RenderMode::bindGraphicDescriptor(reference, pass);
return descriptor;
}
void ext::vulkan::DeferredRenderMode::createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics ) {
float width = this->width > 0 ? this->width : ext::vulkan::settings::width;
float height = this->height > 0 ? this->height : ext::vulkan::settings::height;

View File

@ -6,6 +6,7 @@
#include <uf/utils/window/window.h>
#include <uf/utils/graphic/graphic.h>
#include <uf/ext/vulkan/graphic.h>
#include <uf/ext/gltf/graph.h>
const std::string ext::vulkan::RenderTargetRenderMode::getTarget() const {
auto& metadata = *const_cast<uf::Serializer*>(&this->metadata);
@ -14,6 +15,9 @@ const std::string ext::vulkan::RenderTargetRenderMode::getTarget() const {
void ext::vulkan::RenderTargetRenderMode::setTarget( const std::string& target ) {
this->metadata["target"] = target;
}
void ext::vulkan::RenderTargetRenderMode::bindCallback( int32_t subpass, const ext::vulkan::RenderTargetRenderMode::callback_t& callback ) {
commandBufferCallbacks[subpass] = callback;
}
const std::string ext::vulkan::RenderTargetRenderMode::getType() const {
return "RenderTarget";
@ -33,7 +37,11 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderTargetRenderMode::bindGraphicD
descriptor.parse(metadata["descriptor"]);
std::string type = metadata["type"].as<std::string>();
std::string target = metadata["target"].as<std::string>();
if ( type == "depth" ) {
if ( pass == 0 && type == "svogi" ) {
descriptor.cullMode = VK_CULL_MODE_NONE;
descriptor.depth.test = false;
descriptor.pipeline = "svogi";
} else if ( type == "depth" ) {
descriptor.cullMode = VK_CULL_MODE_NONE;
}
// invalidate
@ -55,7 +63,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
if ( subpasses == 0 ) subpasses = 1;
renderTarget.device = &device;
for ( size_t currentPass = 0; currentPass < subpasses; ++currentPass ) {
if ( type == "depth" ) {
if ( type == "depth" /*|| type == "svogi"*/ ) {
struct {
size_t depth;
} attachments;
@ -273,59 +281,155 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
mesh.indices = {
0, 1, 2, 2, 3, 0
};
blitter.device = &device;
blitter.material.device = &device;
blitter.initializeMesh( mesh );
blitter.material.initializeShaders({
{uf::io::root+"/shaders/display/renderTarget.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{uf::io::root+"/shaders/display/renderTarget.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
if ( ext::json::isArray( metadata["shaders"] ) ) {
ext::json::forEach( metadata["shaders"], [&]( ext::json::Value& value ){
ext::vulkan::enums::Shader::type_t type;
std::string filename = "";
std::string pipeline = "";
Texture2D& texture = blitter.material.textures.emplace_back();
enums::Filter::type_t filter = VK_FILTER_NEAREST;
/*
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties( device.physicalDevice, texture.format, &formatProperties );
if ( formatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT )
filter = VK_FILTER_LINEAR;
*/
texture.sampler.descriptor.filter.min = filter;
texture.sampler.descriptor.filter.mag = filter;
texture.aliasAttachment(attachment);
if ( value.is<std::string>() ) {
filename = value.as<std::string>();
auto split = uf::string::split( filename, "." );
std::string extension = split.back(); split.pop_back();
std::string sType = split.back();
if ( sType == "vert" ) type = ext::vulkan::enums::Shader::VERTEX;
else if ( sType == "frag" ) type = ext::vulkan::enums::Shader::FRAGMENT;
else if ( sType == "geom" ) type = ext::vulkan::enums::Shader::GEOMETRY;
else if ( sType == "comp" ) type = ext::vulkan::enums::Shader::COMPUTE;
} else {
filename = value["filename"].as<std::string>();
pipeline = value["pipeline"].as<std::string>();
std::string sType = value["type"].as<std::string>();
if ( sType == "vertex" ) type = ext::vulkan::enums::Shader::VERTEX;
else if ( sType == "fragment" ) type = ext::vulkan::enums::Shader::FRAGMENT;
else if ( sType == "geometry" ) type = ext::vulkan::enums::Shader::GEOMETRY;
else if ( sType == "compute" ) type = ext::vulkan::enums::Shader::COMPUTE;
}
blitter.material.attachShader( uf::io::root+filename, type, pipeline );
});
} else if ( ext::json::isObject( metadata["shaders"] ) ) {
ext::json::forEach( metadata["shaders"], [&]( const std::string& key, ext::json::Value& value ){
ext::vulkan::enums::Shader::type_t type;
std::string filename = "";
std::string pipeline = "";
if ( value.is<std::string>() ) {
filename = value.as<std::string>();
} else {
filename = value["filename"].as<std::string>();
pipeline = value["pipeline"].as<std::string>();
}
if ( key == "vertex" ) type = ext::vulkan::enums::Shader::VERTEX;
else if ( key == "fragment" ) type = ext::vulkan::enums::Shader::FRAGMENT;
else if ( key == "geometry" ) type = ext::vulkan::enums::Shader::GEOMETRY;
else if ( key == "compute" ) type = ext::vulkan::enums::Shader::COMPUTE;
blitter.material.attachShader( uf::io::root+filename, type, pipeline );
});
} else if ( metadata["shaders"].is<bool>() && !metadata["shaders"].as<bool>() ) {
// do not attach if we're requesting no blitter shaders
blitter.process = false;
} else {
blitter.material.initializeShaders({
{uf::io::root+"/shaders/display/renderTarget.vert.spv", ext::vulkan::enums::Shader::VERTEX},
{uf::io::root+"/shaders/display/renderTarget.frag.spv", ext::vulkan::enums::Shader::FRAGMENT}
});
}
if ( metadata["type"].as<std::string>() == "svogi" ) {
auto& scene = uf::scene::getCurrentScene();
auto& shader = blitter.material.getShader("compute");
struct SpecializationConstant {
uint32_t maxTextures = 512;
};
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;
}
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);
for ( auto& material : materials ) material.colorBase = {0,0,0,0};
this->metadata["lightBufferIndex"] = blitter.initializeBuffer(
(void*) lights.data(),
lights.size() * sizeof(pod::Light::Storage),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
);
this->metadata["materialBufferIndex"] = blitter.initializeBuffer(
(void*) materials.data(),
materials.size() * sizeof(pod::Material::Storage),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
);
this->metadata["textureBufferIndex"] = blitter.initializeBuffer(
(void*) textures.data(),
textures.size() * sizeof(pod::Texture::Storage),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
);
this->metadata["drawCallBufferIndex"] = blitter.initializeBuffer(
(void*) drawCalls.data(),
drawCalls.size() * sizeof(pod::DrawCall::Storage),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
);
} else {
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
Texture2D& texture = blitter.material.textures.emplace_back();
enums::Filter::type_t filter = VK_FILTER_NEAREST;
/*
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties( device.physicalDevice, texture.format, &formatProperties );
if ( formatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT )
filter = VK_FILTER_LINEAR;
*/
texture.sampler.descriptor.filter.min = filter;
texture.sampler.descriptor.filter.mag = filter;
texture.aliasAttachment(attachment);
}
}
}
}
void ext::vulkan::RenderTargetRenderMode::tick() {
ext::vulkan::RenderMode::tick();
if ( metadata["type"].as<std::string>() == "svogi" ) {
if ( ext::vulkan::states::resized ) {
renderTarget.initialize( *renderTarget.device );
if ( blitter.process ) blitter.getPipeline().update( blitter );
}
return;
}
if ( ext::vulkan::states::resized ) {
renderTarget.initialize( *renderTarget.device );
/*
for ( auto& texture : blitter.material.textures ) {
texture.sampler.destroy();
}
*/
// for ( auto& texture : blitter.material.textures ) texture.sampler.destroy();
blitter.material.textures.clear();
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
Texture2D& texture = blitter.material.textures.emplace_back();
enums::Filter::type_t filter = VK_FILTER_NEAREST;
/*
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties( device->physicalDevice, texture.format, &formatProperties );
if ( formatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT )
filter = VK_FILTER_LINEAR;
*/
texture.sampler.descriptor.filter.min = filter;
texture.sampler.descriptor.filter.mag = filter;
texture.aliasAttachment(attachment);
}
if ( blitter.process ) {
blitter.getPipeline().update( blitter );
}
if ( blitter.process ) blitter.getPipeline().update( blitter );
}
}
void ext::vulkan::RenderTargetRenderMode::destroy() {
@ -471,6 +575,9 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const std::vecto
size_t subpasses = renderTarget.passes.size();
size_t currentPass = 0;
// pre-renderpass commands
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commands[i] );
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commands[i], 0, 1, &viewport);
vkCmdSetScissor(commands[i], 0, 1, &scissor);
@ -481,9 +588,13 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const std::vecto
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentPass);
graphic->record( commands[i], descriptor, currentPass, currentDraw++ );
}
if ( commandBufferCallbacks.count( currentPass ) > 0 ) commandBufferCallbacks[currentPass]( commands[i] );
if ( currentPass + 1 < subpasses ) vkCmdNextSubpass(commands[i], VK_SUBPASS_CONTENTS_INLINE);
}
vkCmdEndRenderPass(commands[i]);
// post-renderpass commands
if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) commandBufferCallbacks[CALLBACK_END]( commands[i] );
}
VK_CHECK_RESULT(vkEndCommandBuffer(commands[i]));

View File

@ -1,5 +1,5 @@
#if UF_USE_VULKAN
#include <bitset>
#include <uf/ext/vulkan/texture.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/utils/image/image.h>
@ -372,13 +372,15 @@ void ext::vulkan::Texture::fromBuffers(
if ( this->mips == 0 ) {
this->mips = 1;
} else if ( this->depth == 1 ) {
this->mips = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
// } else if ( this->depth == 1 ) {
} else {
// this->mips = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
this->mips = static_cast<uint32_t>(std::floor(std::log2(std::max(std::max(texWidth, texHeight),texDepth)))) + 1;
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(device.physicalDevice, format, &formatProperties);
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
this->mips = 1;
VK_VALIDATION_MESSAGE("Texture image format does not support linear blitting!");
VK_VALIDATION_MESSAGE("Texture image format `" << format << "` does not support linear blitting!");
}
}
@ -529,6 +531,10 @@ void ext::vulkan::Texture::aliasTexture( const Texture& texture ) {
imageLayout = texture.imageLayout;
deviceMemory = texture.deviceMemory;
sampler = texture.sampler;
width = texture.width;
height = texture.height;
depth = texture.depth;
layers = texture.layers;
this->updateDescriptors();
}
@ -596,7 +602,6 @@ void ext::vulkan::Texture::update( void* data, VkDeviceSize bufferSize, VkImageL
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
subresourceRange
);
// Copy mip levels from staging buffer
vkCmdCopyBufferToImage(
commandBuffer,
@ -606,9 +611,7 @@ void ext::vulkan::Texture::update( void* data, VkDeviceSize bufferSize, VkImageL
1,
&bufferCopyRegion
);
if ( this->mips > 1 ) this->generateMipmaps(commandBuffer, layer);
setImageLayout(
commandBuffer,
image,
@ -616,6 +619,7 @@ void ext::vulkan::Texture::update( void* data, VkDeviceSize bufferSize, VkImageL
targetImageLayout,
subresourceRange
);
device.flushCommandBuffer(commandBuffer);
// Clean up staging resources
staging.destroy();
@ -624,16 +628,17 @@ void ext::vulkan::Texture::update( void* data, VkDeviceSize bufferSize, VkImageL
this->updateDescriptors();
}
void ext::vulkan::Texture::generateMipmaps( VkCommandBuffer commandBuffer, uint32_t layer ) {
auto& device = *this->device;
if ( this->mips <= 1 ) return;
bool blitting = true;
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(device.physicalDevice, format, &formatProperties);
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
UF_EXCEPTION("texture image format does not support linear blitting!");
UF_EXCEPTION("Texture image format `" + std::to_string(format) + "` does not support linear blitting!");
blitting = false;
}
// base layer barrier
@ -662,28 +667,32 @@ void ext::vulkan::Texture::generateMipmaps( VkCommandBuffer commandBuffer, uint3
1, &barrier
);
// blit to current mip layer
VkImageBlit blit{};
blit.srcOffsets[0] = { 0, 0, 0 };
blit.srcOffsets[1] = { mipWidth, mipHeight, mipDepth };
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.mipLevel = i - 1;
blit.srcSubresource.baseArrayLayer = layer;
blit.srcSubresource.layerCount = 1;
blit.dstOffsets[0] = { 0, 0, 0 };
blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, mipDepth > 1 ? mipDepth / 2 : 1 };
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = i;
blit.dstSubresource.baseArrayLayer = layer;
blit.dstSubresource.layerCount = 1;
if ( blitting ) {
// blit to current mip layer
VkImageBlit blit{};
blit.srcOffsets[0] = { 0, 0, 0 };
blit.srcOffsets[1] = { mipWidth, mipHeight, mipDepth };
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.mipLevel = i - 1;
blit.srcSubresource.baseArrayLayer = layer;
blit.srcSubresource.layerCount = 1;
blit.dstOffsets[0] = { 0, 0, 0 };
blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, mipDepth > 1 ? mipDepth / 2 : 1 };
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = i;
blit.dstSubresource.baseArrayLayer = layer;
blit.dstSubresource.layerCount = 1;
vkCmdBlitImage(
commandBuffer,
image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &blit,
VK_FILTER_LINEAR
);
vkCmdBlitImage(
commandBuffer,
image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &blit,
VK_FILTER_LINEAR
);
} else {
}
// transition previous layer back
barrier.subresourceRange.baseMipLevel = i - 1;

View File

@ -217,7 +217,7 @@ void ext::vulkan::initialize() {
};
Texture2D::empty.sampler.descriptor.filter.min = VK_FILTER_NEAREST;
Texture2D::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST;
Texture2D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT );
Texture2D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
}
{
std::vector<uint8_t> pixels = {
@ -229,7 +229,7 @@ void ext::vulkan::initialize() {
};
Texture3D::empty.sampler.descriptor.filter.min = VK_FILTER_NEAREST;
Texture3D::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST;
Texture3D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, 2, 1, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT );
Texture3D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, 2, 1, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
}
{
std::vector<uint8_t> pixels = {
@ -253,7 +253,7 @@ void ext::vulkan::initialize() {
};
TextureCube::empty.sampler.descriptor.filter.min = VK_FILTER_NEAREST;
TextureCube::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST;
TextureCube::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, 1, 6, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT );
TextureCube::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, 1, 6, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
}
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;

View File

@ -121,11 +121,11 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
uf::hooks.call("window:Mouse.CursorVisibility", payload);
uf::hooks.call("window:Mouse.Lock");
}
auto& sceneTextures = this->getComponent<pod::SceneTextures>();
// initialize perlin noise
#if UF_USE_VULKAN
{
auto& texture = this->getComponent<uf::renderer::Texture3D>();
auto& texture = sceneTextures.noise; //this->getComponent<uf::renderer::Texture3D>();
texture.sampler.descriptor.addressMode = {
uf::renderer::enums::AddressMode::MIRRORED_REPEAT,
uf::renderer::enums::AddressMode::MIRRORED_REPEAT,
@ -167,6 +167,8 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
}
texture.fromBuffers( (void*) pixels.data(), pixels.size(), uf::renderer::enums::Format::R8_UNORM, size.x, size.y, size.z, 1 );
}
// initialize voxel map
// initialize cubemap
{
std::vector<std::string> filenames = {
@ -181,7 +183,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
std::vector<uf::Image> images(filenames.size());
pod::Vector2ui size = {0,0};
auto& texture = this->getComponent<uf::renderer::TextureCube>();
auto& texture = sceneTextures.skybox; //this->getComponent<uf::renderer::TextureCube>();
for ( size_t i = 0; i < filenames.size(); ++i ) {
auto& filename = filenames[i];
auto& image = images[i];
@ -361,327 +363,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
if ( !metadata.light.updateThreshold ) metadata.light.updateThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["update threshold"].as<size_t>();
#endif
/* Update lights */ if ( metadata.light.enabled ) {
auto& scene = uf::scene::getCurrentScene();
auto& controller = scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
auto& renderMode = uf::renderer::getRenderMode("", true);
auto& controllerMetadata = controller.getComponent<uf::Serializer>();
auto& controllerTransform = controller.getComponent<pod::Transform<>>();
std::vector<uf::Graphic*> blitters = renderMode.getBlitters();
#if UF_USE_OPENGL
struct LightInfo {
uf::Entity* entity = NULL;
pod::Vector4f position = {0,0,0,1};
pod::Vector4f color = {0,0,0,1};
float distance = 0;
float power = 0;
};
std::vector<LightInfo> entities;
auto graph = uf::scene::generateGraph();
for ( auto entity : graph ) {
if ( entity == &controller || entity == this ) continue;
// if ( entity->getName() != "Light" && !entity->hasComponent<ext::LightBehavior::Metadata>() ) continue;
if ( !entity->hasComponent<ext::LightBehavior::Metadata>() ) continue;
// if ( !entity->hasBehavior(pod::Behavior{.type = ext::LightBehavior::type}) ) continue;
auto& metadata = entity->getComponent<ext::LightBehavior::Metadata>();
if ( metadata.power <= 0 ) continue;
LightInfo& info = entities.emplace_back();
auto& transform = entity->getComponent<pod::Transform<>>();
auto flatten = uf::transform::flatten( transform );
info.entity = entity;
info.position = flatten.position;
info.position.w = 1;
info.color = metadata.color;
info.color.w = 1;
info.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) );
info.power = metadata.power;
}
std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){
return l.distance < r.distance;
});
static GLint glMaxLights = 0;
if ( !glMaxLights ) glGetIntegerv(GL_MAX_LIGHTS, &glMaxLights);
metadata.max.lights = std::min( (size_t) glMaxLights, metadata.max.lights );
// add lighting
{
size_t i = 0;
for ( ; i < entities.size() && i < metadata.max.lights; ++i ) {
auto& info = entities[i];
uf::Entity* entity = info.entity;
GLenum target = GL_LIGHT0+i;
GL_ERROR_CHECK(glEnable(target));
GL_ERROR_CHECK(glLightfv(target, GL_AMBIENT, &metadata.light.ambient[0]));
GL_ERROR_CHECK(glLightfv(target, GL_SPECULAR, &metadata.light.specular[0]));
GL_ERROR_CHECK(glLightfv(target, GL_DIFFUSE, &info.color[0]));
GL_ERROR_CHECK(glLightfv(target, GL_POSITION, &info.position[0]));
GL_ERROR_CHECK(glLightf(target, GL_CONSTANT_ATTENUATION, 0.0f));
GL_ERROR_CHECK(glLightf(target, GL_LINEAR_ATTENUATION, 0));
GL_ERROR_CHECK(glLightf(target, GL_QUADRATIC_ATTENUATION, 1.0f / info.power));
}
for ( ; i < metadata.max.lights; ++i ) GL_ERROR_CHECK(glDisable(GL_LIGHT0+i));
}
#elif UF_USE_VULKAN
size_t maxTextures = metadata.max.textures;
struct UniformDescriptor {
struct Matrices {
alignas(16) pod::Matrix4f view[2];
alignas(16) pod::Matrix4f projection[2];
alignas(16) pod::Matrix4f iView[2];
alignas(16) pod::Matrix4f iProjection[2];
alignas(16) pod::Matrix4f iProjectionView[2];
} matrices;
struct Mode {
alignas(8) pod::Vector2ui type;
alignas(8) pod::Vector2ui padding;
alignas(16) pod::Vector4f parameters;
} mode;
struct {
alignas(16) pod::Vector4f color; // w: stepScale
alignas(16) pod::Vector4f offset; // w: densityScale
alignas(4) float densityThreshold;
alignas(4) float densityMultiplier;
alignas(4) float absorbtion;
alignas(4) float padding1;
alignas(8) pod::Vector2f range;
alignas(4) float padding2;
alignas(4) float padding3;
} fog;
struct {
alignas(4) uint32_t lights = 0;
alignas(4) uint32_t materials = 0;
alignas(4) uint32_t textures = 0;
alignas(4) uint32_t drawCalls = 0;
} lengths;
alignas(16) pod::Vector4f ambient;
// alignas(16) pod::Vector4f position;
alignas(4) uint32_t msaa;
alignas(4) uint32_t poissonSamples;
alignas(4) uint32_t padding1;
alignas(4) uint32_t padding2;
};
struct SpecializationConstant {
uint32_t maxTextures = 512;
} specializationConstants;
specializationConstants.maxTextures = maxTextures;
struct LightInfo {
uf::Entity* entity = NULL;
pod::Vector4f color = {0,0,0,0};
pod::Vector3f position = {0,0,0};
float power = 0;
float distance = 0;
float bias = 0;
bool shadows = false;
size_t type = 0;
};
std::vector<LightInfo> entities;
std::vector<pod::Graph*> graphs;
auto graph = uf::scene::generateGraph();
for ( auto entity : graph ) {
if ( entity == &controller || entity == this ) continue;
if ( entity->hasComponent<pod::Graph>() ) graphs.emplace_back(&entity->getComponent<pod::Graph>());
// if ( entity->getName() != "Light" && !entity->hasComponent<ext::LightBehavior::Metadata>() ) continue;
if ( !entity->hasComponent<ext::LightBehavior::Metadata>() ) continue;
// if ( !entity->hasBehavior(pod::Behavior{.type = ext::LightBehavior::type}) ) continue;
auto& metadata = entity->getComponent<ext::LightBehavior::Metadata>();
if ( entity->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
if ( metadata.renderer.mode == "in-range" ) renderMode.execute = false;
}
if ( metadata.power <= 0 ) continue;
LightInfo& info = entities.emplace_back();
auto& transform = entity->getComponent<pod::Transform<>>();
auto flatten = uf::transform::flatten( transform );
info.entity = entity;
info.position = flatten.position;
info.color = metadata.color;
info.color.w = metadata.power;
info.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) );
info.shadows = metadata.shadows;
info.bias = metadata.bias;
info.type = metadata.type;
}
std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){
return l.distance < r.distance;
});
int shadowSamples = metadata.light.shadowSamples;
int shadowThreshold = metadata.light.shadowThreshold;
if ( shadowSamples <= 0 ) shadowSamples = 16;
if ( shadowThreshold <= 0 ) shadowThreshold = std::numeric_limits<int>::max();
{
std::vector<LightInfo> scratch;
scratch.reserve(entities.size());
for ( size_t i = 0; i < entities.size(); ++i ) {
auto& info = entities[i];
if ( info.shadows && --shadowThreshold <= 0 ) info.shadows = false;
scratch.emplace_back(info);
}
entities = scratch;
}
for ( auto* blitter : blitters ) {
auto& graphic = *blitter;
auto& shader = graphic.material.getShader("fragment");
auto& uniform = shader.getUniform("UBO");
uint8_t* buffer = (uint8_t*) (void*) uniform;
UniformDescriptor* uniforms = (UniformDescriptor*) buffer;
for ( std::size_t i = 0; i < 2; ++i ) {
uniforms->matrices.view[i] = camera.getView( i );
uniforms->matrices.projection[i] = camera.getProjection( i );
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->ambient = metadata.light.ambient;
uniforms->msaa = ext::vulkan::settings::msaa;
uniforms->poissonSamples = shadowSamples;
uniforms->fog.color = metadata.fog.color;
uniforms->fog.color.w = metadata.fog.stepScale;
float timescale = metadata.fog.density.timescale;
uniforms->fog.offset = metadata.fog.density.offset * uf::physics::time::current * timescale;
uniforms->fog.offset.w = metadata.fog.density.scale;
uniforms->fog.densityThreshold = metadata.fog.density.threshold;
uniforms->fog.densityMultiplier = metadata.fog.density.multiplier;
uniforms->fog.absorbtion = metadata.fog.absorbtion;
uniforms->fog.range = metadata.fog.range;
uniforms->mode.type.x = metadataJson["system"]["renderer"]["shader"]["mode"].as<size_t>();
uniforms->mode.type.y = metadataJson["system"]["renderer"]["shader"]["scalar"].as<size_t>();
uniforms->mode.parameters = uf::vector::decode( metadataJson["system"]["renderer"]["shader"]["parameters"], uniforms->mode.parameters );
if ( metadataJson["system"]["renderer"]["shader"]["parameters"][3].as<std::string>() == "time" ) {
uniforms->mode.parameters.w = uf::physics::time::current;
}
std::vector<VkImage> previousTextures;
for ( auto& texture : graphic.material.textures ) previousTextures.emplace_back(texture.image);
graphic.material.textures.clear();
graphic.material.textures.emplace_back().aliasTexture(this->getComponent<uf::renderer::Texture3D>());
graphic.material.textures.emplace_back().aliasTexture(this->getComponent<uf::renderer::TextureCube>());
size_t updateThreshold = metadata.light.updateThreshold;
size_t textureSlot = 0;
std::vector<pod::Light::Storage> lights;
lights.reserve( metadata.max.lights );
std::vector<pod::Material::Storage> materials;
materials.reserve(maxTextures);
materials.emplace_back().colorBase = {0,0,0,0};
std::vector<pod::Texture::Storage> textures;
textures.reserve(maxTextures);
std::vector<pod::DrawCall::Storage> drawCalls;
drawCalls.reserve(maxTextures);
// add materials
for ( auto* entity : graphs ) {
auto& graph = *entity;
drawCalls.emplace_back(pod::DrawCall::Storage{
materials.size(),
graph.materials.size(),
textures.size(),
graph.textures.size()
});
for ( auto& material : graph.materials ) materials.emplace_back( material.storage );
for ( auto& texture : graph.textures ) textures.emplace_back( texture.storage );
for ( auto& texture : graph.textures ) {
if ( !texture.bind ) continue;
graphic.material.textures.emplace_back().aliasTexture(texture.texture);
++textureSlot;
}
}
uniforms->lengths.materials = std::min( materials.size(), maxTextures );
uniforms->lengths.textures = std::min( textures.size(), maxTextures );
uniforms->lengths.drawCalls = std::min( drawCalls.size(), maxTextures );
// add lighting
for ( size_t i = 0; i < entities.size() && lights.size() < metadata.max.lights; ++i ) {
auto& info = entities[i];
uf::Entity* entity = info.entity;
auto& transform = entity->getComponent<pod::Transform<>>();
auto& metadata = entity->getComponent<ext::LightBehavior::Metadata>();
auto& camera = entity->getComponent<uf::Camera>();
metadata.renderer.rendered = true;
pod::Light::Storage light;
light.position = info.position;
light.color = info.color;
light.type = info.type;
light.mapIndex = -1;
light.depthBias = info.bias;
if ( info.shadows && entity->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
if ( metadata.renderer.mode == "in-range" && --updateThreshold > 0 ) {
renderMode.execute = true;
}
size_t view = 0;
for ( auto& attachment : renderMode.renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
if ( attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) continue;
graphic.material.textures.emplace_back().aliasAttachment(attachment);
light.mapIndex = textureSlot++;
light.view = camera.getView(view);
light.projection = camera.getProjection(view);
lights.emplace_back(light);
++view;
}
light.mapIndex = -1;
} else {
lights.emplace_back(light);
}
}
{
uniforms->lengths.lights = std::min( lights.size(), metadata.max.lights );
bool shouldUpdate = graphic.material.textures.size() != previousTextures.size();
for ( size_t i = 0; !shouldUpdate && i < previousTextures.size() && i < graphic.material.textures.size(); ++i ) {
if ( previousTextures[i] != graphic.material.textures[i].image )
shouldUpdate = true;
}
size_t lightBufferIndex = renderMode.metadata["lightBufferIndex"].as<size_t>();
graphic.updateBuffer( (void*) lights.data(), uniforms->lengths.lights * sizeof(pod::Light::Storage), lightBufferIndex, false );
if ( shouldUpdate ) {
size_t materialBufferIndex = renderMode.metadata["materialBufferIndex"].as<size_t>();
graphic.updateBuffer( (void*) materials.data(), uniforms->lengths.materials * sizeof(pod::Material::Storage), materialBufferIndex, false );
size_t textureBufferIndex = renderMode.metadata["textureBufferIndex"].as<size_t>();
graphic.updateBuffer( (void*) textures.data(), uniforms->lengths.textures * sizeof(pod::Texture::Storage), textureBufferIndex, false );
size_t drawCallBufferIndex = renderMode.metadata["drawCallBufferIndex"].as<size_t>();
graphic.updateBuffer( (void*) drawCalls.data(), uniforms->lengths.drawCalls * sizeof(pod::DrawCall::Storage), drawCallBufferIndex, false );
graphic.updatePipelines();
}
shader.updateUniform( "UBO", uniform );
}
}
#endif
ext::ExtSceneBehavior::bindBuffers( *this );
}
#if UF_ENTITY_METADATA_USE_JSON
@ -690,4 +372,362 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
}
void ext::ExtSceneBehavior::render( uf::Object& self ) {}
void ext::ExtSceneBehavior::destroy( uf::Object& self ) {}
void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& renderModeName, bool isCompute ) {
auto& controller = this->getController();
auto& camera = controller.getComponent<uf::Camera>();
auto& controllerMetadata = controller.getComponent<uf::Serializer>();
auto& controllerTransform = controller.getComponent<pod::Transform<>>();
auto& metadata = this->getComponent<ext::ExtSceneBehavior::Metadata>();
auto& metadataJson = this->getComponent<uf::Serializer>();
auto& renderMode = uf::renderer::getRenderMode(renderModeName, true);
std::vector<uf::Graphic*> blitters = renderMode.getBlitters();
#if UF_USE_OPENGL
struct LightInfo {
uf::Entity* entity = NULL;
pod::Vector4f position = {0,0,0,1};
pod::Vector4f color = {0,0,0,1};
float distance = 0;
float power = 0;
};
std::vector<LightInfo> entities;
auto graph = uf::scene::generateGraph();
for ( auto entity : graph ) {
if ( entity == &controller || entity == this ) continue;
// if ( entity->getName() != "Light" && !entity->hasComponent<ext::LightBehavior::Metadata>() ) continue;
if ( !entity->hasComponent<ext::LightBehavior::Metadata>() ) continue;
// if ( !entity->hasBehavior(pod::Behavior{.type = ext::LightBehavior::type}) ) continue;
auto& metadata = entity->getComponent<ext::LightBehavior::Metadata>();
if ( metadata.power <= 0 ) continue;
LightInfo& info = entities.emplace_back();
auto& transform = entity->getComponent<pod::Transform<>>();
auto flatten = uf::transform::flatten( transform );
info.entity = entity;
info.position = flatten.position;
info.position.w = 1;
info.color = metadata.color;
info.color.w = 1;
info.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) );
info.power = metadata.power;
}
std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){
return l.distance < r.distance;
});
static GLint glMaxLights = 0;
if ( !glMaxLights ) glGetIntegerv(GL_MAX_LIGHTS, &glMaxLights);
metadata.max.lights = std::min( (size_t) glMaxLights, metadata.max.lights );
// add lighting
{
size_t i = 0;
for ( ; i < entities.size() && i < metadata.max.lights; ++i ) {
auto& info = entities[i];
uf::Entity* entity = info.entity;
GLenum target = GL_LIGHT0+i;
GL_ERROR_CHECK(glEnable(target));
GL_ERROR_CHECK(glLightfv(target, GL_AMBIENT, &metadata.light.ambient[0]));
GL_ERROR_CHECK(glLightfv(target, GL_SPECULAR, &metadata.light.specular[0]));
GL_ERROR_CHECK(glLightfv(target, GL_DIFFUSE, &info.color[0]));
GL_ERROR_CHECK(glLightfv(target, GL_POSITION, &info.position[0]));
GL_ERROR_CHECK(glLightf(target, GL_CONSTANT_ATTENUATION, 0.0f));
GL_ERROR_CHECK(glLightf(target, GL_LINEAR_ATTENUATION, 0));
GL_ERROR_CHECK(glLightf(target, GL_QUADRATIC_ATTENUATION, 1.0f / info.power));
}
for ( ; i < metadata.max.lights; ++i ) GL_ERROR_CHECK(glDisable(GL_LIGHT0+i));
}
#elif UF_USE_VULKAN
size_t maxTextures = metadata.max.textures;
struct UniformDescriptor {
struct Matrices {
alignas(16) pod::Matrix4f view[2];
alignas(16) pod::Matrix4f projection[2];
alignas(16) pod::Matrix4f iView[2];
alignas(16) pod::Matrix4f iProjection[2];
alignas(16) pod::Matrix4f iProjectionView[2];
alignas(16) pod::Matrix4f ortho;
} matrices;
struct Mode {
alignas(8) pod::Vector2ui type;
alignas(8) pod::Vector2ui padding;
alignas(16) pod::Vector4f parameters;
} mode;
struct {
alignas(16) pod::Vector4f color; // w: stepScale
alignas(16) pod::Vector4f offset; // w: densityScale
alignas(4) float densityThreshold;
alignas(4) float densityMultiplier;
alignas(4) float absorbtion;
alignas(4) float padding1;
alignas(8) pod::Vector2f range;
alignas(4) float padding2;
alignas(4) float padding3;
} fog;
struct {
alignas(4) uint32_t lights = 0;
alignas(4) uint32_t materials = 0;
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(4) uint32_t padding1;
alignas(4) uint32_t padding2;
};
struct SpecializationConstant {
uint32_t maxTextures = 512;
} specializationConstants;
specializationConstants.maxTextures = maxTextures;
struct LightInfo {
uf::Entity* entity = NULL;
pod::Vector4f color = {0,0,0,0};
pod::Vector3f position = {0,0,0};
float power = 0;
float distance = 0;
float bias = 0;
bool shadows = false;
size_t type = 0;
};
std::vector<LightInfo> entities;
std::vector<pod::Graph*> graphs;
auto graph = uf::scene::generateGraph();
for ( auto entity : graph ) {
if ( entity == &controller || entity == this ) continue;
if ( entity->hasComponent<pod::Graph>() ) graphs.emplace_back(&entity->getComponent<pod::Graph>());
if ( !entity->hasComponent<ext::LightBehavior::Metadata>() ) continue;
auto& metadata = entity->getComponent<ext::LightBehavior::Metadata>();
if ( entity->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
if ( metadata.renderer.mode == "in-range" ) renderMode.execute = false;
}
if ( metadata.power <= 0 ) continue;
LightInfo& info = entities.emplace_back();
auto& transform = entity->getComponent<pod::Transform<>>();
auto flatten = uf::transform::flatten( transform );
info.entity = entity;
info.position = flatten.position;
info.color = metadata.color;
info.color.w = metadata.power;
info.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) );
info.shadows = metadata.shadows;
info.bias = metadata.bias;
info.type = metadata.type;
}
std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){
return l.distance < r.distance;
});
int shadowSamples = metadata.light.shadowSamples;
int shadowThreshold = metadata.light.shadowThreshold;
if ( shadowSamples <= 0 ) shadowSamples = 16;
if ( shadowThreshold <= 0 ) shadowThreshold = std::numeric_limits<int>::max();
{
std::vector<LightInfo> scratch;
scratch.reserve(entities.size());
for ( size_t i = 0; i < entities.size(); ++i ) {
auto& info = entities[i];
if ( info.shadows && --shadowThreshold <= 0 ) info.shadows = false;
scratch.emplace_back(info);
}
entities = scratch;
}
auto& sceneTextures = this->getComponent<pod::SceneTextures>();
for ( auto* blitter : blitters ) {
auto& graphic = *blitter;
if ( !graphic.initialized ) continue;
auto& shader = graphic.material.getShader(isCompute ? "compute" : "fragment");
auto& uniform = shader.getUniform("UBO");
uint8_t* buffer = (uint8_t*) (void*) uniform;
UniformDescriptor* uniforms = (UniformDescriptor*) buffer;
for ( std::size_t i = 0; i < 2; ++i ) {
uniforms->matrices.view[i] = camera.getView( i );
uniforms->matrices.projection[i] = camera.getProjection( i );
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->ambient = metadata.light.ambient;
uniforms->msaa = ext::vulkan::settings::msaa;
uniforms->poissonSamples = shadowSamples;
uniforms->fog.color = metadata.fog.color;
uniforms->fog.color.w = metadata.fog.stepScale;
float timescale = metadata.fog.density.timescale;
uniforms->fog.offset = metadata.fog.density.offset * uf::physics::time::current * timescale;
uniforms->fog.offset.w = metadata.fog.density.scale;
uniforms->fog.densityThreshold = metadata.fog.density.threshold;
uniforms->fog.densityMultiplier = metadata.fog.density.multiplier;
uniforms->fog.absorbtion = metadata.fog.absorbtion;
uniforms->fog.range = metadata.fog.range;
uniforms->mode.type.x = metadataJson["system"]["renderer"]["shader"]["mode"].as<size_t>();
uniforms->mode.type.y = metadataJson["system"]["renderer"]["shader"]["scalar"].as<size_t>();
uniforms->mode.parameters = uf::vector::decode( metadataJson["system"]["renderer"]["shader"]["parameters"], uniforms->mode.parameters );
if ( metadataJson["system"]["renderer"]["shader"]["parameters"][3].as<std::string>() == "time" ) {
uniforms->mode.parameters.w = uf::physics::time::current;
}
std::vector<VkImage> previousTextures;
for ( auto& texture : graphic.material.textures ) previousTextures.emplace_back(texture.image);
graphic.material.textures.clear();
if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) {
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>());
}
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.noise); //this->getComponent<uf::renderer::Texture3D>());
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.skybox); //this->getComponent<uf::renderer::TextureCube>());
size_t updateThreshold = metadata.light.updateThreshold;
size_t textureSlot = 0;
std::vector<pod::Light::Storage> lights;
lights.reserve( metadata.max.lights );
std::vector<pod::Material::Storage> materials;
materials.reserve(maxTextures);
materials.emplace_back().colorBase = {0,0,0,0};
std::vector<pod::Texture::Storage> textures;
textures.reserve(maxTextures);
std::vector<pod::DrawCall::Storage> drawCalls;
drawCalls.reserve(maxTextures);
// add materials
pod::Vector3f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
pod::Vector3f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
for ( auto* g : graphs ) {
auto& graph = *g;
drawCalls.emplace_back(pod::DrawCall::Storage{
materials.size(),
graph.materials.size(),
textures.size(),
graph.textures.size()
});
for ( auto& material : graph.materials ) materials.emplace_back( material.storage );
for ( auto& texture : graph.textures ) textures.emplace_back( texture.storage );
for ( auto& texture : graph.textures ) {
if ( !texture.bind ) continue;
graphic.material.textures.emplace_back().aliasTexture(texture.texture);
++textureSlot;
}
// 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 );
uniforms->lengths.materials = std::min( materials.size(), maxTextures );
uniforms->lengths.textures = std::min( textures.size(), maxTextures );
uniforms->lengths.drawCalls = std::min( drawCalls.size(), maxTextures );
// add lighting
for ( size_t i = 0; i < entities.size() && lights.size() < metadata.max.lights; ++i ) {
auto& info = entities[i];
uf::Entity* entity = info.entity;
auto& transform = entity->getComponent<pod::Transform<>>();
auto& metadata = entity->getComponent<ext::LightBehavior::Metadata>();
auto& camera = entity->getComponent<uf::Camera>();
metadata.renderer.rendered = true;
pod::Light::Storage light;
light.position = info.position;
light.color = info.color;
light.type = info.type;
light.mapIndex = -1;
light.depthBias = info.bias;
if ( info.shadows && entity->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
if ( metadata.renderer.mode == "in-range" && --updateThreshold > 0 ) {
renderMode.execute = true;
}
size_t view = 0;
for ( auto& attachment : renderMode.renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
if ( attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) continue;
graphic.material.textures.emplace_back().aliasAttachment(attachment);
light.mapIndex = textureSlot++;
light.view = camera.getView(view);
light.projection = camera.getProjection(view);
lights.emplace_back(light);
++view;
}
light.mapIndex = -1;
} else {
lights.emplace_back(light);
}
}
{
uniforms->lengths.lights = std::min( lights.size(), metadata.max.lights );
bool shouldUpdate = graphic.material.textures.size() != previousTextures.size();
for ( size_t i = 0; !shouldUpdate && i < previousTextures.size() && i < graphic.material.textures.size(); ++i ) {
if ( previousTextures[i] != graphic.material.textures[i].image )
shouldUpdate = true;
}
size_t lightBufferIndex = renderMode.metadata["lightBufferIndex"].as<size_t>();
graphic.updateBuffer( (void*) lights.data(), uniforms->lengths.lights * sizeof(pod::Light::Storage), lightBufferIndex, false );
if ( shouldUpdate ) {
size_t materialBufferIndex = renderMode.metadata["materialBufferIndex"].as<size_t>();
graphic.updateBuffer( (void*) materials.data(), uniforms->lengths.materials * sizeof(pod::Material::Storage), materialBufferIndex, false );
size_t textureBufferIndex = renderMode.metadata["textureBufferIndex"].as<size_t>();
graphic.updateBuffer( (void*) textures.data(), uniforms->lengths.textures * sizeof(pod::Texture::Storage), textureBufferIndex, false );
size_t drawCallBufferIndex = renderMode.metadata["drawCallBufferIndex"].as<size_t>();
graphic.updateBuffer( (void*) drawCalls.data(), uniforms->lengths.drawCalls * sizeof(pod::DrawCall::Storage), drawCallBufferIndex, false );
graphic.updatePipelines();
}
shader.updateUniform( "UBO", uniform );
}
}
#endif
}
#undef this

View File

@ -14,6 +14,7 @@ namespace ext {
void tick( uf::Object& );
void render( uf::Object& );
void destroy( uf::Object& );
struct Metadata {
struct {
size_t textures = 256;
@ -44,5 +45,7 @@ namespace ext {
std::function<void()> serialize;
std::function<void()> deserialize;
};
void bindBuffers( uf::Object&, const std::string& = "", bool = false );
}
}

View File

@ -0,0 +1,149 @@
#include "behavior.h"
#include <uf/utils/renderer/renderer.h>
#include <uf/utils/math/transform.h>
#include <uf/utils/math/physics.h>
#include <uf/utils/camera/camera.h>
#include <uf/ext/gltf/gltf.h>
#include <uf/engine/asset/asset.h>
#include <uf/ext/xatlas/xatlas.h>
#include "../light/behavior.h"
#include "../scene/behavior.h"
#define COMP_SHADER_USED 1
UF_BEHAVIOR_REGISTER_CPP(ext::VoxelizerBehavior)
#define this (&self)
void ext::VoxelizerBehavior::initialize( uf::Object& self ) {
#if UF_USE_VULKAN
auto& metadata = this->getComponent<ext::VoxelizerBehavior::Metadata>();
auto& sceneTextures = this->getComponent<pod::SceneTextures>();
// initialize voxel map
{
if ( metadata.voxelSize.x == 0 ) metadata.voxelSize.x = 256;
if ( metadata.voxelSize.y == 0 ) metadata.voxelSize.y = 256;
if ( metadata.voxelSize.z == 0 ) metadata.voxelSize.z = 256;
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;
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 );
}
// 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;
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
metadata.renderModeName = "SVOGI:" + std::to_string((int) this->getUid());
uf::renderer::addRenderMode( &renderMode, metadata.renderModeName );
renderMode.metadata["type"] = "svogi";
renderMode.metadata["samples"] = 1;
renderMode.blitter.device = &ext::vulkan::device;
renderMode.width = metadata.fragmentSize.x;
renderMode.height = metadata.fragmentSize.y;
#if COMP_SHADER_USED
renderMode.metadata["shaders"]["compute"] = "/shaders/display/svogi.comp.spv";
renderMode.blitter.descriptor.renderMode = metadata.renderModeName;
renderMode.blitter.descriptor.subpass = -1;
renderMode.blitter.process = true;
#else
renderMode.metadata["shaders"] = false;
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>());
renderMode.bindCallback( renderMode.CALLBACK_BEGIN, [&]( VkCommandBuffer commandBuffer ){
// clear textures
VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.baseMipLevel = 0;
subresourceRange.baseArrayLayer = 0;
subresourceRange.levelCount = 1;
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 );
});
renderMode.bindCallback( renderMode.CALLBACK_END, [&]( VkCommandBuffer commandBuffer ){
// parse voxel lighting
#if COMP_SHADER_USED
if ( renderMode.blitter.initialized ) {
auto& pipeline = renderMode.blitter.getPipeline();
pipeline.record(renderMode.blitter, commandBuffer);
vkCmdDispatch(commandBuffer, metadata.voxelSize.x / metadata.dispatchSize.x, metadata.voxelSize.y / metadata.dispatchSize.y, metadata.voxelSize.z / metadata.dispatchSize.z);
}
#endif
// generate mipmaps
VkImageSubresourceRange subresourceRange = {};
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
);
});
}
#endif
}
void ext::VoxelizerBehavior::tick( uf::Object& self ) {
#if UF_USE_VULKAN
if ( !this->hasComponent<uf::renderer::RenderTargetRenderMode>() ) return;
auto& metadata = this->getComponent<ext::VoxelizerBehavior::Metadata>();
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
renderMode.setTarget("");
if ( renderMode.executed && !metadata.initialized ) {
// renderMode.execute = false;
metadata.initialized = true;
}
#if COMP_SHADER_USED
auto& scene = uf::scene::getCurrentScene();
ext::ExtSceneBehavior::bindBuffers( scene, metadata.renderModeName, true );
#endif
#endif
}
void ext::VoxelizerBehavior::render( uf::Object& self ){}
void ext::VoxelizerBehavior::destroy( uf::Object& self ){
#if UF_USE_VULKAN
if ( this->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
uf::renderer::removeRenderMode( &renderMode, false );
this->deleteComponent<uf::renderer::RenderTargetRenderMode>();
}
#endif
}
#undef this

View File

@ -0,0 +1,31 @@
#pragma once
#include <uf/config.h>
#include <uf/ext/ext.h>
#include <uf/engine/entity/entity.h>
#include <uf/engine/scene/scene.h>
#include <uf/utils/math/vector.h>
#include <uf/utils/math/matrix.h>
namespace ext {
namespace VoxelizerBehavior {
UF_BEHAVIOR_DEFINE_TYPE;
void attach( uf::Object& );
void initialize( uf::Object& );
void tick( uf::Object& );
void render( uf::Object& );
void destroy( uf::Object& );
struct Metadata {
pod::Vector3ui fragmentSize = { 0, 0 };
pod::Vector3ui voxelSize = { 256, 256, 256 };
pod::Vector3ui dispatchSize = { 8, 8, 8 };
std::string renderModeName = "SVOGI";
struct {
pod::Vector3f min = {};
pod::Vector3f max = {};
pod::Matrix4f matrix = uf::matrix::identity();
} extents;
bool initialized = false;
};
}
}