如何通过OpenGL缓冲区将glm数据类型直接传递给GPU?

时间:2016-07-28 20:55:42

标签: c++ opengl gpu glm-math

我自己编写了数学实用程序,它为我编程的简单图形做了我需要的一切。但是,我不知道如何使它们有资格直接传递给OpenGL。这可以用glm来完成,例如:

std::vector<glm::vec3> locations;

[...]


glGenBuffers(NUM_BUFFERS, _vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[POSITION_VBO]);

// throw data in vbo[0]
glBufferData(GL_ARRAY_BUFFER, _num_vertices * sizeof(locations[0]), &locations[0], GL_STATIC_DRAW);

我希望能够使用我自己的vec3类型math :: vec3f,因为我不想“浪费”我自己编写这些实用程序的时间。它的实现可以在这里看到:

namespace math
{
    template<typename _type> class vec2;

    template<typename _type>
    class vec3
    {
        private:
            _type _gl_a[3];

        public:
            _type x, y, z;

            vec3() {};
            vec3(_type _x, _type _y, _type _z)
            {
                _gl_a[0] = x = _x;
                _gl_a[1] = y = _y;
                _gl_a[2] = z = _z;
            }

            vec3(vec2<_type> v, _type w)
            {
                _gl_a[0] = x = v.x;
                _gl_a[1] = y = v.y;
                _gl_a[2] = z = w;
            }

            inline vec3<_type> operator=(vec2<_type> &v)
            {
                _gl_a[0] = x = v.x;
                _gl_a[1] = y = v.y;
                _gl_a[2] = z = 0;
            }

            inline vec3<_type> operator+(_type other)        { return vec3<_type>(x + other,   y + other,   z + other); }
            inline vec3<_type> operator-(_type other)        { return vec3<_type>(x - other,   y - other,   z - other); }
            inline vec3<_type> operator*(_type other)        { return vec3<_type>(x * other,   y * other,   z * other); }
            inline vec3<_type> operator/(_type other)        { return vec3<_type>(x / other,   y / other,   z / other); }

            inline vec3<_type> operator+(vec3<_type> &other) { return vec3<_type>(x + other.x, y + other.y, z + other.z); }
            inline vec3<_type> operator-(vec3<_type> &other) { return vec3<_type>(x - other.x, y - other.y, z - other.z); }
            inline vec3<_type> operator*(vec3<_type> &other) { return vec3<_type>(x * other.x, y * other.y, z * other.z); }
            inline vec3<_type> operator/(vec3<_type> &other) { return vec3<_type>(x / other.x, y / other.y, z / other.z); }

            inline _type operator[](int i)
            {
                if(i < 0 || i >= 3)
                    return 0;

                _gl_a[0] = x;
                _gl_a[1] = y;
                _gl_a[2] = z;
                return _gl_a[i];
            }

            inline double magnitude()
            {
                return sqrt(x * x + y * y + z * z);
            }

            inline vec3<_type> normal()
            {
                double m = this->magnitude();
                return vec3<_type>(x / m, y / m, z / m);
            }

            inline _type dot(vec3<_type> other)
            {
                return x * other.x + y * other.y + z * other.z;
            }

            inline vec3<_type> cross(vec3<_type> other)
            {
                return vec3<_type>(y * other.z - other.y * z,
                                   z * other.x - other.z * x,
                                   x * other.y - other.x * y);
            }
    };

    typedef vec3<float>             vec3f;
    typedef vec3<double>            vec3d;
    typedef vec3<int>               vec3i;
    typedef vec3<unsigned int>      vec3ui;
    typedef vec3<short>             vec3s;
    typedef vec3<unsigned short>    vec3us;
};

我必须添加另一个运算符重载函数,还是完全不同的东西?

2 个答案:

答案 0 :(得分:2)

glBufferData()需要void*,所以它不关心你传递给它的类型。该功能只能看到原始内存。

但是,您需要以其他方式告诉OpenGL如何解释该数据(例如glVertexAttribPointer())。如果你告诉它期望一个float x3数组,那么你需要传递一个float x3数组,否则你会得到破坏的输出。

虽然glm::vec3包含3个浮点数,但是你的包含6个浮点数(假设_type是浮点数)。你似乎没有理由复制组件。删除重复项,或告诉opengl期望您的格式,最好是前者。

答案 1 :(得分:1)

glBufferData获取void指针。这正是你使用glm :: vec3的代码片段所做的。但是你可以这样做。

由于GLM将其数据存储在union中,您可以通过多种方式访问​​向量的元素:operator[]或坐标xy,{ {1}}。由于元素是值而不是指针,因此需要z运算符来取消引用它们。因此&&myvec[0]具有相同的效果。

你的代码片段在std :: vector中获取了第一个glm :: vec3的指针。每个glm :: vec3的内存地址是其第一个元素的内存地址。这样你就可以将指针传递给一个浮点数组(向量的元素,如果它们被紧密打包 - 在GLM中它们是):

&myvec.x

我建议你熟悉C ++中指针,引用和联合的概念,因为我的答案的以下部分依赖于它们。

您的std::vector<glm::vec3> locations; glBufferData(GL_ARRAY_BUFFER, _num_vertices * sizeof(locations[0]), &locations[0], GL_STATIC_DRAW); // same as above //glBufferData(GL_ARRAY_BUFFER, _num_vertices * sizeof(locations[0]), &locations[0][0], GL_STATIC_DRAW); // same as above //glBufferData(GL_ARRAY_BUFFER, _num_vertices * sizeof(locations[0]), &locations[0].x, GL_STATIC_DRAW); 实施有多个问题。

1)正如其他人已经在评论中说明的那样,你需要两者

math::vec3

支持_type operator[](int i); _type operator[](int i) const; - ness。

2)返回引用const)而不是值(_type&)。目前,您返回_type的值,因此您的元素是只读的。使用引用,您可以读取和写入它们。

_type operator[](int i);

3)由于您不能拥有否定索引,因此您不应使用签名_type& operator[](int i); _type& operator[](int i) const; 进行索引编制。使用无符号类型:int完成工作,但unsigned int更好。

size_t

4)无需针对&_type operator[](size_t i); &_type operator[](size_t i) const; 进行测试。它只会使你的元素在关键循环中访问速度变慢(当你多次访问元素时)。使用if (i < 0 || i >= 3),您的值不能小于0,并且在正确的代码中,您不应该传递高于矢量实际大小的索引。

5)您将数据存储两次:一次在size_t,一次在_gl_a[3]xy。这是对内存的巨大浪费。相反,您应该使用z以多种方式访问​​相同的数据。

union

一旦正确实施了union // anonymous union { _gl_a[3]; struct { x, y, z, }; // anonymous struct }; ,您就可以像使用glm类型一样使用它。