如何通过GLM / OpenGL绘制多个对象?

时间:2014-04-19 03:50:24

标签: opengl glm-math

我发现很多情况是通过一个顶点数组创建多个对象。然后通过转换来获得不同的内容,例如Draw 2 cubes in OpenGL using GLMCant draw multiple objects in opengl

但我想要的是通过完整的差异顶点数组创建完整的diff对象。典型案例是http://www.spacesimulator.net/wiki/index.php?title=Tutorials:Matrices_%28OpenGL3.3%29。如何通过GLM实施?我试图找到一些示例代码。

2 个答案:

答案 0 :(得分:2)

下一个代码是使用OpenGL和Linux Debian 9 绘制2个立方体的完整示例。此外,如果单击鼠标,还有一个类可以看到按下的按钮和位置。包括所有源和Makefile。

  • 编译:在同一目录中复制具有正确名称的所有文件 输入 make
  • 执行:输入 ./ start

所有需要的库都安装了下一个命令:

apt-get install libglew-dev
apt-get install freeglut3-dev
apt-get install libglm-dev

该示例是从Internet上的多个示例创建的,并更改为面向对象的代码以澄清。

我希望它有用。

文件:cube.hpp

#ifndef CUBE_H
#define CUBE_H

#include <stdio.h>
#include <stdlib.h>
#include <glm/gtc/type_ptr.hpp>
#include <GL/glew.h>
#include <GL/glut.h>

class Cube{

   private:

      GLuint vboCubeVertex, vboCubeColors, vboCubeFaces;
      GLint attribute_coord3d, attribute_v_color;

   public:

      int init_resources(GLuint shaderProgram);
      void draw(GLint uniform_mvp, glm::mat4 mvp);
      void disable();
      void deleteBuffers();
};

#endif

文件:cube.cpp

#include "cube.hpp"

int Cube::init_resources(GLuint shaderProgram)
{
   fprintf(stderr, "init_resources\n");

      //**********************************************************
      // VERTEX **************************************************
      //**********************************************************

      // Each vertex has the format x,y,z

      GLfloat arrCubeVertex[] = {
         // front
         -1.0, -1.0,  1.0,
          1.0, -1.0,  1.0,
          1.0,  1.0,  1.0,
         -1.0,  1.0,  1.0,
         // back
         -1.0, -1.0, -1.0,
         1.0, -1.0, -1.0,
         1.0,  1.0, -1.0,
         -1.0,  1.0, -1.0,
      };
      //**********************************************************
      // COLORS OF EACH VERTEX ***********************************
      //**********************************************************

      GLfloat arrCubeColors[] = {
         // front colors
         1.0, 0.0, 0.0,
         0.0, 1.0, 0.0,
         0.0, 0.0, 1.0,
         1.0, 1.0, 1.0,
         // back colors
         1.0, 0.0, 0.0,
         0.0, 1.0, 0.0,
         0.0, 0.0, 1.0,
         1.0, 1.0, 1.0,
      };

      // Faces are squares, each square are maked wit two triangles.
      // See document OpenGL_Charly.pdf.

      GLushort arrCubeFaces[] = {
         // front
         0, 1, 2,
         2, 3, 0,
         // right
         1, 5, 6,
            6, 2, 1,
         // back
         7, 6, 5,
         5, 4, 7,
         // left
         4, 0, 3,
         3, 7, 4,
         // bottom
         4, 5, 1,
         1, 0, 4,
         // up
         3, 2, 6,
         6, 7, 3,
      };


   glGenBuffers(1, &vboCubeVertex);
   glBindBuffer(GL_ARRAY_BUFFER, vboCubeVertex);
   glBufferData(GL_ARRAY_BUFFER, sizeof(arrCubeVertex), arrCubeVertex, GL_STATIC_DRAW);

   // Las mismas operaciones que hicimos con los vertices, las hacemos ahora con los colores.
   glGenBuffers(1, &vboCubeColors);
   glBindBuffer(GL_ARRAY_BUFFER, vboCubeColors);
   glBufferData(GL_ARRAY_BUFFER, sizeof(arrCubeColors), arrCubeColors, GL_STATIC_DRAW);

   // Ahora lo mismo pero con las caras.
   glGenBuffers(1, &vboCubeFaces);
   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboCubeFaces);
   glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(arrCubeFaces), arrCubeFaces, GL_STATIC_DRAW);

   //**********************************************************


   attribute_coord3d = glGetAttribLocation(shaderProgram, "coord3d");
   if (attribute_coord3d == -1)
   {
      fprintf(stderr, "Could not bind attribute %s\n", "coord3d");
      return 0;
   }

   attribute_v_color = glGetAttribLocation(shaderProgram, "v_color");
   if (attribute_v_color == -1)
   {
      fprintf(stderr, "Could not bind attribute %s\n", "v_color");
      return 0;
   }

   return 1;
}

void Cube::draw(GLint uniform_mvp, glm::mat4 mvp){

   glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp));

   // Cube vertices
   glEnableVertexAttribArray(attribute_coord3d);
   glBindBuffer(GL_ARRAY_BUFFER, vboCubeVertex);

   // Attribute, elements per vertex (x,y,z), the type of each element, take our values as-is, no extra data between each position, offset of first element
   glVertexAttribPointer(attribute_coord3d, 3, GL_FLOAT, GL_FALSE, 0, 0);

   // Cube colors
   glEnableVertexAttribArray(attribute_v_color);
   glBindBuffer(GL_ARRAY_BUFFER, vboCubeColors);

   // Attribute, elements per vertex (R,G,B), the type of each element, take our values as-is, no extra data between each position, offset of first element
   glVertexAttribPointer(attribute_v_color, 3, GL_FLOAT, GL_FALSE, 0, 0);

   /* Push each element in buffer_vertices to the vertex shader */
   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboCubeFaces);

   int size;
   glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
   glDrawElements(GL_TRIANGLES, size/sizeof(GLushort), GL_UNSIGNED_SHORT, 0);

}

void Cube::disable(){

   glDisableVertexAttribArray(attribute_coord3d);
   glDisableVertexAttribArray(attribute_v_color);

}

void Cube::deleteBuffers(){

   glDeleteBuffers(1, &vboCubeVertex);
   glDeleteBuffers(1, &vboCubeColors);
   glDeleteBuffers(1, &vboCubeFaces);
}

文件:mouse.hpp

#ifndef MOUSE_H
#define MOUSE_H

#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>

struct Point {
   GLint x;
   GLint y;
};


class Mouse{

   private:

      Point p1, p2;

   public:

       int show(int button, int state, int x, int y);
};

#endif

文件:mouse.cpp

#include "mouse.hpp"

int Mouse::show(int button, int state, int x, int y)
{

   if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
      printf("%s\n", "LEFT DOWN");
   }
   else if(button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
      printf("%s\n", "LEFT UP");
   }

   printf("mouse X: %d, Y: %d\n", x, y);

}

文件:shader_utils.hpp

#ifndef _CREATE_SHADER_H
#define _CREATE_SHADER_H
#include <GL/glew.h>
char* file_read(const char* filename);
void print_log(GLuint object);
GLuint create_shader(const char* filename, GLenum type);
GLuint create_program(const char* vertexfile, const char *fragmentfile);
GLuint create_gs_program(const char* vertexfile, const char *geometryfile, const char *fragmentfile, GLint input, GLint output, GLint vertices);
GLint get_attrib(GLuint program, const char *name);
GLint get_uniform(GLuint program, const char *name);
#endif

文件:shader_utils.cpp

    #include <stdio.h>
    #include <stdlib.h>
    #include "shader_utils.hpp"

    char* file_read(const char* filename)
    {
       FILE* in = fopen(filename, "rb");
       if (in == NULL) return NULL;

      int res_size = BUFSIZ;
      char* res = (char*)malloc(res_size);
      int nb_read_total = 0;

      while (!feof(in) && !ferror(in)) {
        if (nb_read_total + BUFSIZ > res_size) {
          if (res_size > 10*1024*1024) break;
          res_size = res_size * 2;
          res = (char*)realloc(res, res_size);
        }
        char* p_res = res + nb_read_total;
        nb_read_total += fread(p_res, 1, BUFSIZ, in);
      }

      fclose(in);
      res = (char*)realloc(res, nb_read_total + 1);
      res[nb_read_total] = '\0';
      return res;
    }

    void print_log(GLuint object)
    {
      GLint log_length = 0;
      if (glIsShader(object))
        glGetShaderiv(object, GL_INFO_LOG_LENGTH, &log_length);
      else if (glIsProgram(object))
        glGetProgramiv(object, GL_INFO_LOG_LENGTH, &log_length);
      else {
        fprintf(stderr, "printlog: Not a shader or a program\n");
        return;
      }

      char* log = (char*)malloc(log_length);

      if (glIsShader(object))
        glGetShaderInfoLog(object, log_length, NULL, log);
      else if (glIsProgram(object))
        glGetProgramInfoLog(object, log_length, NULL, log);

      fprintf(stderr, "%s", log);
      free(log);
    }

   GLuint create_shader(const char* filename, GLenum type)
    {
      const GLchar* source = file_read(filename);
      if (source == NULL) {
        fprintf(stderr, "Error opening %s: ", filename); perror("");
        return 0;
      }
      GLuint res = glCreateShader(type);
      const GLchar* sources[] = {
        // Define GLSL version
    #ifdef GL_ES_VERSION_2_0
        "#version 100\n"
    #else
        "#version 120\n"
    #endif
        ,
        // GLES2 precision specifiers
    #ifdef GL_ES_VERSION_2_0

        // Define default float precision for fragment shaders:
        (type == GL_FRAGMENT_SHADER) ?
        "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
        "precision highp float;           \n"
        "#else                            \n"
        "precision mediump float;         \n"
        "#endif                           \n"
        : ""
        // Note: OpenGL ES automatically defines this:
        // #define GL_ES
    #else
        // Ignore GLES 2 precision specifiers:
        "#define lowp   \n"
        "#define mediump\n"
        "#define highp  \n"
    #endif
        ,
        source };
      glShaderSource(res, 3, sources, NULL);
      free((void*)source);

      glCompileShader(res);
      GLint compile_ok = GL_FALSE;
      glGetShaderiv(res, GL_COMPILE_STATUS, &compile_ok);
      if (compile_ok == GL_FALSE) {
        fprintf(stderr, "%s:", filename);
        print_log(res);
        glDeleteShader(res);
        return 0;
      }

      return res;
    }

    GLuint create_program(const char *vertexfile, const char *fragmentfile) {
        GLuint program = glCreateProgram();
        GLuint shader;

        if(vertexfile) {
            shader = create_shader(vertexfile, GL_VERTEX_SHADER);
            if(!shader)
                return 0;
            glAttachShader(program, shader);
        }

        if(fragmentfile) {
            shader = create_shader(fragmentfile, GL_FRAGMENT_SHADER);
            if(!shader)
                return 0;
            glAttachShader(program, shader);
        }

        glLinkProgram(program);
        GLint link_ok = GL_FALSE;
        glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
        if (!link_ok) {
            fprintf(stderr, "glLinkProgram:");
            print_log(program);
            glDeleteProgram(program);
            return 0;
        }

        return program;
    }

    #ifdef GL_GEOMETRY_SHADER
    GLuint create_gs_program(const char *vertexfile, const char *geometryfile, const char *fragmentfile, GLint input, GLint output, GLint vertices) {
        GLuint program = glCreateProgram();
        GLuint shader;

        if(vertexfile) {
            shader = create_shader(vertexfile, GL_VERTEX_SHADER);
            if(!shader)
                return 0;
            glAttachShader(program, shader);
        }

        if(geometryfile) {
            shader = create_shader(geometryfile, GL_GEOMETRY_SHADER);
            if(!shader)
                return 0;
            glAttachShader(program, shader);

            glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, input);
            glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output);
            glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, vertices);
        }

        if(fragmentfile) {
            shader = create_shader(fragmentfile, GL_FRAGMENT_SHADER);
            if(!shader)
                return 0;
            glAttachShader(program, shader);
        }

        glLinkProgram(program);
        GLint link_ok = GL_FALSE;
        glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
        if (!link_ok) {
            fprintf(stderr, "glLinkProgram:");
            print_log(program);
            glDeleteProgram(program);
            return 0;
        }

        return program;
    }
    #else
    GLuint create_gs_program(const char *vertexfile, const char *geometryfile, const char *fragmentfile, GLint input, GLint output, GLint vertices) {
        fprintf(stderr, "Missing support for geometry shaders.\n");
        return 0;
    }
    #endif

    GLint get_attrib(GLuint program, const char *name) {
        GLint attribute = glGetAttribLocation(program, name);
        if(attribute == -1)
            fprintf(stderr, "Could not bind attribute %s\n", name);
        return attribute;
    }

    GLint get_uniform(GLuint program, const char *name) {
        GLint uniform = glGetUniformLocation(program, name);
        if(uniform == -1)
            fprintf(stderr, "Could not bind uniform %s\n", name);
        return uniform;
    }

文件:start.cpp

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "shader_utils.hpp"
#include "mouse.hpp"
#include "cube.hpp"

int scrWidth = 600;
int scrHeight = 600;
GLuint shaderProgram;
GLint uniform_mvp;

Cube cube1;
Cube cube2;
glm::mat4 mvpCube1;
glm::mat4 mvpCube2;
Mouse theMouse;


void onIdle()
{

   glm::vec3 rotationCube1(0, 1, 0);                                  // Rotate cube 1 over Y axis
   float angleCube1 = glutGet(GLUT_ELAPSED_TIME) / 1000.0 * 5;        // 5° per second
   glm::vec3 translationCube1 (0.0, 0.0, -2.0);                       // Translate cube 1 over Z axis

   glm::vec3 rotationCube2(1, 0, 0);                                  // Rotate cube 2 over X axis
   float angleCube2 = glutGet(GLUT_ELAPSED_TIME) / 1000.0 * 3;        // 3° per second
   glm::vec3 translationCube2 (1.0, 0.0, 0.0);                        // Translate cube 2 over X axis

   // Frustum parameters
   float angleVision = 45.0f;     // Also called Fovy
   float aspect = 1.0f * scrWidth / scrHeight;
   float zNear = 0.1f;
   float zFar = 10.f;

   // Camera parameters
   glm::vec3 cameraEye(0.0, 2.0, -10.0);
   glm::vec3 cameraCenter(0.0, 0.0, -5.0);
   glm::vec3 cameraUp(0.0, 1.0, 0.0);

   // Method lookAt has 3 parameters: eye, center, up
   glm::mat4 view = glm::lookAt(cameraEye, cameraCenter, cameraUp);

   // Create the projection matrix
   glm::mat4 projection = glm::perspective(angleVision, aspect, zNear, zFar);

   glm::mat4 modelCube1 = glm::mat4();                                 // Carga model con la identity matrix
   modelCube1 = glm::translate(modelCube1, translationCube1);          // El modelo queda trasladado.
   modelCube1 = glm::rotate(modelCube1, angleCube1, rotationCube1);    // El modelo ahora queda trasladado y rotado.
   mvpCube1 = projection * view * modelCube1;

   glm::mat4 modelCube2 = glm::mat4();                                 // Carga model con la identity matrix
   modelCube2 = glm::translate(modelCube2, translationCube2);          // El modelo queda trasladado.
   modelCube2 = glm::rotate(modelCube2, angleCube2, rotationCube2);    // El modelo ahora queda trasladado y rotado.
   mvpCube2 = projection * view * modelCube2;

   glUseProgram(shaderProgram);
   glutPostRedisplay();
}

void onDisplay()
{
   glClearColor(0.0, 0.0, 0.0, 1.0);   // Set color (0, 0, 0 = Black)
                                       // R,G,B,A

   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
   glUseProgram(shaderProgram);        // Program with loaded shaders

   cube1.draw(uniform_mvp, mvpCube1);
   cube1.disable();

   cube2.draw(uniform_mvp, mvpCube2);
   cube2.disable();

   glutSwapBuffers();
}


void onReshape(int width, int height)
{
   fprintf(stderr, "onReshape\n");

   scrWidth = width;
   scrHeight = height;
   glViewport(0, 0, scrWidth, scrHeight);
}

void free_resources()
{
   fprintf(stderr, "free_resources\n");
   glDeleteProgram(shaderProgram);

   cube1.deleteBuffers();
   cube2.deleteBuffers();
}

void myMouseFunc(int button, int state, int x, int y)
{
   theMouse.show(button, state, x, y);
}

int init(){

   uniform_mvp = glGetUniformLocation(shaderProgram, "mvp");
   if (uniform_mvp == -1)
   {
      fprintf(stderr, "Could not bind uniform %s\n", "mvp");
      return 0;
   }
   return 1;
}

int main(int argc, char* argv[])
{
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_RGBA|GLUT_ALPHA|GLUT_DOUBLE|GLUT_DEPTH);
   glutInitWindowSize(scrWidth, scrHeight);
   glutCreateWindow("Two Cubes");

   GLenum glew_status = glewInit();

   if (glew_status != GLEW_OK)
   {
      fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status));
      return 1;
   }

   if (!GLEW_VERSION_2_0)
   {
      fprintf(stderr, "Error: your graphic card does not support OpenGL 2.0\n");
      return 1;
   }

   GLint link_ok = GL_FALSE;

   GLuint vs, fs;

   if ((vs = create_shader("cube_vertex.glsl", GL_VERTEX_SHADER))   == 0) return 0;
   if ((fs = create_shader("cube_fragment.glsl", GL_FRAGMENT_SHADER)) == 0) return 0;

   shaderProgram = glCreateProgram();
   glAttachShader(shaderProgram, vs);
   glAttachShader(shaderProgram, fs);
   glLinkProgram(shaderProgram);
   glGetProgramiv(shaderProgram, GL_LINK_STATUS, &link_ok);
   if (!link_ok)
   {
      fprintf(stderr, "glLinkProgram:");
      print_log(shaderProgram);
      return 0;
   }

   cube1 = Cube();
   cube2 = Cube();

   if (init() && cube1.init_resources(shaderProgram) && cube2.init_resources(shaderProgram))
   {

      glutMouseFunc(myMouseFunc);

      glutDisplayFunc(onDisplay);      // Set the display function for the current window.
      glutReshapeFunc(onReshape);      // Set the reshape function for the current window.
      glutIdleFunc(onIdle);            // Set the global idle callback (perform background proccessing)

      // Enable server side capabilities
      glEnable(GL_BLEND);              // GL_BLEND: If enabled, blend the computed fragment color values with the
                                       // values in the color buffers. See glBlendFunc.

      glEnable(GL_DEPTH_TEST);         // GL_DEPTH_TEST: If enabled, do depth comparisons and update the depth buffer.
                                       // Note that even if the depth buffer exists and the depth mask is non-zero,
                                       // the depth buffer is not updated if the depth test is disabled. See glDepthFunc
                                       // and glDepthRange.


      //glDepthFunc(GL_LESS);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      glutMainLoop();
   }

   free_resources();
   return 0;
}

文件:cube_fragment.glsl

varying vec3 f_color;

void main(void) {
  gl_FragColor = vec4(f_color.x, f_color.y, f_color.z, 1.0);
}

文件:cube_vertex.glsl

attribute vec3 v_color;
uniform mat4 mvp;
varying vec3 f_color;

void main(void)
{
  gl_Position = mvp * vec4(coord3d, 1.0);
  f_color = v_color;
}

文件:Makefile

LDLIBS=-lglut -lGLEW -lGL -lm
all: start
clean:
    rm -f *.o start
start: mouse.o shader_utils.o cube.o
.PHONY: all clean

结果是两个旋转立方体:

enter image description here

答案 1 :(得分:0)

首先,GLM是一个数学库,提供矢量,矩阵等行为和外观(尽可能多)GLSL中使用的向量和矩阵 - 即着色器代码。在编写使用OpenGL的应用程序时,GLM非常有用,但实际上并不是必需的,它与渲染对象无关。

如果要使用不同的顶点数组绘制不同的对象,请阅读如上所述的教程或查看http://www.arcsynthesis.org/gltut/。了解它如何将数据加载到顶点数组并渲染它,然后对不同的数组执行两次。请记住,切换顶点数组很慢 - 您可能希望将多个对象加载到一个顶点缓冲区中,然后使用带索引偏移的渲染命令(例如glMultiDrawElementsBaseVertex)。