Related
I was following an OpenGL tutorial when I ran into an issue where I wasn't getting the expected outcome. I was expecting to see a triangle in a window, but instead, I got an empty window. I have made many changes to the code to help it run on my machine, but none fixed the issue. Some of these changes include adding:
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
to request the core profile context, adding a VAO with the VBO, I even downloaded the code from the tutorial, but to no avail. Does anyone know a way to fix my issue?
Code:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
static unsigned int CompileShader(unsigned int type, const std::string& source){
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if(result == GL_FALSE){
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader!" << std::endl;
std::cout << message << std::endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int CreateShader(const std::string& vertexshader, const std::string& fragmentshader){
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexshader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentshader);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if(glewInit() != GLEW_OK){
std::cout << "REEEEEEEEEEE" << std::endl;
}
float vertices[6] = {
-0.5f, -0.5f,
0.0f, 0.5f,
-0.5f, -0.5f
};
unsigned int buf;
glGenBuffers(1, &buf);
glBindBuffer(GL_ARRAY_BUFFER, buf);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
std::string vertexshader =
"#version 330 core\n"
"\n"
"in vec4 position;\n"
"out vec4 color;\n"
"\n"
"void main(){\n"
" gl_Position = position;\n"
" color = position;\n"
"}\n";
std::string fragmentshader =
"#version 330 core\n"
"\n"
"in vec4 in_color;\n"
"out vec4 color;\n"
"\n"
"void main(){\n"
" color = in_color;\n"
"}\n";
unsigned int shader = CreateShader(vertexshader, fragmentshader);
glUseProgram(shader);
glClearColor(0.33f, 0.33f, 0.33f, 1.0f);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
CMakeLists:
cmake_minimum_required (VERSION 3.5)
if(POLICY CMP0072)
cmake_policy(SET CMP0072 NEW)
else(NOT POLICY CMP0072)
message(STATUS "Error")
endif(POLICY CMP0072)
project (opengl-learning)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
include_directories(${GLFW_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR})
set (GCC_COVERAGE_LINK_FLAGS "-lglfw3 -pthread -ldl -lGLU -lGL -lrt -lXrandr -lXxf86vm -lXi -lXinerama -lX11 -lGLEW -lGLU -lGL")
add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -std=c++14")
set (source_dir "${PROJECT_SOURCE_DIR}/src/")
file (GLOB source_files "${source_dir}/*.cpp")
add_executable (opengl-learning ${source_files})
find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)
target_link_libraries(opengl-learning ${GLFW_LIBRARIES} ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES})
Versions (requesting core profile)
glGetString(GL_VERSION) >> 3.3 (Core Profile) Mesa 18.3.6
glGetString(GL_SHADING_LANGUAGE_VERSION) >> 3.30
OS: Linux Debian 10
If any extra information is required, feel free to ask.
When you use a core profile OpenGL Context you must create a Vertex Array Object:
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, buf);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
The default Vertex Array Object (0) is only valid using a compatibility profile OpenGL context:
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
I recommend reading Vertex Specification.
Hey there Im trying to draw a simple quad with 2 triangles in OpenGL through a vbo.
However I have looked at my code multiple times and I don't see what I am missing.
I ain't no Open GL expert, The code was working fine without any buffers however when I switchted to VBO Im not seeing anything anymore. OpenGL also doesn't provide any helpfull errors.
Image::Image(Graphics * GFX)
{
glm::vec2 corners[2];
corners[0] = glm::vec2(0, 0);
corners[1] = glm::vec2(1, 1);
vertices = new GLfloat[30]
{
//Vertices XYZ TexCoord X,Y
corners[0].x, corners[0].y, 0.0f, 0,0,
corners[0].x, corners[1].y, 0.0f, 0,1,
corners[1].x, corners[0].y, 0.0f, 1,0,
corners[1].x,corners[1].y,0.0f, 1,1,
corners[0].x, corners[1].y,0.0f, 0,1,
corners[1].x, corners[0].y, 0.0f, 1,0
};
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//Setting up some stuff
const char *vertexShaderSource =
"attribute vec4 vPosition; \n"
"attribute vec2 vTexCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = vPosition; \n"
"} \n";
const char *fragmentShaderSource =
"precision mediump float; \n"
"void main() \n"
"{ \n"
" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); \n"
"} \n";
// Load and compile the vertex/fragment shaders
vertexShader = GFX->LoadShader(GL_VERTEX_SHADER, (const char*)vertexShaderSource);
fragmentShader = GFX->LoadShader(GL_FRAGMENT_SHADER, (const char*)fragmentShaderSource);
// Create the program object
programObject = glCreateProgram();
// now we have the V and F shaders attach them to the progam object
glAttachShader(programObject, vertexShader);
glAttachShader(programObject, fragmentShader);
// Link the program
glLinkProgram(programObject);
// Check the link status
// Link the program
GLint AreTheylinked;
glGetProgramiv(programObject, GL_LINK_STATUS, &AreTheylinked);
if (!AreTheylinked)
{
GLint RetinfoLen = 0;
// check and report any errors
glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &RetinfoLen);
if (RetinfoLen > 1)
{
GLchar* infoLog = (GLchar*)malloc(sizeof(char) * RetinfoLen);
glGetProgramInfoLog(programObject, RetinfoLen, NULL, infoLog);
fprintf(stderr, "Error linking program:\n%s\n", infoLog);
free(infoLog);
}
glDeleteProgram(programObject);
}
positionLocation = glGetAttribLocation(programObject, "vPosition");
textureCoordLocation = glGetAttribLocation(programObject, "vTexCoord");
if (glGetError() == GL_NO_ERROR) {}
else
printf("Init failed!\n");
//End setting up
}
Image::~Image()
{
}
void Image::Draw()
{
std::cout << "Calling Draw on Image" << std::endl;
glUseProgram(programObject);
glEnable(GL_DEPTH_TEST);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLsizei stride = (5) * sizeof(GLfloat);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, 0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 6);
if (glGetError() != GL_NO_ERROR)
{
printf("UI Draw error\n");
}
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
And how I am loading the shaders:
GLuint Graphics::LoadShader(GLenum type, const char *shaderSrc)
{
// 1st create the shader object
GLuint TheShader = glCreateShader(type);
if (TheShader == 0) return FALSE; // can't allocate so stop.
// pass the shader source then compile it
glShaderSource(TheShader, 1, &shaderSrc, NULL);
glCompileShader(TheShader);
GLint IsItCompiled;
// After the compile we need to check the status and report any errors
glGetShaderiv(TheShader, GL_COMPILE_STATUS, &IsItCompiled);
if (!IsItCompiled)
{
GLint RetinfoLen = 0;
glGetShaderiv(TheShader, GL_INFO_LOG_LENGTH, &RetinfoLen);
if (RetinfoLen > 1)
{ // standard output for errors
char* infoLog = (char*)malloc(sizeof(char) * RetinfoLen);
glGetShaderInfoLog(TheShader, RetinfoLen, NULL, infoLog);
fprintf(stderr, "Error compiling this shader:\n%s\n", infoLog);
free(infoLog);
}
glDeleteShader(TheShader);
return FALSE;
}
return TheShader;
}
It worked fine without a buffer previously, and saw a white square by using:
glVertexAttribPointer(0, 6, GL_FLOAT, GL_FALSE, 0, vertices);
But now I want to add texture coordinates to my quad through a VBO but nothing shows anymore.
Smoothy101
Your buffer creation looks fine - the problem is your attribute pointer setup. You've added texture coordinates which has changed data layout for each vertex, but you've not handled that in your code.
You need something like this:
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, stride, 0);
glVertexAttribPointer(textureCoordLocation, 2, GL_FLOAT, GL_FALSE, stride, 8);
... not this:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, 0);
Using GLFW, the C++ OpenGL ES code below calculates the square roots of five numbers and outputs them on the command line. The code makes use of Transform Feedback. When I compile on Ubuntu 17.10, using the following command, I get the result I expect:
$ g++ tf.cpp -lGL -lglfw
If I use Emscripten, however, an exception is thrown, which indicates that
glMapBufferRange is only supported when access is MAP_WRITE|INVALIDATE_BUFFER. I do want to read rather than write, so perhaps I shouldn't use glMapBufferRange, but what can I use instead? I have tried on both Firefox and Chromium. The command I use to compile with Emscripten is:
$ em++ -std=c++11 tf.cpp -s USE_GLFW=3 -s USE_WEBGL2=1 -s FULL_ES3=1 -o a.out.html
The code follows:
#include <iostream>
#define GLFW_INCLUDE_ES3
#include <GLFW/glfw3.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
static const GLuint WIDTH = 800;
static const GLuint HEIGHT = 600;
static const GLchar *vertex_shader_src =
"#version 300 es\n"
"precision mediump float;\n"
"in float inValue;\n"
"out float outValue;\n"
"void main() {\n"
" outValue = sqrt(inValue);\n"
"}\n";
// Emscripten complains if there's no fragment shader
static const GLchar *fragment_shader_src =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 colour;\n"
"void main() {\n"
" colour = vec4(1.0, 1.0, 0.0, 1.0);\n"
"}\n";
static const GLfloat vertices[] = {
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
};
GLint get_shader_prog(const char *vert_src, const char *frag_src = "")
{
enum Consts { INFOLOG_LEN = 512 };
GLchar infoLog[INFOLOG_LEN];
GLint fragment_shader, vertex_shader, shader_program, success;
shader_program = glCreateProgram();
auto mk_shader = [&](GLint &shader, const GLchar **str, GLenum shader_type) {
shader = glCreateShader(shader_type);
glShaderSource(shader, 1, str, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, INFOLOG_LEN, NULL, infoLog);
std::cout << "ERROR::SHADER::COMPILATION_FAILED\n" << infoLog << '\n';
}
glAttachShader(shader_program, shader);
};
mk_shader(vertex_shader, &vert_src, GL_VERTEX_SHADER);
mk_shader(fragment_shader, &frag_src, GL_FRAGMENT_SHADER);
const GLchar* feedbackVaryings[] = { "outValue" };
glTransformFeedbackVaryings(shader_program, 1, feedbackVaryings,
GL_INTERLEAVED_ATTRIBS);
glLinkProgram(shader_program);
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader_program, INFOLOG_LEN, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << '\n';
}
glUseProgram(shader_program);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return shader_program;
}
int main(int argc, char *argv[])
{
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFWwindow *window = glfwCreateWindow(WIDTH, HEIGHT, __FILE__, NULL, NULL);
glfwMakeContextCurrent(window);
GLuint shader_prog = get_shader_prog(vertex_shader_src, fragment_shader_src);
GLint inputAttrib = glGetAttribLocation(shader_prog, "inValue");
glViewport(0, 0, WIDTH, HEIGHT);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLfloat data[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glVertexAttribPointer(inputAttrib, 1, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(inputAttrib);
GLuint tbo;
glGenBuffers(1, &tbo);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(data),
nullptr, GL_STATIC_READ);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
glEnable(GL_RASTERIZER_DISCARD);
glBeginTransformFeedback(GL_POINTS);
glDrawArrays(GL_POINTS, 0, 5);
glEndTransformFeedback();
glDisable(GL_RASTERIZER_DISCARD);
glFlush();
GLfloat feedback[5]{1,2,3,4,5};
void *void_buf = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER,0,
sizeof(feedback), GL_MAP_READ_BIT);
GLfloat *buf = static_cast<GLfloat *>(void_buf);
for (int i = 0; i < 5; i++)
feedback[i] = buf[i];
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
for (int i = 0; i < 5; i++)
std::cout << feedback[i] << ' ';
std::cout << std::endl;
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &tbo);
glDeleteVertexArrays(1, &vao);
glfwTerminate();
return 0;
}
As has been mentioned by another answer, WebGL 2.0 is close to OpenGL ES 3.0, but confusingly does not define glMapBufferRange() function, so that Emscripten tries emulating only part of functionality of this function.
Real WebGL 2.0, however, exposes glGetBufferSubData() analog, which does not exist in OpenGL ES, but exist in desktop OpenGL. The method can be wrapped in code via EM_ASM_:
void myGetBufferSubData (GLenum theTarget, GLintptr theOffset, GLsizeiptr theSize, void* theData)
{
#ifdef __EMSCRIPTEN__
EM_ASM_(
{
Module.ctx.getBufferSubData($0, $1, HEAPU8.subarray($2, $2 + $3));
}, theTarget, theOffset, theData, theSize);
#else
glGetBufferSubData (theTarget, theOffset, theSize, theData);
#endif
}
Fetching VBO data back is troublesome in multi-platform code:
OpenGL 1.5+
glGetBufferSubData(): YES
glMapBufferRange(): YES
OpenGL ES 2.0
glGetBufferSubData(): NO
glMapBufferRange(): NO
OpenGL ES 3.0+
glGetBufferSubData(): NO
glMapBufferRange(): YES
WebGL 1.0
glGetBufferSubData(): NO
glMapBufferRange(): NO
WebGL 2.0
glGetBufferSubData(): YES
glMapBufferRange(): NO
So that:
Desktop OpenGL gives maximum flexibility.
OpenGL ES 2.0 and WebGL 1.0 give no chance to retrieve data back.
OpenGL ES 3.0+ gives only mapping buffer.
WebGL 2.0 gives only getBufferSubData().
WebGL2 does not support MapBufferRange because it would be a security nightmare. Instead it supports getBufferSubData. I have no idea if that is exposed to WebAssembly in emscripten. Emscripten is emulating MapBufferRange for the cases you mentioned by using bufferData. See here and here
If getBufferSubData is not supported you can add it. See the code in library_gl.js for how readPixels is implemented and use that as inspiration for how to expose getBufferSubData to WebAssembly. Either that or add some inline JavaScript with the _EM_ASM. I haven't done it but googling for "getBufferSubData emscripten" bought up this gist
I've been trying to get a handle on using surface references in CUDA for OpenGL interop. I been able to use a surface object without problems to do exactly this, but I want to support older hardware (compute < 2.5) that does not support surface objects.
Please note: I had a similar question yesterday, and it was suggested that I write a simple proof-of-problem. In doing that I've run into a slightly different problem, so I'm asking a new question. In this case, in the code listed below, when I call cudaBindSurfaceToArray I get the error
CUDA error at test.cu:75 code=37(cudaErrorInvalidSurface) "cudaBindSurfaceToArray(outputSurface, textureArray)"
Unfortunately this "minimum" sample code is pretty long because of the GL interop. It has no external dependencies, only the CUDA development files, and the CUDA samples. It compiles in Linux with the command
nvcc -m64 -ccbin g++ -gencode arch=compute_20,code=sm_20 -I<samples_path>/NVIDIA_CUDA-7.0_Samples/common/inc -lGL -lglut test.cu -o test
This code is very similar to the CUDA example simpleSurfaceWrite. I don't understand how the surface reference in my code is any different than the surface reference in that example. For the record, I am able to successfully compile and run simpleSurfaceWrite. Please note that this uses this definition of cudaBindSurfaceToArray from the CUDA C++ API, just like simpleSurfaceWrite. I am getting a runtime error, not a compile error.
Here's the code:
#define GL_GLEXT_PROTOTYPES
#include <GL/freeglut.h>
#include <cuda_runtime.h>
#include <cuda_gl_interop.h>
#include <helper_functions.h>
#include <helper_cuda.h>
#include <helper_cuda_gl.h>
GLuint texID;
GLuint bufID;
GLenum passthroughVertexShaderID;
GLenum simpleFragmentShaderID;
GLenum simpleProgramID;
GLint fragmentShaderTextureID;
cudaGraphicsResource *texResource;
const int width = 640;
const int height = 480;
const int blockSize = 8;
// Define a CUDA surface reference
surface<void, cudaSurfaceType2D> outputSurface;
// Define some simple GL shaders
const GLchar *passthroughVertexSource =
"#version 130"
"in vec3 positionAttrib;"
"in vec2 textureAttrib;"
"out vec2 texCoord;"
"void main()"
"{"
" gl_Position = vec4(positionAttrib,1.0f);"
" texoord = textureAttrib;"
"}";
const GLchar *simpleFragmentSource =
"#version 130"
"uniform sampler2DRect tex;"
"in vec2 texCoord;"
"out vec4 fragColor;"
"void main()"
"{"
" fragColor = texture2DRect(tex, texCoord);"
"}";
__global__ void cudaTestKernel() {
int x = blockIdx.x*blockDim.x + threadIdx.x;
int y = blockIdx.y*blockDim.y + threadIdx.y;
float4 sample = make_float4(0.0f, 1.0f, 0.0f, 1.0f);
surf2Dwrite(sample, outputSurface, (int)sizeof(float4)*x, y, cudaBoundaryModeClamp);
}
void displayFunc() {
// Clear the screen (if nothing else is drawn, screen will be blue)
glClear(GL_COLOR_BUFFER_BIT);
// Make the OpenGL texture available to CUDA through the `outputSurface' surface reference
checkCudaErrors(cudaGraphicsMapResources(1, &texResource, 0));
cudaArray *textureArray;
checkCudaErrors(cudaGraphicsSubResourceGetMappedArray(&textureArray, texResource, 0, 0));
// Bind the array to the surface. This is where I'm getting an error
checkCudaErrors(cudaBindSurfaceToArray(outputSurface, textureArray));
// Call the CUDA kernel
dim3 grid = dim3(blockSize,blockSize,1);
dim3 block = dim3(width/blockSize, height/blockSize, 1);
cudaTestKernel<<<grid,block>>>();
checkCudaErrors(cudaGraphicsUnmapResources(1, &texResource, 0));
// Call the OpenGL shaders to draw the texture
// If the CUDA kernel was successful, the screen will be green
// If not, it will be gray.
glActiveTexture(GL_TEXTURE0);
glUseProgram(simpleProgramID);
glUniform1i(fragmentShaderTextureID, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_NV, texID);
glBindBuffer(GL_ARRAY_BUFFER, bufID);
glDrawArrays(GL_QUADS, 0, 4);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
glutSwapBuffers();
}
int main(int argc, char **argv) {
float *floatBuf;
// Initialize GLUT/GL
glutInit (&argc, argv);
glutInitWindowSize(width,height);
glutCreateWindow("Surface Test");
glutDisplayFunc(displayFunc);
// Initialize CUDA
findCudaGLDevice(argc, (const char**)argv);
// Create Texture
floatBuf = new float[width*height*4];
for(unsigned int i=0;i<width*height*4;i++)
floatBuf[i]=0.5f;
glGenTextures(1, &texID);
glEnable(GL_TEXTURE_RECTANGLE_NV);
glBindTexture(GL_TEXTURE_RECTANGLE_NV, texID);
glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA32F_ARB, width, height, 0, GL_RGBA, GL_FLOAT, floatBuf);
delete [] floatBuf;
// Map Texture into CUDA
checkCudaErrors(cudaGraphicsGLRegisterImage(&texResource, texID, GL_TEXTURE_RECTANGLE_NV, cudaGraphicsRegisterFlagsSurfaceLoadStore));
// Create shader program
simpleProgramID = glCreateProgram();
simpleFragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
passthroughVertexShaderID = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(simpleFragmentShaderID, 1, &simpleFragmentSource, NULL);
glShaderSource(passthroughVertexShaderID, 1, &passthroughVertexSource, NULL);
glCompileShader(simpleFragmentShaderID);
glCompileShader(passthroughVertexShaderID);
glAttachShader(simpleProgramID, simpleFragmentShaderID);
glAttachShader(simpleProgramID, passthroughVertexShaderID);
glBindAttribLocation(simpleProgramID, 0, "positionAttrib");
glBindAttribLocation(simpleProgramID, 1, "textureAttrib");
glLinkProgram(simpleProgramID);
fragmentShaderTextureID = glGetUniformLocation(simpleProgramID, "tex");
// Create Vertex Array Buffer for rendering texture on screen
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
float v[] = {-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
0.0f, 0.0f,
width, 0.0f,
width, height,
0.0f, height
};
glGenBuffers(1, &bufID);
glBindBuffer(GL_ARRAY_BUFFER, bufID);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4+sizeof(float)*2*4, v, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(float)*3*4));
glClearColor(0.f,0.f,1.f,1.f);
glutMainLoop();
}
I'm currently trying to write a OpenGL program in C++. When I try to compile my program I get undefined references, everywhere where i call member functions of my class, although I call these functions from member functions...
These are the error messages I get:
make clean && make
rm -f *.o *~ main
g++ -c main.cpp -o main.o
g++ -c renderer.cpp -o renderer.o
g++ -o main main.o renderer.o -lglut -lGL -lGLEW
renderer.o: In function `Renderer::resize(int, int)':
renderer.cpp:(.text+0x299): undefined reference to `Renderer::Perspective(float*, float, float, float, float)'
renderer.o: In function `Renderer::setupShaders()':
renderer.cpp:(.text+0x43d): undefined reference to `Renderer::loadShaderSrc(char const*, int&)'
renderer.cpp:(.text+0x456): undefined reference to `Renderer::loadShaderSrc(char const*, int&)'
renderer.cpp:(.text+0x4e7): undefined reference to `Renderer::printShaderInfoLog(int)'
renderer.cpp:(.text+0x4fe): undefined reference to `Renderer::printShaderInfoLog(int)'
renderer.cpp:(.text+0x568): undefined reference to `Renderer::printProgramInfoLog(int)'
collect2: Fehler: ld gab 1 als Ende-Status zurück
make: *** [main] Fehler 1
This are my source files:
main.cpp:
#include "renderer.h"
static Renderer *renderer;
static void glutDisplay()
{
renderer->display();
glutSwapBuffers();
}
static void glutResize(int w, int h)
{
renderer->resize(w, h);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowPosition(100, 100);
glutInitWindowSize(320, 320);
glutCreateWindow("Title");
GLenum res = glewInit();
if(res != GLEW_OK)
return -1;
glutDisplayFunc(glutDisplay);
glutReshapeFunc(glutResize);
renderer = new Renderer;
renderer->init();
glutMainLoop();
return 0;
}
renderer.cpp:
#include "renderer.h"
Renderer::Renderer() : programID(0.0), vao(0), vbo(0), vertexLoc(0), colorLoc(0), projectionLoc(0), modelviewLoc(0)
{}
Renderer::~Renderer()
{
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glDeleteProgram(programID);
glDeleteShader(vertShaderID);
glDeleteShader(fragShaderID);
}
void Renderer::init()
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_DEPTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
setupShaders();
//glGenVertexArrays(1, vao);
glGenBuffers(1, &vbo);
float triangleVertexData[] = {
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertexData), triangleVertexData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void Renderer::resize(int w, int h)
{
glViewport(0, 0, w, h);
Perspective(projection, 45.0f, (float)w/(float)h, 0.5f, 4.0f);
}
void Renderer::display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programID);
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, projection);
glUniformMatrix4fv(modelviewLoc, 1, GL_FALSE, modelview);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(vertexLoc);
glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), 0);
glDisableVertexAttribArray(vertexLoc);
glEnableVertexAttribArray(colorLoc);
glVertexAttribPointer(colorLoc, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*) (3 * sizeof(float)));
glDisableVertexAttribArray(colorLoc);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void Renderer::setupShaders()
{
vertShaderID = glCreateShader(GL_VERTEX_SHADER);
fragShaderID = glCreateShader(GL_FRAGMENT_SHADER);
GLint vertlength, fraglength;
const char* vertexshader = loadShaderSrc("shaders/simple.vert", vertlength);
const char* fragmentshader = loadShaderSrc("shaders/simple.frag", fraglength);
glShaderSource(vertShaderID, 1, &vertexshader, &vertlength);
glShaderSource(fragShaderID, 1, &fragmentshader, &fraglength);
free((char*) vertexshader);
free((char*) fragmentshader);
glCompileShader(vertShaderID);
glCompileShader(fragShaderID);
printShaderInfoLog(vertShaderID);
printShaderInfoLog(fragShaderID);
programID = glCreateProgram();
glAttachShader(programID, vertShaderID);
glAttachShader(programID, fragShaderID);
glLinkProgram(programID);
printProgramInfoLog(programID);
vertexLoc = glGetAttribLocation(programID, "vertex_position");
colorLoc = glGetAttribLocation(programID, "vertex_color");
projectionLoc = glGetUniformLocation(programID, "projection");
modelviewLoc = glGetUniformLocation(programID, "modelview");
}
void printShaderInfoLog(GLint obj)
{
int infoLogLength = 0;
int returnLength = 0;
char *infoLog;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength);
if (infoLogLength > 0) {
infoLog = (char *)malloc(infoLogLength);
glGetShaderInfoLog(obj, infoLogLength, &returnLength, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLint obj)
{
int infoLogLength = 0;
int returnLength = 0;
char *infoLog;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength);
if (infoLogLength > 0) {
infoLog = (char *)malloc(infoLogLength);
glGetProgramInfoLog(obj, infoLogLength, &returnLength, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
const char* loadShaderSrc(const char *filename, GLint &filesize)
{
std::ifstream file(filename, std::ios::in);
std::string shader( (std::istreambuf_iterator<char>(file) ),
(std::istreambuf_iterator<char>() ) );
filesize = (GLint) shader.length();
return shader.c_str();
}
void Perspective(float *a, float fov, float aspect, float zNear, float zFar)
{
float f = 1.0f / float(tan(fov / 2.0f * (PI / 180.0f)));
for(int i = 0; i < 16; i++) a[i] = 0.0f;
a[0] = f / aspect;
a[1 * 4 + 1] = f;
a[2 * 4 + 2] = (zNear + zFar) / (zNear - zFar);
a[3 * 4 + 2] = 2.0f * zNear * zFar / (zNear - zFar);
a[2 * 4 + 3] = -1.0f;
}
void Modelview(float *mv)
{
for(int i = 0; i < 16; i++) mv[i] = 0.0f;
for(int i = 0; i < 4; i++) mv[i * 4 + i] = 1.0f;
mv[3 * 4 + 2] = -2.0f;
}
renderer.h:
#include <cmath>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <GL/glew.h>
#include <GL/glut.h>
#define PI 3.14159
class Renderer {
private:
GLuint programID;
GLuint vertShaderID;
GLuint fragShaderID;
GLuint vao;
GLuint vbo;
GLint vertexLoc;
GLint colorLoc;
GLint projectionLoc;
GLint modelviewLoc;
float projection[16];
float modelview[16];
public:
Renderer();
~Renderer();
void init();
void resize(int w, int h);
void display();
private:
void setupShaders();
void printShaderInfoLog(GLint obj);
void printProgramInfoLog(GLint obj);
const char* loadShaderSrc(const char *filename, GLint &filesize);
void Perspective(float *a, float fov, float aspect, float zNear, float zFar);
void Modelview();
};
I compile using this Makefile (using g++ with linux):
CC = g++
CFLAGS = -Wall -g
INCLUDES =
LFLAGS =
LIBS = -lglut -lGL -lGLEW
SRCS = main.cpp renderer.cpp
OBJS = $(SRCS:.cpp=.o)
MAIN = main
all: $(MAIN)
$(MAIN): $(OBJS)
$(CC) $(CLFAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
.cpp.o:
$(CC) $(CLFAGS) $(INCLUDES) -c $< -o $#
clean:
$(RM) *.o *~ $(MAIN)
It's probably just a stupid beginner mistake but I cant find it. I simply don't understand how I can get a undefined reference to a function if that function is defined in the same file.
I hope you can help me =)
In your cpp file the Perspective function is called Perspective rather than Renderer::Perspective. This means that the Perspective method is not actually defined, even though there is now an unused function called Perspective.
Note: you have the same issue with other private methods of your Renderer class.