Skip to content

Commit 4ac9c88

Browse files
Merge pull request #48 from Devsh-Graphics-Programming/animation
Asset Metadata Rework and Quaternion Quantization
2 parents a7cb6e0 + 32fb5f3 commit 4ac9c88

File tree

282 files changed

+5855
-8792
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

282 files changed

+5855
-8792
lines changed

examples_tests/04.Keyframe/main.cpp

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O.
2+
// This file is part of the "Nabla Engine".
3+
// For conditions of distribution and use, see copyright notice in nabla.h
4+
5+
#define _NBL_STATIC_LIB_
6+
#include <iostream>
7+
#include <cstdio>
8+
#include <nabla.h>
9+
10+
//! I advise to check out this file, its a basic input handler
11+
#include "../common/QToQuitEventReceiver.h"
12+
13+
14+
using namespace nbl;
15+
using namespace core;
16+
17+
18+
#include "nbl/nblpack.h"
19+
struct VertexStruct
20+
{
21+
/// every member needs to be at location aligned to its type size for GLSL
22+
float Pos[3]; /// uses float hence need 4 byte alignment
23+
uint8_t Col[2]; /// same logic needs 1 byte alignment
24+
uint8_t uselessPadding[2]; /// so if there is a member with 4 byte alignment then whole struct needs 4 byte align, so pad it
25+
} PACK_STRUCT;
26+
#include "nbl/nblunpack.h"
27+
28+
const char* vertexSource = R"===(
29+
#version 430 core
30+
31+
layout(location = 0) in vec4 vPos; //only a 3d position is passed from irrlicht, but last (the W) coordinate gets filled with default 1.0
32+
layout(location = 1) in vec4 vCol;
33+
34+
layout( push_constant, row_major ) uniform Block {
35+
mat4 modelViewProj;
36+
} PushConstants;
37+
38+
layout(location = 0) out vec4 Color; //per vertex output color, will be interpolated across the triangle
39+
40+
void main()
41+
{
42+
gl_Position = PushConstants.modelViewProj*vPos; //only thing preventing the shader from being core-compliant
43+
Color = vCol;
44+
}
45+
)===";
46+
47+
const char* fragmentSource = R"===(
48+
#version 430 core
49+
50+
layout(location = 0) in vec4 Color; //per vertex output color, will be interpolated across the triangle
51+
52+
layout(location = 0) out vec4 pixelColor;
53+
54+
void main()
55+
{
56+
pixelColor = Color;
57+
}
58+
)===";
59+
60+
int main()
61+
{
62+
// create device with full flexibility over creation parameters
63+
// you can add more parameters if desired, check nbl::SIrrlichtCreationParameters
64+
nbl::SIrrlichtCreationParameters params;
65+
params.Bits = 24; //may have to set to 32bit for some platforms
66+
params.ZBufferBits = 24; //we'd like 32bit here
67+
params.DriverType = video::EDT_OPENGL; //! Only Well functioning driver, software renderer left for sake of 2D image drawing
68+
params.WindowSize = dimension2d<uint32_t>(1280, 720);
69+
params.Fullscreen = false;
70+
params.Vsync = true; //! If supported by target platform
71+
params.Doublebuffer = true;
72+
params.Stencilbuffer = false; //! This will not even be a choice soon
73+
auto device = createDeviceEx(params);
74+
75+
if (!device)
76+
return 1; // could not create selected driver.
77+
78+
79+
//! disable mouse cursor, since camera will force it to the middle
80+
//! and we don't want a jittery cursor in the middle distracting us
81+
device->getCursorControl()->setVisible(false);
82+
83+
//! Since our cursor will be enslaved, there will be no way to close the window
84+
//! So we listen for the "Q" key being pressed and exit the application
85+
QToQuitEventReceiver receiver;
86+
device->setEventReceiver(&receiver);
87+
88+
89+
auto* driver = device->getVideoDriver();
90+
auto* smgr = device->getSceneManager();
91+
92+
//
93+
core::smart_refctd_ptr<video::IGPUMeshBuffer> mb;
94+
{
95+
VertexStruct vertices[8];
96+
vertices[0] = VertexStruct{{-1.f,-1.f,-1.f},{ 0, 0}};
97+
vertices[1] = VertexStruct{{ 1.f,-1.f,-1.f},{127, 0}};
98+
vertices[2] = VertexStruct{{-1.f, 1.f,-1.f},{255, 0}};
99+
vertices[3] = VertexStruct{{ 1.f, 1.f,-1.f},{ 0,127}};
100+
vertices[4] = VertexStruct{{-1.f,-1.f, 1.f},{127,127}};
101+
vertices[5] = VertexStruct{{ 1.f,-1.f, 1.f},{255,127}};
102+
vertices[6] = VertexStruct{{-1.f, 1.f, 1.f},{ 0,255}};
103+
vertices[7] = VertexStruct{{ 1.f, 1.f, 1.f},{127,255}};
104+
105+
uint16_t indices_indexed16[] =
106+
{
107+
0,1,2,1,2,3,
108+
4,5,6,5,6,7,
109+
0,1,4,1,4,5,
110+
2,3,6,3,6,7,
111+
0,2,4,2,4,6,
112+
1,3,5,3,5,7
113+
};
114+
115+
asset::SPushConstantRange range[1] = {asset::ISpecializedShader::ESS_VERTEX,0u,sizeof(core::matrix4SIMD)};
116+
117+
auto createGPUSpecializedShaderFromSource = [=](const char* source, asset::ISpecializedShader::E_SHADER_STAGE stage)
118+
{
119+
auto spirv = device->getAssetManager()->getGLSLCompiler()->createSPIRVFromGLSL(source, stage, "main", "runtimeID");
120+
auto unspec = driver->createGPUShader(std::move(spirv));
121+
return driver->createGPUSpecializedShader(unspec.get(), { nullptr,nullptr,"main",stage });
122+
};
123+
// origFilepath is only relevant when you have filesystem #includes in your shader
124+
auto createGPUSpecializedShaderFromSourceWithIncludes = [&](const char* source, asset::ISpecializedShader::E_SHADER_STAGE stage, const char* origFilepath)
125+
{
126+
auto resolved_includes = device->getAssetManager()->getGLSLCompiler()->resolveIncludeDirectives(source, stage, origFilepath);
127+
return createGPUSpecializedShaderFromSource(reinterpret_cast<const char*>(resolved_includes->getSPVorGLSL()->getPointer()), stage);
128+
};
129+
core::smart_refctd_ptr<video::IGPUSpecializedShader> shaders[2] =
130+
{
131+
createGPUSpecializedShaderFromSourceWithIncludes(vertexSource,asset::ISpecializedShader::ESS_VERTEX, "shader.vert"),
132+
createGPUSpecializedShaderFromSource(fragmentSource,asset::ISpecializedShader::ESS_FRAGMENT)
133+
};
134+
auto shadersPtr = reinterpret_cast<video::IGPUSpecializedShader**>(shaders);
135+
136+
asset::SVertexInputParams inputParams;
137+
inputParams.enabledAttribFlags = 0b11u;
138+
inputParams.enabledBindingFlags = 0b1u;
139+
inputParams.attributes[0].binding = 0u;
140+
inputParams.attributes[0].format = asset::EF_R32G32B32_SFLOAT;
141+
inputParams.attributes[0].relativeOffset = offsetof(VertexStruct,Pos[0]);
142+
inputParams.attributes[1].binding = 0u;
143+
inputParams.attributes[1].format = asset::EF_R8G8_UNORM;
144+
inputParams.attributes[1].relativeOffset = offsetof(VertexStruct,Col[0]);
145+
inputParams.bindings[0].stride = sizeof(VertexStruct);
146+
inputParams.bindings[0].inputRate = asset::EVIR_PER_VERTEX;
147+
148+
asset::SBlendParams blendParams; // defaults are sane
149+
150+
asset::SPrimitiveAssemblyParams assemblyParams = {asset::EPT_TRIANGLE_LIST,false,1u};
151+
152+
asset::SStencilOpParams defaultStencil;
153+
asset::SRasterizationParams rasterParams;
154+
rasterParams.faceCullingMode = asset::EFCM_NONE;
155+
auto pipeline = driver->createGPURenderpassIndependentPipeline( nullptr,driver->createGPUPipelineLayout(range,range+1u,nullptr,nullptr,nullptr,nullptr),
156+
shadersPtr,shadersPtr+sizeof(shaders)/sizeof(core::smart_refctd_ptr<video::IGPUSpecializedShader>),
157+
inputParams,blendParams,assemblyParams,rasterParams);
158+
159+
asset::SBufferBinding<video::IGPUBuffer> bindings[video::IGPUMeshBuffer::MAX_ATTR_BUF_BINDING_COUNT];
160+
bindings[0u] = {0u,driver->createFilledDeviceLocalGPUBufferOnDedMem(sizeof(vertices),vertices)};
161+
mb = core::make_smart_refctd_ptr<video::IGPUMeshBuffer>(std::move(pipeline),nullptr,bindings,asset::SBufferBinding<video::IGPUBuffer>{0u,driver->createFilledDeviceLocalGPUBufferOnDedMem(sizeof(indices_indexed16),indices_indexed16)});
162+
{
163+
mb->setIndexType(asset::EIT_16BIT);
164+
mb->setIndexCount(2*3*6);
165+
}
166+
}
167+
168+
169+
//! we want to move around the scene and view it from different angles
170+
scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0,100.0f,0.001f);
171+
172+
camera->setPosition(core::vector3df(-4,0,0));
173+
camera->setTarget(core::vector3df(0,0,0));
174+
camera->setNearValue(0.01f);
175+
camera->setFarValue(10.0f);
176+
177+
smgr->setActiveCamera(camera);
178+
179+
uint64_t lastFPSTime = 0;
180+
while(device->run() && receiver.keepOpen())
181+
{
182+
driver->beginScene(true, true, video::SColor(255,255,255,255) );
183+
//! This animates (moves) the camera and sets the transforms
184+
camera->OnAnimate(std::chrono::duration_cast<std::chrono::milliseconds>(device->getTimer()->getTime()).count());
185+
camera->render();
186+
core::matrix4SIMD mvp = camera->getConcatenatedMatrix();
187+
188+
//! Stress test for memleaks aside from demo how to create meshes that live on the GPU RAM
189+
{
190+
driver->bindGraphicsPipeline(mb->getPipeline());
191+
driver->pushConstants(mb->getPipeline()->getLayout(), asset::ISpecializedShader::ESS_VERTEX, 0u, sizeof(core::matrix4SIMD), mvp.pointer());
192+
driver->drawMeshBuffer(mb.get());
193+
}
194+
driver->endScene();
195+
196+
// display frames per second in window title
197+
uint64_t time = device->getTimer()->getRealTime();
198+
if (time-lastFPSTime > 1000)
199+
{
200+
std::wostringstream str;
201+
str << L"GPU Mesh Demo - Irrlicht Engine [" << driver->getName() << "] FPS:" << driver->getFPS() << " PrimitvesDrawn:" << driver->getPrimitiveCountDrawn();
202+
203+
device->setWindowCaption(str.str().c_str());
204+
lastFPSTime = time;
205+
}
206+
}
207+
208+
//create a screenshot
209+
{
210+
core::rect<uint32_t> sourceRect(0, 0, params.WindowSize.Width, params.WindowSize.Height);
211+
//ext::ScreenShot::dirtyCPUStallingScreenshot(device, "screenshot.png", sourceRect, asset::EF_R8G8B8_SRGB);
212+
}
213+
214+
return 0;
215+
}

examples_tests/05.NablaTutorialExample/main.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include <nabla.h>
99

1010
#include "../common/QToQuitEventReceiver.h"
11-
#include "nbl/asset/CGeometryCreator.h"
1211

1312
/*
1413
General namespaces. Entire engine consists of those bellow.
@@ -87,7 +86,7 @@ int main()
8786

8887
asset::IAssetLoader::SAssetLoadParams loadingParams;
8988
auto images_bundle = assetManager->getAsset("../../media/color_space_test/R8G8B8A8_1.png", loadingParams);
90-
assert(!images_bundle.isEmpty());
89+
assert(!images_bundle.getContents().empty());
9190
auto image = images_bundle.getContents().begin()[0];
9291
auto image_raw = static_cast<asset::ICPUImage*>(image.get());
9392

@@ -110,8 +109,8 @@ int main()
110109

111110
const IAsset::E_TYPE types[]{ IAsset::E_TYPE::ET_SPECIALIZED_SHADER, IAsset::E_TYPE::ET_SPECIALIZED_SHADER, static_cast<IAsset::E_TYPE>(0u) };
112111

113-
auto cpuVertexShader = core::smart_refctd_ptr_static_cast<ICPUSpecializedShader>(assetManager->findAssets("nbl/builtin/materials/lambertian/singletexture/specializedshader.vert", types)->front().getContents().begin()[0]);
114-
auto cpuFragmentShader = core::smart_refctd_ptr_static_cast<ICPUSpecializedShader>(assetManager->findAssets("nbl/builtin/materials/lambertian/singletexture/specializedshader.frag", types)->front().getContents().begin()[0]);
112+
auto cpuVertexShader = core::smart_refctd_ptr_static_cast<ICPUSpecializedShader>(assetManager->findAssets("nbl/builtin/material/lambertian/singletexture/specialized_shader.vert", types)->front().getContents().begin()[0]);
113+
auto cpuFragmentShader = core::smart_refctd_ptr_static_cast<ICPUSpecializedShader>(assetManager->findAssets("nbl/builtin/material/lambertian/singletexture/specialized_shader.frag", types)->front().getContents().begin()[0]);
115114

116115
auto gpuVertexShader = driver->getGPUObjectsFromAssets(&cpuVertexShader.get(), &cpuVertexShader.get() + 1)->front();
117116
auto gpuFragmentShader = driver->getGPUObjectsFromAssets(&cpuFragmentShader.get(), &cpuFragmentShader.get() + 1)->front();

examples_tests/06.MeshLoaders/main.cpp

Lines changed: 50 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -48,29 +48,40 @@ int main()
4848

4949
auto* driver = device->getVideoDriver();
5050
auto* smgr = device->getSceneManager();
51-
auto* am = device->getAssetManager();
52-
auto* fs = am->getFileSystem();
5351

54-
//
55-
auto* qnc = am->getMeshManipulator()->getQuantNormalCache();
56-
//loading cache from file
57-
qnc->loadNormalQuantCacheFromFile<asset::CQuantNormalCache::E_CACHE_TYPE::ECT_2_10_10_10>(fs,"../../tmp/normalCache101010.sse", true);
52+
asset::ICPUMesh* mesh_raw = nullptr;
53+
const asset::COBJMetadata* metaOBJ = nullptr;
54+
// load
55+
{
56+
auto* am = device->getAssetManager();
57+
auto* fs = am->getFileSystem();
58+
59+
auto* qnc = am->getMeshManipulator()->getQuantNormalCache();
60+
//loading cache from file
61+
qnc->loadCacheFromFile<asset::EF_A2B10G10R10_SNORM_PACK32>(fs, "../../tmp/normalCache101010.sse");
62+
63+
// register the zip
64+
device->getFileSystem()->addFileArchive("../../media/sponza.zip");
5865

59-
// register the zip
60-
device->getFileSystem()->addFileArchive("../../media/sponza.zip");
66+
asset::IAssetLoader::SAssetLoadParams lp;
67+
auto meshes_bundle = am->getAsset("sponza.obj", lp);
68+
assert(!meshes_bundle.getContents().empty());
6169

62-
asset::IAssetLoader::SAssetLoadParams lp;
63-
auto meshes_bundle = am->getAsset("sponza.obj", lp);
64-
assert(!meshes_bundle.isEmpty());
65-
auto mesh = meshes_bundle.getContents().begin()[0];
66-
auto mesh_raw = static_cast<asset::ICPUMesh*>(mesh.get());
70+
metaOBJ = meshes_bundle.getMetadata()->selfCast<const asset::COBJMetadata>();
6771

68-
//saving cache to file
69-
qnc->saveCacheToFile(asset::CQuantNormalCache::E_CACHE_TYPE::ECT_2_10_10_10,fs,"../../tmp/normalCache101010.sse");
72+
auto mesh = meshes_bundle.getContents().begin()[0];
73+
mesh_raw = static_cast<asset::ICPUMesh*>(mesh.get());
74+
75+
//saving cache to file
76+
qnc->saveCacheToFile<asset::EF_A2B10G10R10_SNORM_PACK32>(fs,"../../tmp/normalCache101010.sse");
77+
}
7078

7179
//we can safely assume that all meshbuffers within mesh loaded from OBJ has same DS1 layout (used for camera-specific data)
80+
asset::ICPUMeshBuffer* const first_mb = *mesh_raw->getMeshBuffers().begin();
81+
auto pipelineMetadata = metaOBJ->getAssetSpecificMetadata(first_mb->getPipeline());
82+
7283
//so we can create just one DS
73-
asset::ICPUDescriptorSetLayout* ds1layout = mesh_raw->getMeshBuffer(0u)->getPipeline()->getLayout()->getDescriptorSetLayout(1u);
84+
asset::ICPUDescriptorSetLayout* ds1layout = first_mb->getPipeline()->getLayout()->getDescriptorSetLayout(1u);
7485
uint32_t ds1UboBinding = 0u;
7586
for (const auto& bnd : ds1layout->getBindings())
7687
if (bnd.type==asset::EDT_UNIFORM_BUFFER)
@@ -81,9 +92,8 @@ int main()
8192

8293
size_t neededDS1UBOsz = 0ull;
8394
{
84-
auto pipelineMetadata = static_cast<const asset::IPipelineMetadata*>(mesh_raw->getMeshBuffer(0u)->getPipeline()->getMetadata());
85-
for (const auto& shdrIn : pipelineMetadata->getCommonRequiredInputs())
86-
if (shdrIn.descriptorSection.type==asset::IPipelineMetadata::ShaderInput::ET_UNIFORM_BUFFER && shdrIn.descriptorSection.uniformBufferObject.set==1u && shdrIn.descriptorSection.uniformBufferObject.binding==ds1UboBinding)
95+
for (const auto& shdrIn : pipelineMetadata->m_inputSemantics)
96+
if (shdrIn.descriptorSection.type==asset::IRenderpassIndependentPipelineMetadata::ShaderInput::ET_UNIFORM_BUFFER && shdrIn.descriptorSection.uniformBufferObject.set==1u && shdrIn.descriptorSection.uniformBufferObject.binding==ds1UboBinding)
8797
neededDS1UBOsz = std::max<size_t>(neededDS1UBOsz, shdrIn.descriptorSection.uniformBufferObject.relByteoffset+shdrIn.descriptorSection.uniformBufferObject.bytesize);
8898
}
8999

@@ -130,39 +140,37 @@ int main()
130140
camera->render();
131141

132142
core::vector<uint8_t> uboData(gpuubo->getSize());
133-
auto pipelineMetadata = static_cast<const asset::IPipelineMetadata*>(mesh_raw->getMeshBuffer(0u)->getPipeline()->getMetadata());
134-
for (const auto& shdrIn : pipelineMetadata->getCommonRequiredInputs())
143+
for (const auto& shdrIn : pipelineMetadata->m_inputSemantics)
135144
{
136-
if (shdrIn.descriptorSection.type==asset::IPipelineMetadata::ShaderInput::ET_UNIFORM_BUFFER && shdrIn.descriptorSection.uniformBufferObject.set==1u && shdrIn.descriptorSection.uniformBufferObject.binding==ds1UboBinding)
145+
if (shdrIn.descriptorSection.type==asset::IRenderpassIndependentPipelineMetadata::ShaderInput::ET_UNIFORM_BUFFER && shdrIn.descriptorSection.uniformBufferObject.set==1u && shdrIn.descriptorSection.uniformBufferObject.binding==ds1UboBinding)
137146
{
138147
switch (shdrIn.type)
139148
{
140-
case asset::IPipelineMetadata::ECSI_WORLD_VIEW_PROJ:
141-
{
142-
core::matrix4SIMD mvp = camera->getConcatenatedMatrix();
143-
memcpy(uboData.data()+shdrIn.descriptorSection.uniformBufferObject.relByteoffset, mvp.pointer(), shdrIn.descriptorSection.uniformBufferObject.bytesize);
144-
}
145-
break;
146-
case asset::IPipelineMetadata::ECSI_WORLD_VIEW:
147-
{
148-
core::matrix3x4SIMD MV = camera->getViewMatrix();
149-
memcpy(uboData.data() + shdrIn.descriptorSection.uniformBufferObject.relByteoffset, MV.pointer(), shdrIn.descriptorSection.uniformBufferObject.bytesize);
150-
}
151-
break;
152-
case asset::IPipelineMetadata::ECSI_WORLD_VIEW_INVERSE_TRANSPOSE:
153-
{
154-
core::matrix3x4SIMD MV = camera->getViewMatrix();
155-
memcpy(uboData.data()+shdrIn.descriptorSection.uniformBufferObject.relByteoffset, MV.pointer(), shdrIn.descriptorSection.uniformBufferObject.bytesize);
156-
}
157-
break;
149+
case asset::IRenderpassIndependentPipelineMetadata::ECSI_WORLD_VIEW_PROJ:
150+
{
151+
core::matrix4SIMD mvp = camera->getConcatenatedMatrix();
152+
memcpy(uboData.data()+shdrIn.descriptorSection.uniformBufferObject.relByteoffset, mvp.pointer(), shdrIn.descriptorSection.uniformBufferObject.bytesize);
153+
}
154+
break;
155+
case asset::IRenderpassIndependentPipelineMetadata::ECSI_WORLD_VIEW:
156+
{
157+
core::matrix3x4SIMD MV = camera->getViewMatrix();
158+
memcpy(uboData.data() + shdrIn.descriptorSection.uniformBufferObject.relByteoffset, MV.pointer(), shdrIn.descriptorSection.uniformBufferObject.bytesize);
159+
}
160+
break;
161+
case asset::IRenderpassIndependentPipelineMetadata::ECSI_WORLD_VIEW_INVERSE_TRANSPOSE:
162+
{
163+
core::matrix3x4SIMD MV = camera->getViewMatrix();
164+
memcpy(uboData.data()+shdrIn.descriptorSection.uniformBufferObject.relByteoffset, MV.pointer(), shdrIn.descriptorSection.uniformBufferObject.bytesize);
165+
}
166+
break;
158167
}
159168
}
160169
}
161170
driver->updateBufferRangeViaStagingBuffer(gpuubo.get(), 0ull, gpuubo->getSize(), uboData.data());
162171

163-
for (uint32_t i = 0u; i < gpumesh->getMeshBufferCount(); ++i)
172+
for (auto gpumb : gpumesh->getMeshBuffers())
164173
{
165-
video::IGPUMeshBuffer* gpumb = gpumesh->getMeshBuffer(i);
166174
const video::IGPURenderpassIndependentPipeline* pipeline = gpumb->getPipeline();
167175
const video::IGPUDescriptorSet* ds3 = gpumb->getAttachedDescriptorSet();
168176

examples_tests/07.HardwareSkinning/mesh.frag

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// This file is part of the "Nabla Engine".
33
// For conditions of distribution and use, see copyright notice in nabla.h
44

5-
#version 420 core
5+
#version 440 core
66
layout(binding = 0) uniform sampler2D tex0;
77

88
in vec3 Normal;

0 commit comments

Comments
 (0)