【问题标题】:How to render from world space into camera space?如何从世界空间渲染到相机空间?
【发布时间】:2021-12-14 05:21:43
【问题描述】:

我有 2 个函数,第一个函数在世界上渲染我的对象,而第二个函数应该像 UI 一样直接在相机的视图框架中渲染我的对象。如果相机移动,则物体在随相机移动时看起来是静止的。但是,我的第二个函数似乎不起作用,因为什么都没有出现,我的视图投影矩阵的逻辑是否不正确?

这是将相机的视图投影矩阵发送到顶点着色器以渲染世界中的对象的函数,它起作用了:

void Renderer2D::BeginScene(const OrthographicCamera& camera)
{
    s_Data.shader = LightTextureShader;
    (s_Data.shader)->Bind();
    (s_Data.shader)->SetMat4("u_ViewProjection", camera.GetViewProjectionMatrix());
    s_Data.CameraUniformBuffer->SetData(&s_Data.CameraBuffer, sizeof(Renderer2DData::CameraData));
    s_Data.QuadVertexBuffer = LightQuadVertexBuffer;
    s_Data.QuadVertexArray = LightQuadVertexArray;
    s_Data.QuadIndexCount = LightQuadIndexCount;
    s_Data.QuadVertexBufferBase = LightQuadVertexBufferBase;
    StartBatch();
}

这是应该像 UI 一样将我的对象直接渲染到相机的函数,但它不起作用:

void Renderer2D::BeginUIScene(const OrthographicCamera& camera)
{
    s_Data.shader = TextureShader;
    (s_Data.shader)->Bind();
    Mat4 projection = getOrtho(0.0f, camera.GetWidth(), 0.0f, camera.GetHeight(), -1.0f, 1.f);
    (s_Data.shader)->SetMat4("u_ViewProjection", projection);
    s_Data.CameraUniformBuffer->SetData(&s_Data.CameraBuffer, sizeof(Renderer2DData::CameraData));
    s_Data.QuadVertexBuffer = TexQuadVertexBuffer;
    s_Data.QuadVertexArray = TexQuadVertexArray;
    s_Data.QuadIndexCount = TexQuadIndexCount;
    s_Data.QuadVertexBufferBase = TexQuadVertexBufferBase;
    StartBatch();
}

编辑: getOrtho() 的声明:

Mat4 getOrtho(float left, float right, float bottom, float top, float zNear, float zFar);

【问题讨论】:

  • 在屏幕上绘制 UI 元素时不需要每帧更新视图矩阵
  • 这是真的!但是矩阵仍然不正确
  • 它是 Hazel 引擎! :)

标签: c++ opengl camera vertex-shader coordinate-transformation


【解决方案1】:

我能想到两种方法。一种是直接将屏幕空间坐标传递给不应用模型、视图或投影矩阵的顶点着色器。一个顶点着色器示例如下所示:

#version ...

layout (location = 0) in vec3 aPos; // The vertex coords should be given in screen space

void main()
{
    gl_Position = vec4(aPos, 1.0f);
}

这会将 2D 图像渲染到屏幕的固定位置,该位置不会随着相机的移动而移动。

另一种方法是,如果您想要一个“附加”到相机的 3D 对象(因此它在屏幕上的固定位置),您只需要应用模型和投影矩阵,而不是视图。执行此操作的示例顶点着色器:

#version ...

layout (location = 0) in vec3 aPos;

uniform mat4 model;
uniform mat4 projection;

void main()
{
    gl_Position = projection * model * vec4(aPos, 1.0f);
}

通过不使用视图矩阵,模型将始终显示在屏幕上模型矩阵将模型移动到的任何位置。这里的中心是相机,因此通过矢量vec3(0.1f, 0.0f, -0.2f) 转换的模型矩阵会将模型0.1f 移动到相机中心的右侧,并将0.2f 远离相机移动到屏幕中。本质上,这里的模型矩阵定义了模型相对于相机位置的变换。请注意,如果您想对模型进行光照计算,则需要使用第二种方法而不是第一种方法,并且您需要在该模型的视图/相机空间中进行所有光照计算。

编辑:

将屏幕空间坐标从范围 [0.0, screen resolution] 转换为 [-1.0, 1.0] 是 OpenGL 使用的范围:

float xResolution = 800.0f;
float yResolution = 600.0f;

float x = 200.0f;
float y = 400.0f;

float convertedX = ((x / xResolution) * 2) - 1;
float convertedY = ((y / yResolution) * 2) - 1;

【讨论】:

  • 是的!在正确的轨道上,但是你知道我可以用什么方法输入坐标,比如左下角的 (0,0) 和右下角的 (x resolution, 0)?
  • @tomatto openGL 屏幕空间坐标在 x 轴上的范围从 -1.0 到 1.0,在 y 轴上从 -1.0 到 1.0,因此您需要编写一些代码来将值从范围 [0.0, x 分辨率] 到范围 [-1.0, 1.0f]。如果您需要这方面的帮助,我可以编辑我的帖子以显示此代码。
  • 谢谢您,我想我可以做到,但如果您想获得更完整的答案,请随意
猜你喜欢
  • 1970-01-01
  • 2021-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多