2016-09-26 13 views
1

私の最終的な目標は、60fpsでさまざまなサイズと色の100万球をレンダリングすることです。カメラを画面の周りにも移動できるようにしたい。OpenGLで数百万のオブジェクトをインスタンス化する

this page of the tutorial I am studyingのコードを変更して、100万キューブをインスタンス化しようとしました。私は最大90,000の立方体をインスタンス化することができましたが、160,000個の立方体をインスタンス化しようとすると、プログラムが破損します。プログラムが「動作を停止しました」というエラーが発生し、予期せず終了します。これはどんな種類のエラーなのか分かりませんが、メモリに関連していると思います。

インスタンス化についての私の理解は素朴なので、問題の内容はわかりません。私は100万立方体を立てることは、100万球体を立てるという私の目標の次のステップだと信じています。だから、私の質問:どのように私はOpenGLで100万立方体/オブジェクトをインスタンス化するのですか?

私はthis tutorialを通じてOpenGLを学習されているので、私は、Visual Studio 2013年に32-bit GLEW32-bit GLFWを使用私は2.30 GHz CPUと64ビットのオペレーティング・システム(Windows 7)に8 GBのRAMを持っています。

私のコードは以下の通りです:

(セットライン#2をインスタンス化するキューブの数であるようにライン#2は、全体の数の平方根を持っていることを確認してください)

// Make sure NUM_INS is a square number 
#define NUM_INS 9 

// GLEW 
#define GLEW_STATIC 
#include <GL/glew.h> 

// GLFW 
#include <GLFW/glfw3.h> 

// GL includes 
#include "Shader.h" 

// GLM Mathemtics 
#include <glm/glm.hpp> 
#include <glm/gtc/matrix_transform.hpp> 
#include <glm/gtc/type_ptr.hpp> 

// Properties 
GLuint screenWidth = 800, screenHeight = 600; 

// Function prototypes 
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); 


// The MAIN function, from here we start our application and run the Game loop 
int main() 
{ 
    // Init GLFW 
    glfwInit(); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); 

    GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed 
    glfwMakeContextCurrent(window); 

    // Set the required callback functions 
    glfwSetKeyCallback(window, key_callback); 

    // Initialize GLEW to setup the OpenGL Function pointers 
    glewExperimental = GL_TRUE; 
    glewInit(); 

    // Define the viewport dimensions 
    glViewport(0, 0, screenWidth, screenHeight); 

    // Setup OpenGL options 
    //glEnable(GL_DEPTH_TEST); 

    // Setup and compile our shader(s) 
    Shader shader("core.vs", "core.frag"); 

    // Generate a list of 100 quad locations/translation-vectors 
    glm::vec2 translations[NUM_INS]; 
    int index = 0; 
    GLfloat offset = 1.0f/sqrt(NUM_INS); 
    for (GLint y = -sqrt(NUM_INS); y < sqrt(NUM_INS); y += 2) 
    { 
     for (GLint x = -sqrt(NUM_INS); x < sqrt(NUM_INS); x += 2) 
     { 
      glm::vec2 translation; 
      translation.x = (GLfloat)x/sqrt(NUM_INS) + offset; 
      translation.y = (GLfloat)y/sqrt(NUM_INS) + offset; 
      translations[index++] = translation; 
     } 
    } 

    // Store instance data in an array buffer 
    GLuint instanceVBO; 
    glGenBuffers(1, &instanceVBO); 
    glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * NUM_INS, &translations[0], GL_STATIC_DRAW); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    // Generate quad VAO 
    GLfloat quadVertices[] = { 
     // Positions // Colors 
     -0.05f, 0.05f, 1.0f, 0.0f, 0.0f, 
     0.05f, -0.05f, 0.0f, 1.0f, 0.0f, 
     -0.05f, -0.05f, 0.0f, 0.0f, 1.0f, 

     -0.05f, 0.05f, 1.0f, 0.0f, 0.0f, 
     0.05f, -0.05f, 0.0f, 1.0f, 0.0f, 
     0.05f, 0.05f, 0.0f, 0.0f, 1.0f 
    }; 

    GLfloat vertices[] = { 
     -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 1.0f, 0.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 1.0f, 0.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 1.0f, 1.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 1.0f, 1.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.0f, 1.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.0f, 0.0f, 1.0f, 

     -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.0f, 0.0f, 1.0f, 
     0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 1.0f, 0.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 1.0f, 1.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 1.0f, 1.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.0f, 1.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.0f, 0.0f, 1.0f, 

     -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 1.0f, 0.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 1.0f, 1.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.0f, 1.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.0f, 1.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.0f, 0.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 1.0f, 0.0f, 0.0f, 

     0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 1.0f, 0.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 1.0f, 1.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.0f, 1.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.0f, 1.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.0f, 0.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 1.0f, 0.0f, 0.0f, 

     -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.0f, 1.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 1.0f, 1.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 1.0f, 0.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 1.0f, 0.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.0f, 0.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.0f, 1.0f, 0.0f, 

     -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.0f, 1.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 1.0f, 1.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 1.0f, 0.0f, 0.0f, 
     0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 1.0f, 0.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), 0.0f, 0.0f, 0.0f, 
     -0.5f/sqrt(NUM_INS), 0.5f/sqrt(NUM_INS), -0.5f/sqrt(NUM_INS), 0.0f, 1.0f, 0.0f 
    }; 

    GLuint quadVAO, quadVBO; 
    glGenVertexArrays(1, &quadVAO); 
    glGenBuffers(1, &quadVBO); 
    glBindVertexArray(quadVAO); 
    glBindBuffer(GL_ARRAY_BUFFER, quadVBO); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 
    glEnableVertexAttribArray(0); 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); 
    glEnableVertexAttribArray(1); 
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat))); 
    // Also set instance data 
    glEnableVertexAttribArray(2); 
    glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); 
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glVertexAttribDivisor(2, 1); // Tell OpenGL this is an instanced vertex attribute. 
    glBindVertexArray(0); 


    // Game loop 
    while (!glfwWindowShouldClose(window)) 
    { 
     // Check and call events 
     glfwPollEvents(); 

     // Clear buffers 
     glClearColor(0.03f, 0.03f, 0.03f, 1.0f); 
     glClear(GL_COLOR_BUFFER_BIT); 

     // Draw 100 instanced quads 
     shader.Use(); 
     glBindVertexArray(quadVAO); 
     glDrawArraysInstanced(GL_TRIANGLES, 0, 36, NUM_INS); // 100 triangles of 6 vertices each 
     glBindVertexArray(0); 

     // Swap the buffers 
     glfwSwapBuffers(window); 
    } 

    glfwTerminate(); 
    return 0; 
} 

// Is called whenever a key is pressed/released via GLFW 
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) 
{ 
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) 
     glfwSetWindowShouldClose(window, GL_TRUE); 
} 

頂点シェーダ:(命名core.vs)

#version 330 core 
layout (location = 0) in vec3 position; 
layout (location = 1) in vec3 color; 
layout (location = 2) in vec2 offset; 

out vec3 fColor; 

void main() 
{ 
    gl_Position = vec4(position.x + offset.x, position.y + offset.y, position.z, 1.0f); 
    fColor = color; 
} 

フラグメントシェーダ:(命名core.frag)

#version 330 core 
in vec3 fColor; 
out vec4 color; 

void main() 
{ 
    color = vec4(fColor, 1.0f); 
} 

シェーダクラス:(は、shader.h命名)

#pragma once 

// Std. Includes 
#include <vector> 

// GL Includes 
#include <GL/glew.h> 
#include <glm/glm.hpp> 
#include <glm/gtc/matrix_transform.hpp> 



// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods 
enum Camera_Movement { 
    FORWARD, 
    BACKWARD, 
    LEFT, 
    RIGHT 
}; 

// Default camera values 
const GLfloat YAW = -90.0f; 
const GLfloat PITCH = 0.0f; 
const GLfloat SPEED = 3.0f; 
const GLfloat SENSITIVTY = 0.25f; 
const GLfloat ZOOM = 45.0f; 


// An abstract camera class that processes input and calculates the corresponding Eular Angles, Vectors and Matrices for use in OpenGL 
class Camera 
{ 
public: 
    // Camera Attributes 
    glm::vec3 Position; 
    glm::vec3 Front; 
    glm::vec3 Up; 
    glm::vec3 Right; 
    glm::vec3 WorldUp; 
    // Eular Angles 
    GLfloat Yaw; 
    GLfloat Pitch; 
    // Camera options 
    GLfloat MovementSpeed; 
    GLfloat MouseSensitivity; 
    GLfloat Zoom; 

    // Constructor with vectors 
    Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), GLfloat yaw = YAW, GLfloat pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM) 
    { 
     this->Position = position; 
     this->WorldUp = up; 
     this->Yaw = yaw; 
     this->Pitch = pitch; 
     this->updateCameraVectors(); 
    } 
    // Constructor with scalar values 
    Camera(GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat upX, GLfloat upY, GLfloat upZ, GLfloat yaw, GLfloat pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM) 
    { 
     this->Position = glm::vec3(posX, posY, posZ); 
     this->WorldUp = glm::vec3(upX, upY, upZ); 
     this->Yaw = yaw; 
     this->Pitch = pitch; 
     this->updateCameraVectors(); 
    } 

    // Returns the view matrix calculated using Eular Angles and the LookAt Matrix 
    glm::mat4 GetViewMatrix() 
    { 
     return glm::lookAt(this->Position, this->Position + this->Front, this->Up); 
    } 

    // Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems) 
    void ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime) 
    { 
     GLfloat velocity = this->MovementSpeed * deltaTime; 
     if (direction == FORWARD) 
      this->Position += this->Front * velocity; 
     if (direction == BACKWARD) 
      this->Position -= this->Front * velocity; 
     if (direction == LEFT) 
      this->Position -= this->Right * velocity; 
     if (direction == RIGHT) 
      this->Position += this->Right * velocity; 
    } 

    // Processes input received from a mouse input system. Expects the offset value in both the x and y direction. 
    void ProcessMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean constrainPitch = true) 
    { 
     xoffset *= this->MouseSensitivity; 
     yoffset *= this->MouseSensitivity; 

     this->Yaw += xoffset; 
     this->Pitch += yoffset; 

     // Make sure that when pitch is out of bounds, screen doesn't get flipped 
     if (constrainPitch) 
     { 
      if (this->Pitch > 89.0f) 
       this->Pitch = 89.0f; 
      if (this->Pitch < -89.0f) 
       this->Pitch = -89.0f; 
     } 

     // Update Front, Right and Up Vectors using the updated Eular angles 
     this->updateCameraVectors(); 
    } 

    // Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis 
    void ProcessMouseScroll(GLfloat yoffset) 
    { 
     if (this->Zoom >= 1.0f && this->Zoom <= 45.0f) 
      this->Zoom -= yoffset; 
     if (this->Zoom <= 1.0f) 
      this->Zoom = 1.0f; 
     if (this->Zoom >= 45.0f) 
      this->Zoom = 45.0f; 
    } 

private: 
    // Calculates the front vector from the Camera's (updated) Eular Angles 
    void updateCameraVectors() 
    { 
     // Calculate the new Front vector 
     glm::vec3 front; 
     front.x = cos(glm::radians(this->Yaw)) * cos(glm::radians(this->Pitch)); 
     front.y = sin(glm::radians(this->Pitch)); 
     front.z = sin(glm::radians(this->Yaw)) * cos(glm::radians(this->Pitch)); 
     this->Front = glm::normalize(front); 
     // Also re-calculate the Right and Up vector 
     this->Right = glm::normalize(glm::cross(this->Front, this->WorldUp)); // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement. 
     this->Up = glm::normalize(glm::cross(this->Right, this->Front)); 
    } 
}; 
+3

物事の音からニースと繰り返し可能。 [デバッガ](https://en.wikipedia.org/wiki/Debugger)とは何ですか? – user4581301

+1

質問自体にソースコードを含めてください。さもなければ、pastebinsが削除されるとき、この質問は役に立たない。 – BDL

+2

オブジェクトをローカル変数として割り当てます。スタック上にオブジェクトを配置していますが、これらのオブジェクトは多くのオブジェクトを占有しません。ヒープにオブジェクト配列を割り当てます( 'std :: vector'を使うことができます)。 –

答えて

3

まず、私はあなたのShader classはカメラコードである、しかし、私はまた、そのチュートリアルから学んだ、そう簡単に自分でそれを変更することを言わなければなりません。

スローする問題は、システムのスタックサイズに比例します。 @Matteoイタリアはstd::vectorを使用し、言ったようにNUM_INS

160000.に真の解(編集後)

を設定するときにVisual Studioで、あなただけは、ローカル変数1メガバイトでサイズ、およびプログラムのオーバーフローを作るために許可代わりに、または配列の初期化部分glm::vec2 translations[NUM_INS];glm::vec2* translations = new glm::vec2[NUM_INS];に変更し、使用しないときはdeleteを忘れないでください。私は第二の方法を試して、それは働くことができる。私の以前の悪い答えを申し訳ありません、私はヒープとスタックについてもっと学ぶ必要があります!

バックグラウンドを理解できない人は、ref1,ref2と学習しました。


最悪のソリューション問題をsloveする

を(、以前使用しないでください)は、次の手順でVisual Studioの設定を変更することができます:

  1. 右クリックし、あなたのプロジェクト - >設定 「私の編集者が中国人であるので、私はドン(2M)にヒープ予約サイズを設定
  2. システム

注>-行くリンカへ細部の名前を正確に知っている。あなたは、スタック上の位置のあなたの配列を割り当てている

glm::vec2 translations[NUM_INS]; 

ここ

+3

これは* stack *サイズであり、それを増やすことはほとんど決して解決できません。 OPはスタックの代わりにヒープに自分のものを割り当てなければなりません。 –

+0

@Tokenyetありがとう、あなたのご意見は私の問題を解決するのを助けました。私はこれが別の質問であることを理解しています。私はそれを新しいものとして投稿すべきですか?キューブのコードは〜30 fpsで動作していますが、それよりも高いと予想しています。それをスピードアップするために何か簡単なことはありますか? –

+0

@Paul Terwilligerあなたはfpsカウンタコードやその他の詳細をどのように実装するのか、新しい投稿をしてください。ここでは、私はちょうど何かを思い出させて、あなたの[vsync](http://stackoverflow.com/questions/11312318/my-limited-fps-60)と他の制限設定を確認したいと思います。新しい投稿のために先: – Tokenyet

2

;:これを設定することで、16万以上にNUM_INSを設定する可能性があり、このような結果を参照してください今のところ、NUM_INSが比較的小さい限り、これはそれほど大きな問題ではありませんが、あなたが "大きな"数字(例えば、100000)に向かうと、スタックはそれを取ることができません。

glm::vec2要素は32ビット浮動小数点数の対で構成されていることを考えると(したがって、各vec2は8バイトである)、160000の要素は、スタックオーバーフロー1.28メガバイト、(デフォルトのリンカー設定でWindowsの1メガバイト)を取ります。スタックは意図的にサイズが制限され、大きなものを撮影するために最適化されていません。

この問題を解決するには、は、スタックサイズを増やすことではありません。代わりに、ヒープ上に要素を割り当てる必要があります。これにより、プロセスで使用可能なすべての仮想メモリを利用できます。

std::vector<glm::vec2> translations(NUM_INS); 

あなたのコードの残りの部分があるように動作する必要があります - 単により多く - std::vectorクラスを使用することを学ぶのいずれか、これを行うnew/deleteかを使用するには

関連する問題