Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layer support in renderer #1645

Merged
merged 28 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ae6c34f
renderer: Store terrain tiles in render entity.
heinezen Apr 28, 2024
56994af
renderer: Don't use curve for terrain mesh.
heinezen May 1, 2024
8604027
renderer: Create mesh for individual terrain textures.
heinezen May 1, 2024
2233c71
renderer: Remove old terrain paths from render entity.
heinezen May 1, 2024
fc44940
assets: Add second test terrain asset.
heinezen May 1, 2024
2f20f31
gamestate: Use tile's asset path when updating renderer.
heinezen May 1, 2024
7a02427
gamestate: Add more choices to terrain examples.
heinezen May 1, 2024
8734667
gamestate: Add terrain test layouts to terrain factory.
heinezen May 1, 2024
a46451e
renderer: Fix vertex generation from tiles.
heinezen May 1, 2024
9329095
renderer: Order tayers by position.
heinezen May 3, 2024
f517790
renderer: Remove camera from world object.
heinezen May 3, 2024
fcfc596
renderer: Store uniforms for multiple layers in world object.
heinezen May 3, 2024
b576532
renderer: Draw multiple layers per animation.
heinezen May 3, 2024
d11e926
renderer: Split renderer.h into more source files.
heinezen May 3, 2024
253f94b
renderer: Remove unused variable.
heinezen May 3, 2024
85c4787
renderer: Priority sorting in render pass.
heinezen May 3, 2024
e33d481
renderer: Remove code duplication in render pass operations.
heinezen May 7, 2024
2b3262d
renderer: Autosort renderables into layers on insert.
heinezen May 8, 2024
10140c8
renderer: Make inserion by priority the default.
heinezen May 8, 2024
bf9b2f2
renderer: Move sorting of renderables to render pass.
heinezen May 8, 2024
b328def
renderer: Add more functions for optimization to GLRenderPass.
heinezen May 8, 2024
017c3be
renderer: Turn off optimization for OpenGL.
heinezen May 8, 2024
5746a5b
renderer: Use move semantics for adding renderables to pass.
heinezen May 8, 2024
fb93335
renderer: Add more comments to explain render pass logic.
heinezen May 8, 2024
82356fd
renderer: Revere ordering of layers in pass.
heinezen May 8, 2024
5f74b72
renderer: Allow configuring depth of added layers.
heinezen May 8, 2024
ac1be0f
doc: Document layer usage in level 1 renderer.
heinezen May 8, 2024
52663d6
renderer: Use vector of vectors for storing renderables.
heinezen May 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/test/textures/test_terrain2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions assets/test/textures/test_terrain2.terrain
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2023-2023 the openage authors. See copying.md for legal info.
# openage terrain definition file

version 2

texture 0 "test_terrain2.texture"

scalefactor 1.0

layer 0

frame 0 0 0 0
12 changes: 12 additions & 0 deletions assets/test/textures/test_terrain2.texture
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2023-2023 the openage authors.
# openage texture definition file

version 1

imagefile "test_terrain2.png"

size 500 500

pxformat rgba8 cbits=True

subtex 0 0 500 500 0 0
74 changes: 70 additions & 4 deletions doc/code/renderer/level1.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ Low-level renderer for communicating with the OpenGL and Vulkan APIs.

1. [Overview](#overview)
2. [Architecture](#architecture)
3. [Basic Usage](#basic--usage)
3. [Basic Usage](#basic-usage)
1. [Window/Renderer Creation](#windowrenderer-creation)
2. [Adding a Shader Program](#adding-a-shader-program)
3. [Creating a Renderable](#creating-a-renderable)
4. [Rendering and Displaying the Result](#rendering-and-displaying-the-result)
4. [Advanced Usage](#advanced-usage)
1. [Addressing Uniforms via numeric IDs](#addressing-uniforms-via-numeric-ids)
2. [Framebuffers / Multiple Render Passes](#framebuffers--multiple-render-passes)
3. [Complex Geometry](#complex-geometry)
4. [Uniform Buffers](#uniform-buffers)
3. [Defining Layers in a Render Pass](#defining-layers-in-a-render-pass)
4. [Complex Geometry](#complex-geometry)
5. [Uniform Buffers](#uniform-buffers)
5. [Thread-safety](#thread-safety)


Expand Down Expand Up @@ -44,7 +45,7 @@ The `resources` namespace provides classes for initializing and loading meshes,
These classes are independent from the specific OpenGL/Vulkan backends and can thus be passed to the
abstract interface of the renderer renderer to make them usable with graphics hardware.

## Basic Usage
## Basic Usage

Code examples can be found in the [renderer demos](/libopenage/renderer/demo/).
See the [testing docs](/doc/code/testing.md#python-demos) on how to try them out.
Expand Down Expand Up @@ -200,9 +201,11 @@ Finally, we can execute the rendering pipeline for all objects in the render pas
renderer->render(pass);
```

<!-- TODO: We have deactivated this behaviour for now
Before rendering, the render pass optimizes the order in which renderables are rendered to
minimize state changes on the GPU and save computation time. For example, the render pass
sorts the renderables by shader program, since changing them is an expensive operation.
-->

After rendering is finished, the window has to be updated to display the rendered result.

Expand Down Expand Up @@ -312,6 +315,69 @@ Renderable obj {
obj.depth_test = true;
```


### Defining Layers in a Render Pass

Layers give more fine-grained control over the draw order of renderables in a render pass. Every
layer has a priority that determines when associated renderables are drawn. Lower priority
renderables are drawn earlier, higher priority renderables are drawn later.

In comparison to using multiple render passes, layers do not require the (expensive) switching
of framebuffers between passes. The tradeoff is a slight overhead when inserting new renderables
into the render pass.

To assign renderables to a layer, we have to specify the priority in the `RenderPass::add_renderables(..)`
function call.

```c++
Renderable obj {
input,
geom
};
pass->add_renderables({ obj }, 42);
```

For existing layers, new renderables are always appended to the end of the layer. Renderables
are sorted into the correct position automatically when they are added:

```c++
pass->add_renderables({ obj1, obj2, obj3 }, 42);
pass->add_renderables({ obj4 }, 0);
pass->add_renderables({ obj5, obj6 }, 1337);
pass->add_renderables({ obj7 }, 0);
// draw order: obj4, obj7, obj1, obj2, obj3, obj5, obj6
// layers: prio 0 | prio 42 | prio 1337
```

When no priority is specified when calling `RenderPass::add_renderables(..)`, the highest
priority is assumed (which is `std::numeric_limits<int64_t>::max()`). Therefore,
objects added like this are always drawn last. It also means that these two calls are equal:

```c++
pass->add_renderables({ obj });
pass->add_renderables({ obj }, std::numeric_limits<int64_t>::max());
```


Layers are created lazily during insertion if no layer with the specified priority exists yet.
We can also create layers explicitly for a specific priority:

```c++
pass->add_layer(42);
```

When executing the rendering pipeline for a specific pass, renderables are drawn layer by layer.
By default, the renderer clears the depth buffer when switching to a new layer. This is done
under the assumption that layers with higher priority should always draw over layers with lower
priority, even when depth tests are active. This behavior can be deactivated when explicitly
creating a layer:

```c++
// keep depth testing
pass->add_layer(42, false);
```


### Complex Geometry

For displaying complex geometry like 3D objects or non-rectangular surfaces, the renderer
Expand Down
24 changes: 2 additions & 22 deletions libopenage/gamestate/terrain_chunk.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2023 the openage authors. See copying.md for legal info.
// Copyright 2018-2024 the openage authors. See copying.md for legal info.

#include "terrain_chunk.h"

Expand All @@ -22,22 +22,6 @@ void TerrainChunk::set_render_entity(const std::shared_ptr<renderer::terrain::Te
this->render_entity = entity;
}

void TerrainChunk::render_update(const time::time_t &time,
const std::string &terrain_path) {
if (this->render_entity != nullptr) {
// TODO: Update individual tiles instead of the whole chunk
std::vector<std::pair<terrain_elevation_t, std::string>> tiles;
tiles.reserve(this->tiles.size());
for (const auto &tile : this->tiles) {
tiles.emplace_back(tile.elevation, terrain_path);
}

this->render_entity->update(this->size,
tiles,
time);
}
}

const util::Vector2s &TerrainChunk::get_size() const {
return this->size;
}
Expand All @@ -46,17 +30,13 @@ const coord::tile_delta &TerrainChunk::get_offset() const {
return this->offset;
}

void TerrainChunk::set_terrain_path(const std::string &terrain_path) {
this->terrain_path = terrain_path;
}

void TerrainChunk::render_update(const time::time_t &time) {
if (this->render_entity != nullptr) {
// TODO: Update individual tiles instead of the whole chunk
std::vector<std::pair<terrain_elevation_t, std::string>> tiles;
tiles.reserve(this->tiles.size());
for (const auto &tile : this->tiles) {
tiles.emplace_back(tile.elevation, terrain_path);
tiles.emplace_back(tile.elevation, tile.terrain_asset_path);
}

this->render_entity->update(this->size,
Expand Down
29 changes: 8 additions & 21 deletions libopenage/gamestate/terrain_chunk.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,6 @@ class TerrainChunk {
*/
void set_render_entity(const std::shared_ptr<renderer::terrain::TerrainRenderEntity> &entity);

/**
* Update the render entity.
*
* @param time Simulation time of the update.
* @param terrain_path Path to the terrain definition used at \p time.
*/
void render_update(const time::time_t &time,
const std::string &terrain_path);

/**
* Get the size of this terrain chunk.
*
Expand All @@ -57,14 +48,11 @@ class TerrainChunk {
*/
const coord::tile_delta &get_offset() const;

// TODO: Remove test texture references

// Set the terrain path of this terrain chunk.
// TODO: Remove later
void set_terrain_path(const std::string &terrain_path);

// Send the current texture to the renderer.
// TODO: Replace later with render_update(time, terrain_path)
/**
* Update the render entity.
*
* @param time Simulation time of the update.
*/
void render_update(const time::time_t &time);

private:
Expand All @@ -81,17 +69,16 @@ class TerrainChunk {
coord::tile_delta offset;

/**
* Height map of the terrain chunk.
* Terrain tile info of the terrain chunk.
*
* Layout is row-major.
*/
std::vector<TerrainTile> tiles;

/**
* Render entity for pushing updates to the renderer. Can be \p nullptr.
*/
std::shared_ptr<renderer::terrain::TerrainRenderEntity> render_entity;

// TODO: Remove test texture references
std::string terrain_path;
};

} // namespace openage::gamestate
Loading
Loading