OpenGL vykreslení milionů objektů

C++, C#, Visual Basic, Delphi, Perl a ostatní

Moderátor: Moderátoři Živě.cz

Odeslat příspěvekod marun1 8. 8. 2016 12:42

Programuju renderer pro pointcloud.

Bodů může být i 300M, chci aby ty body měly rozměr takže každý bod je krychle, a každý bod má pozici a barvu popřípadě teplotu

momentálně mám pokusný program kde pomocí glDrawElementsInstanced kreslím krychle z jednoho vbo a ebo
a každá má svůj offset a barvu, ale tento způsob je příliš pomalý, 16.7M krychlí se kreslí na 1080 při 20fps

existuje ještě nějaký jiný způsob nebo se budu muset vynechávat krychle které nejsou vidět? toto ale naráží na problém, že pokud budou v záběru všechny body tak bodeme tam kde sme byli

main.cpp

Kód: Vybrat vše
#define _USE_MATH_DEFINES
#define GLEW_STATIC
#include <GL/glew.h>
#define GLFW_INCLUDE_GLU
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <math.h>
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <fstream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

GLint x,y,z,i,j,k,xl,yl,dx,dy,skok;
GLdouble a,b,c,d,e,f;
const int count = 256;
const GLfloat vertices[32] = { -1,-1,-1,1, -1,-1,1,1, -1,1,-1,1, -1,1,1,1, 1,-1,-1,1, 1,-1,1,1, 1,1,-1,1, 1,1,1,1, };
const GLushort indices[36] = { 2,3,0,3,1,0, 0,6,2,0,4,6, 1,4,0,1,5,4, 1,3,5,3,7,5, 4,5,6,5,7,6, 7,2,6,7,3,2 };
std::vector<GLfloat> pos;
std::vector<GLfloat> color;
GLuint programID;
GLFWwindow* window;
glm::mat4 projectionMatrix, rotationMatrix, translationMatrix, cameraRotationMatrix;
GLfloat aspect;

void draw()
{
    projectionMatrix = glm::perspective(3.1415f*(60.0f/180.0f), aspect, 1.0f, 100.0f);
    translationMatrix = glm::translate(glm::mat4(), glm::vec3(0.0f, 0.0f, -2.0f));

    glm::mat4 fullTransformMatrix = projectionMatrix * cameraRotationMatrix * translationMatrix * rotationMatrix;

    GLint fullTransformMatrixUniformLocation = glGetUniformLocation(programID, "fullTransformMatrix");

    glUniformMatrix4fv(fullTransformMatrixUniformLocation, 1, GL_FALSE, &fullTransformMatrix[0][0]);


    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    glDrawElementsInstanced(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0, count*count*count);


    glfwSwapInterval(1);
    glfwSwapBuffers(window);
    glfwPollEvents();
}

void _update_fps_counter(GLFWwindow* window)
{
    static double pervious_seconds = glfwGetTime();
    static int frame_count;
    double current_seconds = glfwGetTime();
    double elapsed_seconds = current_seconds - pervious_seconds;
    if(elapsed_seconds > 0.25)
    {
        pervious_seconds = current_seconds;
        double fps = (double)frame_count / elapsed_seconds;
        char tmp[128];
        sprintf(tmp,"fps:%.2f",fps);
        glfwSetWindowTitle(window,tmp);
        frame_count = 0;
    }
    frame_count++;
}

static void onerror(int error, const char* description)
{
    printf("%i: %s\n", error, description);
}

static void onkeyboard(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, GL_TRUE);
    };

    switch(key)
    {
    case 65:    //A
        k=5;
        d-=k*cos(x*(M_PI/180));
        f+=k*sin(x*(M_PI/180));
        break;
    case 81:    //Q

        break;
    case 83:    //S
        j=+5;
        f+=j*cos(x*(M_PI/180));
        d+=j*sin(x*(M_PI/180));
        break;
    case 87:    //W
        j=-5;
        f+=j*cos(x*(M_PI/180));
        d+=j*sin(x*(M_PI/180));
        break;
    case 68:    //D
        k=-5;
        d-=k*cos(x*(M_PI/180));
        f+=k*sin(x*(M_PI/180));
        break;
    case 69:    //E

        break;
    case 'R':

        break;
    case 'Y':

        break;
    case 'X':

        break;
    case 'C':

        break;
    case ' ':
        skok=0;
        break;
    }
    j=k=0;
    //printf("x:%i y:%i a:%f b:%f c:%f d:%f e:%f f:%f skok:%i \n",x,y,a,b,c,d,e,f,skok);
}

static void onmouse(GLFWwindow* window, double mx, double my)
{
    x=(1280/2-mx);
    y=(my-720/2);


    cameraRotationMatrix = glm::rotate(glm::mat4(),float(y)/100,glm::vec3(1,0,0));
    cameraRotationMatrix = glm::rotate(cameraRotationMatrix,float(-x)/100,glm::vec3(0,1,0));

    //printf("x:%i y:%i a:%f b:%f c:%f d:%f e:%f f:%f skok:%i \n",x,y,a,b,c,d,e,f,skok);
}

bool checkShaderStatus(GLuint shaderID)
{
    GLint compileStatus;
    glGetShaderiv(shaderID, GL_COMPILE_STATUS, &compileStatus);
    if (compileStatus != GL_TRUE)
    {
        GLint infoLogLength;
        glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
        GLchar* buffer = new GLchar[infoLogLength];

        GLsizei bufferSize;
        glGetShaderInfoLog(shaderID, infoLogLength, &bufferSize, buffer);
        std::cout << buffer << std::endl;
        delete[] buffer;
        return false;
    }
    return true;
}

bool checkProgramStatus(GLuint programID)
{
    GLint linkStatus;
    glGetProgramiv(programID, GL_LINK_STATUS, &linkStatus);
    if (linkStatus != GL_TRUE)
    {
        GLint infoLogLength;
        glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength);
        GLchar* buffer = new GLchar[infoLogLength];

        GLsizei bufferSize;
        glGetProgramInfoLog(programID, infoLogLength, &bufferSize, buffer);
        std::cout << buffer << std::endl;
        delete[] buffer;
        return false;
    }
    return true;
}


int main()
{
    int width, height;

    x=y=z=xl=yl=0;
    i=j=k=0;
    a=b=c=20;
    d=e=0;
    skok=180;


    if(!glfwInit())
    {
        return 1;
    }

    glfwSetErrorCallback(onerror);

    window = glfwCreateWindow(1280,720,"glfw test",NULL,NULL);
    aspect = 1280.0/720.0;

    if( !window )
    {
        glfwTerminate();
        return 1;
    }

    glfwMakeContextCurrent(window);

    glfwWindowHint(GLFW_SAMPLES, 0);

    glewExperimental = GL_TRUE;
    glewInit();

    const GLubyte* renderer = glGetString(GL_RENDERER);
    const GLubyte* version = glGetString(GL_VERSION);
    printf("Renderer: %s\nVersion: %s\n",renderer,version);

    glfwSetKeyCallback(window, onkeyboard);
    glfwSetCursorPosCallback(window, onmouse);

    glDepthFunc( GL_LEQUAL );
    glEnable( GL_DEPTH_TEST );

    //glEnable( GL_LINE_SMOOTH | GL_POINT_SMOOTH );
    //glHint( GL_LINE_SMOOTH_HINT, GL_NICEST);
    //glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
   
    glPointSize(2);


    glfwGetFramebufferSize(window,&width,&height);
    glViewport(0,0,width,height);

    glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );

    pos.clear();
    color.clear();
   
    for(int i=0;i<count;++i)
    {
        for(int j=0;j<count;++j)
        {
            for(int k=0;k<count;++k)
            {
                pos.push_back((i-count/2));
                pos.push_back((j-count/2));
                pos.push_back((k-count/2));
                pos.push_back(1);
                color.push_back(float(rand())/RAND_MAX);
                color.push_back(float(rand())/RAND_MAX);
                color.push_back(float(rand())/RAND_MAX);
                color.push_back(1);
            }
        }
    }

    GLuint vertBufferID;
    glGenBuffers(1, &vertBufferID);
    glBindBuffer(GL_ARRAY_BUFFER, vertBufferID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);


    GLuint posbufID;
    glGenBuffers(1,&posbufID);
    glBindBuffer(GL_ARRAY_BUFFER, posbufID);
    glBufferData(GL_ARRAY_BUFFER, pos.size()*sizeof(GLfloat), pos.data(), GL_STATIC_DRAW);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glVertexAttribDivisor(1,1);

    GLuint colbufID;
    glGenBuffers(1,&colbufID);
    glBindBuffer(GL_ARRAY_BUFFER, colbufID);
    glBufferData(GL_ARRAY_BUFFER, color.size()*sizeof(GLfloat), color.data(), GL_STATIC_DRAW);
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glVertexAttribDivisor(2,1);

    GLuint indexBufferID;
    glGenBuffers(1, &indexBufferID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

    std::ifstream vertexShader;
    vertexShader.open("cube.vert",std::ios::in);
    assert(vertexShader.is_open());
    vertexShader.seekg(0,vertexShader.end);
    unsigned length = vertexShader.tellg();
    vertexShader.seekg(0,vertexShader.beg);
    char* vertex = new char[length+1];
    vertexShader.read(vertex,length);
    vertex[length] = '\0';
    //std::cout << vertex << std::endl;
    glShaderSource(vertexShaderID, 1, &vertex, 0);

    std::ifstream fragmentShader;
    fragmentShader.open("cube.frag",std::ios::in);
    assert(fragmentShader.is_open());
    fragmentShader.seekg(0,fragmentShader.end);
    length = fragmentShader.tellg();
    fragmentShader.seekg(0,fragmentShader.beg);
    char* fragment = new char[length+1];
    fragmentShader.read(fragment,length);
    fragment[length] = '\0';
    //std::cout << fragment << std::endl;
    glShaderSource(fragmentShaderID, 1, &fragment, 0);

    delete [] fragment;
    delete [] vertex;

    glCompileShader(vertexShaderID);
    glCompileShader(fragmentShaderID);

    assert(checkShaderStatus(vertexShaderID) && checkShaderStatus(fragmentShaderID));

    programID = glCreateProgram();
    glAttachShader(programID, vertexShaderID);
    glAttachShader(programID, fragmentShaderID);
    glLinkProgram(programID);

    assert(checkProgramStatus(programID));

    glUseProgram(programID);

    while(!glfwWindowShouldClose(window))
    {

        _update_fps_counter(window);


        draw();


    }

    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}


vertex

Kód: Vybrat vše
#version 330

in layout(location=0) vec4 position;
in layout(location=1) vec4 offset;
in layout(location=2) vec4 vertexColor;

uniform mat4 fullTransformMatrix;

out vec4 theColor;

void main()
{
        gl_Position = fullTransformMatrix * (0.1f*position+offset); //vec4(position.x*0.1f+offset.x,position.y*0.1f+offset.y,position.z*0.1f+offset.z,position.w*0.1f+offset.w);
        theColor = vertexColor;
}


fragment

Kód: Vybrat vše
#version 330

out vec4 daColor;
in vec4 theColor;

void main()
{
        daColor = theColor;
}
marun1
Junior

Odeslat příspěvekod satikcz 8. 8. 2016 13:23

Rozhodně bych nekreslil krychle, ale ideálně jen trojúhelníky nebo aspoň čtverce, otočený ke kameře.
300M už je vážně hodně, takže pokud je to možný a dává to smysl (=nemáš ve výhledu vždycky všechno), zkusil bych i frustum culling, asi bych to zkombinoval s quad/octree (samozřejmě netestovat pozici každýho pointu zvlášť, ale mít je seskupený třeba po cca 10-20M).

Pokud ty pointy nejsou moc velký, tak by vůbec nejlepší bylo kreslit je prostě jako body a akorát je třeba v fragment shaderu vykreslit jako nějaký shluk pixelů.

Další věc je zkusit tu geometrii (čtverce/krychle) vytvářet až v shaderu, jestli to nebude rychlejší.
3x AOC AG271QG (2560x1440, IPS, 165Hz, GSync), MSI RTX 2080Ti Trio, Intel Core i7 8700K@5GHz+EKWB L360, ASUS Maximus X, 32GB G.SKILL TridentZ@3466 MHz, Samsung EVO 840 500 GB + Crucial BX 500 GB + Kingston UV400 1TB, Seasonic P-860 Platinum, FD Define S
satikcz
Junior
Uživatelský avatar

Odeslat příspěvekod marun1 8. 8. 2016 13:37

ty body kreslím jako krychle protože bychom chtěli aby vzdálenější vypadaly menší (navíc pokud by měli pevnou velikost (glPointSize?) tak by se ty vzdálené pravděpodobně překrývaly)
a taky aby se na nás netočily stranou

ale jsme schopní toto obětovat

co jsem měl pokusy s obyčejnými body (zase 16.7M) tak fps nebyli lepší

co se týče té optimalizace, spíš než zahazovat co je mimo záběr by asi bylo lepší zahazovat to, co je skryto za nějakým jiným objektem, protože jak říkám můžou nastat případy, kdy budou v záběru všechny body, ale některé budou pod jinými
marun1
Junior

Odeslat příspěvekod satikcz 8. 8. 2016 13:49

marun1 píše:ty body kreslím jako krychle protože bychom chtěli aby vzdálenější vypadaly menší (navíc pokud by měli pevnou velikost (glPointSize?) tak by se ty vzdálené pravděpodobně překrývaly)
a taky aby se na nás netočily stranou

kreslení čtverců místo krychlí nic z toho nevylučuje, velikost může být podle vzdálenosti a můžete je pořád nechat otočené na vás

marun1 píše:co se týče té optimalizace, spíš než zahazovat co je mimo záběr by asi bylo lepší zahazovat to, co je skryto za nějakým jiným objektem, protože jak říkám můžou nastat případy, kdy budou v záběru všechny body, ale některé budou pod jinými

Tohle je realizovatelné jen pokud by celé skupiny bodů byly najednou skryté - např. když model bude mít nějaké dvě vrstvy nebo něco podobného a muselo by se to předpočítávat a pak na viditelnost využít nejspíš ten octree, ale aplikovat to na jednotlivé body (jako že některé jsou zakryté jinými) je technicky nemožné, ta detekce by zabrala řádově víc času než trvá to kreslení.
3x AOC AG271QG (2560x1440, IPS, 165Hz, GSync), MSI RTX 2080Ti Trio, Intel Core i7 8700K@5GHz+EKWB L360, ASUS Maximus X, 32GB G.SKILL TridentZ@3466 MHz, Samsung EVO 840 500 GB + Crucial BX 500 GB + Kingston UV400 1TB, Seasonic P-860 Platinum, FD Define S
satikcz
Junior
Uživatelský avatar

Odeslat příspěvekod marun1 8. 8. 2016 14:08

takže jediné možné zrychlení je zahazování objektů,

to teď nechám bokem protože potřebuju vyřešit další funkčnost

EDIT: amd už funguje ->

a trápí mě další problém na HD7950, win10 x64 opengl 4.5.13447 cpc 16.300.2311.0 ta aplikace nefunguje - vidím jen bílou obrazovku
na 1080 to funguje ale nemůžu to na ní testovat


programuju to na linuxu na ntb testovat to na jeho 760M není zrovna nejlepší a rozjíždět kompilaci na windows taky není jednoduché protože bych se chtěl vyhnout msvc a mám pomocí mingw rozjetou statickou kompilaci tůdíž nepotřebuju žádné další knihovny pro chod programu
marun1
Junior

Odeslat příspěvekod gandor 8. 8. 2016 15:45

Jedna optimalizacia pokial ten point cloud su fakt len body a nemaju "tvar" v pripade priblizenia - vykresluj to ako body ale pamataj si vzdialenost - ktoru vo fragmente vies priamo namapovat na alfa koordinat z farby (vzdialeny bod ti zabera len cast pixelu = v podstate je ciastocne "priesvitny")....
gandor
Mírně pokročilý


Kdo je online

Uživatelé procházející toto fórum: Žádní registrovaní uživatelé a 0 návštevníků