我写了一些代码来测试OpenGL中的实例化:
#include "exception"
#include "fstream"
#include "GL/glew.h"
#include "glm/fwd.hpp"
#include "glm/glm.hpp"
#include "iostream"
#include "SDL2/SDL.h"
#include "sstream"
#include "stdexcept"
#include "unordered_map"
int g_xRes = 1024, g_yRes = 768;
SDL_Window * g_window = nullptr;
SDL_GLContext g_context = 0;
void init(int * argc, char ** argv);
void cleanup();
void mainLoop();
GLuint loadShader(const char * filepath, GLenum type);
GLuint makeProgram(GLuint vs, GLuint gs, GLuint fs,
const std::unordered_map<std::string, GLuint> & fragDataLocations);
// This is done in order to prevent missing reference error on Windows
#ifdef main
# undef main
#endif
int main(int argc, char ** argv)
{
try
{
init(&argc, argv);
mainLoop();
}
catch(std::exception & ex)
{
std::cerr << argv[0] << ": " << ex.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
void mainLoop()
{
glm::vec3 vertices[] = {
glm::vec3(0, 0, 0),
glm::vec3(0, 0.25, 0),
glm::vec3(0.25, 0, 0),
glm::vec3(0.25, 0.25, 0),
glm::vec3(0.50, 0, 0),
glm::vec3(0.50, 0.25, 0),
glm::vec3(0.75, 0, 0),
glm::vec3(0.75, 0.25, 0),
};
GLushort elements[] = {
0, 1, 2, 3, 2, 1, 4, 5, 6, 7, 6, 5
};
glm::vec3 colors[] = {
glm::vec3(1, 0, 0),
glm::vec3(0, 1, 0)
};
GLuint vao, vboPos, vboCol, ebo;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vboCol);
glGenBuffers(1, &vboPos);
glGenBuffers(1, &ebo);
glBindBuffer(GL_ARRAY_BUFFER, vboPos);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vboCol);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
GLuint vs = loadShader("vs.glsl", GL_VERTEX_SHADER),
fs = loadShader("fs.glsl", GL_FRAGMENT_SHADER);
GLuint program = makeProgram(vs, 0, fs, { { "outColor", 0 } });
glUseProgram(program);
glBindBuffer(GL_ARRAY_BUFFER, vboPos);
GLuint posAttr = glGetAttribLocation(program, "pos");
glEnableVertexAttribArray(posAttr);
glVertexAttribPointer(posAttr, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboCol);
GLuint colAttr = glGetAttribLocation(program, "col");
glEnableVertexAttribArray(colAttr);
glVertexAttribPointer(colAttr, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribDivisor(colAttr, 1);
glEnable(GL_DEPTH_TEST);
SDL_Event e;
while(true)
{
while(SDL_PollEvent(&e) != 0)
{
if(e.type == SDL_QUIT)
return;
}
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawElementsInstanced(GL_TRIANGLES, sizeof(elements)/sizeof(elements[0]), GL_UNSIGNED_SHORT,
nullptr, sizeof(colors)/sizeof(colors[0]));
assert(glGetError() == GL_NO_ERROR);
SDL_GL_SwapWindow(g_window);
}
}
void init(int * argc, char ** argv)
{
std::ostringstream errMsgSStream;
// Initialize SDL
if(SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
errMsgSStream << "" << SDL_GetError();
throw std::runtime_error(errMsgSStream.str());
}
// Manage OpenGL attributes
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
// Create window
g_window = SDL_CreateWindow("Example", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, g_xRes, g_yRes, SDL_WINDOW_OPENGL);
if(!g_window)
{
errMsgSStream << "" << SDL_GetError();
throw std::runtime_error(errMsgSStream.str());
}
// Create a new device context
g_context = SDL_GL_CreateContext(g_window);
if(!g_context)
{
errMsgSStream << "" << SDL_GetError();
throw std::runtime_error(errMsgSStream.str());
}
// Initialize GLEW
glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK)
{
errMsgSStream << "failed to initialize GLEW";
throw std::runtime_error(errMsgSStream.str());
}
// Apparently GLEW can make glGetError return GL_INVALID_ENUM even if initialized correctly
while(glGetError() != GL_NO_ERROR);
if(atexit(cleanup))
{
errMsgSStream << "failed to register cleanup function";
throw std::runtime_error(errMsgSStream.str());
}
return;
}
void cleanup()
{
SDL_GL_DeleteContext(g_context);
SDL_DestroyWindow(g_window);
SDL_Quit();
}
GLuint loadShader(const char * filepath, GLenum type)
{
std::ifstream shaderFile;
shaderFile.exceptions(std::ios_base::failbit);
try {
shaderFile.open(filepath);
} catch(std::exception & ex) {
std::ostringstream ss;
ss << "failed to open file '" << filepath << "': " << ex.what();
throw std::runtime_error(ss.str());
}
shaderFile.exceptions(std::ios_base::goodbit);
GLuint res = glCreateShader(type);
// Get the length of the file
shaderFile.seekg(0, shaderFile.end);
size_t fileSize = shaderFile.tellg();
shaderFile.seekg(0, shaderFile.beg);
// Allocate space for, and read the header source
char * shaderSrc = new char[fileSize + 1];
shaderFile.read(shaderSrc, fileSize);
shaderSrc[fileSize] = '\0';
// Try to compile shader
GLint status;
glShaderSource(res, 1, &shaderSrc, nullptr);
glCompileShader(res);
glGetShaderiv(res, GL_COMPILE_STATUS, &status);
if(status != GL_TRUE)
{
char buf[0x10000];
std::ostringstream ss;
glGetShaderInfoLog(res, 0x10000, nullptr, buf);
ss << "failed to compile file '" << filepath << "':" << std::endl << buf;
glDeleteShader(res);
throw std::runtime_error(ss.str());
}
return res;
}
GLuint makeProgram(GLuint vs, GLuint gs, GLuint fs,
const std::unordered_map<std::string, GLuint> & fragDataLocations)
{
GLuint res = glCreateProgram();
// Attach shaders
if(vs) glAttachShader(res, vs);
if(gs) glAttachShader(res, gs);
if(fs) glAttachShader(res, fs);
// Bind data locations
for(const auto & ent : fragDataLocations)
glBindFragDataLocation(res, ent.second, ent.first.c_str());
// Link program
GLint status;
glLinkProgram(res);
glGetProgramiv(res, GL_LINK_STATUS, &status);
if(vs) glDetachShader(res, vs);
if(gs) glDetachShader(res, gs);
if(fs) glDetachShader(res, fs);
if(status != GL_TRUE)
{
char buf[0x10000];
std::ostringstream ss;
glGetProgramInfoLog(res, 0x10000, nullptr, buf);
ss << "failed to link program: " << std::endl << buf;
glDeleteProgram(res);
throw std::runtime_error(ss.str());
}
return res;
}
VS
#version 330
in vec3 pos;
in vec3 col;
out vec3 fCol;
void main()
{
gl_Position = vec4(pos, 1);
fCol = col;
}
PS:
#version 330
in vec3 fCol;
out vec4 outColor;
void main()
{
outColor = vec4(fCol, 1);
}
我期待的输出看起来像这样:
然而,我得到的是:
我的代码有问题,或者我的驱动程序没有正确实现此功能(我在Ubuntu Linux 16.04上使用专有的NVIDIA驱动程序v340.102)?
答案 0 :(得分:1)
首先,你的$item_id = 752;
表示当有3个时只有1个组件。然后,你渲染2个实例,每个实例都有两个四边形,具有相同的位置,所以你看不到第二个实例
您可以将第二个实例的位置改为例如glVertexAttribPointer
至少看到两个实例。