如何从世界 space 渲染到相机 space?

How to render from world space into camera space?

我有 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);

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

#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 远离相机进入屏幕。本质上,这里的模型矩阵定义了模型相对于相机位置的变换。请注意,如果您想对模型进行光照计算,则需要使用第二种方法而不是第一种方法,为此您需要进行 view/camera space 中的所有光照计算型号。

编辑:

将屏幕 space 坐标从范围 [0.0, 屏幕分辨率] 转换为 [-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;