Commit for 2021.04.15.7z
This commit is contained in:
parent
7cae094543
commit
7794e730aa
@ -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;
|
||||
|
||||
687
bin/data/shaders/display/subpass.svogi.frag.glsl
Normal file
687
bin/data/shaders/display/subpass.svogi.frag.glsl
Normal 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);
|
||||
|
||||
}
|
||||
371
bin/data/shaders/display/svogi.comp.glsl
Normal file
371
bin/data/shaders/display/svogi.comp.glsl
Normal 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));
|
||||
}
|
||||
@ -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 ) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
|
||||
136
bin/data/shaders/gltf/voxelize.frag.glsl
Normal file
136
bin/data/shaders/gltf/voxelize.frag.glsl
Normal 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);
|
||||
}
|
||||
63
bin/data/shaders/gltf/voxelize.geom.glsl
Normal file
63
bin/data/shaders/gltf/voxelize.geom.glsl
Normal 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();
|
||||
}
|
||||
@ -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 );
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
};
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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 ) {
|
||||
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 ) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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]));
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
@ -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 );
|
||||
}
|
||||
}
|
||||
149
ext/behaviors/voxelizer/behavior.cpp
Normal file
149
ext/behaviors/voxelizer/behavior.cpp
Normal 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
|
||||
31
ext/behaviors/voxelizer/behavior.h
Normal file
31
ext/behaviors/voxelizer/behavior.h
Normal 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user