Skip to content

Commit

Permalink
Merge pull request #1639 from heinezen/feature/scale-shader
Browse files Browse the repository at this point in the history
Move subtex scaling to shader
  • Loading branch information
TheJJ authored Apr 21, 2024
2 parents 068ab06 + 185dd98 commit 920367b
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 54 deletions.
12 changes: 10 additions & 2 deletions assets/shaders/terrain.vert.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,17 @@ out vec2 tex_pos;

uniform mat4 model;

// camera parameters for transforming the object position
// and scaling the subtex to the correct size
layout (std140) uniform camera {
mat4 view;
mat4 proj;
// view matrix (world to view space)
mat4 view;
// projection matrix (view to clip space)
mat4 proj;
// inverse zoom factor (1.0 / zoom)
float inv_zoom;
// inverse viewport size (1.0 / viewport size)
vec2 inv_viewport_size;
};

void main() {
Expand Down
59 changes: 45 additions & 14 deletions assets/shaders/world2d.vert.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,19 @@ layout(location=1) in vec2 uv;

out vec2 vert_uv;

// transformation for object (not vertex!) position to clip space
// camera parameters for transforming the object position
// and scaling the subtex to the correct size
layout (std140) uniform camera {
mat4 view;
mat4 proj;
// view matrix (world to view space)
mat4 view;
// projection matrix (view to clip space)
mat4 proj;
// inverse zoom factor (1.0 / zoom)
// high zoom = upscale subtex
// low zoom = downscale subtex
float inv_zoom;
// inverse viewport size (1.0 / viewport size)
vec2 inv_viewport_size;
};

// can be used to move the object position in world space _before_
Expand All @@ -27,33 +36,55 @@ uniform bool flip_y;
// parameters for scaling and moving the subtex
// to the correct position in clip space

// offset from the subtex anchor
// moves the subtex relative to the subtex center
uniform vec2 anchor_offset;

// animation scalefactor
// scales the vertex positions so that they
// match the subtex dimensions
uniform vec2 scale;
//
// high animation scale = downscale subtex
// low animation scale = upscale subtex
uniform float scale;

// size of the subtex (in pixels)
uniform vec2 subtex_size;

// offset of the subtex anchor point
// from the subtex center (in pixels)
// used to move the subtex so that the anchor point
// is at the object position
uniform vec2 anchor_offset;

void main() {
// translate the position of the object from world space to clip space
// this is the position where we want to draw the subtex in 2D
vec4 obj_clip_pos = proj * view * model * vec4(obj_world_position, 1.0);

// subtex has to be scaled to account for the zoom factor
// and the animation scale factor. essentially this is (animation scale / zoom).
float zoom_scale = scale * inv_zoom;

// Scale the subtex vertices
// we have to account for the viewport size to get the correct dimensions
// and then scale the subtex to the zoom factor to get the correct size
vec2 vert_scale = zoom_scale * subtex_size * inv_viewport_size;

// Scale the anchor offset with the same method as above
// to get the correct anchor position in the viewport
vec2 anchor_scale = zoom_scale * anchor_offset * inv_viewport_size;

// if the subtex is flipped, we also need to flip the anchor offset
// essentially, we invert the coordinates for the flipped axis
float anchor_x = float(flip_x) * -1.0 * anchor_offset.x + float(!flip_x) * anchor_offset.x;
float anchor_y = float(flip_y) * -1.0 * anchor_offset.y + float(!flip_y) * anchor_offset.y;
float anchor_x = float(flip_x) * -1.0 * anchor_scale.x + float(!flip_x) * anchor_scale.x;
float anchor_y = float(flip_y) * -1.0 * anchor_scale.y + float(!flip_y) * anchor_scale.y;

// offset the clip position by the offset of the subtex anchor
// imagine this as pinning the subtex to the object position at the subtex anchor point
obj_clip_pos += vec4(anchor_x, anchor_y, 0.0, 0.0);

// create a move matrix for positioning the vertices
// uses the scale and the transformed object position in clip space
mat4 move = mat4(scale.x, 0.0, 0.0, 0.0,
0.0, scale.y, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
// uses the vert scale and the transformed object position in clip space
mat4 move = mat4(vert_scale.x, 0.0, 0.0, 0.0,
0.0, vert_scale.y, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
obj_clip_pos.x, obj_clip_pos.y, obj_clip_pos.z, 1.0);

// calculate the final vertex position
Expand Down
23 changes: 14 additions & 9 deletions libopenage/renderer/camera/camera.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022-2023 the openage authors. See copying.md for legal info.
// Copyright 2022-2024 the openage authors. See copying.md for legal info.

#include "camera.h"

Expand Down Expand Up @@ -28,10 +28,7 @@ Camera::Camera(const std::shared_ptr<Renderer> &renderer,
proj{Eigen::Matrix4f::Identity()} {
this->look_at_scene(Eigen::Vector3f(0.0f, 0.0f, 0.0f));

resources::UBOInput view_input{"view", resources::ubo_input_t::M4F32};
resources::UBOInput proj_input{"proj", resources::ubo_input_t::M4F32};
auto ubo_info = resources::UniformBufferInfo{resources::ubo_layout_t::STD140, {view_input, proj_input}};
this->uniform_buffer = renderer->add_uniform_buffer(ubo_info);
this->init_uniform_buffer(renderer);

log::log(INFO << "Created new camera at position "
<< "(" << this->scene_pos[0]
Expand All @@ -55,10 +52,7 @@ Camera::Camera(const std::shared_ptr<Renderer> &renderer,
viewport_changed{true},
view{Eigen::Matrix4f::Identity()},
proj{Eigen::Matrix4f::Identity()} {
resources::UBOInput view_input{"view", resources::ubo_input_t::M4F32};
resources::UBOInput proj_input{"proj", resources::ubo_input_t::M4F32};
auto ubo_info = resources::UniformBufferInfo{resources::ubo_layout_t::STD140, {view_input, proj_input}};
this->uniform_buffer = renderer->add_uniform_buffer(ubo_info);
this->init_uniform_buffer(renderer);

log::log(INFO << "Created new camera at position "
<< "(" << this->scene_pos[0]
Expand Down Expand Up @@ -269,4 +263,15 @@ const std::shared_ptr<renderer::UniformBuffer> &Camera::get_uniform_buffer() con
return this->uniform_buffer;
}

void Camera::init_uniform_buffer(const std::shared_ptr<Renderer> &renderer) {
resources::UBOInput view_input{"view", resources::ubo_input_t::M4F32};
resources::UBOInput proj_input{"proj", resources::ubo_input_t::M4F32};
resources::UBOInput inv_zoom_input{"inv_zoom", resources::ubo_input_t::F32};
resources::UBOInput inv_viewport_size{"inv_viewport_size", resources::ubo_input_t::V2F32};
auto ubo_info = resources::UniformBufferInfo{
resources::ubo_layout_t::STD140,
{view_input, proj_input, inv_zoom_input, inv_viewport_size}};
this->uniform_buffer = renderer->add_uniform_buffer(ubo_info);
}

} // namespace openage::renderer::camera
9 changes: 9 additions & 0 deletions libopenage/renderer/camera/camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Camera {
* The camera uses default values. Its centered on the origin of the scene (0.0f, 0.0f, 0.0f)
* and has a zoom level of 1.0f.
*
* @param renderer openage renderer instance.
* @param viewport_size Initial viewport size of the camera (width x height).
*/
Camera(const std::shared_ptr<Renderer> &renderer,
Expand All @@ -51,6 +52,7 @@ class Camera {
/**
* Create a new camera for the renderer.
*
* @param renderer openage renderer instance.
* @param viewport_size Viewport size of the camera (width x height).
* @param scene_pos Position of the camera in the scene.
* @param zoom Zoom level of the camera (defaults to 1.0f).
Expand Down Expand Up @@ -187,6 +189,13 @@ class Camera {
const std::shared_ptr<renderer::UniformBuffer> &get_uniform_buffer() const;

private:
/**
* Create the uniform buffer for the camera.
*
* @param renderer openage renderer instance.
*/
void init_uniform_buffer(const std::shared_ptr<Renderer> &renderer);

/**
* Position in the 3D scene.
*/
Expand Down
9 changes: 8 additions & 1 deletion libopenage/renderer/demo/stresstest_0.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@ void renderer_stresstest_0(const util::Path &path) {
"view",
camera->get_view_matrix(),
"proj",
camera->get_projection_matrix());
camera->get_projection_matrix(),
"inv_zoom",
1.0f / camera->get_zoom());
auto viewport_size = camera->get_viewport_size();
Eigen::Vector2f viewport_size_vec{
1.0f / static_cast<float>(viewport_size[0]),
1.0f / static_cast<float>(viewport_size[1])};
cam_unifs->update("inv_viewport_size", viewport_size_vec);
camera->get_uniform_buffer()->update_uniforms(cam_unifs);

// Render stages
Expand Down
16 changes: 11 additions & 5 deletions libopenage/renderer/opengl/renderer.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2023 the openage authors. See copying.md for legal info.
// Copyright 2017-2024 the openage authors. See copying.md for legal info.

#include "renderer.h"

Expand Down Expand Up @@ -33,10 +33,10 @@ GlRenderer::GlRenderer(const std::shared_ptr<GlContext> &ctx,
// global GL alpha blending settings
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendFuncSeparate(
GL_SRC_ALPHA, // source (overlaying) RGB factor
GL_SRC_ALPHA, // source (overlaying) RGB factor
GL_ONE_MINUS_SRC_ALPHA, // destination (underlying) RGB factor
GL_ONE, // source (overlaying) alpha factor
GL_ONE_MINUS_SRC_ALPHA // destination (underlying) alpha factor
GL_ONE, // source (overlaying) alpha factor
GL_ONE_MINUS_SRC_ALPHA // destination (underlying) alpha factor
);

// global GL depth testing settings
Expand Down Expand Up @@ -90,14 +90,20 @@ std::shared_ptr<UniformBuffer> GlRenderer::add_uniform_buffer(resources::Uniform
size_t offset = 0;
for (auto const &input : inputs) {
auto type = GL_UBO_INPUT_TYPE.get(input.type);
auto size = resources::UniformBufferInfo::get_size(input, info.get_layout());

// align offset to the size of the type
offset += offset % size;

uniforms.emplace(
std::make_pair(input.name,
GlInBlockUniform{type,
offset,
resources::UniformBufferInfo::get_size(input, info.get_layout()),
resources::UniformBufferInfo::get_stride_size(input.type, info.get_layout()),
input.count}));
offset += resources::UniformBufferInfo::get_size(input, info.get_layout());

offset += size;
}

return std::make_shared<GlUniformBuffer>(this->gl_context,
Expand Down
9 changes: 7 additions & 2 deletions libopenage/renderer/opengl/shader_program.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2013-2023 the openage authors. See copying.md for legal info.
// Copyright 2013-2024 the openage authors. See copying.md for legal info.

#include "shader_program.h"

Expand Down Expand Up @@ -445,7 +445,12 @@ void GlShaderProgram::bind_uniform_buffer(const char *block_name, std::shared_pt
auto gl_buffer = std::dynamic_pointer_cast<GlUniformBuffer>(buffer);
auto &block = this->uniform_blocks[block_name];

// TODO: Check if the uniform buffer matches the block definition
// Check if the uniform buffer matches the block definition
for (auto const &pair : block.uniforms) {
auto const &unif = pair.second;
ENSURE(gl_buffer->has_uniform(pair.first.c_str()),
"Uniform buffer does not contain uniform '" << pair.first << "' required by block " << block_name);
}

block.binding_point = gl_buffer->get_binding_point();
glUniformBlockBinding(*this->handle, block.index, block.binding_point);
Expand Down
10 changes: 8 additions & 2 deletions libopenage/renderer/resources/buffer_info.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023-2023 the openage authors. See copying.md for legal info.
// Copyright 2023-2024 the openage authors. See copying.md for legal info.

#include "buffer_info.h"

Expand Down Expand Up @@ -27,7 +27,13 @@ const std::vector<UBOInput> &UniformBufferInfo::get_inputs() const {
size_t UniformBufferInfo::get_size() const {
size_t size = 0;
for (const auto &input : this->inputs) {
size += this->get_size(input, this->layout);
// size of the input type
size_t input_size = this->get_size(input, this->layout);

// inputs must additionally be aligned to a multiple of their size
size_t align_size = size % input_size;

size += input_size + align_size;
}
return size;
}
Expand Down
20 changes: 17 additions & 3 deletions libopenage/renderer/stages/camera/manager.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023-2023 the openage authors. See copying.md for legal info.
// Copyright 2023-2024 the openage authors. See copying.md for legal info.

#include "manager.h"

Expand Down Expand Up @@ -97,11 +97,25 @@ void CameraManager::update_motion() {
}

void CameraManager::update_uniforms() {
// transformation matrices
this->uniforms->update(
"view",
camera->get_view_matrix(),
this->camera->get_view_matrix(),
"proj",
camera->get_projection_matrix());
this->camera->get_projection_matrix());

// zoom scaling
this->uniforms->update(
"inv_zoom",
1.0f / this->camera->get_zoom());

auto viewport_size = this->camera->get_viewport_size();
Eigen::Vector2f viewport_size_vec{
1.0f / static_cast<float>(viewport_size[0]),
1.0f / static_cast<float>(viewport_size[1])};
this->uniforms->update("inv_viewport_size", viewport_size_vec);

// update the uniform buffer
this->camera->get_uniform_buffer()->update_uniforms(this->uniforms);
}

Expand Down
31 changes: 16 additions & 15 deletions libopenage/renderer/stages/world/object.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022-2023 the openage authors. See copying.md for legal info.
// Copyright 2022-2024 the openage authors. See copying.md for legal info.

#include "object.h"

Expand Down Expand Up @@ -138,23 +138,24 @@ void WorldObject::update_uniforms(const time::time_t &time) {
auto coords = tex_info->get_subtex_info(subtex_idx).get_tile_params();
this->uniforms->update(this->tile_params, coords);

// scale and keep width x height ratio of texture
// when the viewport size changes
auto scale = animation_info->get_scalefactor() / this->camera->get_zoom();
auto screen_size = this->camera->get_viewport_size();
auto subtex_size = tex_info->get_subtex_info(subtex_idx).get_size();
// Animation scale factor
// Scales the subtex up or down in the shader
auto scale = animation_info->get_scalefactor();
this->uniforms->update(this->scale, scale);

// Scaling with viewport size and zoom
auto scale_vec = Eigen::Vector2f{
scale * (static_cast<float>(subtex_size[0]) / screen_size[0]),
scale * (static_cast<float>(subtex_size[1]) / screen_size[1])};
this->uniforms->update(this->scale, scale_vec);
// Subtexture size in pixels
auto subtex_size = tex_info->get_subtex_info(subtex_idx).get_size();
Eigen::Vector2f subtex_size_vec{
static_cast<float>(subtex_size[0]),
static_cast<float>(subtex_size[1])};
this->uniforms->update(this->subtex_size, subtex_size_vec);

// Move subtexture in scene so that its anchor point is at the object's position
// Anchor point offset (in pixels)
// moves the subtex in the shader so that the anchor point is at the object's position
auto anchor = tex_info->get_subtex_info(subtex_idx).get_anchor_params();
auto anchor_offset = Eigen::Vector2f{
scale * (static_cast<float>(anchor[0]) / screen_size[0]),
scale * (static_cast<float>(anchor[1]) / screen_size[1])};
Eigen::Vector2f anchor_offset{
static_cast<float>(anchor[0]),
static_cast<float>(anchor[1])};
this->uniforms->update(this->anchor_offset, anchor_offset);
}

Expand Down
1 change: 1 addition & 0 deletions libopenage/renderer/stages/world/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class WorldObject {
inline static uniform_id_t tex;
inline static uniform_id_t tile_params;
inline static uniform_id_t scale;
inline static uniform_id_t subtex_size;
inline static uniform_id_t anchor_offset;

private:
Expand Down
3 changes: 2 additions & 1 deletion libopenage/renderer/stages/world/render_stage.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022-2023 the openage authors. See copying.md for legal info.
// Copyright 2022-2024 the openage authors. See copying.md for legal info.

#include "render_stage.h"

Expand Down Expand Up @@ -136,6 +136,7 @@ void WorldRenderStage::init_uniform_ids() {
WorldObject::tex = this->display_shader->get_uniform_id("tex");
WorldObject::tile_params = this->display_shader->get_uniform_id("tile_params");
WorldObject::scale = this->display_shader->get_uniform_id("scale");
WorldObject::subtex_size = this->display_shader->get_uniform_id("subtex_size");
WorldObject::anchor_offset = this->display_shader->get_uniform_id("anchor_offset");
}

Expand Down

0 comments on commit 920367b

Please sign in to comment.