GFX
This is a graphics library for creating 3D apps.
It features a “low level” graphics api abstraction layer called Gfx, supporting 4 backends :
-
OpenGL
-
Vulkan
-
Direct3D 11
-
Direct3D 12
It also features a “high level” api that is implemented on top of the low level api, called Hlgfx, that contains common abstractions for creating 3d apps, a bit like Three.js (Camera, 3D object, Meshes, Scene graph…).
This high level api is used to create a simple 3d engine as an example.
It’s not a finished product, there are still some bugs to fixes and things to add to the libraries, but most of the system is working.
Low level api features
Example Code
This is a very simple example usage of the Gfx api, to create an app that displays a textured triangle with a colour tint passed as a uniform variable : Here’s the full code for that example.
We first initialize the graphics context and the swapchain :
// Initialize the graphics API
gfx::context::initializeInfo ContextInitialize;
ContextInitialize.Extensions = Window->GetRequiredExtensions();
ContextInitialize.ErrorCallback = ErrorCallback;
ContextInitialize.InfoCallback = InfoCallback;
ContextInitialize.Debug = true;
GfxContext = gfx::context::Initialize(ContextInitialize, *Window);
Swapchain = GfxContext->CreateSwapchain(Width, Height);
We then create the texture for the triangle :
gfx::imageData ImageData = gfx::ImageFromFile("resources/Textures/Debug.jpg");
gfx::imageCreateInfo ImageCreateInfo =
{
{0.0f,0.0f,0.0f,0.0f}, //Border Colour
gfx::samplerFilter::Linear, //MinFilter
gfx::samplerFilter::Linear, //MagFilter
gfx::samplerWrapMode::ClampToBorder, //WrapS
gfx::samplerWrapMode::ClampToBorder, //WrapT
gfx::samplerWrapMode::ClampToBorder, //WrapR
true //GenerateMipMaps
};
TextureHandle1 = GfxContext->CreateImage(ImageData, ImageCreateInfo);
gfx::image *Texture1 = GfxContext->GetImage(TextureHandle1);
We then create the vertex stream description, and the vertex buffers for the triangle. A vertex here is defined by a 3d position, and a rgba colour.
float vertices[] =
{
0.0f, 0.25f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.25f, -0.25f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.25f, -0.25f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
};
gfx::vertexStreamData VertexStream1 = {};
VertexStream1
.SetSize(sizeof(vertices))
.SetStride(7 * sizeof(float))
.SetData(&vertices)
.SetStreamIndex(0)
.AddAttribute({sizeof(float), 3, gfx::vertexAttributeType::Float, false, gfx::attributeSemantic::POSITION, 0, 0})
.AddAttribute({sizeof(float), 4, gfx::vertexAttributeType::Float, false, gfx::attributeSemantic::COLOR, 0, 1});
gfx::vertexBufferCreateInfo VertexBufferCreateInfo = {};
VertexBufferCreateInfo.Init()
.AddVertexStream(VertexStream1);
VertexBufferHandle = GfxContext->CreateVertexBuffer(VertexBufferCreateInfo);
We then create a uniform buffer for storing the colour of the triangle :
UniformBufferHandle1 = GfxContext->CreateBuffer(sizeof(uniformData), gfx::bufferUsage::UniformBuffer, gfx::memoryUsage::CpuToGpu);
gfx::buffer *UniformBuffer1 = GfxContext->GetBuffer(UniformBufferHandle1);
UniformBuffer1->CopyData((uint8_t*)&UniformData1, sizeof(uniformData), 0);
We can now create a “uniform group” that contains the texture and the uniform buffer :
Uniforms = std::make_shared<gfx::uniformGroup>();
Uniforms->Reset()
.AddUniformBuffer(0, UniformBufferHandle1)
.AddTexture(4, TextureHandle1);
With all that, we can create a rendering pipeline, and bind this uniform group to that rendering pipeline. We describe pipelines with json files that contain all the needed informations for creating one :
-
Shader Code
-
Vertex Streams
-
Depth Functions
-
Blend Functions
-
Triangle culling
PipelineHandleSwapchain = GfxContext->CreatePipelineFromFile("resources/Shaders/Triangle/Triangle.json");
GfxContext->BindUniformsToPipeline(Uniforms, PipelineHandleSwapchain, 0);
Uniforms->Update();
And that’s all for the initialization. Now, here’s the code for the main render loop :
GfxContext->StartFrame();
// Begin recording commands into the command buffer
std::shared_ptr<gfx::commandBuffer> CommandBuffer = GfxContext->GetCurrentFrameCommandBuffer();
CommandBuffer->Begin();
CommandBuffer->BeginPass(GfxContext->GetSwapchainFramebuffer(), {0.5f, 0.0f, 0.8f, 1.0f}, {1.0f, 0});
CommandBuffer->SetViewport(0.0f, 0.0f, (float)Width, (float)Height);
CommandBuffer->SetScissor(0, 0, Width, Height);
CommandBuffer->BindGraphicsPipeline(PipelineHandleSwapchain);
CommandBuffer->BindUniformGroup(Uniforms, 0);
CommandBuffer->BindVertexBuffer(VertexBufferHandle);
CommandBuffer->DrawArrays(0, 3);
CommandBuffer->EndPass();
GfxContext->EndFrame();
GfxContext->Present();
And here’s the result :
Examples
High level api features
The Hlgfx library contains abstractions classes for creating 3d apps :
-
Camera and Camera Controller for user interaction
-
Vulkan Ray Tracing
Mini engine
The mini engine contained in Main_HelloHLGFX shows how to use the Hlgfx library to create a simple 3d app.
This engine allows to author 3d scenes by importing glTF or any file supported by assimp.
It has a scene graph that allows to parent objects together to create complex 3d object hierarchies.
It also has a PBR material authoring system.
It also contains an asset management system that allows to import and instantiate assets into the scene.