Live Long and Render (I)

320x240

Fun fact: I created a draft for this article in early 2016, while I was rounding up Metal support and shortly after Vulkan was announced. It took me three years, but here it is:

YES.

I’m finally working on a Vulkan-based rendering backend for Crimild.

This time it’s going to be much more than just making a Renderer class with Vulkan code inside as I did with Metal some time ago. This time, thought, I’m willing to go as far as I have to and make a modern rendering architecture.

It’s BIG refactor time!

Why now?

I started this year (2019, I think) talking about how render graphs and shader graphs and other rendering improvements were critical for the next major version of Crimild. But as time has passed, I come to realize that they were not enough.

Despite their benefits, I was headed towards a mixed solution. Neither old school nor modern. Using state of the art techniques, but bounded by OpenGL limitations. And, while it was indeed a step forward towards newer paradigms and APIs (Vulkan, Metal, etc), if I followed that road I was going to have to change most of it again in the near future. After all, there’s no gain in making Vulkan work like OpenGL.

Therefore, I started from scratch and decided to do it the right way from the beginning. I’m going to implement a whole new rendering system on top of Vulkan and it’s major concepts (render devices, swapchains, pipelines, render passes, etc).

What about OpenGL? Well, as much as I love it, I would like to get rid of it. The only environment in which I see OpenGL as still relevant is on web (as in WebGL). Being able to publish apps on browsers (throught Emscripten) is still a goal for Crimild, so I guess OpenGL is not going anywhere for now. But, it’s going to change based on whatever architecture I come up with after this refactor.

What about Metal? I am getting rid of the Metal renderer. Plain and simple. There’s no point in supporting both Vulkan and Metal (at least for the moment). And the current implementation is quite limited. The good size of this is that after having a Vulkan-based rendering system, implementing on in Metal should be straightforward. Provided I needed, of course.

What have I done so far?

I have read articles, books, even tweets. I have watched videos. I have completed the excellent Vulkan Tutorial and looked into several examples.

I recently started working on (that is, actually coding) the new rendering architecture on my spare time (I have other priorities at the moment). This is what I achieved so far:

Yeap, that’s just a window.

Well, it’s a bit more than that.

At the moment, I can create a Vulkan Instance and a Surface, which is not a small feat for Vulkan. I’m working on a Mac (using MoltenVK) with GLFW for window management, but the new implementation is supposed to work on multiple platforms.

I made changes to other parts of Crimild too, like simulations and systems. Nothing too big, just a few tools to better prioritize systems. I am planning to change them a lot once go full ECS in the not-so-distant future. But, one refactor at a time.

That’s it for now. I try and write more posts as I make progress. But I won’t make any promises 🙂

Bye!

Advertisements

Scripting improvements for UI

For my current project (not that one, the other one) I needed a mechanism to create user interfaces in a fast and easy way, without having to position elements explicitly.

In a recent post, I talked about a kind of constraint-based UI layout mechanism included in recent versions of Crimild that allow us to create interfaces in a declarative way:

Each element in the UI defines a set of constraints related with either its parent another element.

Surprisingly, I (almost) didn’t change anything about that (so far). I know, I know, it’s shocking to me as well.

Anyway, that mechanism is pretty powerful, indeed. Still, it requires us to recompile the game every time we make changes (because C++). Therefore, the next evolutionary step was quite obvious: move that feature to Lua.

Using Crimild’s Coding facilities introduced last year, I implemented decoding functions for all of the UI-related components. The result is a Lua script that looks like this:

local UIFrameConstraint = 'crimild.ui.UIFrameConstraint'
local makeConstraint = UIFrameConstraint.Maker
-- Other require calls remove for clarity

-- Create a Restart Button
local restartButton = Group(
{
components = {
UIBackground( { color = { 0.0, 0.0, 1.0, 1.0 } } ),
UIFrame(
{
constraints = {
makeConstraint.after( mainMenuButton ),
makeConstraint.bottom( 10 ),
makeConstraint.width( 80 ),
makeConstraint.height( 20 ),
},
}
),
UILabel( { text = 'Restart' } ),
UIRestartButton(),
},
}
)

Simple and fast. Nice!

BTW, that script is using a new organization for scripts based on Lua modules. But that’s a story for another time…

I’ve been busy

Happy 2019!! First post of the year!! (I checked ;))

During the past month I’ve focused most of my efforts on the new renderer architecture, one of the major changes for Crimild 5. There are many, many things I already changed and a lot more that I want to change and upgrade in order to bring Crimild a little closer to most modern game engines.

At the core of the new rendering pipeline are both Render and Shader Graphs. Both of these tools were already introduced in latest Crimild versions, but as experimental features. It’s time to make them production-ready.

Without further ado, here’s what I’ve been doing so far:

New forward render pass

I’m writing the entire forward pipeline from scratch using shader graphs and fixing exiting errors in lighting calculations.

Point lights with different attenuation values
Spotlights and ambient light, working correctly this time
Directional lighting and specular mapping

Cube and Environmental Mapping

I tried implementing cube mapping years ago, but it was too hard-coded into the engine for it to actually become something useful. Now, with a new Skybox node and cube textures support, working with environmental mapping has become straightforward:

Skybox and Reflections (left bunny)
Refraction

Shadows

Crimild shadow mapping support was bad. Really bad. But that is about to change.

I’m implementing a new shadow pass that creates a single shadow atlas supporting multiple casters with different types and resolutions. Only directional lights can cast shadows at the moment, but except more news in the coming weeks.

Two directional lights casting shadows at the same time!!

Emscripten

Last, but not least, Emscripten support has been greatly improved, with support for WebGL2.

I’m revisiting most of the demos to make them work on the browser.

That’s it for the moment.

2019 has definitely started in a high note for Crimild 🙂