如果我使用 malloc() 而不是堆栈数组,OpenGL 不会渲染对象?

OpenGL does not render objects if I use malloc() instead of stack arrays?

在我的 C++ 2D OpenGL 游戏项目中,我现在正尝试从文件中读取 "quantity of enemies",然后渲染这些敌人。每个敌人由 2 个带纹理的三角形组成(2D 精灵)。

我可以通过数组声明来实现渲染,该结构包含单独的 "enemy" 数据(例如每个敌人的位置),但是如果我尝试使用 malloc 根据我正在读取的数字动态分配内存从文件中,没有呈现任何内容。

我做错了什么?我真的很想使用 malloc,因为敌人的数量会有所不同,我不想使用固定大小的数组。

关于下面的代码:基本上一个名为 "gameEnemies" 的 class 包含一个名为 "Enemy" 的结构;每次你创建一个 class "gameEnemies" 的对象时,该对象应该分配足够的内存来创建与外部文件中定义的一样多的敌人。

  1. 这是带有固定大小数组声明的结构 - 这个正在工作。

    struct Enemy {
    
    
        Point3D center; //object attributes
        Vector3D direction; //gets updated with current direction after rotations to show where object is facing at
        Vector3D collDir; //which direction collided
    
        float deltaX;
        float deltaY;
        float prevDeltaX;
        float prevDeltaY;
        float deltaA;
        float prevDeltaA;
        float speed;
        bool collided;
    
        int qtyCollided; //with how many other objects it collided
    
        bool alive;
    
        //matrices below passed as uniforms to shader
        //rotation
        Transform4D rotateTransf{ 1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
        //moves to world position after being drawn with center at origin (0,0)
        Transform4D modelTransf{  1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
    
        //translation of texture (animation), passed as uniform to shader
        Transform4D transformTex{ 1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
    
    }enemies[MAX_TMX_ENEMIES];
    
  2. 这是不起作用的结构 - 与上面相同,但改为声明指针。

    struct Enemy {
    
    
        Point3D center; //object attributes
        Vector3D direction; //gets updated with current direction after rotations to show where object is facing at
        Vector3D collDir; //which direction collided
    
        float deltaX;
        float deltaY;
        float prevDeltaX;
        float prevDeltaY;
        float deltaA;
        float prevDeltaA;
        float speed;
        bool collided;
    
        int qtyCollided; //with how many other objects it collided
    
        bool alive;
    
        //matrices below passed as uniforms to shader
        //rotation
        Transform4D rotateTransf{ 1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
        //moves to world position after being drawn with center at origin (0,0)
        Transform4D modelTransf{  1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
    
        //translation of texture (animation), passed as uniform to shader
        Transform4D transformTex{ 1.0f, 0.0f, 0.0f, 0.0f,
                                  0.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f, 0.0f, 1.0f, 0.0f };
    
    }*enemies;
    
  3. 下面是分配内存和初始化值的循环 - 似乎可以正常工作,因为我可以访问数据,而且我在编译时和 运行 时都没有出错:

    enemies = (Enemy*)malloc(sizeof(Enemy) * totalObj);
    
    for (int j = 0; j < totalObj; j++) //loop objects in the group
    {
    
        enemies[j].center = mapObj.getObjects(i)[j].center;
        enemies[j].direction = Vector3D{1.0f, 0.0f, 0.0f};
        enemies[j].deltaX = 0.0f;
        enemies[j].deltaY = 0.0f;
        enemies[j].prevDeltaX = 0.0f;
        enemies[j].prevDeltaY = 0.0f;
        enemies[j].deltaA = 0.0f;
        enemies[j].prevDeltaA = 0.0f;
        enemies[j].speed = 6.0f;
        enemies[j].collided = false;
        enemies[j].collDir = Vector3D{ 0.0f, 0.0f, 0.f };
        enemies[j].qtyCollided = 0;
        enemies[j].alive = true;
    
        enemies[j].modelTransf.SetTranslation(Point3D{ enemies[j].center.x, enemies[j].center.y, 0.0f }); //initial translation to world position
        enemies[j].rotateTransf.SetRotationZ(enemies[j].deltaA); //initial rotation = 0
        enemies[j].transformTex.SetTranslation(Point3D{ 0.0f, 0.0f, 0.0f }); //no transform on texture upon object creation
    
    }
    
  4. 下面是使用数组声明时初始化值的循环 - 唯一的变化是没有预设 malloc:

    /*EXCLUDED: enemies = (Enemy*)malloc(sizeof(Enemy) * totalObj);*/
    for (int j = 0; j < totalObj; j++) //loop objects in the group
    {
    
        enemies[j].center = mapObj.getObjects(i)[j].center;
        enemies[j].direction = Vector3D{1.0f, 0.0f, 0.0f};
        enemies[j].deltaX = 0.0f;
        enemies[j].deltaY = 0.0f;
        enemies[j].prevDeltaX = 0.0f;
        enemies[j].prevDeltaY = 0.0f;
        enemies[j].deltaA = 0.0f;
        enemies[j].prevDeltaA = 0.0f;
        enemies[j].speed = 6.0f;
        enemies[j].collided = false;
        enemies[j].collDir = Vector3D{ 0.0f, 0.0f, 0.f };
        enemies[j].qtyCollided = 0;
        enemies[j].alive = true;
    
        enemies[j].modelTransf.SetTranslation(Point3D{ enemies[j].center.x, enemies[j].center.y, 0.0f }); //initial translation to world position
        enemies[j].rotateTransf.SetRotationZ(enemies[j].deltaA); //initial rotation = 0
        enemies[j].transformTex.SetTranslation(Point3D{ 0.0f, 0.0f, 0.0f }); //no transform on texture upon object creation
    
    }
    
  5. 在通用渲染函数下方:与数组配合使用效果很好,如果我使用 malloc 则不会渲染单个对象:

    void render()
    {
        // shader to use
        objShader.use();
        objShader.setVec4("orthoTex", orthoTex); //common to all instances
        //for texture
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glBindTexture(GL_TEXTURE_2D, texture);
    
        glBindVertexArray(VAO);
        for(int i = 0; i< totalEnemies; i++)
        {
            //pass relevant uniforms to shader before drawing each instance
            objShader.setVec4("transfTex", enemies[i].transformTex);
            objShader.setVec4("modelTransf", enemies[i].modelTransf);
            objShader.setVec4("rotateTransf", enemies[i].rotateTransf);
            //draw
            glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        }
        glBindVertexArray(0);
    }
    
  6. Enemy 结构位于名为 "gameEnemies" 的结构中 - 不确定这是否会改变任何内容,但以防万一。这是因为所有 "Enemies" 将共享公共属性,如 OpenGL 缓冲区、顶点、着色器等

    struct gameEnemies {
    
    protected:
    
        //arrays with vertex data and indices
        float vertices[16]; //holds vertex + texture coordinates for VBO (order: obj.x, obj.y, tex.x, tex.y, obj.x...)
        unsigned int indices[6]; //holds triangle indices for the EBO
    
        //the OpenGL buffers
        unsigned int VBO, VAO, EBO;
    
        //object shader
        Shader objShader;
    
        //texture ID
        unsigned int texture;
    
        float width;
        float height;
    
        int totalEnemies;
        int enemyMapPos; //position in the MAP OBJECT (which group) where enemies of specicif "label" for this handler are
    
        //transform texture coordinates to world (png file) coordinates (0,0 //bottom left to 1,1//top right)
        Transform4D orthoTex;
    
        struct Enemy {
    
    
            Point3D center; //object attributes
            Vector3D direction; //gets updated with current direction after rotations to show where object is facing at
            Vector3D collDir; //which direction collided
    
            float deltaX;
            float deltaY;
            float prevDeltaX;
    

    等...

在 C++ 中使用 malloc 是错误的,除非在非常特殊的情况下。

malloc 分配内存,但不在其中构造任何对象。尝试像在其中创建 Enemy 实例一样使用内存会导致未定义的行为。

您需要使用 new[]。它分配内存并构造对象:

enemies = new Enemy[totalObj];

您销毁这些对象并稍后使用 delete[] enemies 释放内存。


但是,您不应该使用手动动态内存管理。使用 std::vector 代替:

std::vector<Enemy> enemies;

enemies.resize(totalObj);

也很不清楚为什么您使用默认成员初始值设定项初始化 class 定义中的某些成员,而其他成员则在外部循环中。

要么为所有成员使用默认成员初始值设定项,要么为您的 struct 编写适当的构造函数来完成所有初始化。

您当前的方法令人困惑且效率较低,因为内存必须迭代两次。

这也是危险的,因为如果在构造 Enemy 之后忘记设置其中一个未初始化的成员,那么在使用它时将出现未定义的行为。