Commit for 2021.07.16 23-54-06.7z

This commit is contained in:
mrq 2021-07-16 23:54:00 -05:00
parent 5d9de97436
commit 6d8fbc6ee5
84 changed files with 2645 additions and 2405 deletions

View File

@ -1,5 +1,5 @@
ARCH = win64
CC = $(shell cat "./bin/exe/default.config")
CC = $(shell cat "./bin/exe/default.config")
TARGET_NAME = program
TARGET_EXTENSION = exe
TARGET_LIB_EXTENSION = dll

View File

@ -1,46 +1,52 @@
{
"engine": {
"scenes": {
"start": "SS2",
"start": "McDonalds",
"lights": {
"max": 512,
"max": 64,
"enabled": true
},
"shadows": {
"enabled": true,
"update": 4,
"update": 2,
"max": 8,
"samples": 2,
"experimental mode": 1
},
"textures": {
"max": {
"2D": 512,
"2D": 1024,
"cube": 128,
"3D": 1
}
},
"meshes": {
"interleave": false
},
"matrix": {
"reverseInfinite": true
},
"vxgi": {
"limiter": 0.125,
"size": 64,
"size": 96,
"dispatch": 8,
"cascades": 4,
"cascades": 6,
"cascadePower": 4,
"shadows": 0,
"granularity": 4,
"extents": {
"min": [ -2.5, -2.5, -2.5 ],
"max": [ 2.5, 2.5, 2.5 ]
"min": [ -1.5, -1.5, -1.5 ],
"max": [ 1.5, 1.5, 1.5 ]
}
}
},
"ext": {
"vulkan": {
"validation": {
"enabled": true,
"enabled": false,
"filters": [
"MessageID = 0x4dae5635", // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout (false positive for cubemaps)
"MessageID = 0x71500fba", // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup)
// "MessageID = 0x71500fba", // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup)
"MessageID = 0x609a13b", // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls)
"MessageID = 0x23e43bb7" // UNASSIGNED-CoreValidation-Shader-InputNotProduced (from depth-only calls)
// "MessageID = 0xe91b58a0" // VUID-vkCmdDrawIndexed-None-02686 (?)
@ -66,8 +72,9 @@
"deferred alias output to swapchain": true,
"vsync": true,
"hdr": false,
"vxgi": false,
"deferred sampling": false
"vxgi": true,
"deferred sampling": true,
"culling": false
},
"formats": {
"depth": "D32_SFLOAT",
@ -76,6 +83,10 @@
"position": "R16G16B16A16_SFLOAT"
},
"features": [
"shaderDrawParameters",
"multiDrawIndirect",
"fillModeNonSolid",
"wideLines",
"independentBlend",
"deviceCoherentMemory",
"robustBufferAccess",
@ -117,7 +128,8 @@
// "deferred mode": "deferredSampling",
"deferred reconstruct position": true,
"deferred alias output to swapchain": true,
"hdr": false
"hdr": false,
"culling": true
},
"formats": {
"depth": "D32_SFLOAT",
@ -159,7 +171,7 @@
},
"debug draw": {
"enabled": false,
"rate": 1.0
"rate": 0.0125
}
},
"discord": {
@ -175,7 +187,7 @@
"streams by default": true
},
"memory pool": {
"enabled": false,
"enabled": true,
"subPools": true,
"alignment": 64,
"override": false,
@ -212,8 +224,8 @@
"announce": true
},
"entity": {
"delete children on destroy": false,
"delete components on destroy": false
"delete children on destroy": true,
"delete components on destroy": true
}
}
},

View File

@ -35,7 +35,7 @@
"slope": 1.75,
"shader": 0.000005 //0.000000005
},
"radius": [0.001, 0],
"radius": [0.001, 256.0],
"resolution": 1024,
"shadows": true,
"static": false

View File

@ -2,7 +2,7 @@
"name": "Gui: Loading",
"type": "Object",
"behaviors": [
"GuiBehavior"
// "GuiBehavior"
],
"assets": [
{ "filename": "./mcdonalds.json", "delay": 0 }

View File

@ -5,9 +5,9 @@
"assets": [
// { "filename": "./static.json", "delay": 8 },
// { "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false }
{ "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false }
// { "filename": "./models/mcdonalds/graph.json", "delay": 0, "single threaded": false, "category": "models" }
{ "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
],
"behaviors": [
"LoadingBehavior"
@ -44,7 +44,7 @@
// "filter": "NEAREST",
"flags": {
"ATLAS": true,
"ATLAS": false,
"INVERT": false,
"TRANSFORM": false,
"SKINNED": false,

View File

@ -5,9 +5,9 @@
"assets": [
// { "filename": "./static.json", "delay": 8 },
// { "filename": "./models/sh_mcd.glb", "delay": 0, "single threaded": false }
{ "filename": "./models/sh_mcd.glb", "delay": 0, "single threaded": false }
// { "filename": "./models/sh_mcd/graph.json", "delay": 0, "single threaded": false, "category": "models" }
{ "filename": "./models/sh_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/sh_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
],
"behaviors": [
"LoadingBehavior"

View File

@ -50,12 +50,13 @@
// "lightmap": "./lightmap.png",
"filter": "NEAREST",
"flags": {
"ATLAS": true,
"ATLAS": false,
"INVERT": false,
"TRANSFORM": false,
"SKINNED": false,
"RENDER": true,
// "SEPARATE": false,
"SEPARATE": false,
"NORMALS": false
},

View File

@ -0,0 +1,13 @@
#version 450
#pragma shader_stage(fragment)
layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec3 inColor;
layout (location = 0) out uvec2 outId;
layout (location = 1) out vec2 outNormals;
layout (location = 2) out vec4 outAlbedo;
void main() {
outAlbedo = vec4(inColor, 1);
}

View File

@ -0,0 +1,28 @@
#version 450
#pragma shader_stage(vertex)
#include "../common/structs.h"
layout (constant_id = 0) const uint PASSES = 6;
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inColor;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
} PushConstant;
layout (binding = 0) uniform Camera {
Viewport viewport[PASSES];
} camera;
layout (location = 0) out vec3 outPosition;
layout (location = 1) out vec3 outColor;
void main() {
outPosition = vec3(camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0));
outColor = inColor;
gl_Position = camera.viewport[PushConstant.pass].projection * camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0);
}

View File

@ -24,6 +24,7 @@ void pbr() {
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
const vec3 Liu = vec3(ubo.eyes[surface.pass].view * vec4(light.position, 1)) - surface.position.eye;
const vec3 Li = normalize(Liu);
const bool reverseZ = light.projection[2][2] < 0.00001;
const float Ls = shadowFactor( light, 0.0 );
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;

View File

@ -86,9 +86,9 @@ struct Material {
int indexOcclusion;
int indexMetallicRoughness;
int indexAtlas;
int indexLightmap;
int modeAlpha;
int padding;
};
struct Texture {
@ -107,9 +107,28 @@ struct DrawCommand {
int vertexID; // starting vertex position
uint instanceID; // starting instance position
uint materialID; // material used for draw
uint objectID; //
uint vertices; //
uint padding; //
uint materialID; // material to use for this draw call
uint vertices; // number of vertices used
};
struct Bounds {
vec3 min;
float padding1;
vec3 max;
float padding2;
};
struct Instance {
mat4 model;
vec4 color;
uint materialID;
uint primitiveID;
uint meshID;
uint objectID;
Bounds bounds;
};
struct SurfaceMaterial {
@ -122,7 +141,6 @@ struct SurfaceMaterial {
float roughness;
float occlusion;
int indexLightmap;
};
struct Surface {

View File

@ -1,18 +1,13 @@
#version 450
#pragma shader_stage(vertex)
#if 0
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inUv;
#endif
layout (location = 0) out vec2 outUv;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
outUv = inUv;
gl_Position = vec4(inPos.xy, 0.0, 1.0);
outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f);
}

View File

@ -19,10 +19,6 @@ layout( push_constant ) uniform PushBlock {
uint draw;
} PushConstant;
out gl_PerVertex {
vec4 gl_Position;
};
struct Matrices {
mat4 model[2];
};
@ -34,9 +30,8 @@ layout (binding = 0) uniform UBO {
} ubo;
void main() {
outUv = inUv;
outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
outCursor = ubo.cursor;
outAlpha = 1;
gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(inPos.xy, 0.0, 1.0);
gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f);
}

View File

@ -53,9 +53,13 @@ layout (binding = 4) uniform UBO {
uint shadowSamples;
uint indexSkybox;
} ubo;
layout (std140, binding = 5) readonly buffer Lights {
Light lights[];
/*
layout (std140, binding = 5) readonly buffer DrawCommands {
DrawCommand drawCommands[];
};
*/
layout (std140, binding = 5) readonly buffer Instances {
Instance instances[];
};
layout (std140, binding = 6) readonly buffer Materials {
Material materials[];
@ -63,8 +67,8 @@ layout (std140, binding = 6) readonly buffer Materials {
layout (std140, binding = 7) readonly buffer Textures {
Texture textures[];
};
layout (std140, binding = 8) readonly buffer DrawCommands {
DrawCommand drawCommands[];
layout (std140, binding = 8) readonly buffer Lights {
Light lights[];
};
layout (binding = 9) uniform sampler2D samplerTextures[TEXTURES];
@ -161,15 +165,17 @@ void populateSurface() {
#endif
surface.normal.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0.0) );
const uint drawID = ID.x - 1;
const uint instanceID = ID.y - 1;
if ( ID.x == 0 || ID.y == 0 ) {
surface.fragment.rgb = texture( samplerCubemaps[ubo.indexSkybox], surface.ray.direction ).rgb;
surface.fragment.a = 0.0;
postProcess();
return;
}
const uint drawId = ID.x - 1;
const DrawCommand drawCommand = drawCommands[drawId];
surface.material.id = ID.y + drawCommand.materialID - 1;
// const DrawCommand drawCommand = drawCommands[drawID];
const Instance instance = instances[instanceID];
surface.material.id = instance.materialID;
const Material material = materials[surface.material.id];
surface.material.albedo = material.colorBase;
surface.fragment = material.colorEmissive;
@ -180,8 +186,6 @@ void populateSurface() {
surface.uv = resolve(samplerUv, ubo.msaa).xy;
#endif
const float mip = mipLevel(inUv.xy);
// if ( validTextureIndex( drawCommand.textureIndex, material.indexAlbedo ) ) {
// surface.material.albedo = sampleTexture( drawCommand.textureIndex, drawCommand.textureSlot, material.indexAlbedo, material.indexAtlas, mip );
if ( validTextureIndex( material.indexAlbedo ) ) {
surface.material.albedo = sampleTexture( material.indexAlbedo, mip );
}
@ -196,8 +200,6 @@ void populateSurface() {
}
// Emissive textures
// if ( validTextureIndex( drawCommand.textureIndex, material.indexEmissive ) ) {
// surface.fragment += sampleTexture( drawCommand.textureIndex, drawCommand.textureSlot, material.indexEmissive, material.indexAtlas, mip );
if ( validTextureIndex( material.indexEmissive ) ) {
surface.fragment += sampleTexture( material.indexEmissive, mip );
}
@ -217,7 +219,7 @@ void populateSurface() {
void directLighting() {
const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb;
surface.fragment.rgb += (0 <= surface.material.indexLightmap) ? (surface.material.albedo.rgb + ambient) : (surface.material.albedo.rgb * ambient);
if ( ubo.lights == 0 ) { surface.fragment.rgb = surface.material.albedo.rgb; return; }
#if PBR
pbr();
#elif LAMBERT

View File

@ -1,9 +1,10 @@
#version 450
#pragma shader_stage(vertex)
#if 0
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inUv;
#endif
layout (location = 0) out vec2 outUv;
layout (location = 1) out flat uint outPushConstantPass;
@ -18,8 +19,11 @@ out gl_PerVertex {
void main() {
outUv = inUv;
outPushConstantPass = PushConstant.pass;
outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f);
#if 0
outUv = inUv;
gl_Position = vec4(inPos.xy, 0.0, 1.0);
#endif
}

View File

@ -36,9 +36,13 @@ layout (binding = 4) uniform UBO {
uint shadowSamples;
uint indexSkybox;
} ubo;
layout (std140, binding = 5) readonly buffer Lights {
Light lights[];
/*
layout (std140, binding = 5) readonly buffer DrawCommands {
DrawCommand drawCommands[];
};
*/
layout (std140, binding = 5) readonly buffer Instances {
Instance instances[];
};
layout (std140, binding = 6) readonly buffer Materials {
Material materials[];
@ -46,8 +50,8 @@ layout (std140, binding = 6) readonly buffer Materials {
layout (std140, binding = 7) readonly buffer Textures {
Texture textures[];
};
layout (std140, binding = 8) readonly buffer DrawCommands {
DrawCommand drawCommands[];
layout (std140, binding = 8) readonly buffer Lights {
Light lights[];
};
layout (binding = 9) uniform sampler2D samplerTextures[TEXTURES];
@ -76,21 +80,21 @@ void main() {
surface.position.world = vec3( inverse(ubo.vxgi.matrix) * vec4( surface.position.eye, 1.0f ) );
const uvec2 ID = uvec2(imageLoad(voxelId[CASCADE], ivec3(tUvw) ).xy);
const uint drawID = ID.x - 1;
const uint instanceID = ID.y - 1;
if ( ID.x == 0 || ID.y == 0 ) {
imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(0));
continue;
}
const uint drawId = ID.x - 1;
const DrawCommand drawCommand = drawCommands[drawId];
surface.material.id = ID.y + drawCommand.materialID - 1;
// const DrawCommand drawCommand = drawCommands[drawID];
const Instance instance = instances[instanceID];
surface.material.id = instance.materialID;
const Material material = materials[surface.material.id];
surface.material.albedo = material.colorBase;
surface.fragment = material.colorEmissive;
#if DEFERRED_SAMPLING
surface.uv = imageLoad(voxelUv[CASCADE], ivec3(tUvw) ).xy;
// if ( validTextureIndex( drawCommand.textureIndex, material.indexAlbedo ) ) {
// surface.material.albedo = sampleTexture( drawCommand.textureIndex, drawCommand.textureSlot, material.indexAlbedo, material.indexAtlas );
if ( validTextureIndex( material.indexAlbedo ) ) {
surface.material.albedo = sampleTexture( material.indexAlbedo );
}
@ -106,8 +110,6 @@ void main() {
}
// Emissive textures
// if ( validTextureIndex( drawCommand.textureIndex, material.indexEmissive ) ) {
// surface.fragment += sampleTexture( drawCommand.textureIndex, drawCommand.textureSlot, material.indexEmissive, material.indexAtlas );
if ( validTextureIndex( material.indexEmissive ) ) {
surface.fragment += sampleTexture( material.indexEmissive );
}

View File

@ -1,50 +0,0 @@
#version 450
#pragma shader_stage(vertex)
layout (constant_id = 0) const uint PASSES = 6;
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUv;
layout (location = 2) in vec2 inSt;
layout (location = 3) in vec3 inNormal;
layout (location = 4) in vec4 inTangent;
layout (location = 5) in uvec2 inId;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
} PushConstant;
layout (std140, binding = 0) readonly buffer Models {
mat4 models[];
};
layout (location = 0) out vec2 outUv;
layout (location = 1) out vec4 outColor;
layout (location = 2) out vec3 outNormal;
layout (location = 3) out mat3 outTBN;
layout (location = 6) out vec3 outPosition;
layout (location = 7) out ivec4 outId;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
outUv = inUv;
outColor = vec4(1.0);
outId = ivec4(inId, PushConstant.pass, PushConstant.draw);
mat4 model = models.length() <= 0 ? mat4(1.0) : models[int(inId.x)];
outPosition = vec3(model * vec4(inPos.xyz, 1.0));
outNormal = vec3(model * vec4(inNormal.xyz, 0.0));
outNormal = normalize(outNormal);
{
vec3 T = vec3(model * vec4(inTangent.xyz, 0.0));
vec3 N = outNormal;
vec3 B = cross(N, T) * inTangent.w;
outTBN = mat3( T, B, N );
}
gl_Position = vec4(inSt * 2.0 - 1.0, 0.0, 1.0);
}

View File

@ -45,5 +45,5 @@ void main() {
A = textureLod( samplerTextures[0], inSt, mip );
#endif
outNormals = encodeNormals( N );
outId = ivec2(inId.w+1, inId.y+1);
outId = ivec2(inId.x+1, inId.y+1);
}

View File

@ -0,0 +1,6 @@
#version 450
#pragma shader_stage(vertex)
#define INSTANCED 1
#define SKINNED 0
#include "../base.vert.h"

View File

@ -1,6 +1,7 @@
#extension GL_EXT_nonuniform_qualifier : enable
#define CUBEMAPS 1
// #define MAX_TEXTURES TEXTURES
#define MAX_TEXTURES textures.length()
layout (constant_id = 0) const uint TEXTURES = 1;
@ -8,7 +9,6 @@ layout (constant_id = 0) const uint TEXTURES = 1;
#include "../common/structs.h"
layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES];
layout (std140, binding = 1) readonly buffer Materials {
Material materials[];
};
@ -35,28 +35,28 @@ layout (location = 1) out vec2 outNormals;
#endif
void main() {
const uint drawID = uint(inId.x);
const uint instanceID = uint(inId.y);
const uint materialID = uint(inId.z);
const float mip = mipLevel(inUv.xy);
const vec2 uv = wrap(inUv.xy);
const vec3 P = inPosition;
vec3 N = inNormal;
vec4 A = vec4(0, 0, 0, 0);
#if DEFERRED_SAMPLING
vec4 outAlbedo = vec4(0,0,0,0);
#endif
#if !DEFERRED_SAMPLING || CAN_DISCARD
const int materialId = int(inId.y);
Material material = materials[materialId];
Material material = materials[materialID];
float M = material.factorMetallic;
float R = material.factorRoughness;
float AO = material.factorOcclusion;
// sample albedo
const bool useAtlas = validTextureIndex( material.indexAtlas );
Texture textureAtlas;
if ( useAtlas ) textureAtlas = textures[material.indexAtlas];
if ( !validTextureIndex( material.indexAlbedo ) ) discard; {
Texture t = textures[material.indexAlbedo];
const Texture t = textures[material.indexAlbedo];
A = textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip );
// alpha mode OPAQUE
if ( material.modeAlpha == 0 ) {
@ -110,5 +110,5 @@ void main() {
outUvs = wrap(inUv.xy);
#endif
outNormals = encodeNormals( N );
outId = ivec2(inId.w+1, inId.y+1);
outId = uvec2(drawID + 1, instanceID + 1);
}

View File

@ -1,5 +1,5 @@
layout (constant_id = 0) const uint PASSES = 6;
#extension GL_ARB_shader_draw_parameters : enable
#include "../common/structs.h"
layout (location = 0) in vec3 inPos;
@ -7,10 +7,9 @@ layout (location = 1) in vec2 inUv;
layout (location = 2) in vec2 inSt;
layout (location = 3) in vec3 inNormal;
layout (location = 4) in vec4 inTangent;
layout (location = 5) in uvec2 inId;
#if SKINNED
layout (location = 6) in uvec4 inJoints;
layout (location = 7) in vec4 inWeights;
layout (location = 5) in uvec4 inJoints;
layout (location = 6) in vec4 inWeights;
#endif
layout( push_constant ) uniform PushBlock {
@ -18,31 +17,23 @@ layout( push_constant ) uniform PushBlock {
uint draw;
} PushConstant;
layout (binding = 3) uniform Camera {
Viewport viewport[PASSES];
} camera;
#if SKINNED && INSTANCED
layout (std140, binding = 4) readonly buffer Models {
mat4 models[];
};
/*
layout (std140, binding = 4) readonly buffer DrawCommands {
DrawCommand drawCommands[];
};
*/
layout (std140, binding = 4) readonly buffer Instances {
Instance instances[];
};
#if SKINNED
layout (std140, binding = 5) readonly buffer Joints {
mat4 joints[];
};
#else
layout (binding = 4) uniform UBO {
mat4 model;
} ubo;
#if SKINNED
layout (std140, binding = 5) readonly buffer Joints {
mat4 joints[];
};
#elif INSTANCED
layout (std140, binding = 5) readonly buffer Models {
mat4 models[];
};
#endif
#endif
layout (location = 0) out vec2 outUv;
@ -64,21 +55,23 @@ vec4 snap(vec4 vertex, vec2 resolution) {
void main() {
outUv = inUv;
outSt = inSt;
outColor = vec4(1); // ubo.color;
outId = ivec4(inId, PushConstant.pass, PushConstant.draw);
const mat4 view = camera.viewport[PushConstant.pass].view;
const mat4 projection = camera.viewport[PushConstant.pass].projection;
#if SKINNED
mat4 skinned = joints.length() <= 0 ? mat4(1.0) : inWeights.x * joints[int(inJoints.x)] + inWeights.y * joints[int(inJoints.y)] + inWeights.z * joints[int(inJoints.z)] + inWeights.w * joints[int(inJoints.w)];
const mat4 skinned = joints.length() <= 0 ? mat4(1.0) : inWeights.x * joints[int(inJoints.x)] + inWeights.y * joints[int(inJoints.y)] + inWeights.z * joints[int(inJoints.z)] + inWeights.w * joints[int(inJoints.w)];
#else
mat4 skinned = mat4(1.0);
#endif
#if INSTANCED
mat4 model = models.length() <= 0 ? skinned : (models[int(inId.x)] * skinned);
#else
mat4 model = ubo.model * skinned;
const mat4 skinned = mat4(1.0);
#endif
const uint drawID = gl_DrawIDARB;
// const DrawCommand drawCommand = drawCommands[drawID];
const uint instanceID = gl_InstanceIndex;
const Instance instance = instances[instanceID];
const uint materialID = instance.materialID;
const mat4 model = instances.length() <= 0 ? skinned : (instance.model * skinned);
outId = ivec4(drawID, instanceID, materialID, PushConstant.pass);
outColor = instance.color;
outPosition = vec3(model * vec4(inPos.xyz, 1.0));
outNormal = vec3(model * vec4(inNormal.xyz, 0.0));
outNormal = normalize(outNormal);

View File

@ -0,0 +1,267 @@
#version 450
#pragma shader_stage(compute)
#extension GL_EXT_nonuniform_qualifier : enable
layout (constant_id = 0) const uint PASSES = 6;
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
#define COMPUTE 1
#include "../common/macros.h"
#include "../common/structs.h"
layout( push_constant ) uniform PushBlock {
uint pass;
uint passes;
} PushConstant;
layout (binding = 0) uniform Camera {
Viewport viewport[PASSES];
} camera;
layout (std140, binding = 1) buffer DrawCommands {
DrawCommand drawCommands[];
};
layout (std140, binding = 2) buffer Instances {
Instance instances[];
};
struct Frustum {
vec4 planes[6];
};
float inside( vec3 v, vec3 min, vec3 max ) {
vec3 s = step(min, v) - step(max, v);
return s.x * s.y * s.z;
}
/*
T f = 1 / tan( fov / 2 );
return pod::Matrix4t<T>({
f / raidou, 0, 0, 0,
0, -f, 0, 0,
0, 0, 0, 1,
0, 0, znear, 0
});
*/
vec4 normalizePlane( vec4 p ) {
return p / length(p.xyz);
}
bool frustumCull( uint id ) {
if ( PushConstant.passes == 0 ) return true;
const DrawCommand drawCommand = drawCommands[id];
const Instance instance = instances[drawCommand.instanceID];
bool visible = false;
for ( uint pass = 0; pass < PushConstant.passes; ++pass ) {
// return if our camera position is inside the AABB
vec3 camPos = vec3( inverse(camera.viewport[pass].view)[3] );
if ( instance.bounds.min.x <= camPos.x && camPos.x <= instance.bounds.max.x && instance.bounds.min.y <= camPos.y && camPos.y <= instance.bounds.max.y && instance.bounds.min.z <= camPos.z && camPos.z <= instance.bounds.max.z ) return true;
// sphere based one, source of this block uses reverse infinite Z, but would be nice if it used AABB
#if 0
vec3 min = vec3(camera.viewport[pass].view * instance.model * vec4(instance.bounds.min, 1));
vec3 max = vec3(camera.viewport[pass].view * instance.model * vec4(instance.bounds.max, 1));
vec3 center = (max + min) * 0.5;
vec3 extent = (max - min) * 0.5;
float radius = length(extent);
mat4 projectionT = transpose(camera.viewport[pass].projection);
vec4 frustumX = normalizePlane(projectionT[3] + projectionT[0]); // x + w < 0
vec4 frustumY = normalizePlane(projectionT[3] + projectionT[1]); // y + w < 0
vec4 frustum = vec4( frustumX.x, frustumX.z, frustumY.y, frustumY.z );
visible = visible && center.z * frustum[1] - abs(center.x) * frustum[0] > -radius;
visible = visible && center.z * frustum[3] - abs(center.y) * frustum[2] > -radius;
// optimized version of the below blocks
#elif 1
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model;
vec3 min = vec3(mat * vec4(instance.bounds.min, 1));
vec3 max = vec3(mat * vec4(instance.bounds.max, 1));
vec3 center = (max + min) * 0.5;
vec3 extent = (max - min) * 0.5;
vec4 planes[6]; {
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 2; ++j) {
planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]);
planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]);
planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]);
planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]);
planes[i*2+j] = normalizePlane( planes[i*2+j] );
}
}
for ( uint p = 0; p < 6; ++p ) {
if ( dot(center + extent * sign(planes[p].xyz), planes[p].xyz ) > -planes[p].w ) return true;
}
// transforms each corner into clip space
// an AABB is not visible if a plane has all 8 corners outside of it
#elif 0
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model;
vec4 corners[9] = {
vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ),
vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ),
vec4( (instance.bounds.max + instance.bounds.min) * 0.5, 1.0 ),
};
for ( uint p = 0; p < 9; ++p ) {
vec4 t = mat * corners[p];
if ( -t.w <= t.x && t.x <= t.w && -t.w <= t.y && t.y <= t.w ) return true;
}
// "optimized" version of the next block, compares bounds to each plane
// an AABB is not visible if a plane has all 8 corners outside of it
#elif 0
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model;
vec4 planes[6]; {
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 2; ++j) {
planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]);
planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]);
planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]);
planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]);
planes[i*2+j] = normalizePlane( planes[i*2+j] );
}
}
for ( uint p = 0; p < 6; ++p ) {
float d = max(instance.bounds.min.x * planes[p].x, instance.bounds.max.x * planes[p].x)
+ max(instance.bounds.min.y * planes[p].y, instance.bounds.max.y * planes[p].y)
+ max(instance.bounds.min.z * planes[p].z, instance.bounds.max.z * planes[p].z);
if ( d > -planes[p].w ) return true;
}
#else
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model;
vec4 corners[9] = {
vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ),
vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ),
vec4( (instance.bounds.max + instance.bounds.min) * 0.5, 1.0 ),
};
vec4 planes[6]; {
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 2; ++j) {
planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]);
planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]);
planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]);
planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]);
planes[i*2+j] = normalizePlane( planes[i*2+j] );
}
}
for ( uint p = 0; p < 9; ++p ) corners[p] = mat * corners[p];
for ( uint p = 0; p < 6; ++p ) {
for ( uint q = 0; q < 9; ++q ) {
if ( dot( corners[q], planes[p] ) > 0 ) return true;
}
return false;
}
#endif
}
return visible;
}
void main() {
const uint gID = gl_GlobalInvocationID.x;
if ( !(0 <= gID && gID < drawCommands.length()) ) return;
drawCommands[gID].instances = frustumCull( gID ) ? 1 : 0;
}
/*
Frustum frustum;
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 2; ++j) {
frustum.planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]);
frustum.planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]);
frustum.planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]);
frustum.planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]);
frustum.planes[i*2+j]*= length(frustum.planes[i*2+j].xyz);
}
for ( uint i = 0; i < 6; ++i ) {
vec4 plane = frustum.planes[i];
float d = dot(instance.bounds.center, plane.xyz);
float r = dot(instance.bounds.extent, abs(plane.xyz));
bool inside = d + r > -plane.w;
if ( !inside ) return 0;
}
return true;
*/
/*
vec4 plane;
vec4 center = vec4( (max + min) * 0.5, 1 );
vec4 extent = vec4( (max - min) * 0.5, 1 );
center = mat * center;
extent = mat * extent;
center.xyz /= center.w;
extent.xyz /= extent.w;
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][0]; // left
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
if ( visible ) return true;
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][0]; // right
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
if ( visible ) return true;
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][1]; // bottom
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
if ( visible ) return true;
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][1]; // top
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
if ( visible ) return true;
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][2]; // near
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
if ( visible ) return true;
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][2]; // far
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
if ( visible ) return true;
*/
/*
for ( uint p = 0; p < 8; ++p ) {
vec4 t = corners[p];
float w = abs(t.w);
visible = -w <= t.x && t.x <= w && -w <= t.y && t.y <= w && 0 <= t.z && t.z <= w; // && -w <= t.z && t.z <= w;
}
*/
/*
mat4 convert( mat4 proj ) {
float f = -proj[1][1];
float raidou = f / proj[0][0];
float zNear = proj[3][2];
float zFar = 32;
float range = zNear - zFar;
float Sx = f * raidou;
float Sy = f;
float Sz = (-zNear - zFar) / range;
float Pz = 2 * zFar * zNear / range;
mat4 new = mat4(1.0);
new[0][0] = Sx;
new[1][1] = -Sy;
new[2][2] = Sz;
new[3][2] = Pz;
new[2][3] = 1;
return new;
}
*/

View File

@ -0,0 +1,58 @@
#version 450
#pragma shader_stage(fragment)
#extension GL_EXT_nonuniform_qualifier : enable
#define CUBEMAPS 1
// #define MAX_TEXTURES TEXTURES
#define MAX_TEXTURES textures.length()
layout (constant_id = 0) const uint TEXTURES = 1;
#include "../common/macros.h"
#include "../common/structs.h"
layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES];
layout (std140, binding = 1) readonly buffer Materials {
Material materials[];
};
layout (std140, binding = 2) readonly buffer Textures {
Texture textures[];
};
#include "../common/functions.h"
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;
void main() {
const uint drawID = uint(inId.x);
const uint instanceID = uint(inId.y);
const uint materialID = uint(inId.z);
const float mip = mipLevel(inUv.xy);
const vec2 uv = wrap(inUv.xy);
vec4 A = vec4(0, 0, 0, 0);
const Material material = materials[materialID];
// sample albedo
if ( !validTextureIndex( material.indexAlbedo ) ) discard; {
const Texture t = textures[material.indexAlbedo];
A = textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip );
// alpha mode OPAQUE
if ( material.modeAlpha == 0 ) {
A.a = 1;
// alpha mode BLEND
} else if ( material.modeAlpha == 1 ) {
// alpha mode MASK
} else if ( material.modeAlpha == 2 ) {
if ( A.a < abs(material.factorAlphaCutoff) ) discard;
A.a = 1;
}
// if ( A.a < 1 - 0.00001 ) discard;
}
}

View File

@ -49,7 +49,7 @@ layout (location = 1) out vec2 outNormals;
#endif
void main() {
const uint CASCADE = inId.z;
const uint CASCADE = inId.w;
if ( CASCADES <= CASCADE ) discard;
const vec3 P = inPosition.xzy * 0.5 + 0.5;
if ( abs(P.x) > 1 || abs(P.y) > 1 || abs(P.z) > 1 ) discard;
@ -58,20 +58,19 @@ void main() {
const vec3 N = inNormal;
const vec2 uv = wrap(inUv.xy);
const float mip = 0; // mipLevel(inUv.xy);
const int materialId = int(inId.y);
const Material material = materials[materialId];
const uint drawID = int(inId.x);
const uint instanceID = int(inId.y);
const uint materialID = int(inId.z);
Material material = materials[materialID];
const float M = material.factorMetallic;
const float R = material.factorRoughness;
const float AO = material.factorOcclusion;
// sample albedo
const bool useAtlas = validTextureIndex( material.indexAtlas );
Texture textureAtlas;
if ( useAtlas ) textureAtlas = textures[material.indexAtlas];
if ( !validTextureIndex( material.indexAlbedo ) ) discard; {
Texture t = textures[material.indexAlbedo];
A = textureLod( samplerTextures[nonuniformEXT((useAtlas) ? textureAtlas.index : t.index)], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
const Texture t = textures[material.indexAlbedo];
A = textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip );
// alpha mode OPAQUE
if ( material.modeAlpha == 0 ) {
A.a = 1;
@ -107,7 +106,7 @@ void main() {
imageStore(voxelDepth[CASCADE], uvw, vec4(inDepth, 0, 0, 0));
#endif
imageStore(voxelId[CASCADE], uvw, uvec4(uvec2(inId.w+1, inId.y+1), 0, 0));
imageStore(voxelId[CASCADE], uvw, uvec4(uvec2(drawID + 1, instanceID + 1), 0, 0));
imageStore(voxelNormal[CASCADE], uvw, vec4(encodeNormals( normalize( N ) ), 0, 0));
#if BLEND
// GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA

View File

@ -47,7 +47,7 @@ void main(){
A = N.z > N[A] ? 2 : A;
#endif
const uint CASCADE = inId[0].z;
const uint CASCADE = inId[0].w;
vec3 P[3] = {
vec3( ubo.voxel * vec4( inPosition[0], 1 ) ) / cascadePower(CASCADE),
vec3( ubo.voxel * vec4( inPosition[1], 1 ) ) / cascadePower(CASCADE),

View File

@ -90,6 +90,11 @@ void client::initialize() {
client::window.setMousePosition(client::window.getSize()/2);
}
});
uf::hooks.addHook( "window:Mouse.Lock", [&](){
if ( client::window.hasFocus() ) {
client::window.setMousePosition(client::window.getSize()/2);
}
});
uf::hooks.addHook( "window:Closed", [&]( ext::json::Value& json ){
client::ready = false;
} );

View File

@ -58,46 +58,6 @@ int main(int argc, char** argv){
signal(SIGABRT, ::handlers::abrt);
signal(SIGSEGV, ::handlers::segv);
{
uf::Mesh mesh;
mesh.bind<pod::Vertex_2F2F, uint16_t>();
mesh.insertVertices<pod::Vertex_2F2F>({
{ {-1.0f, 1.0f}, {0.0f, 1.0f}, },
{ {-1.0f, -1.0f}, {0.0f, 0.0f}, },
{ {1.0f, -1.0f}, {1.0f, 0.0f}, },
{ {1.0f, 1.0f}, {1.0f, 1.0f}, }
});
mesh.insertIndices<uint16_t>({
0, 1, 2, 2, 3, 0
});
/*
mesh.bind<pod::Vertex_3F2F3F>();
mesh.insertVertices<pod::Vertex_3F2F3F>({
{{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f, 7.0f}},
{{8.0f, 9.0f, 10.0f}, {11.0f, 12.0f}, {13.0f, 14.0f, 15.0f}},
{{16.0f, 17.0f, 18.0f}, {19.0f, 20.0f}, {21.0f, 22.0f, 23.0f}},
});
mesh.insertIndices<uint32_t>({
0, 1, 2
});
*/
mesh.print();
/*
auto& buffer = mesh.buffers[0 <= mesh.vertex.interleaved && mesh.vertex.interleaved < mesh.buffers.size() ? mesh.vertex.interleaved :];
uint8_t* pointer = (uint8_t*) buffer.data();
while ( pointer < (uint8_t*) buffer.data() + buffer.size() ) {
for ( auto& attribute : mesh.vertex.attributes ) {
float* vector = pointer + attrribute.descriptor.offset;
for ( auto i = 0; i < attribute.descriptor.components; ++i ) {
UF_MSG_DEBUG( attribute.descriptor.name << ": " << vector[i] );
}
pointer += attribute.descriptor.size;
}
}
*/
}
client::initialize();
ext::initialize();

View File

@ -20,8 +20,12 @@
#if defined(__CYGWIN__)
#define to_string(var) string(var)
#endif
#define _WIN32_WINNT 0x0600
#define WINVER 0x0600
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#ifndef WINVER
#define WINVER 0x0600
#endif
#define UF_IO_ROOT "./data/"
#elif defined(linux) || defined(__linux)

View File

@ -5,7 +5,7 @@
#include <uf/utils/math/transform.h>
#include <uf/utils/mesh/mesh.h>
#include <uf/utils/renderer/renderer.h>
#include <uf/utils/memory/fifo_map.h>
#include <uf/utils/memory/unordered_map.h>
#include <queue>
@ -23,28 +23,27 @@ namespace pod {
uf::Serializer metadata;
pod::Node root;
uf::stl::vector<pod::Node> nodes; // node's position corresponds to its drawCommand and instance
uf::stl::vector<pod::Node> nodes; //
// Render information
uf::stl::vector<uf::stl::vector<pod::DrawCommand>> drawCommands; // draws to dispatch, one per primitive, gets copied per rendermode
uf::stl::vector<uf::stl::string> instances; //
uf::stl::vector<uf::stl::string> primitives; //
uf::stl::vector<uf::stl::string> drawCommands; //
uf::stl::vector<uf::stl::string> meshes; //
uf::stl::vector<pod::Instance> instances; // instance data to use, gets copied per rendermode
uf::stl::vector<uf::stl::string> images; //
uf::stl::vector<uf::stl::string> materials; //
uf::stl::vector<uf::stl::string> textures; //
uf::stl::vector<uf::stl::string> meshes; // collection of primitives (stored as meshes, by material)
uf::stl::vector<uf::stl::string> images; // references global pool of images
uf::stl::vector<uf::stl::string> materials; // references global pool of materials
uf::stl::vector<uf::stl::string> textures; // references global pool of textures
uf::stl::vector<uf::stl::string> texture2Ds; // references global pool of texture2Ds
uf::stl::vector<uf::stl::string> samplers; // references global pool of samplers
uf::stl::vector<uf::stl::string> texture2Ds; //
uf::stl::vector<uf::stl::string> samplers; //
// Lighting information
uf::stl::unordered_map<uf::stl::string, pod::Light> lights;
// Animations
uf::stl::vector<Skin> skins;
uf::stl::unordered_map<uf::stl::string, Animation> animations;
uf::stl::vector<uf::stl::string> skins;
uf::stl::vector<uf::stl::string> animations;
// Animation queue
std::queue<uf::stl::string> sequence;
struct {
@ -61,15 +60,55 @@ namespace pod {
// Local storage, used for save/load
struct Storage {
uf::stl::fifo_map<uf::stl::string, uf::Atlas> atlases;
uf::stl::fifo_map<uf::stl::string, uf::Image> images;
uf::stl::fifo_map<uf::stl::string, pod::Mesh> meshes;
uf::stl::fifo_map<uf::stl::string, pod::Material> materials;
uf::stl::fifo_map<uf::stl::string, pod::Texture> textures;
template<typename T, typename Key = uf::stl::string>
struct KeyMap {
public:
uf::stl::vector<Key> keys;
uf::stl::unordered_map<Key, T> map;
uf::stl::fifo_map<uf::stl::string, uf::renderer::Texture2D> texture2Ds;
uf::stl::fifo_map<uf::stl::string, uf::renderer::Sampler> samplers;
};
T& operator[]( const Key& key ) {
if ( map.count( key ) == 0 ) keys.emplace_back( key );
return map[key];
}
void reserve( size_t i ) {
keys.reserve(i);
map.reserve(i);
}
};
KeyMap<pod::Instance> instances;
KeyMap<uf::stl::vector<pod::Primitive>> primitives;
KeyMap<uf::stl::vector<pod::DrawCommand>> drawCommands;
KeyMap<uf::Mesh> meshes;
KeyMap<uf::Image> images;
KeyMap<pod::Material> materials;
KeyMap<pod::Texture> textures;
KeyMap<uf::renderer::Sampler> samplers;
uf::stl::vector<pod::Light> lights;
KeyMap<pod::Skin> skins;
KeyMap<pod::Animation> animations;
// maps without direct analogues
KeyMap<uf::Atlas> atlases;
KeyMap<pod::Matrix4f> joints;
KeyMap<uf::renderer::Texture2D> texture2Ds;
KeyMap<uf::Entity*> entities;
uf::stl::vector<uf::renderer::Texture2D> shadow2Ds;
uf::stl::vector<uf::renderer::TextureCube> shadowCubes;
struct Buffer {
uf::renderer::Buffer camera;
uf::renderer::Buffer drawCommands;
uf::renderer::Buffer instance;
uf::renderer::Buffer joint;
uf::renderer::Buffer material;
uf::renderer::Buffer texture;
uf::renderer::Buffer light;
} buffers;
} storage;
};
}
@ -100,6 +139,11 @@ namespace uf {
void UF_API update( pod::Graph&, pod::Node& );
void UF_API destroy( pod::Graph& );
void UF_API initialize();
void UF_API tick();
void UF_API render();
void UF_API destroy();
pod::Graph UF_API load( const uf::stl::string&, const uf::Serializer& = ext::json::null() );
void UF_API save( const pod::Graph&, const uf::stl::string& );

View File

@ -4,30 +4,36 @@ namespace pod {
uint32_t instances = 0; // instance count
uint32_t indexID = 0; // starting triangle position
int32_t vertexID = 0; // starting vertex position
uint32_t instanceID = 0; // starting instance position
uint32_t materialID = 0;
uint32_t objectID = 0;
uint32_t vertices = 0;
// extra data
uint32_t padding1 = 0; //
uint32_t padding2 = 0; //
uint32_t vertices = 0; //
};
struct UF_API Instance {
pod::Matrix4f model;
pod::Vector4f color = {1,1,1,1};
alignas(4) uint32_t materialID = 0;
alignas(4) uint32_t padding1 = 0;
alignas(4) uint32_t padding2 = 0;
alignas(4) uint32_t padding3 = 0;
alignas(4) uint32_t primitiveID = 0;
alignas(4) uint32_t meshID = 0;
alignas(4) uint32_t objectID = 0;
struct {
pod::Vector3f min = {};
struct Bounds {
pod::Vector3f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
alignas(4) float padding1 = 0;
pod::Vector3f max = {};
pod::Vector3f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
alignas(4) float padding2 = 0;
} bounds;
};
struct Primitive {
pod::DrawCommand drawCommand;
pod::Instance instance;
};
struct UF_API Material {
pod::Vector4f colorBase = { 0, 0, 0, 0 };
pod::Vector4f colorEmissive = { 0, 0, 0, 0 };
@ -72,11 +78,6 @@ namespace pod {
float depthBias = 0;
};
//
struct UF_API Mesh {
uf::stl::vector<pod::DrawCommand> drawCommands;
uf::Mesh mesh;
};
//
struct UF_API Skin {
uf::stl::string name = "";

View File

@ -58,6 +58,12 @@ namespace ext {
// collider for mesh (static or dynamic)
pod::Bullet& create( uf::Object&, const uf::Mesh&, bool );
pod::Bullet& create( uf::Object&, const void* verticesPointer, size_t verticesCount, size_t verticesStride, const void* indicesPointer, size_t indicesCount, size_t indicesStride, bool );
template<typename T, typename U>
pod::Bullet& create( uf::Object& o, const uf::Mesh_T<T,U>& m, bool b ) {
return create( o, m.vertices.data() + offsetof(T, position), m.vertices.size(), sizeof(T), m.indices.data(), m.indices.size(), sizeof(U), b );
}
// collider for boundingbox
pod::Bullet& UF_API create( uf::Object&, const pod::Vector3f&, float );
// collider for capsule

View File

@ -37,9 +37,9 @@ namespace ext {
extern UF_API bool multiview;
extern UF_API bool vsync;
extern UF_API bool hdr;
extern UF_API bool frustrumCull;
extern UF_API bool vxgi;
extern UF_API bool deferredSampling;
extern UF_API bool culling;
}
namespace formats {

View File

@ -19,11 +19,11 @@ namespace ext {
VkDeviceSize alignment = 0;
void* mapped = nullptr;
VkBufferUsageFlags usage;
VkMemoryPropertyFlags memoryProperties;
VkBufferUsageFlags usage = 0;
VkMemoryPropertyFlags memoryProperties = 0;
VmaAllocation allocation;
VmaAllocationInfo allocationInfo;
VmaAllocation allocation = {};
VmaAllocationInfo allocationInfo = {};
void* map( VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0 );
void unmap();
@ -49,7 +49,7 @@ namespace ext {
};
struct UF_API Buffers {
uf::stl::vector<Buffer> buffers;
Device* device;
Device* device = NULL;
// ~Buffers();
//

View File

@ -16,18 +16,19 @@ namespace ext {
Device* device = NULL;
VkPipeline pipeline;
VkPipelineLayout pipelineLayout;
VkDescriptorSetLayout descriptorSetLayout;
VkDescriptorPool descriptorPool;
VkDescriptorSet descriptorSet;
GraphicDescriptor descriptor;
VkPipeline pipeline = VK_NULL_HANDLE;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
GraphicDescriptor descriptor = {};
struct {
uf::Serializer json;
uf::stl::string type = "";
bool process = true;
bool rebuild = false;
} metadata;
void initialize( const Graphic& graphic );
@ -43,7 +44,7 @@ namespace ext {
struct UF_API Material {
bool aliased = false;
Device* device;
Device* device = NULL;
uf::stl::vector<Sampler> samplers;
uf::stl::vector<Texture2D> textures;
@ -51,6 +52,7 @@ namespace ext {
struct Metadata {
uf::Serializer json;
bool autoInitializeUniforms = true;
uf::stl::unordered_map<uf::stl::string, size_t> shaders;
} metadata;
@ -68,30 +70,17 @@ namespace ext {
};
struct UF_API Graphic : public Buffers {
GraphicDescriptor descriptor;
GraphicDescriptor descriptor = {};
bool initialized = false;
bool process = true;
Material material;
Material material = {};
uf::stl::unordered_map<GraphicDescriptor::hash_t, Pipeline> pipelines;
struct {
uf::stl::unordered_map<uf::stl::string, size_t> buffers;
} metadata;
struct Layout {
uf::stl::vector<VkDescriptorBufferInfo> uniform;
uf::stl::vector<VkDescriptorBufferInfo> storage;
uf::stl::vector<VkDescriptorImageInfo> image;
uf::stl::vector<VkDescriptorImageInfo> image2D;
uf::stl::vector<VkDescriptorImageInfo> imageCube;
uf::stl::vector<VkDescriptorImageInfo> image3D;
uf::stl::vector<VkDescriptorImageInfo> sampler;
uf::stl::vector<VkDescriptorImageInfo> input;
} layout;
~Graphic();
void initialize( const uf::stl::string& = "" );
void destroy();
@ -101,6 +90,7 @@ namespace ext {
// void initializeAttributes( const uf::Mesh::Attributes& mesh );
void initializeMesh( uf::Mesh& mesh, bool buffer = true );
void updateMesh( uf::Mesh& mesh );
bool hasPipeline( const GraphicDescriptor& descriptor ) const;
void initializePipeline();

View File

@ -12,24 +12,23 @@ namespace ext {
bool execute = false;
bool executed = false;
bool rebuild = false;
uint32_t width = 0;
uint32_t height = 0;
struct {
uf::Serializer json;
uf::stl::string name = "";
uf::stl::string type = "";
uf::stl::string target = "";
uf::stl::string pipeline = "";
uf::stl::vector<uf::stl::string> pipelines;
uf::stl::vector<uint8_t> outputs;
uint8_t subpasses = 1;
uint8_t samples = 1;
uint8_t eyes = 1;
size_t lightBufferIndex = 0;
size_t materialBufferIndex = 0;
size_t textureBufferIndex = 0;
size_t drawCallBufferIndex = 0;
} metadata;
Device* device = VK_NULL_HANDLE;

View File

@ -7,7 +7,6 @@ namespace ext {
namespace vulkan {
struct UF_API ComputeRenderMode : public ext::vulkan::RenderMode {
ext::vulkan::Graphic blitter, compute;
pod::Vector2ui dispatchSize = { 32, 32 };
// RAII
virtual const uf::stl::string getType() const;

View File

@ -26,14 +26,15 @@ namespace ext {
uf::stl::string filename = "";
VkShaderModule module = VK_NULL_HANDLE;
VkPipelineShaderStageCreateInfo descriptor;
VkPipelineShaderStageCreateInfo descriptor = {};
uf::stl::vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings;
uf::stl::vector<VkSpecializationMapEntry> specializationMapEntries;
VkSpecializationInfo specializationInfo;
VkSpecializationInfo specializationInfo = {};
struct Metadata {
uf::Serializer json;
bool autoInitializeUniforms = true;
uf::stl::string pipeline = "";
uf::stl::string type = "";

View File

@ -11,7 +11,7 @@ namespace ext {
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
bool initialized = false;
uint32_t buffers;
uint32_t buffers = {};
VkSemaphore presentCompleteSemaphore;
VkSemaphore renderCompleteSemaphore;

View File

@ -10,7 +10,7 @@ namespace ext {
struct UF_API Sampler {
Device* device = NULL;
VkSampler sampler;
VkSampler sampler = VK_NULL_HANDLE;
struct Descriptor {
struct {
VkFilter min = VK_FILTER_LINEAR;
@ -34,7 +34,7 @@ namespace ext {
float max = 16.0f;
} anisotropy;
VkDescriptorImageInfo info;
} descriptor;
} descriptor = {};
void initialize( Device& device );
void destroy();
@ -46,21 +46,24 @@ namespace ext {
struct UF_API Texture {
Device* device = nullptr;
VkImage image;
VkImageView view;
VkImage image = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
VkImageType type = enums::Image::TYPE_2D;
VkImageViewType viewType = enums::Image::VIEW_TYPE_2D;
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkDeviceMemory deviceMemory;
VkDescriptorImageInfo descriptor;
VkFormat format = enums::Format::R8G8B8A8_UNORM;;
VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
VkDescriptorImageInfo descriptor = {};
VkFormat format = enums::Format::R8G8B8A8_UNORM;
Sampler sampler;
Sampler sampler = {};
VmaAllocation allocation;
VmaAllocationInfo allocationInfo;
VmaAllocation allocation = {};
VmaAllocationInfo allocationInfo = {};
uint32_t width, height, depth, layers;
uint32_t width = 0;
uint32_t height = 0;
uint32_t depth = 0;
uint32_t layers = 0;
uint32_t mips = 1;
// RAII
void initialize( Device& device, size_t width, size_t height, size_t depth = 1, size_t layers = 1 );

View File

@ -64,9 +64,9 @@ namespace ext {
extern UF_API bool multiview;
extern UF_API bool vsync;
extern UF_API bool hdr;
extern UF_API bool frustrumCull;
extern UF_API bool vxgi;
extern UF_API bool deferredSampling;
extern UF_API bool culling;
}
namespace formats {

View File

@ -37,7 +37,7 @@
#define UF_MSG_ERROR(X) UF_MSG(X, " ERROR ");
#if UF_NO_EXCEPTIONS
#define UF_EXCEPTION(X) { UF_MSG_ERROR(X); }
#define UF_EXCEPTION(X) { UF_MSG_ERROR(X); std::abort(); }
#else
#define UF_EXCEPTION(X) {\
uf::stl::stringstream str;\

View File

@ -21,13 +21,14 @@ namespace uf {
std::size_t m_format;
public:
// C-tor
/*
Image(); // Default
Image( const Image::vec2_t& size ); // Just Size
Image( Image&& move ); // Move pixels
Image( const Image& copy ); // Copy pixels
Image( Image::container_t&& move, const Image::vec2_t& size ); // Move from vector of pixels
Image( const Image::container_t& copy, const Image::vec2_t& size ); // Copy from vector of pixels
*/
bool open( const uf::stl::string& filename, bool = true ); // from file
void open( const std::istream& stream ); // from stream
void move( Image::container_t&& move, const Image::vec2_t& size ); // move from vector of pixels

View File

@ -570,15 +570,15 @@ pod::Matrix4t<T> /*UF_API*/ uf::matrix::perspective( T fov, T raidou, T znear, T
});
#elif UF_USE_VULKAN
return pod::Matrix4t<T>({
f / raidou, 0.0f, 0.0f, 0.0f,
0.0f, -f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, znear, 0.0f
f / raidou, 0, 0, 0,
0, -f, 0, 0,
0, 0, 0, 1,
0, 0, znear, 0
});
#endif
} else {
T range = znear - zfar;
T f = tanf( static_cast<T>(0.5) * fov );
T f = tan( static_cast<T>(0.5) * fov );
T Sx = static_cast<T>(1) / (f * raidou);
T Sy = static_cast<T>(1) / f;

View File

@ -131,6 +131,11 @@ namespace uf {
template<typename T> T& /*UF_API*/ divide( T& left, const typename T::type_t& scalar ); // Divides this vector by a scalar
template<typename T> T& /*UF_API*/ negate( T& vector ); // Flip sign of all components
template<typename T> T& /*UF_API*/ normalize( T& vector ); // Normalizes a vector
template<typename T> T /*UF_API*/ min( const T& left, const T& right ); //
template<typename T> T /*UF_API*/ max( const T& left, const T& right ); //
template<typename T> T /*UF_API*/ ceil( const T& vector ); //
template<typename T> T /*UF_API*/ floor( const T& vector ); //
template<typename T> T /*UF_API*/ round( const T& vector ); //
// Complex arithmetic
template<typename T> typename T::type_t /*UF_API*/ dot( const T& left, const T& right ); // Compute the dot product between two vectors
template<typename T> pod::Angle /*UF_API*/ angle( const T& a, const T& b ); // Compute the angle between two vectors

View File

@ -266,6 +266,36 @@ T& /*UF_API*/ uf::vector::normalize( T& vector ) {
if ( norm == 0 ) return vector;
return uf::vector::divide(vector, norm);
}
template<typename T> //
T /*UF_API*/ uf::vector::min( const T& left, const T& right ) {
T res = left;
for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::min( left[i], right[i] );
return res;
}
template<typename T> //
T /*UF_API*/ uf::vector::max( const T& left, const T& right ) {
T res;
for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::max( left[i], right[i] );
return res;
}
template<typename T> //
T /*UF_API*/ uf::vector::ceil( const T& vector ) {
T res;
for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::ceil( vector[i] );
return res;
}
template<typename T> //
T /*UF_API*/ uf::vector::floor( const T& vector ) {
T res;
for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::floor( vector[i] );
return res;
}
template<typename T> //
T /*UF_API*/ uf::vector::round( const T& vector ) {
T res;
for ( uint_fast8_t i = 0; i < T::size; ++i ) res[i] = std::round( vector[i] );
return res;
}
// Complex arithmetic
template<typename T> // Compute the dot product between two vectors
typename T::type_t /*UF_API*/ uf::vector::dot( const T& left, const T& right ) {

View File

@ -30,9 +30,6 @@ namespace ext {
uf::stl::string name = "";
ext::RENDERER::enums::Type::type_t type = 0;
size_t components = 0;
// somewhat essential
size_t length = 0;
void* pointer = NULL;
bool operator==( const AttributeDescriptor& right ) const { return
offset == right.offset &&
@ -56,6 +53,10 @@ namespace uf {
ext::RENDERER::AttributeDescriptor descriptor;
int32_t buffer = -1;
size_t offset = 0;
size_t stride = 0;
size_t length = 0;
void* pointer = NULL;
};
struct Input {
uf::stl::vector<Attribute> attributes;
@ -64,16 +65,19 @@ namespace uf {
size_t stride = 0; // size of one element in the input's buffer
size_t offset = 0; // bytes to offset from within the associated buffer
int32_t interleaved = -1; // index to interleaved buffer if in bounds
struct Settings {
bool interleaved = false;
} settings;
} vertex, index, instance, indirect;
/*
struct Bounds {
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() };
} bounds;
*/
uf::stl::vector<buffer_t> buffers;
protected:
void _destroy( uf::Mesh::Input& input );
void _bind( bool interleaved = uf::Mesh::defaultInterleaved );
void _updateDescriptor( uf::Mesh::Input& input );
uf::Mesh::Attribute _remapAttribute( const uf::Mesh::Input& input, const uf::Mesh::Attribute& attribute, size_t i = 0 ) const;
bool _hasV( const uf::Mesh::Input& input, const uf::stl::vector<ext::RENDERER::AttributeDescriptor>& descriptors ) const;
bool _hasV( const uf::Mesh::Input& input, const uf::Mesh::Input& src ) const;
@ -81,10 +85,10 @@ namespace uf {
void _resizeVs( uf::Mesh::Input& input, size_t count );
void _reserveVs( uf::Mesh::Input& input, size_t count );
void _insertV( uf::Mesh::Input& input, const void* data );
void _insertV( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput );
void _insertVs( uf::Mesh::Input& input, const void* data, size_t size );
void _insertVs( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput );
template<typename T> inline bool _hasV( const uf::Mesh::Input& input ) const { return _hasV( input, T::descriptors ); }
template<typename T> inline bool _hasV( const uf::Mesh::Input& input ) const { return _hasV( input, T::descriptor ); }
template<typename T> inline void _bindV( uf::Mesh::Input& input ) { return _bindV( input, T::descriptor ); }
template<typename T> inline void _insertV( uf::Mesh::Input& input, const T& vertex ) { return _insertV( input, (const void*) &vertex ); }
template<typename T> inline void _insertVs( uf::Mesh::Input& input, const uf::stl::vector<T>& vs ) { return _insertVs( input, (const void*) vs.data(), vs.size() ); }
@ -93,8 +97,8 @@ namespace uf {
void _reserveIs( uf::Mesh::Input& input, size_t count, size_t i = 0 );
void _resizeIs( uf::Mesh::Input& input, size_t count, size_t i = 0 );
void _insertI( uf::Mesh::Input& input, const void* data, size_t i );
void _insertI( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput );
void _insertIs( uf::Mesh::Input& input, const void* data, size_t size, size_t i );
void _insertIs( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput );
template<typename U> inline void _bindI( uf::Mesh::Input& input, size_t indices = 1 ) { return _bindI( input, sizeof(U), ext::RENDERER::typeToEnum<U>(), indices ); }
template<typename U> inline void _insertI( uf::Mesh::Input& input, U index, size_t i = 0 ) { return _insertI( input, (const void*) &index, i ); }
@ -105,6 +109,8 @@ namespace uf {
uf::Mesh interleave() const;
void updateDescriptor();
void bind( const uf::Mesh& );
void insert( const uf::Mesh& );
void generateIndices();
@ -121,10 +127,11 @@ namespace uf {
inline void reserveVertices( size_t count ) { return _reserveVs( vertex, count ); }
inline void insertVertex( const void* data ) { return _insertV( vertex, data ); }
inline void insertVertices( const void* data, size_t size ) { return _insertVs( vertex, data, size ); }
inline void insertVertices( const uf::Mesh& mesh ) { return _insertV( vertex, mesh, mesh.vertex ); }
inline void insertVertices( const uf::Mesh& mesh ) { return _insertVs( vertex, mesh, mesh.vertex ); }
inline void updateVertexDescriptor() { return _updateDescriptor( vertex ); }
inline uf::Mesh::Attribute remapVertexAttribute( const uf::Mesh::Attribute& attribute, size_t i = 0 ) const { return _remapAttribute( vertex, attribute, i ); }
template<typename T> inline bool hasVertex() const { return _hasV( vertex, T::descriptors ); }
template<typename T> inline bool hasVertex() const { return _hasV( vertex, T::descriptor ); }
template<typename T> inline void bindVertex() { return _bindV( vertex, T::descriptor ); }
template<typename T> inline void insertVertex( const T& v ) { return _insertV( vertex, (const void*) &v ); }
template<typename T> inline void insertVertices( const uf::stl::vector<T>& vertices ) { return _insertVs( vertex, (const void*) vertices.data(), vertices.size() ); }
@ -134,8 +141,9 @@ namespace uf {
inline void resizeIndices( size_t count, size_t i = 0 ) { return _resizeIs( index, count, i ); }
inline void insertIndex( const void* data, size_t i = 0 ) { return _insertI( index, data, i ); }
inline void insertIndices( const void* data, size_t size, size_t i = 0 ) { return _insertIs( index, data, size, i ); }
inline void insertIndices( const uf::Mesh& mesh ) { return _insertI( index, mesh, mesh.index ); }
inline void insertIndices( const uf::Mesh& mesh ) { return _insertIs( index, mesh, mesh.index ); }
inline void updateIndexDescriptor() { return _updateDescriptor( index ); }
inline uf::Mesh::Attribute remapIndexAttribute( const uf::Mesh::Attribute& attribute, size_t i = 0 ) const { return _remapAttribute( index, attribute, i ); }
template<typename U> inline void bindIndex( size_t count = 1 ) { return _bindI( index, sizeof(U), ext::RENDERER::typeToEnum<U>(), count ); }
template<typename U> inline void insertIndex( U I, size_t i = 0 ) { return _insertI( index, (const void*) &I, i ); }
@ -148,10 +156,10 @@ namespace uf {
inline void reserveInstances( size_t count ) { return _reserveVs( instance, count ); }
inline void insertInstance( const void* data ) { return _insertV( instance, data ); }
inline void insertInstances( const void* data, size_t size ) { return _insertVs( instance, data, size ); }
inline void insertInstances( const uf::Mesh& mesh ) { return _insertV( instance, mesh, mesh.instance ); }
inline void insertInstances( const uf::Mesh& mesh ) { return _insertVs( instance, mesh, mesh.instance ); }
inline void updateInstanceDescriptor() { return _updateDescriptor( instance ); }
template<typename T> inline bool hasInstance() const { return _hasV( instance, T::descriptors ); }
template<typename T> inline bool hasInstance() const { return _hasV( instance, T::descriptor ); }
template<typename T> inline void bindInstance() { return _bindV( instance, T::descriptor ); }
template<typename T> inline void insertInstance( const T& v ) { return _insertV( instance, (const void*) &v ); }
template<typename T> inline void insertInstances( const uf::stl::vector<T>& instances ) { return _insertVs( instance, (const void*) instances.data(), instances.size() ); }
@ -161,7 +169,7 @@ namespace uf {
inline void resizeIndirects( size_t count, size_t i = 0 ) { return _resizeIs( indirect, count, i ); }
inline void insertIndirect( const void* data, size_t i = 0 ) { return _insertI( indirect, data, i ); }
inline void insertIndirects( const void* data, size_t size, size_t i = 0 ) { return _insertIs( indirect, data, size, i ); }
inline void insertIndirects( const uf::Mesh& mesh ) { return _insertI( indirect, mesh, mesh.indirect ); }
inline void insertIndirects( const uf::Mesh& mesh ) { return _insertIs( indirect, mesh, mesh.indirect ); }
inline void updateIndirectDescriptor() { return _updateDescriptor( indirect ); }
template<typename U> inline void bindIndirect( size_t i = 1 ) { return _bindI( indirect, sizeof(U), ext::RENDERER::typeToEnum<U>(), i ); }
@ -175,6 +183,15 @@ namespace uf {
_bind( interleave );
}
};
template<typename T, typename U = uint32_t>
struct UF_API Mesh_T {
typedef T vertex_t;
typedef U index_t;
uf::stl::vector<vertex_t> vertices;
uf::stl::vector<index_t> indices;
};
}
namespace ext {
@ -195,6 +212,7 @@ namespace ext {
struct {
uf::Mesh::Input vertex, index, instance, indirect;
size_t bufferOffset = 0;
pod::Vector3ui dispatch = { 0, 0, 0 };
} inputs;
ext::RENDERER::enums::PrimitiveTopology::type_t topology = ext::RENDERER::enums::PrimitiveTopology::TRIANGLE_LIST;

View File

@ -176,8 +176,8 @@ uf::stl::string uf::Asset::load( const uf::stl::string& uri, const uf::stl::stri
metadata[uri]["flags"]["ATLAS"] = false;
metadata[uri]["flags"]["SEPARATE"] = true;
#elif UF_GRAPH_INDIRECT_DRAW
metadata[uri]["flags"]["ATLAS"] = false;
metadata[uri]["flags"]["SEPARATE"] = false;
// metadata[uri]["flags"]["ATLAS"] = false;
// metadata[uri]["flags"]["SEPARATE"] = false;
#endif
asset = uf::graph::load( filename, metadata[uri] );
uf::graph::process( asset );

File diff suppressed because it is too large Load Diff

View File

@ -66,6 +66,10 @@ void uf::GraphBehavior::initialize( uf::Object& self ) {
}
void uf::GraphBehavior::destroy( uf::Object& self ) {}
void uf::GraphBehavior::tick( uf::Object& self ) {
if ( this->hasComponent<pod::Graph>() ) {
auto& graph = this->getComponent<pod::Graph>();
uf::graph::update( graph );
}
#if 0
/* Update animations */ if ( this->hasComponent<pod::Graph>() ) {
auto& graph = this->getComponent<pod::Graph>();

View File

@ -18,6 +18,7 @@ UF_BEHAVIOR_TRAITS_CPP(uf::RenderBehavior, ticks = true, renders = true, multith
#define this (&self)
void uf::RenderBehavior::initialize( uf::Object& self ) {}
void uf::RenderBehavior::tick( uf::Object& self ) {
#if 0
if ( !this->hasComponent<uf::Graphic>() ) return;
const auto& metadata = this->getComponent<uf::Serializer>();
const auto& scene = uf::scene::getCurrentScene();
@ -67,8 +68,10 @@ void uf::RenderBehavior::tick( uf::Object& self ) {
#endif
}
#endif
#endif
}
void uf::RenderBehavior::render( uf::Object& self ) {
#if 0
if ( !this->hasComponent<uf::Graphic>() ) return;
const auto& metadata = this->getComponent<uf::Serializer>();
const auto& scene = uf::scene::getCurrentScene();
@ -119,7 +122,7 @@ void uf::RenderBehavior::render( uf::Object& self ) {
#endif
#endif
}
#endif
#endif
}
void uf::RenderBehavior::destroy( uf::Object& self ) {}

View File

@ -5,8 +5,21 @@
#include <uf/utils/renderer/renderer.h>
#include <uf/utils/graphic/graphic.h>
#include <uf/engine/scene/scene.h>
#include <uf/engine/graph/graph.h>
#include <BulletCollision/CollisionShapes/btTriangleShape.h>
struct VertexLine {
pod::Vector3f position;
pod::Vector3f color;
static UF_API uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
};
UF_VERTEX_DESCRIPTOR(VertexLine,
UF_VERTEX_DESCRIPTION(VertexLine, R32G32B32_SFLOAT, position)
UF_VERTEX_DESCRIPTION(VertexLine, R32G32B32_SFLOAT, color)
);
class BulletDebugDrawer : public btIDebugDraw {
protected:
int m;
@ -16,15 +29,19 @@ public:
drawLine( from, to, color, color );
}
virtual void drawLine( const btVector3& from, const btVector3& to, const btVector3& fromColor, const btVector3& toColor ) {
pod::Vertex_3F2F3F4F vertex;
vertex.position = { from.getX(), from.getY(), from.getZ() };
vertex.color = { fromColor.getX(), fromColor.getY(), fromColor.getZ(), 1.0f };
mesh.insertVertex(vertex);
vertex.position = { to.getX(), to.getY(), to.getZ() };
vertex.color = { toColor.getX(), toColor.getY(), toColor.getZ(), 1.0f };
mesh.insertVertex(vertex);
uf::stl::vector<VertexLine> vertices;
{
auto& vertex = vertices.emplace_back();
vertex.position = { from.getX(), from.getY(), from.getZ() };
vertex.color = { fromColor.getX(), fromColor.getY(), fromColor.getZ() };
}
{
auto& vertex = vertices.emplace_back();
vertex.position = { to.getX(), to.getY(), to.getZ() };
vertex.color = { toColor.getX(), toColor.getY(), toColor.getZ() };
}
if ( !mesh.hasVertex<VertexLine>() ) mesh.bind<VertexLine>();
mesh.insertVertices(vertices);
}
virtual void drawContactPoint(const btVector3&, const btVector3&, btScalar, int, const btVector3&) {
@ -39,7 +56,9 @@ public:
m = p;
}
virtual void clearLines() {
mesh.destroy();
for ( auto& buffer : mesh.buffers ) buffer.clear();
mesh.vertex.count = 0;
mesh.index.count = 0;
}
virtual void flushLines() {
auto& scene = uf::scene::getCurrentScene();
@ -113,6 +132,9 @@ void ext::bullet::initialize() {
ext::bullet::debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawWireframe);
ext::bullet::dynamicsWorld->setDebugDrawer(&ext::bullet::debugDrawer);
auto& mesh = ext::bullet::debugDrawer.getMesh();
mesh.bind<VertexLine>();
#if !UF_ENV_DREAMCAST
gContactAddedCallback = contactCallback;
#endif
@ -276,42 +298,110 @@ void ext::bullet::detach( pod::Bullet& collider ) {
}
pod::Bullet& ext::bullet::create( uf::Object& object, const uf::Mesh& mesh, bool dynamic ) {
auto& transform = object.getComponent<pod::Transform<>>();
btTriangleIndexVertexArray* bMesh = new btTriangleIndexVertexArray();
if ( mesh.index.count ) {
uf::Mesh::Attribute vertexAttribute;
for ( auto& attribute : mesh.vertex.attributes ) if ( attribute.descriptor.name == "position" ) { vertexAttribute = attribute; break; }
UF_ASSERT( vertexAttribute.descriptor.name == "position" );
auto& indexAttribute = mesh.index.attributes.front();
PHY_ScalarType indexType = PHY_INTEGER;
PHY_ScalarType vertexType = PHY_FLOAT;
switch ( mesh.index.stride ) {
case sizeof(uint8_t): indexType = PHY_UCHAR; break;
case sizeof(uint16_t): indexType = PHY_SHORT; break;
case sizeof(uint32_t): indexType = PHY_INTEGER; break;
default: UF_EXCEPTION("unsupported index type"); break;
}
btIndexedMesh iMesh;
if ( mesh.indirect.count ) {
uf::Mesh::Attribute remappedVertexAttribute;
uf::Mesh::Attribute remappedIndexAttribute;
for ( auto i = 0; i < mesh.indirect.count; ++i ) {
remappedVertexAttribute = mesh.remapVertexAttribute( vertexAttribute, i );
remappedIndexAttribute = mesh.remapIndexAttribute( indexAttribute, i );
iMesh.m_numTriangles = remappedIndexAttribute.length / 3;
iMesh.m_triangleIndexBase = (const uint8_t*) remappedIndexAttribute.pointer;
iMesh.m_triangleIndexStride = remappedIndexAttribute.stride * 3;
iMesh.m_numVertices = remappedVertexAttribute.length;
iMesh.m_vertexBase = (const uint8_t*) remappedVertexAttribute.pointer;
iMesh.m_vertexStride = remappedVertexAttribute.stride;
iMesh.m_indexType = indexType;
iMesh.m_vertexType = vertexType;
bMesh->addIndexedMesh( iMesh, indexType );
}
} else {
iMesh.m_numTriangles = indexAttribute.length / 3;
iMesh.m_triangleIndexBase = (const uint8_t*) indexAttribute.pointer;
iMesh.m_triangleIndexStride = indexAttribute.stride * 3;
iMesh.m_numVertices = vertexAttribute.length;
iMesh.m_vertexBase = (const uint8_t*) vertexAttribute.pointer;
iMesh.m_vertexStride = vertexAttribute.stride;
iMesh.m_indexType = indexType;
iMesh.m_vertexType = vertexType;
bMesh->addIndexedMesh( iMesh, indexType );
}
} else UF_EXCEPTION("to-do: not require indices for meshes");
auto& collider = ext::bullet::create( object );
auto model = uf::transform::model( collider.transform );
btTriangleMesh* bMesh = new btTriangleMesh( true, false );
for ( auto& attribute : mesh.vertex.attributes ) {
if ( attribute.descriptor.name != "position" ) continue;
const pod::Vector3f* pointer = (const pod::Vector3f*) attribute.descriptor.pointer;
bMesh->preallocateVertices( mesh.vertex.count );
for ( auto i = 0; i < mesh.vertex.count; ++i ) {
bMesh->findOrAddVertex( btVector3( pointer[i].x, pointer[i].y, pointer[i].z ), false );
}
break;
}
if ( mesh.index.count ) {
bMesh->preallocateIndices( mesh.index.count );
for ( auto& attribute : mesh.index.attributes ) {
size_t count = attribute.descriptor.length / attribute.descriptor.size;
const uint8_t* pointer = (const uint8_t*) attribute.descriptor.pointer;
for ( auto i = 0; i < count; ++i ) {
uint32_t index = 0;
switch ( attribute.descriptor.size ) {
case sizeof( uint8_t): index = (( uint8_t*) pointer)[i]; break;
case sizeof(uint16_t): index = ((uint16_t*) pointer)[i]; break;
case sizeof(uint32_t): index = ((uint32_t*) pointer)[i]; break;
}
bMesh->addIndex( index );
}
}
}
collider.shape = new btBvhTriangleMeshShape(bMesh, true);
collider.shape = new btBvhTriangleMeshShape( bMesh, true, true );
ext::bullet::attach( collider );
auto& transform = object.getComponent<pod::Transform<>>();
auto model = uf::transform::model( collider.transform );
btTransform t = collider.body->getWorldTransform();
t.setFromOpenGLMatrix(&model[0]);
collider.body->setWorldTransform(t);
collider.body->setCenterOfMassTransform(t);
btBvhTriangleMeshShape* triangleMeshShape = (btBvhTriangleMeshShape*) collider.shape;
btTriangleInfoMap* triangleInfoMap = new btTriangleInfoMap();
triangleInfoMap->m_edgeDistanceThreshold = 0.01f;
triangleInfoMap->m_maxEdgeAngleThreshold = SIMD_HALF_PI*0.25;
if ( !false ) btGenerateInternalEdgeInfo( triangleMeshShape, triangleInfoMap );
collider.body->setCollisionFlags(collider.body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
return collider;
}
pod::Bullet& ext::bullet::create( uf::Object& object, const void* verticesPointer, size_t verticesCount, size_t verticesStride, const void* indicesPointer, size_t indicesCount, size_t indicesStride, bool dynamic ) {
btTriangleIndexVertexArray* bMesh = new btTriangleIndexVertexArray();
if ( indicesCount ) {
PHY_ScalarType indexType = PHY_INTEGER;
PHY_ScalarType vertexType = PHY_FLOAT;
switch ( indicesStride ) {
case 1: indexType = PHY_UCHAR; break;
case 2: indexType = PHY_SHORT; break;
case 4: indexType = PHY_INTEGER; break;
}
const uint8_t* indicesBuffer = (const uint8_t*) indicesPointer;
const uint8_t* verticesBuffer = (const uint8_t*) verticesPointer;
btIndexedMesh iMesh;
iMesh.m_numTriangles = indicesCount / 3;
iMesh.m_triangleIndexBase = indicesBuffer;
iMesh.m_triangleIndexStride = 3 * indicesStride;
iMesh.m_numVertices = verticesCount;
iMesh.m_vertexBase = verticesBuffer;
iMesh.m_vertexStride = verticesStride;
iMesh.m_indexType = indexType;
iMesh.m_vertexType = vertexType;
bMesh->addIndexedMesh( iMesh, indexType );
} else UF_EXCEPTION("to-do: not require indices for meshes");
auto& collider = ext::bullet::create( object );
collider.shape = new btBvhTriangleMeshShape( bMesh, true, true );
ext::bullet::attach( collider );
auto& transform = object.getComponent<pod::Transform<>>();
auto model = uf::transform::model( collider.transform );
btTransform t = collider.body->getWorldTransform();
t.setFromOpenGLMatrix(&model[0]);
collider.body->setWorldTransform(t);
@ -443,33 +533,32 @@ void UF_API ext::bullet::activateCollision( pod::Bullet& collider, bool enabled
void UF_API ext::bullet::debugDraw( uf::Object& object ) {
auto& mesh = ext::bullet::debugDrawer.getMesh();
mesh.bind<pod::Vertex_3F2F3F4F>();
if ( !mesh.vertex.count ) return;
bool create = !object.hasComponent<uf::Graphic>();
auto& graphic = object.getComponent<uf::Graphic>();
graphic.process = false;
if ( create ) {
graphic.process = true;
graphic.device = &uf::renderer::device;
graphic.material.device = &uf::renderer::device;
graphic.descriptor.cullMode = uf::renderer::enums::CullMode::NONE;
graphic.material.attachShader(uf::io::root + "/shaders/base/colored.vert.spv", uf::renderer::enums::Shader::VERTEX);
graphic.material.attachShader(uf::io::root + "/shaders/base/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT);
graphic.material.metadata.json["shader"]["autoInitializeUniformBuffers"] = false;
graphic.initialize();
graphic.material.attachShader(uf::io::root + "/shaders/bullet/base.vert.spv", uf::renderer::enums::Shader::VERTEX);
graphic.material.attachShader(uf::io::root + "/shaders/bullet/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT);
graphic.material.getShader("vertex").buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera );
graphic.initialize("Gui");
graphic.initializeMesh( mesh );
graphic.descriptor.topology = uf::renderer::enums::PrimitiveTopology::LINE_LIST;
graphic.descriptor.fill = uf::renderer::enums::PolygonMode::LINE;
graphic.descriptor.lineWidth = 8.0f;
} else {
graphic.process = true;
graphic.initializeMesh( mesh );
graphic.getPipeline().update( graphic );
graphic.updateMesh( mesh );
}
graphic.process = true;
}
#endif

View File

@ -133,11 +133,26 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
return graph;
}
// load images
{
graph.images.reserve(model.images.size());
graph.storage.images.reserve(model.images.size());
for ( auto& i : model.images ) {
auto imageID = graph.images.size();
auto keyName = graph.images.emplace_back(filename + "/" + i.name);
auto& image = graph.storage.images[keyName];
image.loadFromBuffer( &i.image[0], {i.width, i.height}, 8, i.component, true );
}
}
// load samplers
{
uf::graph::storage.samplers.reserve(model.samplers.size());
graph.storage.samplers.reserve(model.samplers.size());
for ( auto& s : model.samplers ) {
auto& sampler = uf::graph::storage.samplers[graph.samplers.emplace_back(s.name)];
auto samplerID = graph.samplers.size();
auto keyName = graph.samplers.emplace_back(filename + "/" + s.name);
auto& sampler = graph.storage.samplers[keyName];
sampler.descriptor.filter.min = getFilterMode( s.minFilter );
sampler.descriptor.filter.mag = getFilterMode( s.magFilter );
sampler.descriptor.addressMode.u = getWrapMode( s.wrapS );
@ -145,44 +160,30 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
sampler.descriptor.addressMode.w = sampler.descriptor.addressMode.v;
}
}
// load images
{
uf::graph::storage.images.reserve(model.images.size());
for ( auto& i : model.images ) {
auto& image = uf::graph::storage.images[graph.images.emplace_back(i.name)];
image.loadFromBuffer( &i.image[0], {i.width, i.height}, 8, i.component, true );
}
}
// generate atlas
if ( graph.metadata["flags"]["ATLAS"].as<bool>() ) {
// uf::graph::storage.atlases[filename].generate();
}
// load textures
{
uf::graph::storage.textures.reserve(model.textures.size());
graph.textures.reserve(model.textures.size());
graph.storage.textures.reserve(model.textures.size());
for ( auto& t : model.textures ) {
auto& texture = uf::graph::storage.textures[graph.textures.emplace_back(t.name)];
auto textureID = graph.textures.size();
auto keyName = graph.textures.emplace_back((t.name == "" ? graph.images[t.source] : (filename + "/" + t.name)));
auto& texture = graph.storage.textures[keyName];
texture.index = t.source;
texture.sampler = t.sampler;
if ( 0 <= t.source && uf::graph::storage.atlases[filename].generated() ) {
auto& image = graph.images[t.source];
const auto& hash = uf::graph::storage.images[image].getHash();
auto atlasMin = uf::graph::storage.atlases[filename].mapUv( {0, 0}, hash );
auto atlasMax = uf::graph::storage.atlases[filename].mapUv( {1, 1}, hash );
texture.lerp = { atlasMin.x, atlasMin.y, atlasMax.x, atlasMax.y, };
}
}
}
// clear source images
if ( uf::graph::storage.atlases[filename].generated() ) {
uf::graph::storage.atlases[filename].clear(false);
}
// load materials
{
uf::graph::storage.materials.reserve(model.materials.size());
graph.materials.reserve(model.materials.size());
graph.storage.materials.reserve(model.materials.size());
for ( auto& m : model.materials ) {
auto& material = uf::graph::storage.materials[graph.materials.emplace_back(m.name)];
auto materialID = graph.materials.size();
auto keyName = graph.materials.emplace_back(filename + "/" + m.name);
auto& material = graph.storage.materials[keyName];
material.indexAlbedo = m.pbrMetallicRoughness.baseColorTexture.index;
material.indexNormal = m.normalTexture.index;
material.indexEmissive = m.emissiveTexture.index;
@ -219,14 +220,28 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
// load meshes
{
graph.meshes.reserve(model.meshes.size());
for ( auto& m : model.meshes ) {
auto& pair = uf::graph::storage.meshes[graph.meshes.emplace_back(m.name)];
auto& mesh = pair.mesh;
mesh.bind<uf::graph::mesh::Skinned, uint32_t>();
graph.storage.meshes.reserve(model.meshes.size());
for ( auto& m : model.meshes ) {
auto meshID = graph.meshes.size();
auto keyName = graph.meshes.emplace_back(filename + "/" + m.name);
graph.primitives.emplace_back(keyName);
graph.drawCommands.emplace_back(keyName);
auto& drawCommands = graph.storage.drawCommands[keyName];
auto& primitives = graph.storage.primitives[keyName];
auto& mesh = graph.storage.meshes[keyName];
mesh.bindIndirect<pod::DrawCommand>();
mesh.bind<uf::graph::mesh::Skinned, uint32_t>();
/*
size_t primitiveID = 0;
*/
uf::stl::vector<uf::graph::mesh::Skinned> vertices;
uf::stl::vector<uint32_t> indices;
for ( auto& p : m.primitives ) {
uf::stl::vector<uf::graph::mesh::Skinned> vertices;
uf::stl::vector<uint32_t> indices;
vertices.clear();
indices.clear();
auto& primitive = primitives.emplace_back();
struct Attribute {
uf::stl::string name = "";
@ -234,6 +249,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
uf::stl::vector<float> floats;
uf::stl::vector<uint16_t> ints;
};
uf::stl::unordered_map<uf::stl::string, Attribute> attributes = {
{"POSITION", {}},
{"TEXCOORD_0", {}},
@ -254,11 +270,8 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
if ( attribute.name == "POSITION" ) {
vertices.resize(accessor.count);
pod::Vector3f minCorner = { accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] };
pod::Vector3f maxCorner = { accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] };
pod::Vector3f origin = (maxCorner + minCorner) * 0.5f;
pod::Vector3f size = (maxCorner - minCorner) * 0.5f;
primitive.instance.bounds.min = pod::Vector3f{ accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] };
primitive.instance.bounds.max = pod::Vector3f{ accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] };
}
if ( attribute.name == "JOINTS_0" ) {
auto* buffer = reinterpret_cast<const uint16_t*>(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
@ -300,8 +313,6 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
vertex.normal.x *= -1;
vertex.tangent.x *= -1;
}
}
if ( p.indices > -1 ) {
@ -311,9 +322,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
indices.reserve( static_cast<uint32_t>(accessor.count) );
#define COPY_INDICES()\
for (size_t index = 0; index < indices.size(); index++)\
indices.emplace_back(buf[index]);
#define COPY_INDICES() for (size_t index = 0; index < accessor.count; index++) indices.emplace_back(buf[index]);
const void* pointer = &(buffer.data[accessor.byteOffset + view.byteOffset]);
switch (accessor.componentType) {
@ -336,49 +345,46 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
#undef COPY_INDICES
}
pair.drawCommands.emplace_back(pod::DrawCommand{
primitive.instance.materialID = p.material;
primitive.instance.primitiveID = primitives.size() - 1;
primitive.instance.meshID = meshID;
primitive.instance.objectID = 0;
primitive.drawCommand.indices = indices.size();
primitive.drawCommand.instances = 1;
primitive.drawCommand.indexID = 0;
primitive.drawCommand.vertexID = 0;
primitive.drawCommand.instanceID = 0;
primitive.drawCommand.vertices = vertices.size();
auto& drawCommand = drawCommands.emplace_back(pod::DrawCommand{
.indices = indices.size(),
.instances = 1,
.indexID = mesh.index.count,
.vertexID = mesh.vertex.count,
.instanceID = mesh.instance.count,
.materialID = p.material,
.objectID = 0,
.instanceID = 0,
// .meshID = meshID,
// .objectID = materialID,
.vertices = vertices.size(),
});
mesh.insertVertices(vertices);
mesh.insertIndices(indices);
}
mesh.insertIndirects(drawCommands);
mesh.updateDescriptor();
}
}
// load node information/meshes
{
const auto& scene = model.scenes[model.defaultScene > -1 ? model.defaultScene : 0];
graph.nodes.resize( model.nodes.size() );
graph.root.index = -1;
graph.root.children.reserve( scene.nodes.size() );
for ( auto i : scene.nodes ) {
size_t childIndex = loadNode( model, graph, i, -1 );
graph.root.children.emplace_back(childIndex);
}
}
// load lights
{
for ( auto& l : model.lights ) {
auto& light = graph.lights[l.name];
light.color = { l.color[0], l.color[1], l.color[2], };
light.intensity = l.intensity;
light.range = l.range;
}
}
// load skins
{
graph.skins.reserve( model.skins.size() );
graph.storage.skins.reserve( model.skins.size() );
for ( auto& s : model.skins ) {
auto& skin = graph.skins.emplace_back();
auto skinID = graph.skins.size();
auto keyName = graph.skins.emplace_back(filename + "/" + s.name);
auto& skin = graph.storage.skins[keyName];
skin.name = s.name;
if ( s.inverseBindMatrices > -1 ) {
const tinygltf::Accessor& accessor = model.accessors[s.inverseBindMatrices];
@ -406,8 +412,12 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
// load animations
{
graph.animations.reserve( model.animations.size() );
graph.storage.animations.reserve( model.animations.size() );
for ( auto& a : model.animations ) {
auto& animation = graph.animations[a.name];
auto animationID = graph.animations.size();
auto keyName = graph.animations.emplace_back(filename + "/" + a.name);
auto& animation = graph.storage.animations[keyName];
animation.name = a.name;
// load samplers
@ -460,6 +470,62 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
}
}
}
// load lights
{
for ( auto& l : model.lights ) {
auto& light = graph.lights[l.name];
light.color = { l.color[0], l.color[1], l.color[2], };
light.intensity = l.intensity;
light.range = l.range;
}
}
// load node information/meshes
{
const auto& scene = model.scenes[model.defaultScene > -1 ? model.defaultScene : 0];
graph.nodes.resize( model.nodes.size() );
graph.root.name = "%ROOT%";
graph.root.index = -1;
graph.root.children.reserve( scene.nodes.size() );
for ( auto i : scene.nodes ) {
size_t childIndex = loadNode( model, graph, i, -1 );
graph.root.children.emplace_back(childIndex);
}
}
// generate atlas
if ( graph.metadata["flags"]["ATLAS"].as<bool>() ) {
auto atlasName = filename + "/" + "atlas";
auto& atlas = graph.storage.atlases[atlasName];
auto atlasImageIndex = graph.images.size();
auto atlasTextureIndex = graph.textures.size();
for ( auto& keyName : graph.images ) atlas.addImage( graph.storage.images[keyName] );
atlas.generate();
for ( auto& keyName : graph.images ) {
auto& texture = graph.storage.textures[keyName];
if ( texture.index < 0 ) continue;
auto& image = graph.storage.images[keyName];
const auto& hash = image.getHash();
auto min = atlas.mapUv( {0, 0}, hash );
auto max = atlas.mapUv( {1, 1}, hash );
texture.lerp = pod::Vector4f{ min.x, min.y, max.x, max.y, };
texture.index = atlasImageIndex;
}
{
graph.images.emplace_back(atlasName);
auto& image = graph.storage.images[atlasName];
image = atlas.getAtlas();
graph.textures.emplace_back(atlasName);
auto& texture = graph.storage.textures[atlasName];
texture.index = atlasImageIndex;
}
}
if ( graph.metadata["export"]["should"].as<bool>() ) uf::graph::save( graph, filename );
return graph;
}

View File

@ -163,61 +163,6 @@ void ext::opengl::CommandBuffer::record( const CommandBuffer::Info& header ) {
info = &userdata.get<InfoDraw>();
info->type = enums::Command::DRAW;
} break;
/*
case ext::opengl::enums::Command::BIND_BUFFER: {
InfoBuffer* info = (InfoBuffer*) &header;
info->next = NULL;
auto& userdata = infos.emplace_back();
userdata.autoDestruct = false;
userdata.create<InfoBuffer>( *info );
info = &userdata.get<InfoBuffer>();
info->type = enums::Command::BIND_BUFFER;
} break;
case ext::opengl::enums::Command::BIND_GRAPHIC_BUFFER: {
InfoGraphicBuffer* info = (InfoGraphicBuffer*) &header;
info->next = NULL;
auto& userdata = infos.emplace_back();
userdata.autoDestruct = false;
userdata.create<InfoGraphicBuffer>( *info );
info = &userdata.get<InfoGraphicBuffer>();
info->type = enums::Command::BIND_GRAPHIC_BUFFER;
} break;
case ext::opengl::enums::Command::BIND_TEXTURE: {
InfoTexture* info = (InfoTexture*) &header;
info->next = NULL;
auto& userdata = infos.emplace_back();
userdata.autoDestruct = false;
userdata.create<InfoTexture>( *info );
info = &userdata.get<InfoTexture>();
info->type = enums::Command::BIND_TEXTURE;
} break;
case ext::opengl::enums::Command::BIND_PIPELINE: {
InfoPipeline* info = (InfoPipeline*) &header;
info->next = NULL;
auto& userdata = infos.emplace_back();
userdata.autoDestruct = false;
userdata.create<InfoPipeline>( *info );
info = &userdata.get<InfoPipeline>();
info->type = enums::Command::BIND_PIPELINE;
} break;
case ext::opengl::enums::Command::DRAW: {
InfoDraw* info = (InfoDraw*) &header;
info->next = NULL;
auto& userdata = infos.emplace_back();
userdata.autoDestruct = false;
userdata.create<InfoDraw>( *info );
info = &userdata.get<InfoDraw>();
info->type = enums::Command::DRAW;
} break;
case ext::opengl::enums::Command::GENERATE_TEXTURE: {
InfoGenerateTexture* info = (InfoGenerateTexture*) &header;
auto& userdata = infos.emplace_back();
userdata.autoDestruct = false;
userdata.create( *info );
info = &userdata.get<InfoGenerateTexture>();
info->type = enums::Command::GENERATE_TEXTURE;
} break;
*/
default: {
} break;
}
@ -271,82 +216,6 @@ void ext::opengl::CommandBuffer::submit() {
} break;
}
}
#if 0
CommandBuffer::Info* vertexBufferInfo = GL_NULL_HANDLE;
CommandBuffer::Info* indexBufferInfo = GL_NULL_HANDLE;
uf::stl::vector<CommandBuffer::InfoTexture*> textureInfos;
textureInfos.reserve(maxTextures);
if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "==== ["<<this<<"] COMMAND BUFFER SUBMIT START ====\n";
// 50us each process
for ( auto& info : infos ) {
CommandBuffer::Info* header = (CommandBuffer::Info*) (void*) info;
switch ( header->type ) {
case ext::opengl::enums::Command::CLEAR: {
InfoClear* info = (InfoClear*) header;
if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<<info<<"] CLEARING SCREEN TO " << uf::vector::toString( info->color ) << " | DEPTH: " << info->depth << " | BITS: " << std::bitset<32>(info->bits) << "\n";
GL_ERROR_CHECK(glClearColor(info->color[0], info->color[1], info->color[2], info->color[3]));
GL_ERROR_CHECK(glClearDepth(info->depth));
GL_ERROR_CHECK(glClear(info->bits));
GL_ERROR_CHECK(glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &info->color[0]));
} break;
case ext::opengl::enums::Command::VIEWPORT: {
InfoViewport* info = (InfoViewport*) header;
if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<<info<<"] SETTING VIEWPORT TO " << uf::vector::toString(info->corner) << " | " << uf::vector::toString(info->size) << "\n";
GL_ERROR_CHECK(glViewport(info->corner[0], info->corner[1], info->size[0], info->size[1]));
} break;
case ext::opengl::enums::Command::VARIANT: {
InfoVariant* info = (InfoVariant*) header;
if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<<info<<"] CALLING LAMBDA\n";
if ( info->lambda ) info->lambda();
} break;
case ext::opengl::enums::Command::BIND_BUFFER: {
InfoBuffer* info = (InfoBuffer*) header;
if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<<info<<"] BINDING BUFFER: " << info->descriptor.buffer << " | FLAGS: " << /*std::bitset<16>*/(info->usage) << "\n";
if ( info->usage & enums::Buffer::UNIFORM ) bindUniform( info->descriptor );
if ( info->usage & enums::Buffer::VERTEX ) vertexBufferInfo = header;
if ( info->usage & enums::Buffer::INDEX ) indexBufferInfo = header;
} break;
case ext::opengl::enums::Command::BIND_GRAPHIC_BUFFER: {
InfoGraphicBuffer* info = (InfoGraphicBuffer*) header;
if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<<info<<"] BINDING BUFFER: ";
auto& buffer = info->graphic->buffers[info->bufferIndex];
if ( state == 2 && VERBOSE_SUBMIT ) std::cout << buffer.descriptor.buffer << " | FLAGS: " << /*std::bitset<16>*/(buffer.usage) << "\n";
if ( buffer.usage & enums::Buffer::UNIFORM ) bindUniform( buffer.descriptor );
if ( buffer.usage & enums::Buffer::VERTEX ) vertexBufferInfo = header;
if ( buffer.usage & enums::Buffer::INDEX ) indexBufferInfo = header;
} break;
case ext::opengl::enums::Command::BIND_TEXTURE: {
InfoTexture* info = (InfoTexture*) header;
if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<<info<<"] BINDING TEXTURE: " << info->descriptor.image << " | " << info->descriptor.viewType << "\n";
textureInfos.emplace_back(info);
} break;
case ext::opengl::enums::Command::BIND_PIPELINE: {
InfoPipeline* info = (InfoPipeline*) header;
if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<<info<<"] BINDING PIPELINE: " << info->descriptor.pipeline << " | " << info->descriptor.vertexArray << "\n";
#if !UF_USE_OPENGL_FIXED_FUNCTION
GL_ERROR_CHECK(glUseProgram(info->descriptor.pipeline));
#endif
} break;
case ext::opengl::enums::Command::DRAW: {
InfoDraw* info = (InfoDraw*) header;
if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<<info<<"] DRAW CALL | COUNT: " << info->length << " | VERTEX INFO: " << vertexBufferInfo << " | INDEX INFO: " << indexBufferInfo << "\n";
if ( vertexBufferInfo ) {
if ( indexBufferInfo ) drawIndexed( *info, *vertexBufferInfo, *indexBufferInfo, textureInfos );
else draw( *info, *vertexBufferInfo, textureInfos );
}
textureInfos.clear();
vertexBufferInfo = NULL;
indexBufferInfo = NULL;
} break;
default: {
if ( state == 2 && VERBOSE_SUBMIT ) {
std::cout << "["<<header<<"] UNKNOWN COMMAND TYPE: " << header->type << ": " << info.data().len << std::endl;;
}
} break;
}
}
if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "==== ["<<this<<"] COMMAND BUFFER SUBMIT END ==== " << std::endl;
#endif
state = 3;
mutex->unlock();
}
@ -355,10 +224,6 @@ void ext::opengl::CommandBuffer::flush() {
for ( auto& userdata : infos ) userdata.destroy();
infos.clear();
state = 0;
/*
startInfo = NULL;
endInfo = NULL;
*/
mutex->unlock();
}
size_t ext::opengl::CommandBuffer::size() const {
@ -378,164 +243,6 @@ pod::Matrix4f ext::opengl::CommandBuffer::bindUniform( const ext::opengl::Buffer
return uniform->projection * uniform->modelView;
#endif
}
#if 0
void ext::opengl::CommandBuffer::draw( const ext::opengl::CommandBuffer::InfoDraw& drawInfo, const ext::opengl::CommandBuffer::Info& vertexBufferInfo, const uf::stl::vector<InfoTexture*>& textureInfos ) {
ext::opengl::Buffer::Descriptor vertexBuffer = {};
switch ( vertexBufferInfo.type ) {
case ext::opengl::enums::Command::BIND_BUFFER: {
ext::opengl::CommandBuffer::InfoBuffer* info = (ext::opengl::CommandBuffer::InfoBuffer*) &vertexBufferInfo;
vertexBuffer = info->descriptor;
} break;
case ext::opengl::enums::Command::BIND_GRAPHIC_BUFFER: {
ext::opengl::CommandBuffer::InfoGraphicBuffer* info = (ext::opengl::CommandBuffer::InfoGraphicBuffer*) &vertexBufferInfo;
vertexBuffer = info->graphic->buffers[info->bufferIndex].descriptor;
} break;
}
if ( !vertexBuffer.buffer ) return;
size_t vertexStride = drawInfo.descriptor.attributes.vertex.size;
size_t vertices = vertexBuffer.range / vertexStride;
uf::renderer::AttributeDescriptor vertexAttributePosition,
vertexAttributeNormal,
vertexAttributeColor,
vertexAttributeUv,
vertexAttributeSt,
vertexAttributeId;
for ( auto& attribute : drawInfo.descriptor.attributes.vertex.descriptor ) {
if ( attribute.name == "position" ) vertexAttributePosition = attribute;
else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute;
else if ( attribute.name == "color" ) vertexAttributeColor = attribute;
else if ( attribute.name == "uv" ) vertexAttributeUv = attribute;
else if ( attribute.name == "st" ) vertexAttributeSt = attribute;
else if ( attribute.name == "id" ) vertexAttributeId = attribute;
}
if ( vertexAttributePosition.name == "" ) return;
if ( drawInfo.descriptor.cullMode == GL_NONE ) {
GL_ERROR_CHECK(glDisable(GL_CULL_FACE));
} else {
GL_ERROR_CHECK(glEnable(GL_CULL_FACE));
GL_ERROR_CHECK(glFrontFace(drawInfo.descriptor.frontFace));
GL_ERROR_CHECK(glCullFace(drawInfo.descriptor.cullMode));
}
if ( drawInfo.descriptor.depth.test ) {
GL_ERROR_CHECK(glEnable(GL_DEPTH_TEST));
} else {
GL_ERROR_CHECK(glDisable(GL_DEPTH_TEST));
}
GL_ERROR_CHECK(glDepthMask(drawInfo.descriptor.depth.write ? GL_TRUE : GL_FALSE));
// GPU-buffer based command dispatching
#if !UF_USE_OPENGL_FIXED_FUNCTION
#else
// CPU-buffer based command dispatching
uint8_t* vertexPointer = (uint8_t*) ( device->getBuffer( vertexBuffer.buffer ) + vertexBuffer.offset );
// vertices do not need to be transformed
//if ( vertexAttributeId.name == "" )
#if !UF_USE_OPENGL_IMMEDIATE_MODE
if ( vertexAttributeNormal.name != "" ) GL_ERROR_CHECK(glEnableClientState(GL_NORMAL_ARRAY));
if ( vertexAttributeColor.name != "" )GL_ERROR_CHECK(glEnableClientState(GL_COLOR_ARRAY));
if ( vertexAttributeUv.name != "" ) GL_ERROR_CHECK(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
GL_ERROR_CHECK(glEnableClientState(GL_VERTEX_ARRAY));
// no ID attribute found, fallback
if ( vertexAttributeId.name == "" ) {
if ( !textureInfos.empty() ) {
InfoTexture* info = textureInfos.front();
GL_ERROR_CHECK(glEnable(info->descriptor.viewType));
GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image));
}
GL_BIND_POINTERS();
GL_ERROR_CHECK(glDrawArrays(GL_TRIANGLES, 0, vertices));
} else {
if ( textureInfos.empty() ) {
GL_BIND_POINTERS();
GL_ERROR_CHECK(glDrawArrays(GL_TRIANGLES, 0, vertices));
} else if ( textureInfos.size() == 1 ) {
InfoTexture* info = textureInfos.front();
GL_ERROR_CHECK(glEnable(info->descriptor.viewType));
GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image));
GL_BIND_POINTERS();
GL_ERROR_CHECK(glDrawArrays(GL_TRIANGLES, 0, vertices));
} else {
uf::stl::vector<uf::stl::vector<uf::renderer::index_t>> sorted( textureInfos.size() );
for ( uf::renderer::index_t index = 0; index < vertices; ++index ) {
uint8_t* vertex = vertexPointer + (index * vertexStride);
const pod::Vector<uf::graph::id_t,2>& id = *((pod::Vector<uf::graph::id_t,2>*) (vertex + vertexAttributeId.offset));
size_t textureId = id.y;
if ( textureInfos.size() < textureId ) continue;
sorted[textureId].emplace_back(index);
}
GLenum indicesType = GL_UNSIGNED_INT;
switch ( sizeof(uf::renderer::index_t) ) {
case sizeof(uint32_t): indicesType = GL_UNSIGNED_INT; break;
case sizeof(uint16_t): indicesType = GL_UNSIGNED_SHORT; break;
case sizeof(uint8_t): indicesType = GL_UNSIGNED_BYTE; break;
}
for ( size_t textureId = 0; textureId < sorted.size(); ++textureId ) {
auto& indices = sorted[textureId];
if ( indices.empty() ) continue;
InfoTexture* info = textureInfos[textureId];
GL_ERROR_CHECK(glEnable(info->descriptor.viewType));
GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image));
GL_BIND_POINTERS();
GL_ERROR_CHECK(glDrawElements(GL_TRIANGLES, indices.size(), indicesType, &indices[0]));
}
}
}
if ( vertexAttributeNormal.name != "" ) GL_ERROR_CHECK(glDisableClientState(GL_NORMAL_ARRAY));
if ( vertexAttributeColor.name != "" ) GL_ERROR_CHECK(glDisableClientState(GL_COLOR_ARRAY));
if ( vertexAttributeUv.name != "" ) GL_ERROR_CHECK(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
GL_ERROR_CHECK(glDisableClientState(GL_VERTEX_ARRAY));
#else
// no ID attribute found, fallback
if ( vertexAttributeId.name == "" ) {
if ( !textureInfos.empty() ) {
InfoTexture* info = textureInfos.front();
GL_ERROR_CHECK(glEnable(info->descriptor.viewType));
GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image));
}
GL_DRAW_ARRAYS( vertexPointer, vertices );
} else {
if ( textureInfos.empty() ) {
GL_DRAW_ARRAYS( vertexPointer, vertices );
} else if ( textureInfos.size() == 1 ) {
InfoTexture* info = textureInfos.front();
GL_ERROR_CHECK(glEnable(info->descriptor.viewType));
GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image));
GL_DRAW_ARRAYS( vertexPointer, vertices );
} else {
uf::stl::vector<uf::stl::vector<uf::renderer::index_t>> sorted( textureInfos.size() );
for ( uf::renderer::index_t index = 0; index < vertices; ++index ) {
uint8_t* vertex = vertexPointer + (index * vertexStride);
const pod::Vector<uf::graph::id_t,2>& id = *((pod::Vector<uf::graph::id_t,2>*) (vertex + vertexAttributeId.offset));
size_t textureId = id.y;
if ( textureInfos.size() < textureId ) continue;
sorted[textureId].emplace_back(index);
}
for ( size_t textureId = 0; textureId < sorted.size(); ++textureId ) {
auto& indices = sorted[textureId];
if ( indices.empty() ) continue;
InfoTexture* info = textureInfos[textureId];
GL_ERROR_CHECK(glEnable(info->descriptor.viewType));
GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, info->descriptor.image));
GL_DRAW_ELEMENTS( (&indices[0]) , (indices.size()) );
}
}
}
#endif
#endif
}
#endif
void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer::InfoDraw& drawInfo ) {
auto projectionViewMatrix = bindUniform( drawInfo.uniformBuffer );
@ -601,7 +308,8 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer::
GL_ERROR_CHECK(glVertexPointer(3, GL_FLOAT, vertexStride, vertexPointer + drawInfo.attributes.position));
// frustrum culling
if ( ext::opengl::settings::experimental::frustrumCull ) {
#if 0
if ( ext::opengl::settings::experimental::culling ) {
uf::stl::vector<uf::renderer::index_t> unculled;
unculled.reserve(indices);
for ( size_t currentIndex = 0; currentIndex < indices; currentIndex += 3 ) {
@ -641,6 +349,9 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer::
} else {
GL_ERROR_CHECK(glDrawElements(GL_TRIANGLES, indices, indicesType, indicesPointer));
}
#else
GL_ERROR_CHECK(glDrawElements(GL_TRIANGLES, indices, indicesType, indicesPointer));
#endif
if ( drawInfo.auxTexture.image ) {
#if UF_ENV_DREAMCAST

View File

@ -38,9 +38,9 @@ bool ext::opengl::settings::experimental::deferredAliasOutputToSwapchain = true;
bool ext::opengl::settings::experimental::multiview = true;
bool ext::opengl::settings::experimental::vsync = true;
bool ext::opengl::settings::experimental::hdr = true;
bool ext::opengl::settings::experimental::frustrumCull = false;
bool ext::opengl::settings::experimental::vxgi = true;
bool ext::opengl::settings::experimental::deferredSampling = true;
bool ext::opengl::settings::experimental::culling = false;
GLhandle(VkColorSpaceKHR) ext::opengl::settings::formats::colorSpace;
ext::opengl::enums::Format::type_t ext::opengl::settings::formats::color = ext::opengl::enums::Format::R8G8B8A8_UNORM;
@ -171,7 +171,7 @@ void UF_API ext::opengl::initialize() {
// bind shaders
#if !UF_ENV_DREAMCAST
{
ext::opengl::Shader::bind( uf::io::root + "shaders/gltf/instanced.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) {
ext::opengl::Shader::bind( uf::io::root + "shaders/graph/instanced.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) {
if ( !userdata ) return;
uint8_t* verticesSrc = (uint8_t*) userdata;
@ -240,7 +240,7 @@ void UF_API ext::opengl::initialize() {
}
}
});
ext::opengl::Shader::bind( uf::io::root + "shaders/gltf/skinned.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) {
ext::opengl::Shader::bind( uf::io::root + "shaders/graph/skinned.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) {
if ( !userdata ) return;
uint8_t* verticesSrc = (uint8_t*) userdata;

View File

@ -55,31 +55,14 @@ void ext::vulkan::Buffer::copyTo( void* data, VkDeviceSize size ) {
}
VkResult ext::vulkan::Buffer::flush( VkDeviceSize size, VkDeviceSize offset ) const {
/*
VkMappedMemoryRange mappedRange = {};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = memory;
mappedRange.offset = offset;
mappedRange.size = size;
return vkFlushMappedMemoryRanges(device, 1, &mappedRange);
*/
return VK_SUCCESS;
}
VkResult ext::vulkan::Buffer::invalidate( VkDeviceSize size, VkDeviceSize offset ) {
/*
VkMappedMemoryRange mappedRange = {};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = memory;
mappedRange.offset = offset;
mappedRange.size = size;
return vkInvalidateMappedMemoryRanges(device, 1, &mappedRange);
*/
return VK_SUCCESS;
}
void ext::vulkan::Buffer::allocate( VkBufferCreateInfo bufferCreateInfo ) {
// VK_CHECK_RESULT(vkCreateBuffer( device, &bufferCreateInfo, nullptr, &buffer));
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
@ -89,10 +72,6 @@ void ext::vulkan::Buffer::allocate( VkBufferCreateInfo bufferCreateInfo ) {
}
vmaCreateBuffer( allocator, &bufferCreateInfo, &allocCreateInfo, &buffer, &allocation, &allocationInfo );
// VkMemoryPropertyFlags memFlags;
// vmaGetMemoryTypeProperties(allocator, allocationInfo.memoryType, &memFlags);
// memory = allocationInfo.deviceMemory;
// size = allocationInfo.size;
}
// RAII
@ -107,14 +86,13 @@ void ext::vulkan::Buffer::destroy() {
if ( buffer ) {
vmaDestroyBuffer( allocator, buffer, allocation );
// vkDestroyBuffer(device, buffer, nullptr);
}
// if ( memory ) vkFreeMemory(device, memory, nullptr);
buffer = nullptr;
memory = nullptr;
}
void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, bool stage ) {
if ( !device ) device = &ext::vulkan::device;
if ( stage ) usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; // implicitly set properties
VK_CHECK_RESULT(device->createBuffer(
usage,
@ -122,9 +100,11 @@ void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkB
*this,
length
));
if ( data ) update( data, length, stage );
if ( data && length ) update( data, length, stage );
}
void ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool stage ) const {
if ( !data || !length ) return;
if ( length > allocationInfo.size ) {
UF_MSG_DEBUG("LENGTH OF " << length << " EXCEEDS BUFFER SIZE " << allocationInfo.size );
Buffer& b = *const_cast<Buffer*>(this);
@ -141,6 +121,8 @@ void ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool st
}
Buffer staging;
ext::vulkan::Device* device = this->device ? this->device : &ext::vulkan::device;
device->createBuffer(
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,

View File

@ -5,6 +5,7 @@
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/openvr/openvr.h>
#include <uf/utils/camera/camera.h>
#include <uf/engine/graph/graph.h>
#include <spirv_cross/spirv_cross.hpp>
#include <spirv_cross/spirv_glsl.hpp>
@ -42,15 +43,16 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
uf::stl::vector<VkPipelineColorBlendAttachmentState> blendAttachmentStates;
uf::stl::vector<VkPipelineShaderStageCreateInfo> shaderDescriptors;
uf::stl::vector<VkSpecializationInfo> shaderSpecializationInfos;
uf::stl::vector<VkVertexInputBindingDescription> inputBindingDescriptions;
uf::stl::vector<VkVertexInputAttributeDescription> attributeDescriptions;
{
for ( auto* shaderPointer : shaders ) {
auto& shader = *shaderPointer;
descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() );
descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.end(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() );
std::size_t offset = 0;
size_t offset = 0;
for ( auto& pushConstant : shader.pushConstants ) {
size_t len = pushConstant.data().len;
if ( len <= 0 || len > device.properties.limits.maxPushConstantsSize ) {
@ -186,6 +188,15 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
descriptor.depth.write,
descriptor.depth.operation
);
if ( uf::matrix::reverseInfiniteProjection ) {
depthStencilState.depthCompareOp = ext::vulkan::enums::Compare::GREATER_OR_EQUAL;
depthStencilState.minDepthBounds = 1.0f;
depthStencilState.maxDepthBounds = 0.0f;
} else {
depthStencilState.depthCompareOp = ext::vulkan::enums::Compare::LESS;
depthStencilState.minDepthBounds = 0.0f;
depthStencilState.maxDepthBounds = 1.0f;
}
VkPipelineViewportStateCreateInfo viewportState = ext::vulkan::initializers::pipelineViewportStateCreateInfo(
1, 1, 0
);
@ -250,7 +261,38 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
vertexInputState.vertexAttributeDescriptionCount = attributeDescriptions.size();
vertexInputState.pVertexAttributeDescriptions = attributeDescriptions.data();
#if 0
for ( auto* SHADER : shaders ) {
ext::vulkan::Shader* shader = const_cast<ext::vulkan::Shader*>(SHADER);
void* s = (void*) shader->specializationConstants;
size_t len = shader->specializationConstants.data().len;
bool invalidated = true;
for ( auto pair : shader->metadata.definitions.specializationConstants ) {
auto& name = pair.first;
auto& payload = pair.second;
uf::stl::string type = payload.type;
if ( type == "int32_t" ) {
int32_t& v = ((int32_t*) s)[payload.index];
UF_MSG_DEBUG("SC " << payload.name << " = " << v << " = " << payload.value.i << "`" << shader->filename << "`");
if ( payload.validate && v != payload.value.i ) v = payload.value.i;
payload.value.i = v;
} else if ( type == "uint32_t" ) {
uint32_t& v = ((uint32_t*) s)[payload.index];
UF_MSG_DEBUG("SC " << payload.name << " = " << v << " = " << payload.value.ui << "`" << shader->filename << "`");
if ( payload.validate && v != payload.value.ui ) v = payload.value.ui;
payload.value.ui = v;
} else if ( type == "float" ) {
float& v = ((float*) s)[payload.index];
UF_MSG_DEBUG("SC " << payload.name << " = " << v << " = " << payload.value.f << "`" << shader->filename << "`");
if ( payload.validate && v != payload.value.f ) v = payload.value.f;
payload.value.f = v;
}
}
shaderDescriptors.push_back(shader->descriptor);
}
#else
for ( auto* shader : shaders ) shaderDescriptors.emplace_back(shader->descriptor);
#endif
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
@ -287,15 +329,15 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, VkCommandBuffer comm
auto shaders = getShaders( graphic.material.shaders );
for ( auto* shader : shaders ) {
if ( shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
#if 0
#if 1
if ( shader->metadata.definitions.pushConstants.count("PushConstant") > 0 ) {
if ( shader->descriptor.stage == VK_SHADER_STAGE_VERTEX_BIT ) {
struct PushConstant {
uint32_t pass;
uint32_t draw;
} pushConstant = { pass, draw };
( commandBuffer, pipelineLayout, shader->descriptor.stage, 0, sizeof(pushConstant), &pushConstant );
}
if ( shader->descriptor.stage == VK_SHADER_STAGE_VERTEX_BIT || shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) {
struct PushConstant {
uint32_t pass;
uint32_t draw;
} pushConstant = { pass, draw };
vkCmdPushConstants( commandBuffer, pipelineLayout, shader->descriptor.stage, 0, sizeof(pushConstant), &pushConstant );
}
} else
#endif
if ( !shader->pushConstants.empty() ) {
@ -332,6 +374,10 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, VkCommandBuffer comm
// Bind the rendering pipeline
// The pipeline (state object) contains all states of the rendering pipeline, binding it will set all the states specified at pipeline creation time
vkCmdBindPipeline(commandBuffer, bindPoint, pipeline);
if ( bindPoint == VK_PIPELINE_BIND_POINT_COMPUTE && descriptor.inputs.dispatch.x != 0 && descriptor.inputs.dispatch.y != 0 && descriptor.inputs.dispatch.z != 0 ) {
vkCmdDispatch(commandBuffer, descriptor.inputs.dispatch.x, descriptor.inputs.dispatch.y, descriptor.inputs.dispatch.z);
}
}
void ext::vulkan::Pipeline::update( const Graphic& graphic ) {
return this->update( graphic, descriptor );
@ -348,7 +394,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
auto shaders = getShaders( graphic.material.shaders );
uf::stl::vector<VkWriteDescriptorSet> writeDescriptorSets;
struct {
struct Infos {
uf::stl::vector<VkDescriptorBufferInfo> uniform;
uf::stl::vector<VkDescriptorBufferInfo> storage;
@ -360,35 +406,38 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
uf::stl::vector<VkDescriptorImageInfo> sampler;
uf::stl::vector<VkDescriptorImageInfo> input;
} infos;
};
uf::stl::vector<Infos> INFOS; INFOS.reserve( shaders.size() );
uf::stl::vector<ext::vulkan::enums::Image::viewType_t> types;
if ( descriptor.subpass < renderTarget.passes.size() ) {
auto& subpass = renderTarget.passes[descriptor.subpass];
for ( auto& input : subpass.inputs ) {
infos.input.emplace_back(ext::vulkan::initializers::descriptorImageInfo(
renderTarget.attachments[input.attachment].views[subpass.layer],
input.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : input.layout
));
}
}
for ( auto& texture : graphic.material.textures ) {
infos.image.emplace_back(texture.descriptor);
switch ( texture.viewType ) {
case VK_IMAGE_VIEW_TYPE_2D: infos.image2D.emplace_back(texture.descriptor); break;
case VK_IMAGE_VIEW_TYPE_CUBE: infos.imageCube.emplace_back(texture.descriptor); break;
case VK_IMAGE_VIEW_TYPE_3D: infos.image3D.emplace_back(texture.descriptor); break;
default: infos.imageUnknown.emplace_back(texture.descriptor); break;
}
}
for ( auto& sampler : graphic.material.samplers ) {
infos.sampler.emplace_back(sampler.descriptor.info);
}
size_t consumes = 0;
for ( auto* shader : shaders ) {
auto& infos = INFOS.emplace_back();
uf::stl::vector<ext::vulkan::enums::Image::viewType_t> types;
if ( descriptor.subpass < renderTarget.passes.size() ) {
auto& subpass = renderTarget.passes[descriptor.subpass];
for ( auto& input : subpass.inputs ) {
infos.input.emplace_back(ext::vulkan::initializers::descriptorImageInfo(
renderTarget.attachments[input.attachment].views[subpass.layer],
input.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : input.layout
));
}
}
for ( auto& texture : graphic.material.textures ) {
infos.image.emplace_back(texture.descriptor);
switch ( texture.viewType ) {
case VK_IMAGE_VIEW_TYPE_2D: infos.image2D.emplace_back(texture.descriptor); break;
case VK_IMAGE_VIEW_TYPE_CUBE: infos.imageCube.emplace_back(texture.descriptor); break;
case VK_IMAGE_VIEW_TYPE_3D: infos.image3D.emplace_back(texture.descriptor); break;
default: infos.imageUnknown.emplace_back(texture.descriptor); break;
}
}
for ( auto& sampler : graphic.material.samplers ) {
infos.sampler.emplace_back(sampler.descriptor.info);
}
size_t consumes = 0;
for ( auto& buffer : shader->buffers ) {
if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor);
if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor);
@ -408,45 +457,43 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
} break;
}
}
}
size_t maxTextures2D = 0;
size_t maxTextures3D = 0;
size_t maxTexturesCube = 0;
size_t maxTexturesUnknown = 0;
for ( auto& type : types ) {
if ( type == ext::vulkan::enums::Image::VIEW_TYPE_3D ) ++maxTextures3D;
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) ++maxTexturesCube;
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_2D ) ++maxTextures2D;
else ++maxTexturesUnknown;
}
size_t maxTextures2D = 0;
size_t maxTextures3D = 0;
size_t maxTexturesCube = 0;
size_t maxTexturesUnknown = 0;
for ( auto& type : types ) {
if ( type == ext::vulkan::enums::Image::VIEW_TYPE_3D ) ++maxTextures3D;
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) ++maxTexturesCube;
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_2D ) ++maxTextures2D;
else ++maxTexturesUnknown;
}
while ( infos.image2D.size() < maxTextures2D ) infos.image2D.emplace_back(Texture2D::empty.descriptor);
while ( infos.imageCube.size() < maxTexturesCube ) infos.imageCube.emplace_back(TextureCube::empty.descriptor);
while ( infos.image3D.size() < maxTextures3D ) infos.image3D.emplace_back(Texture3D::empty.descriptor);
while ( infos.imageUnknown.size() < maxTexturesUnknown ) infos.imageUnknown.emplace_back(Texture2D::empty.descriptor);
while ( infos.image2D.size() < maxTextures2D ) infos.image2D.emplace_back(Texture2D::empty.descriptor);
while ( infos.imageCube.size() < maxTexturesCube ) infos.imageCube.emplace_back(TextureCube::empty.descriptor);
while ( infos.image3D.size() < maxTextures3D ) infos.image3D.emplace_back(Texture3D::empty.descriptor);
while ( infos.imageUnknown.size() < maxTexturesUnknown ) infos.imageUnknown.emplace_back(Texture2D::empty.descriptor);
for ( size_t i = infos.image.size(); i < consumes; ++i ) {
ext::vulkan::enums::Image::viewType_t type = i < types.size() ? types[i] : ext::vulkan::enums::Image::viewType_t{};
if ( type == ext::vulkan::enums::Image::VIEW_TYPE_3D ) infos.image.emplace_back(Texture3D::empty.descriptor);
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) infos.image.emplace_back(TextureCube::empty.descriptor);
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_2D ) infos.image.emplace_back(Texture2D::empty.descriptor);
else infos.image.emplace_back(Texture2D::empty.descriptor);
}
auto uniformBufferInfo = infos.uniform.begin();
auto storageBufferInfo = infos.storage.begin();
auto imageInfo = infos.image.begin();
auto image2DInfo = infos.image2D.begin();
auto imageCubeInfo = infos.imageCube.begin();
auto image3DInfo = infos.image3D.begin();
auto imageUnknownInfo = infos.imageUnknown.begin();
for ( size_t i = infos.image.size(); i < consumes; ++i ) {
ext::vulkan::enums::Image::viewType_t type = i < types.size() ? types[i] : ext::vulkan::enums::Image::viewType_t{};
if ( type == ext::vulkan::enums::Image::VIEW_TYPE_3D ) infos.image.emplace_back(Texture3D::empty.descriptor);
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_CUBE ) infos.image.emplace_back(TextureCube::empty.descriptor);
else if ( type == ext::vulkan::enums::Image::VIEW_TYPE_2D ) infos.image.emplace_back(Texture2D::empty.descriptor);
else infos.image.emplace_back(Texture2D::empty.descriptor);
}
auto uniformBufferInfo = infos.uniform.begin();
auto storageBufferInfo = infos.storage.begin();
auto imageInfo = infos.image.begin();
auto image2DInfo = infos.image2D.begin();
auto imageCubeInfo = infos.imageCube.begin();
auto image3DInfo = infos.image3D.begin();
auto imageUnknownInfo = infos.imageUnknown.begin();
auto samplerInfo = infos.sampler.begin();
auto inputInfo = infos.input.begin();
auto samplerInfo = infos.sampler.begin();
auto inputInfo = infos.input.begin();
for ( auto* shader : shaders ) {
for ( auto& layout : shader->descriptorSetLayoutBindings ) {
switch ( layout.descriptorType ) {
// consume an texture image info
@ -635,8 +682,14 @@ void ext::vulkan::Pipeline::destroy() {
uf::stl::vector<ext::vulkan::Shader*> ext::vulkan::Pipeline::getShaders( uf::stl::vector<ext::vulkan::Shader>& shaders ) {
uf::stl::unordered_map<uf::stl::string, ext::vulkan::Shader*> map;
uf::stl::vector<ext::vulkan::Shader*> res;
bool isCompute = false;
for ( auto& shader : shaders ) {
if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue;
if ( shader.descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) isCompute = true;
}
for ( auto& shader : shaders ) {
if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue;
if ( isCompute && shader.descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue;
map[shader.metadata.type] = &shader;
}
for ( auto pair : map ) res.insert( res.begin(), pair.second);
@ -645,8 +698,14 @@ uf::stl::vector<ext::vulkan::Shader*> ext::vulkan::Pipeline::getShaders( uf::stl
uf::stl::vector<const ext::vulkan::Shader*> ext::vulkan::Pipeline::getShaders( const uf::stl::vector<ext::vulkan::Shader>& shaders ) const {
uf::stl::unordered_map<uf::stl::string, const ext::vulkan::Shader*> map;
uf::stl::vector<const ext::vulkan::Shader*> res;
bool isCompute = false;
for ( auto& shader : shaders ) {
if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue;
if ( shader.descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) isCompute = true;
}
for ( auto& shader : shaders ) {
if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue;
if ( isCompute && shader.descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue;
map[shader.metadata.type] = &shader;
}
for ( auto pair : map ) res.insert( res.begin(), pair.second);
@ -668,9 +727,12 @@ void ext::vulkan::Material::destroy() {
}
void ext::vulkan::Material::attachShader( const uf::stl::string& filename, VkShaderStageFlagBits stage, const uf::stl::string& pipeline ) {
auto& shader = shaders.emplace_back();
shader.metadata.json = metadata.json["shader"];
shader.metadata.autoInitializeUniforms = metadata.autoInitializeUniforms;
shader.initialize( *device, filename, stage );
// repoint our specialization info descriptor because our shaders will change memory locations when attaching one by one
for ( auto& shader : shaders ) {
shader.specializationInfo.mapEntryCount = shader.specializationMapEntries.size();
shader.specializationInfo.pMapEntries = shader.specializationMapEntries.data();
@ -755,7 +817,6 @@ ext::vulkan::Pipeline& ext::vulkan::Graphic::initializePipeline( const GraphicDe
pipeline.initialize(*this, descriptor);
pipeline.update(*this, descriptor);
// process = true;
initialized = true;
material.validate();
@ -763,9 +824,9 @@ ext::vulkan::Pipeline& ext::vulkan::Graphic::initializePipeline( const GraphicDe
}
void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) {
// generate indices if not found
if ( mesh.index.count == 0 ) mesh.generateIndices();
// if ( mesh.index.count == 0 ) mesh.generateIndices();
// generate indirect data if not found
if ( mesh.indirect.count == 0 ) mesh.generateIndirect();
// if ( mesh.indirect.count == 0 ) mesh.generateIndirect();
// ensure our descriptors are proper
mesh.updateDescriptor();
@ -776,12 +837,12 @@ void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) {
descriptor.inputs.indirect = mesh.indirect;
// create buffer if not set and requested
if ( !initialized && buffer ) {
if ( buffer ) {
// ensures each buffer index reflects nicely
struct Queue {
void* data;
size_t size;
uf::renderer::enums::Buffer::type_t usage;
VkBufferUsageFlags usage;
};
uf::stl::vector<Queue> queue;
descriptor.inputs.bufferOffset = buffers.empty() ? 0 : buffers.size() - 1;
@ -799,10 +860,11 @@ void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) {
PARSE_INPUT(vertex, uf::renderer::enums::Buffer::VERTEX)
PARSE_INPUT(index, uf::renderer::enums::Buffer::INDEX)
PARSE_INPUT(instance, uf::renderer::enums::Buffer::VERTEX)
PARSE_INPUT(indirect, uf::renderer::enums::Buffer::INDIRECT)
PARSE_INPUT(indirect, uf::renderer::enums::Buffer::INDIRECT | uf::renderer::enums::Buffer::STORAGE)
// allocate buffers
for ( auto& q : queue ) {
for ( auto i = 0; i < queue.size(); ++i ) {
auto& q = queue[i];
initializeBuffer( q.data, q.size, q.usage );
}
}
@ -811,6 +873,54 @@ void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) {
descriptor.inputs.instance.count = 1;
}
}
void ext::vulkan::Graphic::updateMesh( uf::Mesh& mesh ) {
// generate indices if not found
// if ( mesh.index.count == 0 ) mesh.generateIndices();
// generate indirect data if not found
// if ( mesh.indirect.count == 0 ) mesh.generateIndirect();
// ensure our descriptors are proper
mesh.updateDescriptor();
// copy descriptors
descriptor.inputs.vertex = mesh.vertex;
descriptor.inputs.index = mesh.index;
descriptor.inputs.instance = mesh.instance;
descriptor.inputs.indirect = mesh.indirect;
// create buffer if not set and requested
// ensures each buffer index reflects nicely
struct Queue {
void* data;
size_t size;
uf::renderer::enums::Buffer::type_t usage;
};
uf::stl::vector<Queue> queue;
#define PARSE_ATTRIBUTE(i, usage) {\
auto& buffer = mesh.buffers[i];\
if ( queue.size() <= i ) queue.resize( i );\
if ( !buffer.empty() ) queue.emplace_back(Queue{ (void*) buffer.data(), buffer.size(), usage });\
}
#define PARSE_INPUT(name, usage){\
if ( mesh.isInterleaved( mesh.name.interleaved ) ) PARSE_ATTRIBUTE(descriptor.inputs.name.interleaved, usage)\
else for ( auto& attribute : descriptor.inputs.name.attributes ) PARSE_ATTRIBUTE(attribute.buffer, usage)\
}
PARSE_INPUT(vertex, uf::renderer::enums::Buffer::VERTEX)
PARSE_INPUT(index, uf::renderer::enums::Buffer::INDEX)
PARSE_INPUT(instance, uf::renderer::enums::Buffer::VERTEX)
PARSE_INPUT(indirect, uf::renderer::enums::Buffer::INDIRECT)
// allocate buffers
for ( auto i = 0; i < queue.size(); ++i ) {
auto& q = queue[i];
updateBuffer( q.data, q.size, descriptor.inputs.bufferOffset + i );
}
if ( mesh.instance.count == 0 && mesh.instance.attributes.empty() ) {
descriptor.inputs.instance.count = 1;
}
}
bool ext::vulkan::Graphic::hasPipeline( const GraphicDescriptor& descriptor ) const {
return pipelines.count( descriptor.hash() ) > 0;
}
@ -849,44 +959,8 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD
if ( !pipeline.metadata.process ) return;
pipeline.record(*this, commandBuffer, pass, draw);
/*
struct VertexInstance {
VkBuffer buffer;
VkDeviceSize offset;
};
struct {
struct {
size_t min;
size_t max;
} binding;
uf::stl::vector<VkBuffer> buffer;
uf::stl::vector<VkDeviceSize> offset;
} vertexInstance;
uf::stl::unordered_map<size_t, VertexInstance> vertexInstanceRemap;
for ( auto& attribute : descriptor.inputs.vertex.attributes ) {
vertexInstanceRemap[attribute.binding] = {
.buffer = buffers.at(attribute.buffer).buffer,
.offset = attribute.offset,
};
vertexInstance.binding.min = MIN(vertexInstance.binding.min, attribute.binding);
vertexInstance.binding.max = MAX(vertexInstance.binding.max, attribute.binding);
}
for ( auto& attribute : descriptor.inputs.instance.attributes ) {
vertexInstanceRemap[attribute.binding] = {
.buffer = buffers.at(attribute.buffer).buffer,
.offset = attribute.offset,
};
vertexInstance.binding.min = MIN(vertexInstance.binding.min, attribute.binding);
vertexInstance.binding.max = MAX(vertexInstance.binding.max, attribute.binding);
}
vertexInstance.buffer.resize( vertexInstanceRemap.size() );
vertexInstance.offset.resize( vertexInstanceRemap.size() );
for ( auto i = vertexInstance.binding.min; i <= vertexInstance.binding.max; ++i ) {
vertexInstance.buffer.emplace_back(vertexInstanceRemap[i].buffer);
vertexInstance.offset.emplace_back(vertexInstanceRemap[i].offset);
}
*/
auto shaders = pipeline.getShaders( material.shaders );
for ( auto* shader : shaders ) if ( shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) return;
struct {
uf::stl::vector<VkBuffer> buffer;
@ -918,6 +992,26 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD
auto& attribute = descriptor.inputs.indirect.attributes.front();
indirect.buffer = buffers.at((0 <= descriptor.inputs.indirect.interleaved ? descriptor.inputs.indirect.interleaved : attribute.buffer) + descriptor.inputs.bufferOffset).buffer;
indirect.offset = 0 <= descriptor.inputs.indirect.interleaved ? descriptor.inputs.indirect.offset : attribute.offset;
/*
.indices = indices.size(),
.instances = 1,
.indexID = mesh.index.count,
.vertexID = mesh.vertex.count,
.instanceID = mesh.instance.count,
.materialID = p.material,
.objectID = 0,
.vertices = vertices.size(),
if ( attribute.descriptor.pointer ) {
pod::DrawCommand* drawCommands = (pod::DrawCommand*) attribute.descriptor.pointer;
for ( auto i = 0; i < descriptor.inputs.indirect.count; ++i ) {
auto& drawCommand = drawCommands[i];
// UF_MSG_DEBUG( "DrawCommand[" << i << "]: " << drawCommand.indices << " " << drawCommand.instances << " " << drawCommand.indexID << " " << drawCommand.vertexID << " " << drawCommand.instanceID << " " << drawCommand.materialID << " " << drawCommand.objectID << " " << drawCommand.vertices );
}
}
*/
}
for ( auto& buffer : buffers ) {
@ -941,12 +1035,36 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD
}
vkCmdBindIndexBuffer(commandBuffer, index.buffer, index.offset, indicesType);
}
if ( index.buffer && indirect.buffer ) {
vkCmdDrawIndexedIndirect(commandBuffer, indirect.buffer,
descriptor.inputs.indirect.offset, // offset
descriptor.inputs.indirect.count, // drawCount
descriptor.inputs.indirect.stride // stride
);
const bool cpuSideIndirection = false;
if ( index.buffer && indirect.buffer && cpuSideIndirection ) {
auto& indirectAttribute = descriptor.inputs.indirect.attributes.front();
const pod::DrawCommand* drawCommands = (const pod::DrawCommand*) indirectAttribute.pointer;
for ( auto i = 0; i < descriptor.inputs.indirect.count; ++i ) {
auto& drawCommand = drawCommands[i];
vkCmdDrawIndexed(commandBuffer,
drawCommand.indices, // indexCount
drawCommand.instances, // instanceCount
drawCommand.indexID, // firstIndex
drawCommand.vertexID, // vertexOffset
drawCommand.instanceID // firstInstance
);
}
} else if ( index.buffer && indirect.buffer ) {
if ( device->enabledFeatures.multiDrawIndirect || descriptor.inputs.indirect.count <= 1 ) {
vkCmdDrawIndexedIndirect(commandBuffer, indirect.buffer,
descriptor.inputs.indirect.offset, // offset
descriptor.inputs.indirect.count, // drawCount
descriptor.inputs.indirect.stride // stride
);
} else {
for ( auto i = 0; i < descriptor.inputs.indirect.count; ++i ) {
vkCmdDrawIndexedIndirect(commandBuffer, indirect.buffer,
descriptor.inputs.indirect.offset + i * descriptor.inputs.indirect.stride, // offset
1, // drawCount
descriptor.inputs.indirect.stride // stride
);
}
}
} else if ( index.buffer && !indirect.buffer ) {
vkCmdDrawIndexed(commandBuffer,
descriptor.inputs.index.count, // indexCount
@ -1006,24 +1124,26 @@ ext::vulkan::GraphicDescriptor::hash_t ext::vulkan::GraphicDescriptor::hash() co
hash += std::hash<decltype(renderMode)>{}(renderMode);
hash += std::hash<decltype(renderTarget)>{}(renderTarget);
hash += std::hash<decltype(pipeline)>{}(pipeline);
/*
hash += std::hash<decltype(vertex.attributes.size)>{}(vertex.attributes.size);
hash += std::hash<decltype(vertex.attributes.length)>{}(vertex.attributes.length);
hash += std::hash<decltype(index.attributes.size)>{}(index.attributes.size);
hash += std::hash<decltype(index.attributes.length)>{}(index.attributes.length);
hash += std::hash<decltype(instance.attributes.size)>{}(instance.attributes.size);
hash += std::hash<decltype(instance.attributes.length)>{}(instance.attributes.length);
*/
for ( uint8_t i = 0; i < inputs.vertex.attributes.size(); ++i ) {
for ( auto i = 0; i < inputs.vertex.attributes.size(); ++i ) {
hash += std::hash<decltype(inputs.vertex.attributes[i].descriptor.format)>{}(inputs.vertex.attributes[i].descriptor.format);
hash += std::hash<decltype(inputs.vertex.attributes[i].descriptor.offset)>{}(inputs.vertex.attributes[i].descriptor.offset);
}
for ( uint8_t i = 0; i < inputs.index.attributes.size(); ++i ) {
for ( auto i = 0; i < inputs.index.attributes.size(); ++i ) {
hash += std::hash<decltype(inputs.index.attributes[i].descriptor.format)>{}(inputs.index.attributes[i].descriptor.format);
hash += std::hash<decltype(inputs.index.attributes[i].descriptor.offset)>{}(inputs.index.attributes[i].descriptor.offset);
}
for ( auto i = 0; i < inputs.instance.attributes.size(); ++i ) {
hash += std::hash<decltype(inputs.instance.attributes[i].descriptor.format)>{}(inputs.instance.attributes[i].descriptor.format);
hash += std::hash<decltype(inputs.instance.attributes[i].descriptor.offset)>{}(inputs.instance.attributes[i].descriptor.offset);
}
/*
for ( auto i = 0; i < inputs.indirect.attributes.size(); ++i ) {
hash += std::hash<decltype(inputs.indirect.attributes[i].descriptor.format)>{}(inputs.indirect.attributes[i].descriptor.format);
hash += std::hash<decltype(inputs.indirect.attributes[i].descriptor.offset)>{}(inputs.indirect.attributes[i].descriptor.offset);
}
*/
hash += std::hash<decltype(topology)>{}(topology);
hash += std::hash<decltype(cullMode)>{}(cullMode);

View File

@ -163,6 +163,7 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderMode::bindGraphicDescriptor( c
ext::vulkan::GraphicDescriptor descriptor = reference;
// descriptor.renderMode = this->getName();
descriptor.subpass = pass;
descriptor.pipeline = metadata.pipeline;
descriptor.parse( metadata.json["descriptor"] );
return descriptor;
}
@ -177,7 +178,7 @@ void ext::vulkan::RenderMode::createCommandBuffers() {
if ( !entity->hasComponent<uf::Graphic>() ) continue;
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
if ( !graphic.initialized || !graphic.process ) continue;
graphics.push_back(&graphic);
graphics.emplace_back(&graphic);
}
this->synchronize();
@ -196,7 +197,7 @@ ext::vulkan::RenderMode::commands_container_t& ext::vulkan::RenderMode::getComma
commands.resize( swapchain.buffers );
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo(
this->getType() == "Compute" ? device->getCommandPool(Device::QueueEnum::COMPUTE) : device->getCommandPool(Device::QueueEnum::GRAPHICS),
device->getCommandPool(this->getType() == "Compute" ? Device::QueueEnum::COMPUTE : Device::QueueEnum::GRAPHICS),
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
static_cast<uint32_t>(commands.size())
);
@ -219,7 +220,7 @@ void ext::vulkan::RenderMode::bindPipelines() {
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
if ( !graphic.initialized || !graphic.process ) continue;
// if ( graphic.descriptor.renderMode != "" && graphic.descriptor.renderMode != this->getName() ) continue;
graphics.push_back(&graphic);
graphics.emplace_back(&graphic);
}
this->synchronize();
this->bindPipelines( graphics );
@ -230,42 +231,26 @@ void ext::vulkan::RenderMode::bindPipelines( const uf::stl::vector<ext::vulkan::
for ( size_t currentPass = 0; currentPass < renderTarget.passes.size(); ++currentPass ) {
auto& subpass = renderTarget.passes[currentPass];
if ( !subpass.autoBuildPipeline ) continue;
// bind to this render mode
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic.descriptor, currentPass);
// ignore invalidated descriptors
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 == descriptor.pipeline ) ++shaders;
for ( auto& pipeline : metadata.pipelines ) {
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic.descriptor, currentPass);
descriptor.pipeline = pipeline;
// ignore invalidated descriptors
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 == descriptor.pipeline ) ++shaders;
if ( shaders == 0 ) continue;
graphic.initializePipeline( descriptor );
}
if ( shaders == 0 ) continue;
graphic.initializePipeline( descriptor );
}
}
/*
size_t subpasses = metadata["subpasses"].as<size_t>();
for ( auto* pointer : graphics ) {
auto& graphic = *pointer;
for ( size_t currentPass = 0; currentPass < subpasses; ++currentPass ) {
// bind to this render mode
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic.descriptor, currentPass);
// ignore if pipeline exists for this render mode
if ( graphic.hasPipeline( descriptor ) ) continue;
graphic.initializePipeline( descriptor );
}
}
*/
}
void ext::vulkan::RenderMode::render() {
/*
if ( ext::openvr::context ) {
ext::openvr::submit();
}
*/
auto& commands = getCommands( this->mostRecentCommandPoolId );
// Get next image in the swap chain (back/front buffer)
VK_CHECK_RESULT(swapchain.acquireNextImage(&states::currentBuffer, swapchain.presentCompleteSemaphore));
@ -308,20 +293,6 @@ void ext::vulkan::RenderMode::initialize( Device& device ) {
if ( this->height > 0 ) renderTarget.height = this->height;
}
// Create command buffers
/*
{
commands.resize( swapchain.buffers );
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo(
this->getType() == "Compute" ? device.getCommandPool(Device::QueueEnum::COMPUTE) : device.getCommandPool(Device::QueueEnum::GRAPHICS),
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
static_cast<uint32_t>(commands.size())
);
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, commands.data()));
}
*/
// Set sync objects
{
// Fences (Used to check draw command buffer completion)
@ -343,6 +314,11 @@ void ext::vulkan::RenderMode::initialize( Device& device ) {
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderCompleteSemaphore));
}
}
if ( std::find( metadata.pipelines.begin(), metadata.pipelines.end(), metadata.pipeline ) == metadata.pipelines.end() ) {
metadata.pipelines.emplace_back(metadata.pipeline);
}
}
void ext::vulkan::RenderMode::tick() {

View File

@ -104,9 +104,11 @@ void ext::vulkan::ComputeRenderMode::initialize( Device& device ) {
0, 1, 2, 2, 3, 0
};
*/
blitter.device = &device;
blitter.material.device = &device;
blitter.descriptor.subpass = 1;
blitter.descriptor.inputs.dispatch = { (width / 32) + 1, (height / 32) + 1, 1 };
blitter.descriptor.depth.test = false;
blitter.descriptor.depth.write = false;
@ -246,7 +248,6 @@ void ext::vulkan::ComputeRenderMode::createCommandBuffers( ) {
for (size_t i = 0; i < commands.size(); ++i) {
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo));
pipeline.record(compute, commands[i]);
vkCmdDispatch(commands[i], width / dispatchSize.x, height / dispatchSize.y, 1);
VK_CHECK_RESULT(vkEndCommandBuffer(commands[i]));
}

View File

@ -193,6 +193,8 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
{
uf::Mesh mesh;
mesh.vertex.count = 3;
/*
mesh.bind<pod::Vertex_2F2F, uint16_t>();
mesh.insertVertices<pod::Vertex_2F2F>({
{ {-1.0f, 1.0f}, {0.0f, 1.0f}, },
@ -203,18 +205,8 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
mesh.insertIndices<uint16_t>({
0, 1, 2, 2, 3, 0
});
/*
uf::Mesh<pod::Vertex_2F2F, uint16_t> mesh;
mesh.vertices = {
{ {-1.0f, 1.0f}, {0.0f, 1.0f}, },
{ {-1.0f, -1.0f}, {0.0f, 0.0f}, },
{ {1.0f, -1.0f}, {1.0f, 0.0f}, },
{ {1.0f, 1.0f}, {1.0f, 1.0f}, }
};
mesh.indices = {
0, 1, 2, 0, 2, 3
};
*/
blitter.descriptor.subpass = 1;
blitter.descriptor.depth.test = false;
blitter.descriptor.depth.write = false;
@ -237,20 +229,10 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
{uf::io::resolveURI(vertexShaderFilename), VK_SHADER_STAGE_VERTEX_BIT},
{uf::io::resolveURI(fragmentShaderFilename), VK_SHADER_STAGE_FRAGMENT_BIT}
});
/*
uf::stl::string fragmentShaderFilename = ( msaa <= 1 ) ? "no-msaa." : "";
if ( ext::vulkan::settings::experimental::vxgi ) {
fragmentShaderFilename = ( msaa <= 1 ) ? "vxgi.no-msaa." : "vxgi.";
}
blitter.material.initializeShaders({
{uf::io::root+"/shaders/display/subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{uf::io::root+"/shaders/display/subpass." + fragmentShaderFilename + "frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
*/
{
auto& scene = uf::scene::getCurrentScene();
auto& shader = blitter.material.shaders.back();
auto& shader = blitter.material.getShader("fragment");
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
size_t maxLights = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as<size_t>(512);
size_t maxTextures2D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["2D"].as<size_t>(512);
@ -258,19 +240,35 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
size_t maxTextures3D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["3D"].as<size_t>(128);
size_t maxCascades = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as<size_t>(16);
// shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera );
// shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.joint );
shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance );
shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.material );
shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture );
shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light );
if ( ext::vulkan::settings::experimental::vxgi ) {
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures2D);
else if ( sc.name == "CUBEMAPS" ) sc.value.ui = (specializationConstants[sc.index] = maxTexturesCube);
else if ( sc.name == "CASCADES" ) sc.value.ui = (specializationConstants[sc.index] = maxCascades);
}
for ( auto pair : shader.metadata.definitions.textures ) {
auto& tx = pair.second;
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures2D;
else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube;
else if ( tx.name == "voxelId" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelUv" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelNormal" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelRadiance" ) layout.descriptorCount = maxCascades;
}
}
/*
struct SpecializationConstant {
uint32_t maxTextures2D = 512;
uint32_t maxTexturesCube = 128;
uint32_t maxCascades = 16;
};
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
specializationConstants.maxTextures2D = maxTextures2D;
specializationConstants.maxTexturesCube = maxTexturesCube;
specializationConstants.maxCascades = maxCascades;
*/
uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants;
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){
uf::stl::string name = sc["name"].as<uf::stl::string>();
if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D);
@ -290,17 +288,24 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
else if ( name == "voxelRadiance" ) layout.descriptorCount = maxCascades;
}
});
} else {
/*
struct SpecializationConstant {
uint32_t maxTextures2D = 512;
uint32_t maxTexturesCube = 128;
};
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
specializationConstants.maxTextures2D = maxTextures2D;
specializationConstants.maxTexturesCube = maxTexturesCube;
*/
uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants;
} else {
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures2D);
else if ( sc.name == "CUBEMAPS" ) sc.value.ui = (specializationConstants[sc.index] = maxTexturesCube);
}
for ( auto pair : shader.metadata.definitions.textures ) {
auto& tx = pair.second;
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures2D;
else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube;
}
}
/*
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){
uf::stl::string name = sc["name"].as<uf::stl::string>();
if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D);
@ -316,15 +321,15 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
else if ( name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube;
}
});
*/
}
/*
uf::stl::vector<pod::Light> lights(maxLights);
uf::stl::vector<pod::Material> materials(maxTextures2D);
uf::stl::vector<pod::Texture> textures(maxTextures2D);
uf::stl::vector<pod::DrawCommand> drawCommands(maxTextures2D);
for ( auto& material : materials ) material.colorBase = {0,0,0,0};
metadata.lightBufferIndex = shader.initializeBuffer(
(const void*) lights.data(),
lights.size() * sizeof(pod::Light),
@ -347,6 +352,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
drawCommands.size() * sizeof(pod::DrawCommand),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
);
*/
}
// blitter.initializePipeline();
for ( size_t eye = 0; eye < metadata.eyes; ++eye ) {
@ -427,10 +433,16 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
clearValue.color = { { 0, 0, 0, 0 } };
}
} else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) {
clearValue.depthStencil = { 0.0f, 0 };
if ( uf::matrix::reverseInfiniteProjection ) {
clearValue.depthStencil = { 0.0f, 0 };
} else {
clearValue.depthStencil = { 1.0f, 0 };
}
}
clearValues.push_back(clearValue);
}
// uf::matrix::reverseInfiniteProjection
// descriptor.depth.operation ext::RENDERER::enums::Compare::GREATER_OR_EQUAL
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
@ -462,8 +474,19 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
for ( auto layer : layers ) {
layer->pipelineBarrier( commands[i], 0 );
}
size_t currentSubpass = 0;
for ( auto& pipeline : metadata.pipelines ) {
if ( pipeline == metadata.pipeline ) continue;
for ( auto graphic : graphics ) {
if ( graphic->descriptor.renderMode != this->getName() ) continue;
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass);
descriptor.pipeline = pipeline;
graphic->record( commands[i], descriptor, 0, metadata.eyes );
}
}
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commands[i], 0, 1, &viewport);
vkCmdSetScissor(commands[i], 0, 1, &scissor);

View File

@ -42,7 +42,6 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderTargetRenderMode::bindGraphicD
descriptor.cullMode = VK_CULL_MODE_NONE;
descriptor.depth.test = false;
descriptor.depth.write = false;
descriptor.pipeline = "vxgi";
} else if ( metadata.type == "depth" ) {
descriptor.cullMode = VK_CULL_MODE_NONE;
}
@ -304,6 +303,8 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
if ( blitter.process ) {
uf::Mesh mesh;
mesh.vertex.count = 3;
/*
mesh.bind<pod::Vertex_2F2F, uint16_t>();
mesh.insertVertices<pod::Vertex_2F2F>({
{ {-1.0f, 1.0f}, {0.0f, 1.0f}, },
@ -314,6 +315,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
mesh.insertIndices<uint16_t>({
0, 1, 2, 2, 3, 0
});
*/
blitter.device = &device;
blitter.material.device = &device;
@ -412,15 +414,39 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
size_t maxCascades = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as<size_t>(16);
auto& shader = blitter.material.getShader("compute");
// shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera );
// shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.joint );
shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance );
shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.material );
shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture );
shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light );
uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants;
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures2D);
else if ( sc.name == "CUBEMAPS" ) sc.value.ui = (specializationConstants[sc.index] = maxTexturesCube);
else if ( sc.name == "CASCADES" ) sc.value.ui = (specializationConstants[sc.index] = maxCascades);
}
for ( auto pair : shader.metadata.definitions.textures ) {
auto& tx = pair.second;
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures2D;
else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube;
else if ( tx.name == "voxelId" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelUv" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelNormal" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelRadiance" ) layout.descriptorCount = maxCascades;
}
}
/*
ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){
uf::stl::string name = sc["name"].as<uf::stl::string>();
if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D);
else if ( name == "CUBEMAPS" ) sc["value"] = (specializationConstants[i] = maxTexturesCube);
else if ( name == "CASCADES" ) sc["value"] = (specializationConstants[i] = maxCascades);
});
ext::json::forEach( shader.metadata.json["definitions"]["textures"], [&]( ext::json::Value& t ){
size_t binding = t["binding"].as<size_t>();
uf::stl::string name = t["name"].as<uf::stl::string>();
@ -434,36 +460,8 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
else if ( name == "voxelRadiance" ) layout.descriptorCount = maxCascades;
}
});
*/
uf::stl::vector<pod::Light> lights(maxLights);
uf::stl::vector<pod::Material> materials(maxTextures2D);
uf::stl::vector<pod::Texture> textures(maxTextures2D);
uf::stl::vector<pod::DrawCommand> drawCalls(maxTextures2D);
for ( auto& material : materials ) material.colorBase = {0,0,0,0};
metadata.lightBufferIndex = shader.initializeBuffer(
(const void*) lights.data(),
lights.size() * sizeof(pod::Light),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
);
metadata.materialBufferIndex = shader.initializeBuffer(
(const void*) materials.data(),
materials.size() * sizeof(pod::Material),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
);
metadata.textureBufferIndex = shader.initializeBuffer(
(const void*) textures.data(),
textures.size() * sizeof(pod::Texture),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
);
metadata.drawCallBufferIndex = shader.initializeBuffer(
(const void*) drawCalls.data(),
drawCalls.size() * sizeof(pod::DrawCommand),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
);
} else {
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
@ -648,7 +646,11 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
if ( attachment.descriptor.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) {
clearValue.color = { { 0.0f, 0.0f, 0.0f, 0.0f } };
} else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) {
clearValue.depthStencil = { 0.0f, 0 };
if ( uf::matrix::reverseInfiniteProjection ) {
clearValue.depthStencil = { 0.0f, 0 };
} else {
clearValue.depthStencil = { 1.0f, 0 };
}
}
clearValues.push_back(clearValue);
}
@ -684,6 +686,16 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
size_t currentPass = 0;
// pre-renderpass commands
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commands[i] );
for ( auto& pipeline : metadata.pipelines ) {
if ( pipeline == metadata.pipeline ) continue;
for ( auto graphic : graphics ) {
if ( graphic->descriptor.renderMode != this->getTarget() ) continue;
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentPass);
descriptor.pipeline = pipeline;
graphic->record( commands[i], descriptor, 0, metadata.type == "vxgi" ? 0 : MIN(subpasses,6) );
}
}
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commands[i], 0, 1, &viewport);

View File

@ -557,7 +557,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
auto& userdata = uniforms.emplace_back();
userdata.create( definition.size, nullptr );
initializeBuffer(
if ( metadata.autoInitializeUniforms ) initializeBuffer(
(const void*) userdata.data().data,
userdata.data().len,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
@ -658,19 +658,26 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
}
size_t specializationSize = 0;
uf::stl::vector<VkSpecializationMapEntry> specializationRemap;
specializationRemap.resize( comp.get_specialization_constants().size() );
for ( const auto& constant : comp.get_specialization_constants() ) {
const auto& value = comp.get_constant(constant.id);
const auto& type = comp.get_type(value.constant_type);
uf::stl::string name = comp.get_name (constant.id);
size_t size = 4; //comp.get_declared_struct_size(type);
VkSpecializationMapEntry specializationMapEntry;
auto& specializationMapEntry = specializationRemap[constant.constant_id];
specializationMapEntry.constantID = constant.constant_id;
specializationMapEntry.size = size;
specializationMapEntry.offset = specializationSize;
specializationMapEntries.emplace_back(specializationMapEntry);
specializationSize += size;
}
if ( specializationSize > 0 ) {
specializationRemap.reserve( specializationRemap.size() );
for ( auto& specializationMapEntry : specializationRemap ) {
specializationMapEntries.emplace_back(specializationMapEntry);
}
specializationConstants.create( specializationSize );
VK_DEBUG_VALIDATION_MESSAGE("Specialization constants size of " << specializationSize << " for shader " << filename);

View File

@ -81,6 +81,7 @@ void ext::vulkan::Texture::initialize( Device& device, size_t width, size_t heig
this->height = height;
this->depth = depth;
this->layers = layers;
// implicitly set type
if ( width > 1 && height > 1 && depth > 1 ) {
this->type = ext::vulkan::enums::Image::TYPE_3D;
@ -361,8 +362,8 @@ void ext::vulkan::Texture::loadFromImage(
(void*) image.getPixelsPtr(),
image.getPixels().size(),
format,
image.getDimensions()[0],
image.getDimensions()[1],
image.getDimensions().x,
image.getDimensions().y,
1,
1,
device,
@ -500,29 +501,8 @@ void ext::vulkan::Texture::fromBuffers(
device.flushCommandBuffer(commandBuffer);
this->imageLayout = imageLayout;
this->updateDescriptors();
}
/*
if ( this->layers > 1 ) {
// Create image view
VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.baseMipLevel = 0;
subresourceRange.baseArrayLayer = 1;
subresourceRange.levelCount = this->mips;
subresourceRange.layerCount = this->layers - 1;
VkCommandBuffer commandBuffer = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
setImageLayout(
commandBuffer,
image,
VK_IMAGE_LAYOUT_UNDEFINED,
imageLayout,
subresourceRange
);
device.flushCommandBuffer(commandBuffer);
}
*/
this->updateDescriptors();
}
@ -588,20 +568,31 @@ void ext::vulkan::Texture::asRenderTarget( Device& device, uint32_t width, uint3
this->updateDescriptors();
}
void ext::vulkan::Texture::aliasTexture( const Texture& texture ) {
image = texture.image;
view = texture.view;
type = texture.type;
viewType = texture.viewType;
imageLayout = texture.imageLayout;
deviceMemory = texture.deviceMemory;
width = texture.width;
height = texture.height;
depth = texture.depth;
layers = texture.layers;
sampler = texture.sampler;
sampler.device = NULL;
*this = {
.device = nullptr,
.image = texture.image,
.view = texture.view,
.type = texture.type,
.viewType = texture.viewType,
.imageLayout = texture.imageLayout,
.deviceMemory = texture.deviceMemory,
.descriptor = texture.descriptor,
.format = texture.format,
.sampler = texture.sampler,
.allocation = texture.allocation,
.allocationInfo = texture.allocationInfo,
.width = texture.width,
.height = texture.height,
.depth = texture.depth,
.layers = texture.layers,
.mips = texture.mips,
};
sampler.device = nullptr;
this->updateDescriptors();
}
void ext::vulkan::Texture::aliasAttachment( const RenderTarget::Attachment& attachment, bool createSampler ) {

View File

@ -5,6 +5,7 @@
#include <uf/ext/vulkan/graphic.h>
#include <uf/ext/vulkan/rendermode.h>
#include <uf/utils/graphic/graphic.h>
#include <uf/engine/graph/graph.h>
#include <uf/ext/openvr/openvr.h>
@ -37,9 +38,9 @@ bool ext::vulkan::settings::experimental::deferredAliasOutputToSwapchain = true;
bool ext::vulkan::settings::experimental::multiview = true;
bool ext::vulkan::settings::experimental::vsync = true;
bool ext::vulkan::settings::experimental::hdr = true;
bool ext::vulkan::settings::experimental::frustrumCull = false;
bool ext::vulkan::settings::experimental::vxgi = true;
bool ext::vulkan::settings::experimental::deferredSampling = true;
bool ext::vulkan::settings::experimental::culling = false;
VkColorSpaceKHR ext::vulkan::settings::formats::colorSpace;
ext::vulkan::enums::Format::type_t ext::vulkan::settings::formats::color = ext::vulkan::enums::Format::R8G8B8A8_UNORM;
@ -213,6 +214,7 @@ void ext::vulkan::removeRenderMode( ext::vulkan::RenderMode* mode, bool free ) {
}
void ext::vulkan::initialize() {
ext::vulkan::mutex.lock();
device.initialize();
swapchain.initialize( device );
{
@ -260,6 +262,9 @@ void ext::vulkan::initialize() {
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 | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
}
uf::graph::initialize();
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
renderMode->initialize(device);
@ -272,6 +277,7 @@ void ext::vulkan::initialize() {
else renderMode->createCommandBuffers();
}
if ( !jobs.empty() ) uf::thread::batchWorkers( jobs );
ext::vulkan::mutex.unlock();
}
void ext::vulkan::tick() {
ext::vulkan::mutex.lock();
@ -335,11 +341,13 @@ void ext::vulkan::render() {
ext::vulkan::currentRenderMode = renderMode;
if ( settings::experimental::multithreadedCommandRendering ) {
jobs.emplace_back([&]{
uf::graph::render();
uf::scene::render();
renderMode->render();
renderMode->executed = true;
});
} else {
uf::graph::render();
uf::scene::render();
renderMode->render();
renderMode->executed = true;

View File

@ -4,60 +4,93 @@
#endif
pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
#if UF_USE_XATLAS
struct Pair {
size_t index = 0;
size_t command = 0;
::xatlas::MeshDecl decl;
};
uf::stl::vector<Pair> entries;
entries.reserve(graph.meshes.size());
uf::stl::vector<uf::Mesh> sources;
sources.reserve(graph.meshes.size());
::xatlas::Atlas* atlas = ::xatlas::Create();
#if 0
for ( auto& name : graph.meshes ) {
for ( auto index = 0; index < graph.meshes.size(); ++index ) {
auto& name = graph.meshes[index];
auto& mesh = uf::graph::storage.meshes[name];
mesh.updateDescriptor();
sources.emplace_back(mesh);
size_t indices = mesh.attributes.index.length;
size_t indexStride = mesh.attributes.index.size;
uint8_t* indexPointer = (uint8_t*) mesh.attributes.index.pointer;
if ( mesh.index.count ) {
uf::Mesh::Attribute positionAttribute;
uf::Mesh::Attribute uvAttribute;
uf::Mesh::Attribute stAttribute;
for ( auto& attribute : mesh.vertex.attributes ) {
if ( attribute.descriptor.name == "position" ) positionAttribute = attribute;
else if ( attribute.descriptor.name == "uv" ) uvAttribute = attribute;
else if ( attribute.descriptor.name == "st" ) stAttribute = attribute;
}
UF_ASSERT( positionAttribute.descriptor.name == "position" && uvAttribute.descriptor.name == "uv" && uvAttribute.descriptor.name == "st" );
size_t vertices = mesh.attributes.vertex.length;
size_t vertexStride = mesh.attributes.vertex.size;
uint8_t* vertexPointer = (uint8_t*) mesh.attributes.vertex.pointer;
auto& indexAttribute = mesh.index.attributes.front();
::xatlas::IndexFormat indexType = ::xatlas::IndexFormat::UInt32;
switch ( mesh.index.stride ) {
case sizeof(uint16_t): indexType = ::xatlas::IndexFormat::UInt16; break;
case sizeof(uint32_t): indexType = ::xatlas::IndexFormat::UInt32; break;
default: UF_EXCEPTION("unsupported index type"); break;
}
uf::renderer::AttributeDescriptor vertexAttributePosition,
vertexAttributeNormal,
vertexAttributeUv,
vertexAttributeSt,
vertexAttributeId;
if ( mesh.indirect.count ) {
uf::Mesh::Attribute remappedPositionAttribute;
uf::Mesh::Attribute remappedUvAttribute;
uf::Mesh::Attribute remappedIndexAttribute;
for ( auto i = 0; i < mesh.indirect.count; ++i ) {
remappedPositionAttribute = mesh.remapVertexAttribute( positionAttribute, i );
remappedUvAttribute = mesh.remapVertexAttribute( uvAttribute, i );
remappedIndexAttribute = mesh.remapIndexAttribute( indexAttribute, i );
for ( auto& attribute : mesh.attributes.vertex.descriptor ) {
if ( attribute.name == "position" ) vertexAttributePosition = attribute;
else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute;
else if ( attribute.name == "uv" ) vertexAttributeUv = attribute;
else if ( attribute.name == "st" ) vertexAttributeSt = attribute;
else if ( attribute.name == "id" ) vertexAttributeId = attribute;
}
UF_ASSERT( vertexAttributePosition.name != "" );
auto& entry = entries.emplace_back();
entry.index = index;
entry.command = i;
::xatlas::MeshDecl meshDecl;
meshDecl.vertexCount = vertices; // mesh.vertices.size();
meshDecl.vertexPositionData = (uint8_t*) mesh.attributes.vertex.pointer + vertexAttributePosition.offset; /*((uint8_t*) mesh.vertices.data()) + vertexAttributePosition.offset*/
meshDecl.vertexPositionStride = vertexStride;
if ( vertexAttributeUv.name != "" ) {
meshDecl.vertexUvData = (uint8_t*) mesh.attributes.vertex.pointer + vertexAttributeUv.offset;// ((uint8_t*) mesh.vertices.data()) + vertexAttributeUv.offset;
meshDecl.vertexUvStride = vertexStride;
}
/*
if ( vertexAttributeNormal.name != "" ) {
meshDecl.vertexNormalData = ((uint8_t*) mesh.vertices.data()) + vertexAttributeNormal.offset;
meshDecl.vertexNormalStride = mesh.attributes.vertex.size;
}
*/
meshDecl.indexCount = indices; // mesh.indices.size();
meshDecl.indexData = mesh.attributes.index.pointer; // mesh.indices.data();
meshDecl.indexFormat = indexStride == 4 ? ::xatlas::IndexFormat::UInt32 : ::xatlas::IndexFormat::UInt16;
auto& decl = entry.decl;
decl.vertexCount = remappedUvAttribute.length;
decl.vertexPositionData = remappedPositionAttribute.pointer;
decl.vertexPositionStride = remappedPositionAttribute.stride;
decl.vertexUvData = remappedUvAttribute.pointer;
decl.vertexUvStride = remappedUvAttribute.stride;
::xatlas::AddMeshError error = ::xatlas::AddMesh(atlas, meshDecl, graph.meshes.size());
decl.indexCount = remappedIndexAttribute.length;
decl.indexData = remappedIndexAttribute.pointer;
decl.indexFormat = indexType;
}
} else {
auto& entry = entries.emplace_back();
entry.index = index;
auto& decl = entry.decl;
decl.vertexCount = uvAttribute.length;
decl.vertexPositionData = positionAttribute.pointer;
decl.vertexPositionStride = positionAttribute.stride;
decl.vertexUvData = uvAttribute.pointer;
decl.vertexUvStride = uvAttribute.stride;
decl.indexCount = indexAttribute.length;
decl.indexData = indexAttribute.pointer;
decl.indexFormat = indexType;
decl.indexFormat = indexType;
}
} else UF_EXCEPTION("to-do: not require indices for meshes");
}
for ( auto& mesh : entries ) {
::xatlas::AddMeshError error = ::xatlas::AddMesh(atlas, mesh.decl, entries.size());
if (error != ::xatlas::AddMeshError::Success) {
::xatlas::Destroy(atlas);
UF_MSG_ERROR(::xatlas::StringForEnum(error));
return {};
UF_EXCEPTION(::xatlas::StringForEnum(error));
}
}
}
::xatlas::ChartOptions chartOptions{};
// chartOptions.useInputMeshUvs = true;
@ -72,61 +105,79 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) {
for ( size_t i = 0; i < atlas->meshCount; i++ ) {
auto& xmesh = atlas->meshes[i];
auto& mesh = uf::graph::storage.meshes[graph.meshes[i]];
auto& entry = entries[i];
auto& mesh = graph.meshes[entry.index];
auto& source = sources[entry.index];
source.updateDescriptor();
size_t indices = mesh.attributes.index.length;
size_t indexStride = mesh.attributes.index.size;
uint8_t* indexPointer = (uint8_t*) mesh.attributes.index.pointer;
uf::stl::vector<uint8_t> oldVertexBuffer( (uint8_t*) mesh.attributes.vertex.pointer, (uint8_t*) mesh.attributes.vertex.pointer + mesh.attributes.vertex.length * mesh.attributes.vertex.size );
}
size_t vertices = xmesh.vertexCount;
size_t vertexStride = mesh.attributes.vertex.size;
mesh.resizeVertices( vertices );
#if 0
for ( size_t i = 0; i < atlas->meshCount; i++ ) {
auto& xmesh = atlas->meshes[i];
auto& mesh = *meshes[i];
uint8_t* oldVertexPointer = oldVertexBuffer.data();
uint8_t* newvertexPointer = (uint8_t*) mesh.attributes.vertex.pointer;
uf::Mesh src;
src.buffers = mesh.buffers;
src.vertex = mesh.vertex;
src.index = mesh.index;
src.instance = mesh.instance;
src.indirect = mesh.indirect;
uf::renderer::AttributeDescriptor vertexAttributePosition,
vertexAttributeNormal,
vertexAttributeUv,
vertexAttributeSt;
mesh.resizeVertices( xmesh.vertexCount );
for ( auto& attribute : mesh.attributes.vertex.descriptor ) {
if ( attribute.name == "position" ) vertexAttributePosition = attribute;
else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute;
else if ( attribute.name == "uv" ) vertexAttributeUv = attribute;
else if ( attribute.name == "st" ) vertexAttributeSt = attribute;
}
UF_ASSERT( vertexAttributePosition.name != "" );
if ( mesh.isInterleaved( mesh.vertex.interleaved ) ) {
for ( auto& attribute : mesh.vertex.attributes ) {
if ( attribute.descriptor.name != "st" ) continue;
for ( size_t v = 0; v < xmesh.vertexCount; v++) {
auto& xvertex = xmesh.vertexArray[v];
uint8_t* oldVertexSrc = oldVertexPointer + (xvertex.xref * vertexStride);
uint8_t* newVertexSrc = newvertexPointer + (v * vertexStride);
uint8_t* srcBuffer = src.buffers[mesh.vertex.interleaved].data();
uint8_t* dstBuffer = mesh.buffers[mesh.vertex.interleaved].data();
for ( auto v = 0; v < xmesh.vertexCount; ++v ) {
auto& vertex = xmesh.vertexArray[v];
auto ref = vertex.xref;
memcpy( newVertexSrc, oldVertexSrc, vertexStride );
memcpy( dstBuffer + v * mesh.vertex.stride, srcBuffer + ref * mesh.vertex.stride, mesh.vertex.stride );
pod::Vector2f& st = *((pod::Vector2f*) (newVertexSrc + vertexAttributeSt.offset));
st = { xvertex.uv[0] / atlas->width, xvertex.uv[1] / atlas->height };
pod::Vector2f& st = *((pod::Vector2f*) dstBuffer + v * mesh.vertex.stride + attribute.descriptor.offset);
st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height };
}
break;
}
} else for ( auto& attribute : mesh.vertex.attributes ) {
uint8_t* srcBuffer = src.buffers[attribute.buffer].data();
uint8_t* dstBuffer = mesh.buffers[attribute.buffer].data();
for ( auto v = 0; v < xmesh.vertexCount; ++v ) {
auto& vertex = xmesh.vertexArray[v];
auto ref = vertex.xref;
if ( attribute.descriptor.name == "st" ) {
pod::Vector2f& st = *((pod::Vector2f*) dstBuffer + v * attribute.descriptor.size);
st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height };
} else {
memcpy( dstBuffer + v * attribute.descriptor.size, srcBuffer + ref * attribute.descriptor.size, attribute.descriptor.size );
}
}
}
for ( size_t currentIndex = 0; currentIndex < xmesh.indexCount; ++currentIndex ) {
uint32_t index = xmesh.indexArray[currentIndex];
uint8_t* indexSrc = indexPointer + (currentIndex * indexStride);
switch ( indexStride ) {
case sizeof( uint8_t): *(( uint8_t*) indexSrc) = index; break;
case sizeof(uint16_t): *((uint16_t*) indexSrc) = index; break;
case sizeof(uint32_t): *((uint32_t*) indexSrc) = index; break;
{
auto& buffer = mesh.buffers[mesh.isInterleaved(mesh.index.interleaved) ? mesh.index.interleaved : mesh.index.attributes.front().buffer];
uint8_t* pointer = (uint8_t*) buffer.data();
for ( auto index = 0; index < mesh.index.count; ++index ) {
switch ( mesh.index.stride ) {
case 1: *( uint8_t*) pointer = xmesh.indexArray[index]; break;
case 2: *(uint16_t*) pointer = xmesh.indexArray[index]; break;
case 4: *(uint32_t*) pointer = xmesh.indexArray[index]; break;
}
}
}
}
#endif
pod::Vector2ui size = pod::Vector2ui{ atlas->width, atlas->height };
::xatlas::Destroy(atlas);
return size;
#endif
#endif
}

View File

@ -14,6 +14,7 @@
// C-tor
// Default
/*
uf::Image::Image() :
m_bpp(8),
m_channels(4),
@ -71,7 +72,7 @@ uf::Image::Image( const Image::container_t& copy, const Image::vec2_t& size ) :
{
}
*/
uf::stl::string uf::Image::getFilename() const {
return this->m_filename;
}

View File

@ -48,7 +48,6 @@ UF_VERTEX_DESCRIPTOR(pod::Vertex_3F,
)
bool uf::Mesh::defaultInterleaved = false;
void uf::Mesh::initialize() {
}
void uf::Mesh::destroy() {
@ -82,23 +81,26 @@ void uf::Mesh::updateDescriptor() {
_updateDescriptor(instance);
_updateDescriptor(indirect);
}
void uf::Mesh::insert( const uf::Mesh& mesh ) {
insertVertex(mesh);
insertIndex(mesh);
insertInstance(mesh);
insertIndirect(mesh);
}
/*
uint32_t indices = 0; // triangle count
uint32_t instances = 0; // instance count
uint32_t indexID = 0; // starting triangle position
int32_t vertexID = 0; // starting vertex position
void uf::Mesh::bind( const uf::Mesh& mesh ) {
vertex.attributes = mesh.vertex.attributes;
vertex.interleaved = mesh.vertex.interleaved;
index.attributes = mesh.index.attributes;
index.interleaved = mesh.index.interleaved;
instance.attributes = mesh.instance.attributes;
instance.interleaved = mesh.instance.interleaved;
indirect.attributes = mesh.indirect.attributes;
indirect.interleaved = mesh.indirect.interleaved;
uint32_t instanceID = 0; // starting instance position
uint32_t materialID = 0;
uint32_t objectID = 0;
uint32_t vertices = 0;
*/
_bind();
}
void uf::Mesh::insert( const uf::Mesh& mesh ) {
if ( vertex.attributes.empty() && index.attributes.empty() && instance.attributes.empty() && indirect.attributes.empty() ) bind( mesh );
insertVertices(mesh);
insertIndices(mesh);
insertInstances(mesh);
insertIndirects(mesh);
}
void uf::Mesh::generateIndices() {
// deduce type
size_t size = sizeof(uint32_t);
@ -125,14 +127,16 @@ void uf::Mesh::generateIndirect() {
uf::stl::vector<pod::DrawCommand> commands;
for ( auto& attribute : index.attributes ) {
auto& buffer = buffers[isInterleaved(index.interleaved) ? index.interleaved : attribute.buffer];
auto& command = commands.emplace_back();
command.indices = buffer.size() / attribute.descriptor.size;
command.instances = instance.count == 0 && instance.attributes.empty() ? 1 : instance.count;
command.indexID = 0;
command.vertexID = 0;
command.instanceID = 0;
command.objectID = 0;
command.vertices = vertex.count;
commands.emplace_back(pod::DrawCommand{
.indices = buffer.size() / attribute.descriptor.size,
.instances = instance.count == 0 && instance.attributes.empty() ? 1 : instance.count,
.indexID = 0,
.vertexID = 0,
.instanceID = 0,
// .materialID = 0,
// .objectID = 0,
// .vertices = vertex.count,
});
}
_destroy( indirect );
@ -234,8 +238,8 @@ void uf::Mesh::print() const {
//
void uf::Mesh::_destroy( uf::Mesh::Input& input ) {
for ( auto& attribute : input.attributes ) {
attribute.descriptor.length = 0;
attribute.descriptor.pointer = NULL;
attribute.length = 0;
attribute.pointer = NULL;
attribute.buffer = 0;
}
input.attributes.clear();
@ -262,13 +266,33 @@ void uf::Mesh::_bind( bool interleave ) {
void uf::Mesh::_updateDescriptor( uf::Mesh::Input& input ) {
input.stride = 0;
for ( auto& attribute : input.attributes ) {
auto& buffer = buffers[isInterleaved(input.interleaved) ? input.interleaved : attribute.buffer];
attribute.descriptor.length = buffer.size();
attribute.descriptor.pointer = (void*) (buffer.data());
const bool interleaved = isInterleaved(input.interleaved);
auto& buffer = buffers[interleaved ? input.interleaved : attribute.buffer];
attribute.length = buffer.size();
attribute.pointer = (void*) (buffer.data());
if ( !interleaved ) attribute.stride = attribute.descriptor.size;
input.stride += attribute.descriptor.size;
}
for ( auto& attribute : input.attributes ) {
const bool interleaved = isInterleaved(input.interleaved);
if ( interleaved ) attribute.stride = input.stride;
}
}
void uf::Mesh::_insertV( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) {
uf::Mesh::Attribute uf::Mesh::_remapAttribute( const uf::Mesh::Input& input, const uf::Mesh::Attribute& attribute, size_t i ) const {
uf::Mesh::Attribute res = attribute;
if ( i < indirect.count ) {
auto& drawCommand = ((const pod::DrawCommand*) buffers[isInterleaved(indirect.interleaved) ? indirect.interleaved : indirect.attributes.front().buffer].data())[i];
if ( &input == &vertex ) {
res.pointer = (void*) ((uint8_t*) res.pointer + drawCommand.vertexID * res.stride);
res.length = drawCommand.vertices;
} else if ( &input == &index ) {
res.pointer = (void*) ((uint8_t*) res.pointer + drawCommand.indexID * res.stride);
res.length = drawCommand.indices;
}
}
return res;
}
void uf::Mesh::_insertVs( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) {
if ( !_hasV( input, srcInput ) ) return;
_reserveVs( input, input.count += srcInput.count );
@ -292,7 +316,7 @@ void uf::Mesh::_insertV( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf:
}
_updateDescriptor( input );
}
void uf::Mesh::_insertI( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) {
void uf::Mesh::_insertIs( uf::Mesh::Input& input, const uf::Mesh& mesh, const uf::Mesh::Input& srcInput ) {
// if ( !_hasI( source ) ) return;
_reserveIs( input, input.count += srcInput.count );
@ -339,26 +363,26 @@ void uf::Mesh::_reserveVs( uf::Mesh::Input& input, size_t count ) {
if ( isInterleaved(input.interleaved) ) {
buffers[input.interleaved].reserve( count * input.stride );
for ( auto& attribute : input.attributes ) {
attribute.descriptor.length = buffers[input.interleaved].size();
attribute.descriptor.pointer = (void*) (buffers[input.interleaved].data());
attribute.length = buffers[input.interleaved].size();
attribute.pointer = (void*) (buffers[input.interleaved].data());
}
} else for ( auto& attribute : input.attributes ) {
buffers[attribute.buffer].reserve( count * attribute.descriptor.size );
attribute.descriptor.length = buffers[attribute.buffer].size();
attribute.descriptor.pointer = (void*) (buffers[attribute.buffer].data());
attribute.length = buffers[attribute.buffer].size();
attribute.pointer = (void*) (buffers[attribute.buffer].data());
}
}
void uf::Mesh::_resizeVs( uf::Mesh::Input& input, size_t count ) {
if ( isInterleaved(input.interleaved) ) {
buffers[input.interleaved].resize( count * input.stride );
for ( auto& attribute : input.attributes ) {
attribute.descriptor.length = buffers[input.interleaved].size();
attribute.descriptor.pointer = (void*) (buffers[input.interleaved].data());
attribute.length = buffers[input.interleaved].size();
attribute.pointer = (void*) (buffers[input.interleaved].data());
}
} else for ( auto& attribute : input.attributes ) {
buffers[attribute.buffer].resize( count * attribute.descriptor.size );
attribute.descriptor.length = buffers[attribute.buffer].size();
attribute.descriptor.pointer = (void*) (buffers[attribute.buffer].data());
attribute.length = buffers[attribute.buffer].size();
attribute.pointer = (void*) (buffers[attribute.buffer].data());
}
}
void uf::Mesh::_insertV( uf::Mesh::Input& input, const void* data ) {
@ -400,14 +424,14 @@ void uf::Mesh::_bindI( uf::Mesh::Input& input, size_t size, ext::RENDERER::enums
void uf::Mesh::_reserveIs( uf::Mesh::Input& input, size_t count, size_t i ) {
auto& attribute = input.attributes[i];
buffers[attribute.buffer].reserve( count * attribute.descriptor.size );
attribute.descriptor.length = buffers[attribute.buffer].size();
attribute.descriptor.pointer = (void*) (buffers[attribute.buffer].data());
attribute.length = buffers[attribute.buffer].size();
attribute.pointer = (void*) (buffers[attribute.buffer].data());
}
void uf::Mesh::_resizeIs( uf::Mesh::Input& input, size_t count, size_t i ) {
auto& attribute = input.attributes[i];
buffers[attribute.buffer].resize( count * attribute.descriptor.size );
attribute.descriptor.length = buffers[attribute.buffer].size();
attribute.descriptor.pointer = (void*) (buffers[attribute.buffer].data());
attribute.length = buffers[attribute.buffer].size();
attribute.pointer = (void*) (buffers[attribute.buffer].data());
}
void uf::Mesh::_insertI( uf::Mesh::Input& input, const void* data, size_t i ) {
auto& attribute = input.attributes[i];

View File

@ -369,9 +369,9 @@ void ext::BakingBehavior::initialize( uf::Object& self ) {
// standard pipeline
{
uf::stl::string vertexShaderFilename = "/gltf/baking/bake.vert.spv";
uf::stl::string vertexShaderFilename = "/graph/baking/bake.vert.spv";
uf::stl::string geometryShaderFilename = "";
uf::stl::string fragmentShaderFilename = "/gltf/baking/bake.frag.spv";
uf::stl::string fragmentShaderFilename = "/graph/baking/bake.frag.spv";
if ( uf::renderer::settings::experimental::deferredSampling ) {
fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "deferredSampling.frag" );
}

View File

@ -64,6 +64,10 @@ void ext::LightBehavior::initialize( uf::Object& self ) {
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
renderMode.metadata.type = "depth";
renderMode.metadata.pipeline = "depth";
if ( uf::renderer::settings::experimental::culling ) {
renderMode.metadata.pipelines.emplace_back("culling");
}
renderMode.metadata.json["descriptor"]["depth bias"] = metadataJson["light"]["bias"];
renderMode.metadata.json["descriptor"]["renderMode"] = metadataJson["renderMode"];
@ -84,6 +88,7 @@ void ext::LightBehavior::initialize( uf::Object& self ) {
} else {
size = pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height };
}
if ( radius.y < radius.x ) radius.y = 256;
camera.setProjection( uf::matrix::perspective( fov, (float) size.x / (float) size.y, radius.x, radius.y ) );
camera.update(true);

View File

@ -241,7 +241,8 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
if ( stats.menu == "" && keys.paused ) {
stats.menu = "paused";
metadata.system.control = false;
uf::hooks.call("menu:Pause");
uf::Serializer payload;
uf::hooks.call("menu:Pause", payload);
}
else if ( !metadata.system.control ) {
stats.menu = "menu";

View File

@ -67,17 +67,14 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
if ( !timer.running() ) timer.start( uf::Time<>(-1000000) );
if ( timer.elapsed().asDouble() < 1 ) return;
timer.reset();
uf::Object* manager = (uf::Object*) this->globalFindByName("Gui Manager");
if ( !manager ) return;
uf::Serializer payload;
uf::stl::string config = metadataJson["menus"]["pause"].is<uf::stl::string>() ? metadataJson["menus"]["pause"].as<uf::stl::string>() : "/scenes/worldscape/gui/pause/menu.json";
uf::stl::string config = metadataJson["menus"]["pause"].as<uf::stl::string>("/entites/gui/pause/menu.json");
uf::Object& gui = manager->loadChild(config, false);
payload["uid"] = gui.getUid();
uf::Serializer& metadataJson = gui.getComponent<uf::Serializer>();
metadataJson["menu"] = json["menu"];
gui.initialize();
});
this->addHook( "world:Entity.LoadAsset", [&](ext::json::Value& json){
@ -318,6 +315,159 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
metadata.shader.parameters[metadata.shader.time] = uf::physics::time::current;
}
#endif
{
auto& graph = this->getGraph();
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& metadataVxgi = this->getComponent<ext::VoxelizerBehavior::Metadata>();
auto& metadataJson = this->getComponent<uf::Serializer>();
struct LightInfo {
uf::Entity* entity = NULL;
pod::Vector3f position = {0,0,0};
float range = 0.0f;
pod::Vector3f color = {0,0,0};
float intensity = 0.0f;
float distance = 0;
float bias = 0;
int32_t type = 0;
bool shadows = false;
};
uf::stl::vector<LightInfo> entities; entities.reserve(graph.size() / 2);
uf::graph::storage.lights.clear(); uf::graph::storage.lights.reserve(metadata.max.lights);
uf::graph::storage.shadow2Ds.clear(); uf::graph::storage.shadow2Ds.reserve(metadata.max.lights);
uf::graph::storage.shadowCubes.clear(); uf::graph::storage.shadowCubes.reserve(metadata.max.lights);
// traverse scene graph
for ( auto entity : graph ) {
// ignore this scene, our controller, and anything that isn't actually a light
if ( entity == this || entity == &controller || !entity->hasComponent<ext::LightBehavior::Metadata>() ) continue;
auto& metadata = entity->getComponent<ext::LightBehavior::Metadata>();
// disables shadow mappers that activate when in range
bool hasRT = entity->hasComponent<uf::renderer::RenderTargetRenderMode>();
if ( hasRT ) {
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
if ( metadata.renderer.mode == "in-range" ) renderMode.execute = false;
}
if ( metadata.power <= 0 ) continue;
auto flatten = uf::transform::flatten( entity->getComponent<pod::Transform<>>() );
LightInfo& info = entities.emplace_back(LightInfo{
.entity = entity,
.position = flatten.position,
.range = 0,
.color = pod::Vector4f{ metadata.color.x, metadata.color.y, metadata.color.z },
.intensity = metadata.power,
.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) ),
.bias = metadata.bias,
.type = metadata.type,
.shadows = metadata.shadows && hasRT,
});
}
// prioritize closer lights; it would be nice to also prioritize lights in view, but because of VXGI it's not really something to do
std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){
return l.distance < r.distance;
});
int32_t shadowUpdateThreshold = metadata.shadow.update; // how many shadow maps we should update, based on range
int32_t shadowCount = metadata.shadow.max; // how many shadow maps we should pass, based on range
if ( shadowCount <= 0 ) shadowCount = std::numeric_limits<int32_t>::max();
// disable shadows if that light is outside our threshold
for ( auto& info : entities ) if ( info.shadows && shadowCount-- <= 0 ) info.shadows = false;
// bind lighting and requested shadow maps
for ( uint32_t i = 0; i < entities.size() && uf::graph::storage.lights.size() < metadata.max.lights; ++i ) {
auto& info = entities[i];
uf::Entity* entity = info.entity;
if ( !info.shadows ) {
uf::graph::storage.lights.emplace_back(pod::Light{
.view = uf::matrix::identity(),
.projection = uf::matrix::identity(),
.position = info.position,
.range = info.range,
.color = info.color,
.intensity = info.intensity,
.type = info.type,
.typeMap = 0,
.indexMap = -1,
.depthBias = info.bias,
});
} else {
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
auto& lightCamera = entity->getComponent<uf::Camera>();
auto& lightMetadata = entity->getComponent<ext::LightBehavior::Metadata>();
lightMetadata.renderer.rendered = true;
// activate our shadow mapper if it's range-basedd
if ( lightMetadata.renderer.mode == "in-range" && shadowUpdateThreshold-- > 0 ) renderMode.execute = true;
// if point light, and combining is requested
if ( metadata.shadow.experimentalMode > 0 && renderMode.renderTarget.views == 6 ) {
int32_t index = -1;
// separated texture2Ds
if ( metadata.shadow.experimentalMode == 2 ) {
index = uf::graph::storage.shadow2Ds.size();
for ( auto& attachment : renderMode.renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) {
uf::graph::storage.shadow2Ds.emplace_back().aliasAttachment(attachment, view);
}
break;
}
// cubemapped
} else {
index = uf::graph::storage.shadowCubes.size();
for ( auto& attachment : renderMode.renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
uf::graph::storage.shadowCubes.emplace_back().aliasAttachment(attachment);
break;
}
}
uf::graph::storage.lights.emplace_back(pod::Light{
.view = lightCamera.getView(0),
.projection = lightCamera.getProjection(0),
.position = info.position,
.range = info.range,
.color = info.color,
.intensity = info.intensity,
.type = info.type,
.typeMap = metadata.shadow.experimentalMode,
.indexMap = index,
.depthBias = info.bias,
});
// any other shadowing light, even point lights, are split by shadow maps
} else {
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;
for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) {
uf::graph::storage.lights.emplace_back(pod::Light{
.view = lightCamera.getView(view),
.projection = lightCamera.getProjection(view),
.position = info.position,
.range = info.range,
.color = info.color,
.intensity = info.intensity,
.type = info.type,
.typeMap = 0,
.indexMap = uf::graph::storage.shadow2Ds.size(),
.depthBias = info.bias,
});
uf::graph::storage.shadow2Ds.emplace_back().aliasAttachment(attachment, view);
}
}
}
}
}
uf::graph::storage.buffers.light.update( (const void*) uf::graph::storage.lights.data(), uf::graph::storage.lights.size() * sizeof(pod::Light) );
}
/* Update lights */ if ( !uf::renderer::settings::experimental::vxgi ) {
ext::ExtSceneBehavior::bindBuffers( *this );
}
@ -535,18 +685,6 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string
alignas(4) uint32_t indexSkybox;
};
struct LightInfo {
uf::Entity* entity = NULL;
pod::Vector4f color = {0,0,0,0};
pod::Vector3f position = {0,0,0};
float distance = 0;
float bias = 0;
int32_t type = 0;
bool shadows = false;
};
uf::stl::vector<LightInfo> entities;
entities.reserve(graph.size() / 2);
// struct that contains our skybox cubemap, noise texture, and VXGI voxels
auto& sceneTextures = this->getComponent<pod::SceneTextures>();
uf::stl::vector<uf::renderer::Texture> textures2D;
@ -558,174 +696,19 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string
uf::stl::vector<uf::renderer::Texture> texturesCube;
texturesCube.reserve( metadata.max.texturesCube );
// lighting information
uf::stl::vector<pod::Light> lights;
lights.reserve( metadata.max.lights );
// material information
uf::stl::vector<pod::Material> materials;
materials.reserve( metadata.max.textures2D );
materials.emplace_back().colorBase = {0,0,0,0}; // setup our fallback material information
// texture information
uf::stl::vector<pod::Texture> textures;
textures.reserve( metadata.max.textures2D );
// drawcall information
uf::stl::vector<pod::DrawCommand> drawCommands;
drawCommands.reserve( metadata.max.textures2D );
// bind materials
for ( auto pair : uf::graph::storage.materials ) materials.emplace_back(pair.second);
for ( auto pair : uf::graph::storage.textures ) textures.emplace_back(pair.second);
// bind textures
// bind texture2Ds
for ( auto pair : uf::graph::storage.images ) {
auto& image = pair.second;
auto& texture2D = uf::graph::storage.texture2Ds[pair.first];
if ( !texture2D.generated() ) texture2D.loadFromImage( pair.second );
textures2D.emplace_back().aliasTexture(texture2D);
}
// traverse scene graph
for ( auto entity : graph ) {
// needed to grab our necessary materials/texture information, until i add it globally
#if 0
if ( entity->hasComponent<pod::Graph>() ) {
auto& graph = entity->getComponent<pod::Graph>();
// pass our draw call information, necessary in shader
/*
drawCommands.emplace_back(pod::DrawCall{
materials.size(),
textures.size(),
textures2D.size(),
0,
});
*/
// pass material information
for ( auto& material : graph.materials ) {
materials.emplace_back( uf::graph::storage.materials[material] );
}
// pass texture information
for ( auto& texture : graph.textures ) {
textures.emplace_back( uf::graph::storage.textures[texture] );
// attach the actual texture if the texture information requests it
// if ( texture.bind ) textures2D.emplace_back().aliasTexture(texture.texture);
}
}
#endif
// ignore this scene, our controller, and anything that isn't actually a light
if ( entity == this || entity == &controller || !entity->hasComponent<ext::LightBehavior::Metadata>() ) continue;
auto& metadata = entity->getComponent<ext::LightBehavior::Metadata>();
// disables shadow mappers that activate when in range
bool hasRT = entity->hasComponent<uf::renderer::RenderTargetRenderMode>();
if ( hasRT ) {
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
if ( metadata.renderer.mode == "in-range" ) renderMode.execute = false;
}
if ( metadata.power <= 0 ) continue;
auto flatten = uf::transform::flatten( entity->getComponent<pod::Transform<>>() );
LightInfo& info = entities.emplace_back(LightInfo{
.entity = entity,
.color = pod::Vector4f{ metadata.color.x, metadata.color.y, metadata.color.z, metadata.power },
.position = flatten.position,
.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) ),
.bias = metadata.bias,
.type = metadata.type,
.shadows = metadata.shadows && hasRT,
});
}
// prioritize closer lights; it would be nice to also prioritize lights in view, but because of VXGI it's not really something to do
std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){
return l.distance < r.distance;
});
int32_t shadowUpdateThreshold = metadata.shadow.update; // how many shadow maps we should update, based on range
int32_t shadowCount = metadata.shadow.max; // how many shadow maps we should pass, based on range
if ( shadowCount <= 0 ) shadowCount = std::numeric_limits<int32_t>::max();
// disable shadows if that light is outside our threshold
for ( auto& info : entities ) if ( info.shadows && shadowCount-- <= 0 ) info.shadows = false;
// bind scene textures
for ( auto& key : uf::graph::storage.texture2Ds.keys ) textures2D.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[key] );
// bind shadow maps
for ( auto& texture : uf::graph::storage.shadow2Ds ) textures2D.emplace_back().aliasTexture(texture);
for ( auto& texture : uf::graph::storage.shadowCubes ) texturesCube.emplace_back().aliasTexture(texture);
// bind skybox
size_t indexSkybox = texturesCube.size();
texturesCube.emplace_back().aliasTexture(sceneTextures.skybox);
// bind noise texture
size_t indexNoise = textures3D.size();
textures3D.emplace_back().aliasTexture(sceneTextures.noise);
// bind lighting and requested shadow maps
for ( uint32_t i = 0; i < entities.size() && lights.size() < metadata.max.lights; ++i ) {
auto& info = entities[i];
uf::Entity* entity = info.entity;
if ( !info.shadows ) {
lights.emplace_back(pod::Light{
.view = uf::matrix::identity(),
.projection = uf::matrix::identity(),
.position = info.position,
.color = info.color,
.type = info.type,
.typeMap = 0,
.indexMap = -1,
.depthBias = info.bias,
});
} else {
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
auto& lightCamera = entity->getComponent<uf::Camera>();
auto& lightMetadata = entity->getComponent<ext::LightBehavior::Metadata>();
lightMetadata.renderer.rendered = true;
// activate our shadow mapper if it's range-basedd
if ( lightMetadata.renderer.mode == "in-range" && shadowUpdateThreshold-- > 0 ) renderMode.execute = true;
// if point light, and combining is requested
if ( metadata.shadow.experimentalMode > 0 && renderMode.renderTarget.views == 6 ) {
int32_t index = -1;
// separated texture2Ds
if ( metadata.shadow.experimentalMode == 2 ) {
index = textures2D.size();
for ( auto& attachment : renderMode.renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) {
textures2D.emplace_back().aliasAttachment(attachment, view);
}
break;
}
// cubemapped
} else {
index = texturesCube.size();
for ( auto& attachment : renderMode.renderTarget.attachments ) {
if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
texturesCube.emplace_back().aliasAttachment(attachment);
break;
}
}
lights.emplace_back(pod::Light{
.view = lightCamera.getView(0),
.projection = lightCamera.getProjection(0),
.position = info.position,
.color = info.color,
.type = info.type,
.typeMap = metadata.shadow.experimentalMode,
.indexMap = index,
.depthBias = info.bias,
});
// any other shadowing light, even point lights, are split by shadow maps
} else {
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;
for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) {
lights.emplace_back(pod::Light{
.view = lightCamera.getView(view),
.projection = lightCamera.getProjection(view),
.position = info.position,
.color = info.color,
.type = info.type,
.typeMap = 0,
.indexMap = textures2D.size(),
.depthBias = info.bias,
});
textures2D.emplace_back().aliasAttachment(attachment, view);
}
}
}
}
}
// attach VXGI voxels
if ( uf::renderer::settings::experimental::vxgi ) {
@ -781,10 +764,10 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string
};
uniforms.lengths = UniformDescriptor::Lengths{
.lights = MIN( lights.size(), metadata.max.lights ),
.materials = MIN( materials.size(), metadata.max.textures2D ),
.textures = MIN( textures.size(), metadata.max.textures2D ),
// .drawCommands = MIN( drawCommands.size(), metadata.max.textures2D ),
.lights = MIN( uf::graph::storage.lights.size(), metadata.max.lights ),
.materials = MIN( uf::graph::storage.materials.keys.size(), metadata.max.textures2D ),
.textures = MIN( uf::graph::storage.textures.keys.size(), metadata.max.textures2D ),
.drawCommands = MIN( 0, metadata.max.textures2D ),
};
uniforms.ambient = metadata.light.ambient;
@ -793,7 +776,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string
uniforms.exposure = metadata.light.exposure;
uniforms.msaa = ext::vulkan::settings::msaa;
uniforms.shadowSamples = std::min( 0, metadata.shadow.samples );
uniforms.indexSkybox = 0;
uniforms.indexSkybox = indexSkybox;
}
for ( auto* blitter : blitters ) {
@ -817,25 +800,9 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string
if ( previousTextures[i] != graphic.material.textures[i].image )
shouldUpdate = true;
}
// update lighting buffer
shader.updateBuffer( (const void*) lights.data(), uniforms.lengths.lights * sizeof(pod::Light), renderMode.metadata.lightBufferIndex, false );
//
if ( shouldUpdate ) {
shader.updateBuffer( (const void*) materials.data(), uniforms.lengths.materials * sizeof(pod::Material), renderMode.metadata.materialBufferIndex, false );
shader.updateBuffer( (const void*) textures.data(), uniforms.lengths.textures * sizeof(pod::Texture), renderMode.metadata.textureBufferIndex, false );
shader.updateBuffer( (const void*) drawCommands.data(), uniforms.lengths.drawCommands * sizeof(pod::DrawCommand), renderMode.metadata.drawCallBufferIndex, false );
graphic.updatePipelines();
}
if ( shouldUpdate ) graphic.updatePipelines();
// shader.updateBuffer( (const void*) &uniforms, sizeof(uniforms), shader.getUniformBuffer("UBO") );
shader.updateBuffer( uniforms, shader.getUniformBuffer("UBO") );
/*
auto& uniform = shader.getUniform("UBO");
memcpy( (void*) uniform, &uniforms, sizeof(uniforms) );
shader.updateUniform( "UBO", uniform );
*/
}
}
#endif

View File

@ -82,6 +82,11 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) {
uf::renderer::addRenderMode( &renderMode, metadata.renderModeName );
renderMode.metadata.type = "vxgi";
renderMode.metadata.pipeline = "vxgi";
renderMode.metadata.pipelines.emplace_back("vxgi");
if ( uf::renderer::settings::experimental::culling ) {
renderMode.metadata.pipelines.emplace_back("culling");
}
renderMode.metadata.samples = 1;
renderMode.metadata.subpasses = metadata.cascades;
@ -99,6 +104,11 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) {
renderMode.metadata.json["shaders"]["compute"] = computeShaderFilename;
renderMode.blitter.descriptor.renderMode = metadata.renderModeName;
renderMode.blitter.descriptor.subpass = -1;
renderMode.blitter.descriptor.inputs.dispatch = {
(metadata.voxelSize.x / metadata.dispatchSize.x),
(metadata.voxelSize.y / metadata.dispatchSize.y),
(metadata.voxelSize.z / metadata.dispatchSize.z),
};
renderMode.blitter.process = true;
size_t maxTextures2D = ext::config["engine"]["scenes"]["textures"]["max"]["2D"].as<size_t>(512);
@ -136,7 +146,7 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) {
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);
// vkCmdDispatch(commandBuffer, metadata.voxelSize.x / metadata.dispatchSize.x, metadata.voxelSize.y / metadata.dispatchSize.y, metadata.voxelSize.z / metadata.dispatchSize.z);
}
// generate mipmaps
@ -198,7 +208,6 @@ void ext::VoxelizerBehavior::tick( uf::Object& self ) {
controllerPosition.y = floor(controllerPosition.y);
controllerPosition.z = floor(controllerPosition.z);
controllerPosition += metadata.extents.min;
controllerPosition.x = floor(controllerPosition.x);
controllerPosition.y = floor(controllerPosition.y);
controllerPosition.z = -floor(controllerPosition.z);

View File

@ -349,7 +349,10 @@ void ext::Gui::load( const uf::Image& image ) {
}
metadataJson["cull mode"] = "none";
graphic.descriptor.parse( metadataJson );
if ( uf::matrix::reverseInfiniteProjection ) {
} else {
metadata.depth = -metadata.depth;
}
if ( metadataJson["flip uv"].as<bool>() ) for ( auto& v : vertices ) v.uv.y = 1 - v.uv.y;
if ( metadata.depth != 0.0f ) for ( auto& v : vertices ) v.position.z = metadata.depth;
@ -816,7 +819,8 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
.color = metadata.color,
.mode = metadata.shader,
.depth = 1 - metadata.depth,
// .depth = 1 - metadata.depth,
.depth = uf::matrix::reverseInfiniteProjection ? 1 - metadata.depth : metadata.depth,
};
// set glyph-based uniforms
if ( isGlyph && uniform.size() == sizeof(::GlyphUniformDescriptor<>) ) {

View File

@ -24,6 +24,7 @@
#include <uf/utils/http/http.h>
#include <uf/engine/entity/entity.h>
#include <uf/engine/graph/graph.h>
#include <sys/stat.h>
@ -241,6 +242,10 @@ void EXT_API ext::initialize() {
}
uf::allocator::override = ::config["engine"]["memory pool"]["override"].as( uf::allocator::override );
}
{
uf::Mesh::defaultInterleaved = ::config["engine"]["scenes"]["meshes"]["interleaved"].as( uf::Mesh::defaultInterleaved );
uf::matrix::reverseInfiniteProjection = ::config["engine"]["scenes"]["matrix"]["reverseInfinite"].as( uf::matrix::reverseInfiniteProjection );
}
/* Create initial scene (kludge) */ {
uf::Scene& scene = uf::instantiator::instantiate<uf::Scene>(); //new uf::Scene;
@ -348,6 +353,7 @@ void EXT_API ext::initialize() {
uf::renderer::settings::experimental::hdr = ::config["engine"]["ext"][RENDERER]["experimental"]["hdr"].as( uf::renderer::settings::experimental::hdr );
uf::renderer::settings::experimental::vxgi = ::config["engine"]["ext"][RENDERER]["experimental"]["vxgi"].as( uf::renderer::settings::experimental::vxgi );
uf::renderer::settings::experimental::deferredSampling = ::config["engine"]["ext"][RENDERER]["experimental"]["deferred sampling"].as( uf::renderer::settings::experimental::deferredSampling );
uf::renderer::settings::experimental::culling = ::config["engine"]["ext"][RENDERER]["experimental"]["culling"].as( uf::renderer::settings::experimental::culling );
#define JSON_TO_VKFORMAT( key ) if ( ::config["engine"]["ext"][RENDERER]["formats"][#key].is<uf::stl::string>() ) {\
uf::stl::string format = ::config["engine"]["ext"][RENDERER]["formats"][#key].as<uf::stl::string>();\
format = uf::string::replace( uf::string::uppercase(format), " ", "_" );\
@ -408,7 +414,12 @@ void EXT_API ext::initialize() {
if ( ::config["engine"]["render modes"]["deferred"].as<bool>() ) {
uf::renderer::addRenderMode( new uf::renderer::DeferredRenderMode, "" );
auto& renderMode = uf::renderer::getRenderMode("Deferred", true);
if ( ::config["engine"]["render modes"]["stereo deferred"].as<bool>() ) renderMode.metadata.eyes = 2;
if ( ::config["engine"]["render modes"]["stereo deferred"].as<bool>() ) {
renderMode.metadata.eyes = 2;
}
if ( uf::renderer::settings::experimental::culling ) {
renderMode.metadata.pipelines.emplace_back("culling");
}
}
#endif
@ -470,7 +481,6 @@ void EXT_API ext::initialize() {
});
}
#endif
uf::renderer::initialize();
}
@ -622,6 +632,9 @@ void EXT_API ext::tick() {
}
#endif
//UF_TIMER_TRACE("ticking physics");
/* Update graph */ {
uf::graph::tick();
}
/* Update entities */ {
uf::scene::tick();
}
@ -740,7 +753,12 @@ void EXT_API ext::terminate() {
ext::lua::terminate();
}
#endif
uf::scene::destroy();
{
uf::graph::destroy();
}
{
uf::scene::destroy();
}
/* Garbage collection */ if ( false ) {
uint8_t mode = ::config["engine"]["debug"]["garbage collection"]["mode"].as<uint64_t>();

View File

@ -1,24 +0,0 @@
Stack trace:
Frame Function Args
000FFFF5848 00180062C9C (000FFFF5A68, 00010000002, 000FFFFCE00, 000FFFFDE50)
000FFFF58F0 00180065090 (001800FA0BE, 00100140000, 100000000000101, 00000000000)
000FFFF5F70 00180047D1B (00000000000, 00000000000, 00000000000, 00000000000)
000FFFF6050 001801711AC (00000000001, 00000000000, 0000000019C, FFFFFFFF00000000)
000FFFF99F0 0018014761E (0018035B200, 008000F0610, 008000B36F0, 00000001003)
000FFFFAB80 00180148201 (00180352408, 0018037A8A0, 000FFFFAD02, 00000000000)
000FFFFAC30 00180065873 (001801B48F6, 000FFFFAE48, 00000000000, FFFFFFFFFFFFFFFF)
000FFFFAD90 001801389AB (001801B48F6, 000FFFFAE48, 00000000000, FFFFFFFFFFFFFFFF)
000FFFFAD90 0010040E131 (000FFFFAE48, 008000FE8F0, 00000000000, 001FFFFAE48)
00100433CA8 0010040E3DB (0080006D408, 008000F0610, 008000ED0A0, 008000B2AF0)
00100433CA8 0010040E8E4 (00000000000, 008000E8D43, 00000000008, 008000E8D3A)
000FFFFAFF0 0010040F34B (00100000000, 000FFFFB0F0, 00000000000, 00000000001)
000FFFFAFF0 0010040FB20 (00000000000, 183A92A3F1E23A87, 000000020C0, 00800063A21)
00000000001 0010041A5AF (00100000002, 0010040BA66, 00000000001, 001004335A8)
00000000001 0010041A9D9 (0080006CA36, 00000000001, 00000000028, 0080006CF10)
00000000001 00100419958 (00800000000, 6176652D2A2D2824, 2D7367616C662D6C, 00000292D2A)
001004369F0 0010041ADC7 (00100423B48, 00000000001, 00430B39190, 00000000000)
000FFFFB400 00100423FD8 (000FFFFCC90, 00800000160, 00000000000, 00180330BA0)
000FFFFCCE0 0018004A01B (00000000000, 00000000000, 00000000000, 00000000000)
000FFFFCDA0 0018004794A (00000000000, 00000000000, 00000000000, 00000000000)
000FFFFCE50 00180047A0C (00000000000, 00000000000, 00000000000, 00000000000)
End of stack trace