我目前正在实施一个模拟OpenGL的软件渲染器,作为基于these lessons的学习体验。我的项目代码可以是found here.
我在处理顶点法线方面遇到了一些困难。我想用模型矩阵对它们进行变换,我知道当矩阵不是正交时我应该使用模型矩阵的逆转置。光的方向应该在世界空间中指定,因此法线应该被变换,然后是用于计算光强度的世界空间光方向的点积。
这是问题所在。它在这里工作正常,请注意相机在上轴旋转45度,看模型。
如果我在任何轴上旋转模型90度,现在取向上轴,光线方向翻转指向另一个方向。正如你在这里看到的那样,光线来自背面。
如果我旋转到180度,那就再好了。
如果我旋转到45度,光点会指向90度,如此处所示。注意尖峰以查看光源的来源。
这让我困惑了好几个小时。我无法弄清楚出了什么问题。好像旋转灯在灯光上翻倍。虽然光的矢量没有改变,但请看:
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(模型,视图,投影)和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;
知道我做错了吗?
答案 0 :(得分:1)
你应该使用模型矩阵而不是逆矩阵来变换法线。您的光照照原样,因为您正在以与顶点位置相反的方向旋转顶点法线。
vec4 normal = M * embed<4>(model->normal(iFace, nthVert), 0.f);
为了避免这种混淆,我建议使用命名方案advocated by Tom Forsyth,并调用M
world_from_object
矩阵,因为它是来自对象的转换空间到世界空间。
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!
我个人使用以下术语来描述不同的空间:
因此,我会将MVP
矩阵称为clip_from_object
矩阵。
答案 1 :(得分:1)
您将模型矩阵传递给着色器:
o->shader->M = cameraRotate * cameraTranslate * Model;
所以实际的M矩阵不是Model Matrix而是ModelView Matrix,即你现在在ModelView Space中相乘。我不确定,但可能会导致模棱两可的结果。