c++ - 尝试制作一个 DirectX 顶点数组,直到运行时才知道它们将是什么类型

标签 c++ arrays algorithm memory directx

为不了解 DirectX 的人准备的一些背景知识。顶点不仅仅是一个 XYZ 位置,它还可以包含其他数据。 DirectX 使用一个称为灵活顶点格式 (FVF) 的系统来让您定义顶点的格式。您可以通过将数字传递给 DirectX 使用按位或构建它来定义这些格式,例如 (D3DFVF_XYZ | D3DFVF_DIFFUSE)意味着您将开始使用(从您告诉 DirectX 时起)具有 XYZ(三个 float )和 RGB 分量(DWORD/unsigned long)的顶点。

为了将顶点传递给显卡,您基本上将内存锁定在缓冲区所在的显卡中,然后使用 memcpy 将数组传输过来。

你的数组是你自己定义的结构的数组,所以在这种情况下你会制作一个类似...的结构

struct CUSTOMVERTEX {
    FLOAT X, Y, Z;
    DWORD COLOR;
};

然后创建一个 CUSTOMVERTEX 类型的数组并填写数据字段。

我认为我最好的方法是让我的类(class)建立一个包含每种组件类型的数组,所以一个 struct pos{ flaot x,y,z;}; 数组 struct colour{ DWROD colour;};

但是我需要将它们合并在一起,这样我就有了一个像 CUSTOMVERTEX 这样的数组结构。

现在,我想我已经创建了一个函数,可以将数组合并在一起,但我不确定它是否会按预期工作,就在这里(目前缺少实际返回这个“交错”数组的能力)

void Utils::MergeArrays(char *ArrayA, char *ArrayB, int elementSizeA, int elementSizeB, int numElements)
{
    char *packedElements = (char*)malloc(numElements* (elementSizeA, elementSizeB));
    char *nextElement = packedElements;
    for(int i = 0; i < numElements; ++i)
    {
        memcpy(nextElement, (void*)ArrayA[i], elementSizeA);
        nextElement += elementSizeA;
        memcpy(nextElement, (void*)ArrayB[i], elementSizeB);
        nextElement += elementSizeB;
    }
}

调用此函数时,您将传入要合并的两个数组,以及每个数组中元素的大小和数组中元素的数量。

我在聊天中询问了一段时间,而 SO 正在关闭。有几点要说。

我正在处理相当小的数据集,比如 100 个顶部,这(理论上)更像是一个初始化任务,所以应该只完成一次,所以我可以花一点时间。

我希望能够使用 memcpy 传输到显卡的最终数组需要没有填充,它必须是连续的数据。

编辑 顶点数据的组合数组将传输到 GPU,这首先通过请求 GPU 将 void* 设置为我有权访问的内存的开头并请求空间来完成我的 customVertex * NumOfVertex 的大小。因此,如果我的 mergeArray 函数确实丢失了其中的类型,那没关系,只要我让我的单个组合数组在一个 block 中传输 /EDIT

最后,这是一个很好的机会,我用这个咆哮错误的树,所以他们很可能是一个更简单的方法,首先只是没有这个问题,但我的一部分已经挖掘了我的治疗方法并想让这个系统工作,所以我很高兴知道如何让这样的系统工作(隔行扫描阵列)

非常感谢...我现在需要冷静一下,所以我期待听到关于这个问题的任何想法。

最佳答案

不,不,不。 FVF 系统已被弃用多年,甚至在 D3D10 或更高版本中也不可用。 D3D9 使用 VertexElement 系统。示例代码:

D3DVERTEXELEMENT9 VertexColElements[] =
{
    {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
    {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
    D3DDECL_END(),
};

FVF 系统有许多根本性缺陷 - 例如,字节进入的顺序。

最重要的是,如果你想制作一个运行时可变的顶点数据格式,那么你需要为你可能想要的每一个可能的变体编写一个着色器,然后编译它们,并花费你的生命交换他们身边。而且,对最终产品的影响将是疯狂的 - 例如,如果您决定取出 Phong 阴影所需的照明数据,您怎么可能编写有竞争力的渲染引擎?

现实情况是运行时可变的顶点格式有点疯狂。

不过,我想我最好伸出援手。您真正需要的是一个多态函数对象和一些普通内存——D3D 采用 void*s 或类似的东西,所以这没什么大不了的。当您调用函数对象时,它会添加到 FVF 声明并将数据复制到内存中。

class FunctionBase {
public:
    virtual ~FunctionBase() {}
    virtual void Call(std::vector<std::vector<char>>& vertices, std::vector<D3DVERTEXELEMENT9>& vertexdecl, int& offset) = 0;
};
// Example implementation
class Position : public FunctionBase {
    virtual void Call(std::vector<std::vector<char>>& vertices, std::vector<D3DVERTEXELEMENT9>& vertexdecl, int& offset) {
        std::for_each(vertices.begin(), vertices.end(), [&](std::vector<char>& data) {
            float x[3] = {0};
            char* ptr = (char*)x;
            for(int i = 0; i < sizeof(x); i++) {
                data.push_back(ptr[i]);
            }
        }
        vertexdecl.push_back({0, offset, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0});
        offset += sizeof(x);
    }
};

std::vector<std::vector<char>> vertices;
std::vector<D3DVERTEXELEMENT9> vertexdecl;
vertices.resize(vertex_count);
std::vector<std::shared_ptr<FunctionBase>> functions;
// add to functions here
int offset = 0;
std::for_each(functions.begin(), functions.end(), [&](std::shared_ptr<FunctionBase>& ref) {
    ref->Call(vertices, vertexdecl, offset);
});
vertexdecl.push_back(D3DDECL_END());

请原谅我使用 lambda,我使用的是 C++0x 编译器。

关于c++ - 尝试制作一个 DirectX 顶点数组,直到运行时才知道它们将是什么类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4056604/

相关文章:

PHP - 如何将数组中的数据显示到树或表中?

algorithm - 在时空中寻找最近的点来插值数据

algorithm - 3-PARTITION问题

javascript - 使我的 JavaScript(假定 CSV 是二维的)适用于一维 CSV

php - 尝试打印或回显数组中的数组

algorithm - 对和算法 - 二进制搜索的性能

C++20 概念 : int not swappable_with int

c++ - 如何使用 gradle (5.3.1) new native eplugin 将仅包含外部 header 的库包含到 gradle native 构建中?

c++ - 找到 2 个 vector 之间的 vector (2D)

c++ - opencv imshow 导致内存泄漏 (c++)