c++ - 3D图形网格法 vector 旋转加倍

标签 c++ matrix graphics 3d rotation

我目前正在实现一个模拟 OpenGL 的软件渲染器,作为基于 these lessons 的学习体验。 。我的项目代码可以是 found here.

我在处理顶点法线时遇到了相当大的困难。我想用模型矩阵来转换它们,我知道当矩阵不正交时我应该使用模型矩阵的逆变换。光线方向应在世界空间中指定,因此应变换法线,然后使用世界空间光线方向的点积来计算光线强度。

但这就是问题所在。它在这里工作正常,请注意,观察模型时相机在上轴上旋转 45 度。

Front view

如果我在任何轴上将模型旋转 90 度,现在取向上轴,光线方向会翻转以指向另一个方向。正如您在这里所看到的,光线来自背面。

enter image description here

如果我旋转到180度,就又没问题了。

enter image description here

如果我旋转到 45 度,光点将变为 90 度,如下所示。注意尖峰以查看光来自哪里。

enter image description here

这让我困惑了好几个小时。我不知道出了什么问题。就好像灯光上的旋转增加了一倍。但光的 vector 没有改变,请看这里:

vec4 SmoothShader::Vertex(int iFace, int nthVert)
{
    vec3 vposition = model->vert(iFace, nthVert);
    vec4 projectionSpace = MVP * embed<4>(vposition);

    vec3 light = vec3(0, 0, 1);

    mat4 normTrans = M.invert_transpose();
    vec4 normal =  normTrans * embed<4>(model->normal(iFace, nthVert), 0.f);
    vec3 norm = proj<3>(normal);
    intensity[nthVert] = std::max(0.0f, norm.normalise() * light.normalise());

    return projectionSpace;
}

bool SmoothShader::Fragment(vec3 barycentric, vec3 &Colour)
{
    float pixelIntensity = intensity * barycentric;
    Colour = vec3(255, 122, 122) * pixelIntensity;
    return true;
}

MVP(模型、 View 、投影)和 M(模型)矩阵的计算方式如下:

// Model Matrix, converts to world space
mat4 scale = MakeScale(o->scale); 
mat4 translate = MakeTranslate(o->position);
mat4 rotate = MakeRotate(o->rotation);

// Move objects backward from the camera's position
mat4 cameraTranslate = MakeTranslate(vec3(-cameraPosition.x, -cameraPosition.y, -cameraPosition.z));

// Get the camera's rotated basis vectors to rotate everything to camera space.
vec3 Forward;
vec3 Right;
vec3 Up;
GetAxesFromRotation(cameraRotation, Forward, Right, Up);
mat4 cameraRotate = MakeLookAt(Forward, Up);

// Convert from camera space to perspective projection space
mat4 projection = MakePerspective(surf->w, surf->h, 1, 10, cameraFOV);

// Convert from projection space (-1, 1) to viewport space
mat4 viewport = MakeViewport(surf->w, surf->h);

mat4 M = translate * rotate * scale;
mat4 MVP = viewport * projection * cameraRotate * cameraTranslate * M;

知道我做错了什么吗?

最佳答案

您应该使用模型矩阵来转换法线,而不是其逆矩阵。您的光照之所以如此,是因为您以与顶点位置相反的方向旋转顶点法线。

vec4 normal =  M * embed<4>(model->normal(iFace, nthVert), 0.f);

为了避免这种困惑,我建议使用命名方案 advocated by Tom Forsyth ,并将 M 称为 world_from_object 矩阵,因为它是从 object 空间到 world 空间的变换。

vec4 light_world = vec4(0.f, 0.f, 1.f, 0.f);
vec4 normal_object = embed<4>(model->normal(iFace, nthVert), 0.f);
vec4 normal_world = world_from_object * normal_object;
float intensity = std::max(0.f, light_world * normal_world);

如果您使用了此方案,那么很明显您使用了错误的转换。

mat4 object_from_world = world_from_object.invert_transpose();
vec4 normal_world = object_from_world * normal_object; // wrong!

我个人使用以下术语来描述不同的空间:

  • 对象空间 - 模型的局部坐标系
  • View 空间 – 相机的本地坐标系
  • 光照空间 – 光照的局部坐标系
  • 世界空间 - 场景的全局坐标系
  • 剪辑空间 - 标准化屏幕坐标

因此,我将 MVP 矩阵称为 clip_from_object 矩阵。

关于c++ - 3D图形网格法 vector 旋转加倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43243249/

相关文章:

numpy 矩阵跟踪行为

java - 零空间二进制矩阵 : Java

java - 使用 JOGL 在屏幕外绘制

c++ - QGraphicsItem::paint():如何检查 QGraphicsScene 是否被打印

java - 是否可以在 Windows 2008 服务器上使用 Java FX 启用硬件加速?

c++ - 使用时间位置将日期时间从/转换为 UTC 时间戳

c++ - 矩阵乘法 cicle 中的逻辑错误? (C++面向对象)

c++ - Xcode 从我的主文件夹而不是资源加载程序资源 - C++

c++ - 除了使 TMP 编译之外,::template 意味着什么

python - np.loadtxt 用于包含多个矩阵的文件