You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

低资源系统3D渲染库开发:坐标变换后无法获取归一化坐标求助

3D图形渲染坐标流水线问题排查请求

我正在为低资源系统开发3D图形渲染库,目前在理解图形坐标系统流水线时遇到问题。我清楚流程是Local space→World space→View space→Clip space→Screen space,先对顶点应用model矩阵,再依次应用view矩阵和projection矩阵,预期得到[-1,1]范围的归一化坐标,但实际未能实现,恳请协助排查。

相关代码如下:

//vertices to create a cube from 12 triangles 
std::vector<linear::vector3> vertices{
    vector3(-1, -1, -1), vector3(1, -1, -1), vector3(1, 1, -1), vector3(-1, 1, -1),
    vector3(-1, -1, 1), vector3(1, -1, 1), vector3(1, 1, 1), vector3(-1, 1, 1)  
};

float aspec = 1080 / 720;
linear::Matrix4x4 modelMat = linear::modelMat(vector3(30, 30, 30), vector3(100, 100, 0 ), 0.0, 0.0, linear::toRadians(45.0));  
linear::Matrix4x4 viewMat = linear::lookAt(vector3(0, 0, 5), vector3(0, 0, 0), vector3(0, 1, 0));
linear::Matrix4x4 projectionMat = linear::perspectiveMat(linear::toRadians(60.0f), aspec, 1.0f, 1000.0);


vector3 transformAndNormalizeVertex(const vector3& vertex, const Matrix4x4& modelMat, const Matrix4x4& viewMat, const Matrix4x4& projectionMat) {
    vector4 vec1(vertex.x, vertex.y, vertex.z, 1.0);

    vec1 = matrixVector(modelMat, vec1);
    vec1 = matrixVector(viewMat, vec1);
    vec1 = matrixVector(projectionMat, vec1);

    if (vec1.w != 0.0) {
        vec1.x /= vec1.w;
        vec1.y /= vec1.w;
        vec1.z /= vec1.w;
    }

    return vector3(vec1.x, vec1.y, vec1.z);
}

//code block to apply the transformations.
for (auto &triangle : triangles){  
    cout<< "triangle " << i << endl;
    for (auto &vertex : triangle)
    {
        vertex = transformAndNormalizeVertex(vertex, modelMat, viewMat, projectionMat);
        cout<< vertex.x << " " << vertex.y << " " << vertex.z << endl;
    }
    
    drawtriangle(linear::vertex2{round(triangle[0].x), round(triangle[0].y)}, linear::vertex2{round(triangle[1].x), round(triangle[1].y)}, linear::vertex2{round(triangle[2].x), round(triangle[2].y)});
}

可能的问题点排查:

  • 宽高比计算错误:float aspec = 1080 / 720; 是整数除法,结果为1而非预期的1.5。需改成float aspec = 1080.0f / 720.0f; 确保浮点运算。
  • 模型位置超出相机视野:modelMat将立方体平移到(30,30,30),但相机在(0,0,5)看向原点,立方体处于相机后方(z=30 > 相机z=5),会被视锥体裁剪。建议先将模型平移改为vector3(0, 0, 0),确保立方体在相机视野内。
  • view矩阵实现正确性:确认lookAt函数是否正确构建右手坐标系的视图矩阵,是否正确计算相机的前向、右向、上向向量(比如前向向量是否是target - eye的反方向,因为相机通常看向-z方向)。
  • 透视矩阵实现验证:检查perspectiveMat是否符合标准透视投影矩阵公式,特别是z轴映射是否正确——标准透视矩阵会将[near, far]范围内的z值映射到[-1,1](NDC空间)。
  • 缺少NDC到屏幕空间的转换:当前直接将归一化坐标传入drawtriangle,但NDC的[-1,1]需要转换为屏幕像素坐标。示例转换逻辑:
    // 假设屏幕宽高为1080和720
    float screenX = (vertex.x + 1.0f) * (1080.0f / 2.0f);
    float screenY = (1.0f - vertex.y) * (720.0f / 2.0f);
    
    否则会导致图形显示位置异常或超出屏幕。

内容的提问来源于stack exchange,提问作者Francisco Zavala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 19:33:09