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

Move subtex scaling to shader #1639

Merged
merged 9 commits into from
Apr 21, 2024
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
Loading