Kuesa basic Example
Demonstrates the use of the KuesaSerenity API to import a glTF2 file inside a Window
Setup Window
Kuesa::Serenity::Window can be conveniently used to create a Window suitable for Serenity.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | int main(int ac, char **av)
{
KDGui::GuiApplication app;
// Setup Window
Kuesa::Serenity::Window w;
auto engine = std::make_unique<::Serenity::AspectEngine>();
w.visible.valueChanged().connect([&app](const bool &visible) {
if (visible == false)
app.quit();
});
w.title = KDBindings::makeBinding(makeTitle(w.width, w.height, engine->fps));
w.width = 1920;
w.height = 1080;
w.visible = true;
// Setup KDGpu
std::unique_ptr<KDGpu::GraphicsApi> api = std::make_unique<KDGpu::VulkanGraphicsApi>();
KDGpu::Instance instance = api->createInstance(KDGpu::InstanceOptions{
.applicationVersion = SERENITY_MAKE_API_VERSION(0, 1, 0, 0) });
const KDGpu::SurfaceOptions surfaceOptions = KDGpuKDGui::View::surfaceOptions(&w);
KDGpu::Surface surface = instance.createSurface(surfaceOptions);
KDGpu::AdapterAndDevice defaultDevice = instance.createDefaultDevice(surface);
KDGpu::Device device = std::move(defaultDevice.device);
|
Filename: basic/main.cpp
Importing a glTF2 File
We add the default Kuesa Layers to the [LayerManager ] so that meshes can be tagged with the appropriate layer mask based on their material properties upon importing.
This will be required to filter which Entities to render at the appropriate time.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | std::unique_ptr<::Serenity::Entity> createKuesaScene(Kuesa::Serenity::AssetCollections *assetCollections,
::Serenity::LayerManager *layerManager)
{
Kuesa::Serenity::GLTF2Importer importer;
importer.assetCollections = assetCollections;
importer.layerManager = layerManager;
importer.source = String(SHARED_ASSETS_DIR "/models/car/DodgeViper.gltf");
// Insert the generated Kuesa Entities into rootEntity
auto rootEntity = std::make_unique<::Serenity::Entity>();
{
// Add a default light
::Serenity::Entity *e = rootEntity->createChildEntity<::Serenity::Entity>();
::Serenity::Light *l = e->createComponent<::Serenity::Light>();
l->type = ::Serenity::Light::Type::Point;
::Serenity::SrtTransform *t = e->createComponent<::Serenity::SrtTransform>();
t->translation = glm::vec3(0.0f, 40.0f, 0.0f);
}
for (std::unique_ptr<::Serenity::Entity> &sceneRoot : importer.sceneRoots()) {
// Take ownership
rootEntity->addChildEntity(std::move(sceneRoot));
}
return std::move(rootEntity);
}
|
Filename: basic/main.cpp
We make use of the GLTF2Importer to load a glTF2 file and feed our AssectCollections .
| // Setup Kuesa Scene
Kuesa::Serenity::AssetCollections collections;
::Serenity::LayerManager layerManager;
layerManager.addLayer(Kuesa::Serenity::Layers::ZFillLayerName);
layerManager.addLayer(Kuesa::Serenity::Layers::OpaqueLayerName);
layerManager.addLayer(Kuesa::Serenity::Layers::AlphaLayerName);
std::unique_ptr<::Serenity::Entity> root = createKuesaScene(&collections, &layerManager);
|
Filename: basic/main.cpp
Retrieving Animations
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 | // Animations
{
auto *camCenterAnimator = root->createComponent<::Serenity::ClipAnimator>();
camCenterAnimator->clip = collections.animationClips("SweepCamCenterAction");
camCenterAnimator->mapper = collections.animationMappers("SweepCamCenterAction");
camCenterAnimator->loops = -1;
camCenterAnimator->setRunning(true);
auto *camPitchAnimator = root->createComponent<::Serenity::ClipAnimator>();
camPitchAnimator->clip = collections.animationClips("SweepCamPitchAction");
camPitchAnimator->mapper = collections.animationMappers("SweepCamPitchAction");
camPitchAnimator->loops = -1;
camPitchAnimator->setRunning(true);
auto *hoodAnimator = root->createComponent<::Serenity::ClipAnimator>();
hoodAnimator->clip = collections.animationClips("HoodAction");
hoodAnimator->mapper = collections.animationMappers("HoodAction");
hoodAnimator->loops = 1;
hoodAnimator->setRunning(true);
const String wheelNames[] = {
String("WheelBLDriveAction"),
String("WheelBRDriveAction"),
String("WheelFLDriveAction"),
String("WheelFRDriveAction"),
};
for (const String &wheelName : wheelNames) {
auto *wheelAnimator = root->createComponent<::Serenity::ClipAnimator>();
wheelAnimator->clip = collections.animationClips(wheelName);
wheelAnimator->mapper = collections.animationMappers(wheelName);
wheelAnimator->loops = -1;
wheelAnimator->setRunning(true);
}
}
|
Filename: basic/main.cpp
Setting up serenity
We start by creating the various aspects we will make use of.
| // Setup Serenity Engine
auto renderAspect = engine->createAspect<::Serenity::RenderAspect>(std::move(device));
auto spatialAspect = engine->createAspect<::Serenity::SpatialAspect>();
auto logicAspect = engine->createAspect<::Serenity::LogicAspect>();
auto animationAspect = engine->createAspect<::Serenity::AnimationAspect>();
|
Filename: basic/main.cpp
And then we configure the Serenity Rendering algorithm. Rendering will be split in 2 phases, one for Opaque and one for Alpha objects.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 | // Create Render Algo
auto algo = std::make_unique<::Serenity::ForwardAlgorithm>();
auto createOpaquePhase = [&layerManager]() {
::Serenity::ForwardAlgorithm::RenderPhase opaquePhase{
layerManager.layerMask({ Kuesa::Serenity::Layers::OpaqueLayerName }),
::Serenity::ForwardAlgorithm::RenderPhase::Type::Opaque,
::Serenity::LayerFilterType::AcceptAny,
{},
true
};
auto depthState = std::make_shared<::Serenity::DepthStencilState>();
depthState->depthTestEnabled = true;
depthState->depthWritesEnabled = true;
depthState->depthCompareOperation = KDGpu::CompareOperation::Less;
opaquePhase.renderStates.setDepthStencilState(std::move(depthState));
auto rasterizerState = std::make_shared<::Serenity::PrimitiveRasterizerState>();
rasterizerState->cullMode = KDGpu::CullModeFlagBits::BackBit;
opaquePhase.renderStates.setPrimitiveRasterizerState(std::move(rasterizerState));
return opaquePhase;
};
auto createAlphaPhase = [&layerManager]() {
::Serenity::ForwardAlgorithm::RenderPhase alphaPhase{
layerManager.layerMask({ Kuesa::Serenity::Layers::AlphaLayerName }),
::Serenity::ForwardAlgorithm::RenderPhase::Type::Alpha,
::Serenity::LayerFilterType::AcceptAll,
{},
true
};
auto depthState = std::make_shared<::Serenity::DepthStencilState>();
depthState->depthTestEnabled = true;
depthState->depthWritesEnabled = false;
depthState->depthCompareOperation = KDGpu::CompareOperation::LessOrEqual;
alphaPhase.renderStates.setDepthStencilState(std::move(depthState));
auto blendState = std::make_shared<::Serenity::ColorBlendState>();
::Serenity::ColorBlendState::AttachmentBlendState attachmentBlendState;
attachmentBlendState.format = KDGpu::Format::UNDEFINED;
attachmentBlendState.blending.blendingEnabled = true;
attachmentBlendState.blending.alpha.operation = KDGpu::BlendOperation::Add;
attachmentBlendState.blending.color.operation = KDGpu::BlendOperation::Add;
attachmentBlendState.blending.alpha.srcFactor = KDGpu::BlendFactor::SrcAlpha;
attachmentBlendState.blending.color.srcFactor = KDGpu::BlendFactor::SrcAlpha;
attachmentBlendState.blending.color.dstFactor = KDGpu::BlendFactor::OneMinusSrcAlpha;
attachmentBlendState.blending.alpha.dstFactor = KDGpu::BlendFactor::One;
blendState->attachmentBlendStates = { attachmentBlendState };
alphaPhase.renderStates.setColorBlendState(std::move(blendState));
return alphaPhase;
};
// ImGUI Overlay
Serenity::AbstractOverlay *overlay = createOverlay(w, engine.get(), algo.get());
// Specify RT
algo->renderTargetRefs = { Serenity::RenderTargetRef::fromWindow(&w, instance) };
// Specify which RenderTarget to render to, which render phases and which camera to use
algo->renderViews = {
Serenity::ForwardAlgorithm::RenderView(0,
{ createOpaquePhase(),
createAlphaPhase() },
overlay,
sweepCamera)
};
algo->msaaSamples = Serenity::RenderAlgorithm::SamplesCount::Samples_4;
|
Filename: basic/main.cpp
Finally we can set the Render Algorithm and the scene root before starting the Serenity engine.
| renderAspect->setRenderAlgorithm(std::move(algo));
engine->setRootEntity(std::move(root));
engine->running = true;
|
Filename: basic/main.cpp
Updated on 2023-07-03 at 11:02:17 +0000