首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用法线绘制DirectX 11索引绘图

用法线绘制DirectX 11索引绘图
EN

Stack Overflow用户
提问于 2013-07-09 12:34:51
回答 1查看 3.4K关注 0票数 3

我正在为DirectX 11开发一个OBJ加载程序。在OBJ格式中,一个正方形(两个三角形)如下所示:

代码语言:javascript
复制
v 0 0 0
v 0 1 0
v 1 1 0
v 1 0 0

f 1 2 3
f 1 3 4

因此,首先用v给出顶点数据,然后用f给出人脸。因此,只需将顶点读入顶点缓冲区,将索引读入索引缓冲区。但是现在我需要计算像素着色器的法线。我是否可以在使用索引渲染时存储人脸的正常数据,还是必须创建一个没有索引的顶点缓冲区?(因为这样我就可以存储每个顶点的正常数据,因为每个顶点只在一个面使用)

EN

回答 1

Stack Overflow用户

发布于 2013-07-09 14:03:34

通常的方法是为一张脸的所有三个顶点存储相同的法向量。就像这样:

代码语言:javascript
复制
Vertex
{
    Vector3 position;
    Vector3 normal;
}

std::vector<Vertex>  vertices;
std::vector<uint32_t>  indices;

for(each face f)
{
    Vector3 faceNormal = CalculateFaceNormalFromPositions(f); // Generate normal for given face number `f`;
    for(each vertex v)
    {
        Vertex vertex;
        vertex.position = LoadPosition(f, v); // Load position from OBJ based on face index (f) and vertex index (v);
        vertex.normal = faceNormal;
        vertices.push_back(vertex);

        indices.push_back(GetPosIndex()); // only position index from OBJ file needed
    }
}

注意:通常您希望使用顶点法线而不是人脸法线,因为顶点法线允许应用更好看的照明算法(每像素照明):

代码语言:javascript
复制
for(each face f)
{
    for(each vertex v)
    {
        Vertex vertex;
        vertex.position = LoadPosition(f, v);
        vertex.normal = ...precalculated somewhere...
        vertices.push_back(vertex);
    }
}

Note2:通常您希望从资产文件中读取预计算的法线,而不是在运行时计算它:

代码语言:javascript
复制
for(each face f)
{
    for(each vertex v)
    {
        Vertex vertex;
        vertex.position = LoadPosition(f, v);
        vertex.normal = LoadNormal(f, v);
        vertices.push_back(vertex);
    }
}

.obj格式允许存储每个顶点法线).google的例子:

代码语言:javascript
复制
# cube.obj
#

g cube

# positions
v  0.0  0.0  0.0
v  0.0  0.0  1.0
v  0.0  1.0  0.0
v  0.0  1.0  1.0
v  1.0  0.0  0.0
v  1.0  0.0  1.0
v  1.0  1.0  0.0
v  1.0  1.0  1.0

# normals
vn  0.0  0.0  1.0
vn  0.0  0.0 -1.0
vn  0.0  1.0  0.0
vn  0.0 -1.0  0.0
vn  1.0  0.0  0.0
vn -1.0  0.0  0.0

# faces: indices of position / texcoord(empty) / normal 
f  1//2  7//2  5//2
f  1//2  3//2  7//2 
f  1//6  4//6  3//6 
f  1//6  2//6  4//6 
f  3//3  8//3  7//3 
f  3//3  4//3  8//3 
f  5//5  7//5  8//5 
f  5//5  8//5  6//5 
f  1//4  5//4  6//4 
f  1//4  6//4  2//4 
f  2//1  6//1  8//1 
f  2//1  8//1  4//1 

C++中的示例代码(未测试)

代码语言:javascript
复制
struct Vector3{ float x, y, z; };

struct Face
{
    uint32_t position_ids[3];
    uint32_t normal_ids[3];
};

struct Vertex
{
    Vector3 position;
    Vector3 normal;
};

std::vector<Vertex>  vertices; // Your future vertex buffer
std::vector<uint32_t>  indices;  // Your future index buffer

void ParseOBJ(std::vector<Vector3>& positions, std::vector <Vector3>& normals, std::vector<Face>& faces) {  /*TODO*/ }

void LoadOBJ(const std::wstring& filename, std::vector<Vertex>& vertices, std::vector<uint32_t>& indices)
{
    // after parsing obj file
    // you will have positions, normals 
    // and faces (which contains indices for positions and normals)
    std::vector<Vector3> positions;
    std::vector<Vector3> normals;
    std::vector<Face> faces;
    ParseOBJ(positions, normals, faces);

    for (auto itFace = faces.begin(); itFace != faces.end(); ++itFace) // for each face
    {
        for (uint32_t i = 0; i < 3; ++i) // for each face vertex
        {
            uint32_t position_id = itFace->position_ids[i]; // just for short writing later
            uint32_t normal_id = itFace->normal_ids[i];

            Vertex vertex;
            vertex.position = positions[position_id];
            vertex.normal = normals[normal_id];

            indices.push_back(position_id);     // Note: only position's indices
            vertices.push_back(vertex);
        }
    }
}

注意,在将normal的数据合并到顶点之后,您将不再需要normal的索引了。因此,法线没有索引(两个相等的法线可以存储在不同的顶点,这是对空间的浪费)。但是仍然可以使用索引呈现,因为位置是索引的。

我必须说,当然,现代GPU的可编程管道允许做更棘手的事情:

  • 为每个人创建缓冲区:位置、法线、pos_indices和nor_indices
  • 使用电流vertex_id,读取着色电流position_id及对应位置,normal_id及相应法线
  • 您甚至可以在着色器中生成法线(因此根本不需要normal_id和普通缓冲区)。
  • 你可以在几何图形着色器里组装你的脸。
  • 在这样的算法中,呈现系统变得更加复杂,几乎没有任何增益。
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17548298

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档