Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am writing a program using shaders and getting some error when running the built exe.
Shader program failed to link
The fragment shader uses varying color, but previous shader does not write to it.
Out of resource error.
This is my code:
example.cpp:
// Two-Dimensional Sierpinski Gasket
// Generated using randomly selected vertices and bisection
#include "Angel.h"
const int NumTimesToSubdivide = 5;
const int NumTetraeder = 1024;
const int NumVertices = 9 * NumTetraeder;
vec4 points[NumVertices];
int Index = 0;
int fps = 20;
float angle_param = 0.5;
float etime;
GLint time_loc;
//----------------------------------------------------------------------------
void triangle(const vec4& a, const vec4& b, const vec4& c)
{
points[Index++] = a;
points[Index++] = b;
points[Index++] = c;
}
void divide_tetraeder(const vec4& a, const vec4& b, const vec4& c, const vec4& d, int count)
{
if(count > 0)
{
//compute midpoints
vec4 ab = (a + b) / 2.0;
vec4 ac = (a + c) / 2.0;
vec4 ad = (a + d) / 2.0;
vec4 bc = (b + c) / 2.0;
vec4 bd = (b + d) / 2.0;
vec4 cd = (c + d) / 2.0;
divide_tetraeder( a, ab, ac, ad, count -1);
divide_tetraeder(ab, b, bc, bd, count -1);
divide_tetraeder(ad, bd, cd, d, count -1);
divide_tetraeder(ac, bc, c, cd, count -1);
}
else
{
triangle(a,b,c);
triangle(b,d,c);
triangle(d,a,c);
}
}
void
init( void )
{
// Specifiy the vertices for the initial tetraeder
vec4 vertices[4] = {
vec4( 0.0, -1.0, -1.0, 1.0 ),
vec4( 0.866, -1.0, 0.5, 1.0 ),
vec4( 0.0, 1.0, 0.0, 1.0 ),
vec4( -0.866, -1.0, 0.5, 1.0 )
};
divide_tetraeder(vertices[0], vertices[1], vertices[2], vertices[3], NumTimesToSubdivide);
// Create a vertex array object
GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
// Create and initialize a buffer object
GLuint buffer;
glGenBuffers( 1, &buffer );
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW );
// Load shaders and use the resulting shader program
GLuint program = InitShader( "../shader/vshader_03.glsl", "../shader/fshader_03.glsl" );
glUseProgram( program );
// Initialize the vertex position attribute from the vertex shader
GLuint loc = glGetAttribLocation( program, "vPosition" );
glEnableVertexAttribArray( loc );
glVertexAttribPointer( loc, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
//Initialize the time parameter
time_loc = glGetUniformLocation(program, "time");
glClearColor( 1.0, 1.0, 1.0, 1.0 ); // white background
}
//----------------------------------------------------------------------------
void
display( void )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the window
glDrawArrays( GL_TRIANGLES, 0, NumVertices ); // draw the points
glutSwapBuffers();
}
//----------------------------------------------------------------------------
void
keyboard( unsigned char key, int x, int y )
{
switch ( key ) {
case 033:
exit( EXIT_SUCCESS );
break;
}
}
void specialKeys(int key, int x, int y)
{
switch (key ) {
case GLUT_KEY_UP:
fps += 1;
std::cout << "fps: " << fps << std::endl;
break;
case GLUT_KEY_DOWN:
if(fps > 1) fps -= 1;
std::cout << "fps: " << fps << std::endl;
break;
case GLUT_KEY_LEFT:
angle_param -= 0.05;
std::cout << "angle_param: " << angle_param << std::endl;
break;
case GLUT_KEY_RIGHT:
angle_param += 0.05;
std::cout << "angle_param: " << angle_param << std::endl;
break;
default:
break;
}
}
//----------------------------------------------------------------------------
void timer(int value){
static float currentangle = 0.0f;
currentangle += angle_param;
float angle = currentangle*DegreesToRadians; // small angle in radians
//**************************************************************
//Füge hier deinen code ein, der die Punkte um die z-Achse dreht und neu zur Grafikkarte hochlädt
//Benutze die Funktion RotateY um eine 4x4 Rotationsmatrix zu erzeugen
mat4 rotMat = RotateY(angle);
//Berechne die rotierten Vertices auf der CPU durch Multiplikation mit der Matrix
for(int i = 0; i < NumVertices; i++) {
points[i] = rotMat * points[i];
}
//Anzahl der Sekunden seit dem letzten Aufruf
//http://www.opengl.org/documentation/specs/glut/spec3/node70.html
etime = 0.001 * glutGet(GLUT_ELAPSED_TIME);
//Schicke diesen Wert zum Vertex Shader
glUniform1f(time_loc, etime);
//Sende alle Vertices erneut an die GPU
glBufferData( GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW );
//*******************************************************************/
glutPostRedisplay();
int delay = ceil(1000.0f / fps);
glutTimerFunc( delay,timer,0);
}
int
main( int argc, char **argv )
{
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
//glEnable(GL_DEPTH_TEST);
glutInitWindowSize( 512, 512 );
// If you are using freeglut, the next two lines will check if
// the code is truly 3.2. Otherwise, comment them out
//glutInitContextVersion( 3, 1 );
//glutInitContextProfile( GLUT_CORE_PROFILE );
glutCreateWindow( "Sierpinski Gasket" );
glewInit();
init();
glutDisplayFunc( display );
glutKeyboardFunc( keyboard );
glutSpecialFunc( specialKeys );
int delay = ceil(1000.0f / fps);
glutTimerFunc( delay,timer,0);
glutMainLoop();
return 0;
}
InitShader.cpp:
#include "Angel.h"
char vSource[] = "#version 130\n in vec4 vPosition;\nvoid main() {\n gl_Position = vPosition;\n}\n";
char fsource[] = "#version 130\n out vec4 color;\n void main() {\n color = vec4(1.0, 0.0, 0.0, 1.0);\n}\n";
namespace Angel {
// Create a NULL-terminated string by reading the provided file
static char*
readShaderSource(const char* shaderFile)
{
//öffne die Datei
FILE* fp = fopen(shaderFile, "r");
//wenn das nicht klappt, hör sofort auf
if ( fp == NULL ) { return NULL; }
//finde heraus wie groß in bytes die datei ist
//1. gehe zum ende der datei
fseek(fp, 0L, SEEK_END);
//2. frage nach der Größe
long size = ftell(fp);
//mache einen speicherbereich für den shadertext von ausreichender Größe
char* buf = new char[size + 1];
//gehe zum Anfang der datei
fseek(fp, 0L, SEEK_SET);
//lies das erste Zeichen
char c;
c = fgetc(fp);
//initialisiere den index für den buffer
int i = 0;
//Solange das Ende der Datei nicht erreicht ist
while(c != EOF)
{
//Zeichen abspeichern
buf[i] = c;
//Nächstes Zeichen lesen
c = fgetc(fp);
//index für den Puffer inkrementieren
i++;
}
//Am Ende den Puffer mit 0 terminieren
buf[i] = '\0';
//Datei schließen
fclose(fp);
//printf("buf is: %s",buf);
return buf;
}
// Create a GLSL program object from vertex and fragment shader files
GLuint
InitShader(const char* vShaderFile, const char* fShaderFile)
{
struct Shader {
const char* filename;
GLenum type;
GLchar* source;
} shaders[2] = {
{ vShaderFile, GL_VERTEX_SHADER, NULL },
{ fShaderFile, GL_FRAGMENT_SHADER, NULL }
};
GLuint program = glCreateProgram();
for ( int i = 0; i < 2; ++i ) {
Shader& s = shaders[i];
s.source = readShaderSource( s.filename );
if ( shaders[i].source == NULL ) {
std::cerr << "Failed to read " << s.filename << std::endl;
exit( EXIT_FAILURE );
}
/*
if(i==0) s.source = vSource;
else s.source = fsource;
*/
GLuint shader = glCreateShader( s.type );
glShaderSource( shader, 1, (const GLchar**) &s.source, NULL );
glCompileShader( shader );
GLint compiled;
glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );
if ( !compiled ) {
std::cerr << s.filename << " failed to compile:" << std::endl;
GLint logSize;
glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &logSize );
char* logMsg = new char[logSize];
glGetShaderInfoLog( shader, logSize, NULL, logMsg );
std::cerr << logMsg << std::endl;
delete [] logMsg;
exit( EXIT_FAILURE );
}
//delete [] s.source;
glAttachShader( program, shader );
}
/* link and error check */
glLinkProgram(program);
GLint linked;
glGetProgramiv( program, GL_LINK_STATUS, &linked );
if ( !linked ) {
std::cerr << "Shader program failed to link" << std::endl;
GLint logSize;
glGetProgramiv( program, GL_INFO_LOG_LENGTH, &logSize);
char* logMsg = new char[logSize];
glGetProgramInfoLog( program, logSize, NULL, logMsg );
std::cerr << logMsg << std::endl;
delete [] logMsg;
exit( EXIT_FAILURE );
}
/* use program object */
glUseProgram(program);
return program;
}
} // Close namespace Angel block
vshader_03.glsl:
#version 130
uniform float time;
in vec4 vPosition;
void main()
{
vec4 temp = vPosition;
temp.x *= (1+sin(time));
gl_Position = temp;
}
fshader_03.glsl:
#version 130
in vec4 color;
void main()
{
gl_FragColor = color;
}
Your fragment shader has a varying variable in vec4 color, but none of the preceding shader stages (the vertex shader in your case) does define an varying output out vec4 color. This is also what the error message told you. Solution: Your vertex shader must define a out vec4 color and write to it.
Related
I'm having classes of computer graphics on OpenGL. There we study and work with Visual Studio 2015 while I run Linux on my laptop. So there some differences between composing a program in our classes and in lessons I found on Wikibooks. I tried to run one tutorial code from there and everything was fine, while I couldn't run my code I wrote at my lesson.
So I tried manipulating with my and tutorial code. I succeeded a few. The program runs but not shows my figures. So it actually must show a chesstable. But, for my regret, it shows a background color only. What may be wrong with that?
The first part on onDisplay() is not displayed. The commented part is from tutorial which works and shows a triangle.
Full code:
#include <stdio.h>
#include <stdlib.h>
/* Use glew.h instead of gl.h to get all the GL prototypes declared */
#include <GL/glew.h>
/* Using the GLUT library for the base windowing setup */
#include <GL/freeglut.h>
GLuint program;
GLint attribute_coord2d;
int init_resources()
{
GLint compile_ok = GL_FALSE, link_ok = GL_FALSE;
GLuint vs = glCreateShader( GL_VERTEX_SHADER );
const char *vs_source =
#ifdef GL_ES_VERSION_2_0
"#version 100\n" // OpenGL ES 2.0
#else
"#version 120\n" // OpenGL 2.1
#endif
"attribute vec2 coord2d; "
"void main(void) { "
" gl_Position = vec4(coord2d, 0.0, 1.0); "
"}";
glShaderSource( vs, 1, &vs_source, NULL );
glCompileShader( vs );
glGetShaderiv( vs, GL_COMPILE_STATUS, &compile_ok );
if( !compile_ok )
{
fprintf( stderr, "Error in vertex shader\n" );
return 0;
}
GLuint fs = glCreateShader( GL_FRAGMENT_SHADER );
const char *fs_source =
#ifdef GL_ES_VERSION_2_0
"#version 100\n" // OpenGL ES 2.0
#else
"#version 120\n" // OpenGL 2.1
#endif
"void main(void) { "
" gl_FragColor[0] = 0.0; "
" gl_FragColor[1] = 0.0; "
" gl_FragColor[2] = 1.0; "
"}";
glShaderSource( fs, 1, &fs_source, NULL );
glCompileShader( fs );
glGetShaderiv( fs, GL_COMPILE_STATUS, &compile_ok );
if( !compile_ok )
{
fprintf( stderr, "Error in fragment shader\n" );
return 0;
}
program = glCreateProgram();
glAttachShader( program, vs );
glAttachShader( program, fs );
glLinkProgram( program );
glGetProgramiv( program, GL_LINK_STATUS, &link_ok );
if( !link_ok )
{
fprintf( stderr, "glLinkProgram:" );
return 0;
}
const char* attribute_name = "coord2d";
attribute_coord2d = glGetAttribLocation( program, attribute_name );
if( attribute_coord2d == -1 )
{
fprintf( stderr, "Could not bind attribute %s\n", attribute_name );
return 0;
}
return 1;
}
void chess( double x, double y, double w, double h, int k )
{
glColor3f( 0.6, 0.6, 0.6 );
glRecti( 20, 20, 480, 480 );
for( int i = 0; i < 8; i++ )
{
glRasterPos2i( ( i + 1 )*x + 20, 30 );
glutBitmapCharacter( GLUT_BITMAP_9_BY_15, 'A' + i );
}
for( int j = 0; j < 8; j++ )
{
for( int i = 0; i < 8; i++ )
{
if( k % 2 == 0 )
{
glColor3f( 1, 1, 1 );
}
else glColor3f( 0, 0, 0 );
glRecti( x + w*i, y + h*j, 2 * x + w*i, 2 * y + h*j );
k++;
}
k++;
}
}
void onDisplay()
{
glClearColor( 0.5, 1.0, 1.0, 1.0 );
glClear( GL_COLOR_BUFFER_BIT );
glUseProgram( program );
glEnableVertexAttribArray( attribute_coord2d );
double x, y, w, h;
int k;
x = 50;
y = 50;
h = 50;
w = 50;
k = 1;
chess( x, y, w, h, k );
glFlush();
/*
GLfloat triangle_vertices[] = {
0.0, 0.8,
-0.8, -0.8,
0.8, -0.8,
};
// Describe our vertices array to OpenGL (it can't guess its format automatically)
glVertexAttribPointer(
attribute_coord2d, // attribute
2, // number of elements per vertex, here (x,y)
GL_FLOAT, // the type of each element
GL_FALSE, // take our values as-is
0, // no extra data between each position
triangle_vertices // pointer to the C array
);
// Push each element in buffer_vertices to the vertex shader
glDrawArrays(GL_TRIANGLES, 0, 3);
*/
glDisableVertexAttribArray( attribute_coord2d );
glutSwapBuffers();
}
void free_resources()
{
glDeleteProgram( program );
}
int main( int argc, char* argv[] )
{
glutInit( &argc, argv );
glutInitContextVersion( 2, 0 );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
glutInitWindowSize( 640, 640 );
glutCreateWindow( "chesstable" );
GLenum glew_status = glewInit();
if( glew_status != GLEW_OK )
{
fprintf( stderr, "Error: %s\n", glewGetErrorString( glew_status ) );
return 1;
}
if( init_resources() )
{
glutDisplayFunc( onDisplay );
glutMainLoop();
}
free_resources();
return 0;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm trying to write a modern OpenGL application from scratch and I can't get a basic Triangle to render. This is odd because I've managed this in some older code and I cant find a difference in how I've done everything.
I'm using shaders, and as far as I can tell they're compiled and linked properly.
I'm using GLFW and gl3w.
All I get from this code is my window with the clear color on it.
I'll Dump my code
Main.cpp
#include <GL/gl3w.h>
#include "Display/Display.h"
#include "Shader/Shader.h"
#include "Mesh/Mesh.h"
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define WINDOW_TITLE "CompSci Coursework"
int main() {
//Create Display and Context
Display display( WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE );
//Create Basic Shaders
Shader basicShader( "BasicShader" );
basicShader.useShader();
//Create VAO
GLuint VAO;
glGenVertexArrays( 1, &VAO );
glBindVertexArray( VAO );
std::vector<float> verticies = {
-0.5f, -0.5f,
0.5f, -0.5f,
0.0f, 0.5f
};
//Create Mesh
Mesh triangle( verticies );
//While Open Loop
while ( !display.CheckShouldClose()) {
//Clear Buffer
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
//Draw Triangle
glDrawArrays( GL_TRIANGLES, 0, 3 );
//Update Display
display.Update();
}
return 0;
}
Display.cpp
#include <iostream>
#include <GL/gl3w.h>
#include "Display.h"
Display::Display( int width, int height, const char* title ) {
//Init GLFW
if ( glfwInit() == 0 ) {
std::cerr << "Could not initialise GLFW\n";
return;
} else {
std::cout << "GLFW initialised\n";
}
//Window Hints
glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 2 );
glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE );
glfwWindowHint( GLFW_RESIZABLE, GL_FALSE );
//Create Window
m_window = glfwCreateWindow( width, height, title, NULL, NULL );
//Make Context
glfwMakeContextCurrent( m_window );
//Initialise GL3W
if ( gl3wInit() != 0 ) {
std::cerr << "Could not init GL3W\n";
return;
} else {
std::cout << "Initialised GL3W\n";
}
}
Display::~Display() {
//Delete Context
glfwMakeContextCurrent( 0 );
//Destroy Window
glfwDestroyWindow( m_window );
//Terminate GLFW
glfwTerminate();
}
bool Display::CheckShouldClose() {
return (bool)glfwWindowShouldClose( m_window );
}
void Display::Update() {
//Swap Buffers
glfwSwapBuffers( m_window );
//Poll Events
glfwPollEvents();
}
Mesh.cpp
#include <GL/gl3w.h>
#include <iostream>
#include "Mesh.h"
Mesh::Mesh( std::vector<float> verticies ) {
m_verticies = verticies;
//Generate VBO
glGenBuffers( 1, &m_vbo );
//Bind VBO
glBindBuffer( GL_ARRAY_BUFFER, m_vbo );;
//Pass Buffer Data
glBufferData( GL_ARRAY_BUFFER, m_verticies.size() * sizeof( float), &m_verticies[0], GL_STATIC_DRAW );
}
Mesh::~Mesh() {
glDeleteBuffers( 1, &m_vbo );
}
Shader.cpp
#include <fstream>
#include <iostream>
#include <vector>
#include <GL/gl3w.h>
#include "Shader.h"
#define SHADER_LIST { VERTEX_SHADER, FRAGMENT_SHADER }
Shader::Shader( std::string shaderName ) {
//Load Source Code
std::vector<std::string> shaderSources;
shaderSources.push_back( loadShaderSource( shaderName + ".vert" ));
shaderSources.push_back( loadShaderSource( shaderName + ".frag" ));
//Cast into C-Style Strings
const char* shaderSourcesCString[NUM_SHADER];
for ( int i : SHADER_LIST ) {
shaderSourcesCString[ i ] = shaderSources[ i ].c_str();
}
//Create Shaders
m_shaders[ VERTEX_SHADER ] = glCreateShader( GL_VERTEX_SHADER );
m_shaders[ FRAGMENT_SHADER ] = glCreateShader( GL_FRAGMENT_SHADER );
//Source Shaders
glShaderSource( m_shaders[ VERTEX_SHADER ], 1, &shaderSourcesCString[ VERTEX_SHADER ], NULL );
glShaderSource( m_shaders[ FRAGMENT_SHADER ], 1, &shaderSourcesCString[ FRAGMENT_SHADER ], NULL );
//Compile Shaders
for ( int i : SHADER_LIST ) {
glCompileShader( m_shaders[ i ] );
GLint status;
glGetShaderiv( m_shaders[ i ], GL_COMPILE_STATUS, &status );
if ( status != GL_TRUE ) {
char buffer[512];
glGetShaderInfoLog( m_shaders[ i ], 512, NULL, buffer );
std::cerr << "Shader Compilation Error on shader " << i << ": " << buffer << "\n";
return;
}
}
//Create Program
m_program = glCreateProgram();
//Attach Shaders
for ( int i : SHADER_LIST ) {
glAttachShader( m_program, m_shaders[ i ] );
}
//Link Shader
glLinkProgram( m_program );
//Find Link Error
{
GLint status;
glGetProgramiv(m_program, GL_LINK_STATUS, &status);
if (status != GL_TRUE){
std::cerr << "Unable to link shaders\n";
char buffer[512];
glGetProgramInfoLog(m_program, 512, NULL, buffer);
std::cerr << buffer;
return;
}
}
//Bind outColor
glBindFragDataLocation(m_program, 0, "outColor");
//Attributes
GLint posAttrib = glGetAttribLocation(m_program, "position");
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(posAttrib);
std::cout << "Shaders Compiled Successfully\n";
}
Shader::~Shader() {
for ( int i : SHADER_LIST ) {
//Detach Shader
glDetachShader( m_program, m_shaders[ i ] );
//Delete Shader
glDeleteShader( m_shaders[ i ] );
}
//Delete Program
glDeleteProgram( m_program );
}
std::string Shader::loadShaderSource( std::string filename ) {
//Locals
std::string output, line;
//Open File
std::fstream file;
file.open( "Shaders/" + filename );
//Check for error loading file
if ( file.bad()) {
std::cerr << "Could not load shader file: " << filename << "\n";
return NULL;
} else {
std::cout << "Loaded shader file: " << filename << "\n";
}
//Read file into locals
while ( file.good()) {
getline( file, line );
if ( line != "" )
output += line + "\n";
}
//Return C-String
return output;
}
void Shader::useShader() {
glUseProgram( m_program );
}
GLuint Shader::getProgram() {
return m_program;
}
These Are my shaders
Vertex Shader
#version 150 core
in vec2 position;
void main(){
gl_Position = vec4(position, 0.0, 1.0);
}
Fragment Shader
#version 150 core
out vec4 outColor;
void main(){
outColor = vec4(1.0, 1.0, 1.0, 1.0);
}
First you have to create the vertex array buffer:
std::vector< GLfloat > verticies;
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (GLsizeiptr)verticies.size(), verticies.data(), GL_STATIC_DRAW);
Once your shader program is linked you have to determine the index of the vertex attribute(s):
GLuint prog = ...;
GLint posAttrLoc = glGetAttribLocation(prog, "position");
Before drawing, you have to bind and enable the vertex attribute(s):
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(posAttrLoc );
glVertexAttribPointer(posAttrLoc , 2, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays( GL_TRIANGLES, 0, 3 );
I'm building a 3D model viewer in OpenGL 3.3 but I can't get my textures to show properly. I'm pretty sure the texcoords (coming from the object I'm loading) are correct.
This is my code:
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "InputState.h"
#include "Viewer.h"
#include "Shader.hpp"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
std::string folder = "cube-tex/";
std::string objPath = folder + "cube-tex.obj";
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::vector<GLuint> texID;
std::string meshMode = "WIREFRAME";
std::string lightMode = "DIRECTIONAL";
double startTime = glfwGetTime();
float initScale = 1;
float zoom = 0;
float xRot, yRot;
int winX = 500;
int winY = 500;
std::vector<unsigned int> vaoHandle;
ObjectViewer *ObjCam;
Viewer *Camera;
glm::vec3 cameraPos(0.0f, 0.0f, -10.0f);
// Data structure storing mouse input info
InputState Input;
unsigned int programID;
unsigned int debugShader;
unsigned int lightTexShader;
//
// Callbacks
//
void key_callback(GLFWwindow* window,
int key, int scancode, int action, int mods)
{
if (action == GLFW_PRESS) {
switch(key)
{
case GLFW_KEY_S:
if (programID == lightTexShader) {
programID = debugShader;
meshMode = "WIREFRAME";
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
else {
programID = lightTexShader;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
break;
case GLFW_KEY_ESCAPE: // escape key pressed
glfwSetWindowShouldClose(window, GL_TRUE);
break;
case GLFW_KEY_D:
if(programID == debugShader){
if(meshMode == "WIREFRAME") {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
meshMode = "NORMAL";
}else if(meshMode == "NORMAL"){
meshMode = "MATERIAL";
}else{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
meshMode = "WIREFRAME";
}
}
break;
case GLFW_KEY_L:
if(programID == lightTexShader){
if(lightMode == "DIRECTIONAL") {
lightMode = "HEADLIGHT";
}else if(lightMode == "HEADLIGHT"){
lightMode = "ROTATING";
}else{
lightMode = "DIRECTIONAL";
}
}
break;
default:
break;
}
}
}
// Set the projection matrix. Takes into account window aspect ratio, so called
// when the window is resized.
void setProjection(unsigned int id)
{
glm::mat4 projection;
projection = glm::perspective( (float)M_PI/3.0f, (float) winX / winY, 1.0f, 30.0f );
// Load it to the shader program
int projHandle = glGetUniformLocation(id, "projection");
if (projHandle == -1) {
std::cout << "Uniform: projection_matrix is not an active uniform label\n";
}
glUniformMatrix4fv( projHandle, 1, false, glm::value_ptr(projection) );
}
// Called when the window is resized.
void reshape_callback( GLFWwindow *window, int x, int y )
{
winX = x;
winY = y;
setProjection(programID);
glViewport( 0, 0, x, y );
}
void mouse_pos_callback(GLFWwindow* window, double x, double y)
{
// Use a global data structure to store mouse info
// We can then use it however we want
Input.update((float)x, (float)y);
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) {
Input.rMousePressed = true;
}
else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_RELEASE) {
Input.rMousePressed = false;
}
else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
Input.lMousePressed = true;
}
else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) {
Input.lMousePressed = false;
}
}
int setupLight()
{
// light position uniform
int lightposHandle = glGetUniformLocation(programID, "light_pos");
if (lightposHandle == -1) {
fprintf(stderr, "Error: can't find matrix uniforms\n");
exit(1);
}
// Uniform lighting variables
int lightambientHandle = glGetUniformLocation(programID, "light_ambient");
int lightdiffuseHandle = glGetUniformLocation(programID, "light_diffuse");
int lightspecularHandle = glGetUniformLocation(programID, "light_specular");
if ( lightambientHandle == -1 ||
lightdiffuseHandle == -1 ||
lightspecularHandle == -1) {
fprintf(stderr, "Error: can't find light uniform variables\n");
return 1;
}
float lightPos[4]; // light position //= { 0.0f, 10.0f, 0.0f, 1.0f };
float lightambient[3]; // ambient light components
float lightdiffuse[3]; // diffuse light components
float lightspecular[3]; // specular light components
if(lightMode == "DIRECTIONAL"){
lightambient[0] = 0.0f;
lightambient[1] = 0.0f;
lightambient[2] = 0.0f;
lightdiffuse[0] = 0.5f;
lightdiffuse[1] = 0.5f;
lightdiffuse[2] = 1.0f;
lightspecular[0] = 1.0f;
lightspecular[1] = 1.0f;
lightspecular[2] = 1.0f;
lightPos[0] = -10.0f;
lightPos[1] = -10.0f;
lightPos[2] = -10.0f;
lightPos[3] = 0.0f;
}else if(lightMode == "HEADLIGHT"){
lightambient[0] = 0.0f;
lightambient[1] = 0.0f;
lightambient[2] = 0.0f;
lightdiffuse[0] = 1.0f;
lightdiffuse[1] = 1.0f;
lightdiffuse[2] = 1.0f;
lightspecular[0] = 1.0f;
lightspecular[1] = 1.0f;
lightspecular[2] = 1.0f;
glm::mat3 rotMat(Camera->getViewMtx());
glm::vec3 d((Camera->getViewMtx())[3]);
glm::vec3 tmp = -d * rotMat;
lightPos[0] = tmp[0];
lightPos[1] = tmp[1];
lightPos[2] = tmp[2];
lightPos[3] = 1.0f;
}else if(lightMode == "ROTATING"){
lightambient[0] = 0.0f;
lightambient[1] = 0.0f;
lightambient[2] = 0.0f;
lightdiffuse[0] = 1.0f;
lightdiffuse[1] = 1.0f;
lightdiffuse[2] = 0.2f;
lightspecular[0] = 1.0f;
lightspecular[1] = 1.0f;
lightspecular[2] = 0.2f;
double now = glfwGetTime();
lightPos[0] = 10 * cos((now - startTime));
lightPos[1] = 0.0f;
lightPos[2] = 10 * sin((now - startTime));
lightPos[3] = 1.0f;
}
glUniform4fv(lightposHandle, 1, lightPos);
glUniform3fv(lightambientHandle, 1, lightambient);
glUniform3fv(lightdiffuseHandle, 1, lightdiffuse);
glUniform3fv(lightspecularHandle, 1, lightspecular);
return 0; // return success
}
void computeInitScale(){
float minX = 0;
float minY = 0;
float maxX = 0;
float maxY = 0;
for(int i = 0; i < shapes.size(); i++){
for(int j = 0; j < shapes[i].mesh.positions.size()/3; j++){
//max and min X
if(shapes[i].mesh.positions[3*j+0] > maxX){
maxX = shapes[i].mesh.positions[3*j+0];
}else if(shapes[i].mesh.positions[3*j+0] < minX){
minX = shapes[i].mesh.positions[3*j+0];
}
//max and min Y
if(shapes[i].mesh.positions[3*j+1] > maxY){
maxY = shapes[i].mesh.positions[3*j+1];
}else if(shapes[i].mesh.positions[3*j+1] < minY){
minY = shapes[i].mesh.positions[3*j+1];
}
}
}
initScale = 2 / std::max(maxX - minX, maxY - minY);
}
void loadRGBTexture(const char *path)
{
int x, y, n;
// Load from file. Force RGB image pixel format
unsigned char *data = stbi_load(path, &x, &y, &n, 3);
// Copy to GPU as data for the currently active texture.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
glGenerateMipmap(GL_TEXTURE_2D);
}
void setMaterials(int i){
// material
int mtlambientHandle = glGetUniformLocation(programID, "mtl_ambient");
int mtldiffuseHandle = glGetUniformLocation(programID, "mtl_diffuse");
int mtlspecularHandle = glGetUniformLocation(programID, "mtl_specular");
if (mtlambientHandle == -1 || mtldiffuseHandle == -1 || mtlspecularHandle == -1) {
fprintf(stderr, "Error: can't find material uniform variables\n");
}
float mtlambient[3];
mtlambient[0] = materials[shapes[i].mesh.material_ids[0]].ambient[0];
mtlambient[1] = materials[shapes[i].mesh.material_ids[0]].ambient[1];
mtlambient[2] = materials[shapes[i].mesh.material_ids[0]].ambient[2];
float mtldiffuse[3];
mtldiffuse[0] = materials[shapes[i].mesh.material_ids[0]].diffuse[0];
mtldiffuse[1] = materials[shapes[i].mesh.material_ids[0]].diffuse[1];
mtldiffuse[2] = materials[shapes[i].mesh.material_ids[0]].diffuse[2];
float mtlspecular[3];
mtlspecular[0] = materials[shapes[i].mesh.material_ids[0]].specular[0];
mtlspecular[1] = materials[shapes[i].mesh.material_ids[0]].specular[1];
mtlspecular[2] = materials[shapes[i].mesh.material_ids[0]].specular[2];
glUniform3fv(mtlambientHandle, 1, mtlambient);
glUniform3fv(mtldiffuseHandle, 1, mtldiffuse);
glUniform3fv(mtlspecularHandle, 1, mtlspecular);
}
void loadObj(){
std::string err;
bool ret = tinyobj::LoadObj(shapes, materials, err, objPath.c_str(), folder.c_str());
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
exit(1);
}
std::cout << "# of shapes : " << shapes.size() << std::endl;
std::cout << "# of materials : " << materials.size() << std::endl;
for (size_t i = 0; i < shapes.size(); i++) {
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
assert((shapes[i].mesh.indices.size() % 3) == 0);
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
printf(" idx[%ld] = %d, %d, %d. mat_id = %d\n", f, shapes[i].mesh.indices[3*f+0], shapes[i].mesh.indices[3*f+1], shapes[i].mesh.indices[3*f+2], shapes[i].mesh.material_ids[f]);
}
printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
assert((shapes[i].mesh.positions.size() % 3) == 0);
for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
printf(" v[%ld] = (%f, %f, %f)\n", v,
shapes[i].mesh.positions[3*v+0],
shapes[i].mesh.positions[3*v+1],
shapes[i].mesh.positions[3*v+2]);
}
}
for (size_t i = 0; i < materials.size(); i++) {
printf("material[%ld].name = %s\n", i, materials[i].name.c_str());
printf(" material.Ka = (%f, %f ,%f)\n", materials[i].ambient[0], materials[i].ambient[1], materials[i].ambient[2]);
printf(" material.Kd = (%f, %f ,%f)\n", materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]);
printf(" material.Ks = (%f, %f ,%f)\n", materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]);
printf(" material.Tr = (%f, %f ,%f)\n", materials[i].transmittance[0], materials[i].transmittance[1], materials[i].transmittance[2]);
printf(" material.Ke = (%f, %f ,%f)\n", materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]);
printf(" material.Ns = %f\n", materials[i].shininess);
printf(" material.Ni = %f\n", materials[i].ior);
printf(" material.dissolve = %f\n", materials[i].dissolve);
printf(" material.illum = %d\n", materials[i].illum);
printf(" material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
printf(" material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
printf(" material.map_Ks = %s\n", materials[i].specular_texname.c_str());
printf(" material.map_Ns = %s\n", materials[i].specular_highlight_texname.c_str());
std::map<std::string, std::string>::const_iterator it(materials[i].unknown_parameter.begin());
std::map<std::string, std::string>::const_iterator itEnd(materials[i].unknown_parameter.end());
for (; it != itEnd; it++) {
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
}
printf("\n");
}
computeInitScale();
}
void createVAO()
{
for(int i = 0; i < shapes.size(); i++){
vaoHandle.push_back(0);
glGenVertexArrays(1, &vaoHandle[i]);
glBindVertexArray(vaoHandle[i]);
unsigned int buffer[5];
glGenBuffers(4, buffer);
// Set vertex attribute
glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(float) * shapes[i].mesh.positions.size(), &shapes[i].mesh.positions[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Set vertex attribute
glBindBuffer(GL_ARRAY_BUFFER, buffer[1]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(float) * shapes[i].mesh.normals.size(), &shapes[i].mesh.normals[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
// create material array
float diffuse[shapes[i].mesh.indices.size() * 3];
for(int j = 0; j<shapes[i].mesh.indices.size(); j++){
int index = j*3;
diffuse[index] = materials[shapes[i].mesh.material_ids[j/3]].diffuse[0];
diffuse[index + 1] = materials[shapes[i].mesh.material_ids[j/3]].diffuse[1];
diffuse[index + 2] = materials[shapes[i].mesh.material_ids[j/3]].diffuse[2];
}
// Set vertex attribute
glBindBuffer(GL_ARRAY_BUFFER, buffer[2]);
glBufferData(GL_ARRAY_BUFFER,
shapes[i].mesh.indices.size() * 3 * sizeof(float) , &diffuse[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Set element attributes. Notice the change to using GL_ELEMENT_ARRAY_BUFFER
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[3]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof(float) * shapes[i].mesh.indices.size(), &shapes[i].mesh.indices[0], GL_STATIC_DRAW);
// load textures
texID.push_back(0);
glGenTextures(1, &texID[i] );
glActiveTexture(GL_TEXTURE0);
glBindTexture( GL_TEXTURE_2D, texID[i] );
loadRGBTexture((folder + (std::string) materials[shapes[i].mesh.material_ids[0]].diffuse_texname).c_str());
// load texture coordinates
int texLoc = glGetAttribLocation(programID, "a_tex_coord");
glBindBuffer(GL_ARRAY_BUFFER, buffer[4]);
glBufferData(GL_ARRAY_BUFFER,
shapes[i].mesh.texcoords.size() * sizeof(float) , &shapes[i].mesh.texcoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(texLoc);
glVertexAttribPointer(texLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Un-bind
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
}
void render()
{
glUseProgram(programID);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
setProjection(programID);
Camera->update(Input);
glm::mat4 viewMatrix;
viewMatrix = Camera->getViewMtx();
// Load viex to the shader program
int viewHandle = glGetUniformLocation(programID, "view");
if (viewHandle == -1) {
std::cout << "Uniform: view is not an active uniform label\n";
}
glUniformMatrix4fv( viewHandle, 1, false, glm::value_ptr(viewMatrix) );
// Load the model matrix
int modelUniformHandle = glGetUniformLocation(programID, "model");
if (modelUniformHandle == -1)
exit(1);
// calculate zoom
if(Input.rMousePressed){
zoom += Input.yDiff/10;
if (zoom < 0) zoom = 0;
if (zoom > 1.5) zoom = 1.5;
}
glm::mat4 model;
model = glm::scale( model, glm::vec3(initScale + zoom, initScale + zoom, initScale + zoom));
glUniformMatrix4fv( modelUniformHandle, 1, false, glm::value_ptr(model) );
if (programID == debugShader){
// set colour mode
int modeHandle = glGetUniformLocation(programID, "mode");
if (modeHandle == -1) {
std::cout << "Uniform: mode is not an active uniform label\n";
}
if(meshMode == "MATERIAL"){
glUniform1i( modeHandle, 1);
}else{
glUniform1i( modeHandle, 0);
}
}else{
setupLight();
}
// Load meshes
for(int i = 0; i < shapes.size(); i++){
glBindVertexArray(vaoHandle[i]);
glDrawElements(GL_TRIANGLES, shapes[i].mesh.indices.size(), GL_UNSIGNED_INT, 0);
if (programID == lightTexShader){
setMaterials(i);
int texHandle = glGetUniformLocation(programID, "texMap");
if (texHandle == -1) {
fprintf(stderr, "Could not find uniform variables\n");
exit(1);
}
glBindTexture(GL_TEXTURE_2D, texID[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_NEAREST);
}
glBindVertexArray(0);
}
}
/**
* Error callback for GLFW. Simply prints error message to stderr.
*/
static void error_callback(int error, const char* description)
{
fputs(description, stderr);
}
int main (int argc, char **argv)
{
GLFWwindow* window;
glfwSetErrorCallback(error_callback);
if (!glfwInit()) {
exit(1);
}
// Specify that we want OpenGL 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Create the window and OpenGL context
window = glfwCreateWindow(winX, winY, "Modelling and viewing", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(1);
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
exit(1);
}
// load shaders
debugShader = LoadShaders("mview.vert", "mview.frag");
lightTexShader = LoadShaders("light-texture.vert", "light-texture.frag");
if (debugShader == 0 || lightTexShader == 0) {
exit(1);
}
programID = debugShader;
// Set OpenGL state we need for this application.
glClearColor(0.5F, 0.5F, 0.5F, 0.0F);
glEnable(GL_DEPTH_TEST);
glUseProgram(programID);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// Set up the scene and the cameras
//setProjection(debugShader);
//setProjection(lightTexShader);
loadObj();
createVAO();
ObjCam = new ObjectViewer( cameraPos );
Camera = ObjCam;
// Define callback functions and start main loop
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, mouse_pos_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetFramebufferSizeCallback(window, reshape_callback);
while (!glfwWindowShouldClose(window))
{
render();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(0);
return 0;
}
Vertex shader
#version 330
uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
//uniform mat3 normal_matrix;
layout (location = 0) in vec3 a_vertex;
layout (location = 1) in vec3 a_normal;
layout (location = 2) in vec3 a_diffuse;
in vec2 a_tex_coord;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
//uniform int mode;
uniform vec3 mtl_diffuse;
out vec4 vertex; // vertex position in eye space
out vec3 normal; // the eye space normal
out vec2 st;
void main(void)
{
vertex = view * model * vec4(a_vertex, 1.0);
//normal = normalize(normal_matrix * a_normal);
normal = a_normal;
st = a_tex_coord;
gl_Position = projection * view * model * vec4(a_vertex, 1.0);
}
Fragment shader
#version 330
in vec4 vertex;
in vec3 normal;
in vec2 st;
out vec4 fragColour;
uniform sampler2D texMap;
uniform vec4 light_pos;
uniform vec3 light_ambient; // Light ambient RGBA values
uniform vec3 light_diffuse; // Light diffuse RGBA values
uniform vec3 light_specular; // Light specular RGBA values
uniform vec3 mtl_ambient; // Ambient surface colour
uniform vec3 mtl_diffuse; // Diffuse surface colour
uniform vec3 mtl_specular; // Specular surface colour
const float shininess = 32;
vec3 phongPointLight(in vec4 position, in vec3 norm)
{
vec3 s = normalize(vec3(light_pos - position));
if(light_pos.w == 0.0){
s = -normalize(light_pos.xyz);
}
vec3 v = normalize(-position.xyz);
vec3 r = reflect( -s, norm );
vec3 ambient = light_ambient * mtl_ambient;
// The diffuse component
float sDotN = max( dot(s,norm), 0.0 );
vec3 diffuse = light_diffuse * mtl_diffuse * sDotN;
// The specular component BLINN
vec3 spec = vec3(0.0);
vec3 halfwayDir = normalize(s + v);
if ( sDotN > 0.0 )
spec = light_specular * mtl_specular * pow(max(dot(normalize(normal), halfwayDir), 0.0), 32.0);
return ambient + diffuse + spec;
}
void main(void)
{
fragColour = vec4(phongPointLight(vertex, normalize(normal)), 1.0) * texture(texMap, st);
}
This is the result. As you can see the texture is not properly positioned on the car.
I send double precision data to my compute shader using an ssbo but somehow looses precision somewhere in the shader. I posted this problem here but has not yet received a response.
I read a position which contains 4 doubles that I use in calculations. If I in the beginning of the shader write the position to the buffer the values are correct. If I write to the buffer after my calculations I get a precision loss. I never change the values in the position. In my test I can even change "true" to "variable == variable" and loose precision only on that. Some of the code is shown in the post i linked to.
I had a similar problem with my constants which was solved with the LF suffix. Is there a similar fix for variables?
I have tried to isolate the problem, here is my code:
My .csh-file:
#version 430
struct aVec4 {
double x, y, z, w;
};
struct FT {
aVec4 force;
aVec4 torque;
};
struct Triangle {
aVec4 position;
aVec4 normal;
aVec4 depth;
};
layout( std430, binding = 0 ) buffer abc { Triangle bs[]; };
layout( std430, binding = 1 ) buffer def { FT forces[]; };
layout( local_size_x = 1 ) in;
dvec3 toVec3( in aVec4 vector ) {
dvec3 v = dvec3( vector.x, vector.y, vector.z );
return v;
}
aVec4 function1( inout Triangle triangles[2], inout int numTriangles ) {
Triangle anotherTriangle = bs[gl_GlobalInvocationID.x];
int numBelow = 1;
if ( anotherTriangle.depth.x < 0.0LF ) {
numBelow++;
}
if ( numBelow == numBelow ) {
numTriangles = 1;
aVec4 result = anotherTriangle.position;
return result;
}
}
FT function2( in Triangle triangles[2], in int numTriangles ) {
FT ft;
dvec3 force = dvec3( 0.0LF, 0.0LF, 0.0LF );
for ( int i = 0; i < numTriangles; i++ ){
dvec3 normal = toVec3( triangles[i].normal );
force += - normal;
}
ft.force = triangles[0].position;
return ft;
}
void main()
{
Triangle triangles[2];
triangles[0] = bs[gl_GlobalInvocationID.x];
int numTriangles = 1;
aVec4 result = function1( triangles, numTriangles );
FT ft = function2( triangles, numTriangles );
ft.torque = result;
forces[gl_GlobalInvocationID.x] = ft;
}
My .cpp-file:
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <vector>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
#include <cmath>
class Vec3
{
public:
Vec3()
: x(0)
, y(0)
, z(0)
, w(0)
{
}
Vec3(double x, double y, double z)
: x(x)
, y(y)
, z(z)
, w(0)
{
}
double x, y, z, w;
};
std::ostream& operator<<(std::ostream& stream, const Vec3& v)
{
stream << std::setprecision(20) << std::setw(20) << std::scientific;
stream << "Vec3(" <<
std::setw(23) << v.x << ", " <<
std::setw(23) << v.y << ", " <<
std::setw(23) << v.z << ") (" <<
std::setw(23) << v.w << ")";
return stream;
}
GLuint loadShader( std::string fileName )
{
GLuint program = glCreateProgram( );
GLuint shader = glCreateShader( GL_COMPUTE_SHADER );
std::ifstream shaderStream(fileName.c_str(), std::ios::in );
if (!shaderStream.is_open())
{
std::cout << "Could not open shader source file '" << fileName << "'." << std::endl;
exit(1);
}
std::string src;
std::string line = "";
while ( getline( shaderStream, line ) )
src += "\n" + line;
char const* srcPointer = src.c_str( );
glShaderSource( shader, 1, &srcPointer, NULL );
glCompileShader( shader );
int rValue;
glGetShaderiv( shader, GL_COMPILE_STATUS, &rValue );
if (!rValue)
{
std::cout << "Unable to compile compute shader" << std::endl;
GLchar log[ 10240 ];
GLsizei length;
glGetShaderInfoLog( shader, 10239, &length, log );
fprintf( stderr, "Compiler log:\n%s\n", log );
exit( 40 );
}
glAttachShader(program, shader);
glLinkProgram(program);
glGetProgramiv( program, GL_LINK_STATUS, &rValue );
if (!rValue)
{
std::cout << "Unable to link compute shader program" << std::endl;
GLchar log[ 10240 ];
GLsizei length;
glGetProgramInfoLog( program, 10239, &length, log );
fprintf( stderr, "Linker log:\n%s\n", log );
exit( 41 );
}
glDeleteShader( shader );
return program;
}
struct ShaderData
{
Vec3 position;
Vec3 normal;
Vec3 depth;
};
int main( int argc, char **argv ) {
glutInit( &argc, argv );
glutCreateWindow( "TEST1" ); //TODO: Why?
glewInit( );
std::string shaderFileName = "tutorial_computeShaderBugSearch.csh";
GLuint program = loadShader( shaderFileName );
GLuint ssbo;
GLuint result;
glGenBuffers( 1, &ssbo );
glGenBuffers( 1, &result );
glUseProgram( program );
std::vector< ShaderData > buf;
buf.resize( 1 );
ShaderData shaderData;
shaderData.position = Vec3( double(1) / double(3), 0, 0 );
shaderData.normal = Vec3( 1, 1, 1 );
shaderData.depth.x = 1;
buf[ 0 ] = shaderData;
glBindBuffer( GL_SHADER_STORAGE_BUFFER, ssbo );
glBufferData( GL_SHADER_STORAGE_BUFFER, buf.size( ) * sizeof(ShaderData), buf.data( ), GL_STATIC_DRAW );
std::vector< Vec3 > forces;
forces.resize( 2 ); // 1 for the forces + 1 for the torques
glBindBuffer( GL_SHADER_STORAGE_BUFFER, result );
glBufferData( GL_SHADER_STORAGE_BUFFER, forces.size( ) * sizeof(Vec3), forces.data( ), GL_STATIC_DRAW );
glUseProgram( program );
glBindBufferBase( GL_SHADER_STORAGE_BUFFER, 0, ssbo );
glBindBufferBase( GL_SHADER_STORAGE_BUFFER, 1, result );
glDispatchCompute( 1, 1, 1 );
glMemoryBarrier( GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT );
glBindBuffer( GL_SHADER_STORAGE_BUFFER, result );
Vec3* ptr = (Vec3*)glMapBuffer( GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY );
Vec3 a = ptr[ 0 ];
Vec3 b = ptr[ 1 ];
std::cout << "a: " << std::setprecision(20) << a.x << std::endl;
std::cout << "b: " << std::setprecision(20) << b.x << std::endl;
std::cout << "diff: " << std::abs(a.x-b.x) << std::endl;
}
This produces the output:
a: 0.3333333432674408
b: 0.33333333333333331
diff: 9.9341074810688212e-099
I attach a vertex and fragment shader to a program object, then attempt to link the said program. GL_LINK_STATUS returns false. I check the info log, it's a bunch of gibberish characters. I check GL_INFO_LOG_LENGTH, it's 0. How do I debug this situation?
//this is the end of my LoadBasicShaders function
glAttachShader(program, vertShader);
glAttachShader(program, fragShader);
glLinkProgram(program);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
GLint logLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
std::vector<GLchar> log(logLength + 1);
glGetProgramInfoLog(program, logLength, &logLength, &log[0]);
fprintf(stderr, "%s\n\n", log);
//logLength returns 0, log returns seemingly random chars
return -3;//just my error code
}
My shaders are the simplest ones possible, since I'm just starting out.
Here's the vertex shader:
#version 330
layout(location = 0) in vec4 position;
void main()
{
gl_Position = position;
}
And here's the fragment shader:
#version 330
out vec4 outputColor;
void main()
{
outputColor = vec4(1.0, 1.0, 1.0, 1.0);
}
I use GLFW to create the OpenGL window, and GLEW to load the functions:
if (!glfwInit())
{/*error checking*/}
window = glfwCreateWindow(800, 600, "Swash", NULL, NULL);
if (!window)
{/*more error checking*/}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glfwSetKeyCallback(window, key_callback);
if (glewInit() != GLEW_OK)
{/*you guessed it*/}
//don't call anything that involves nonstandard OpenGL functions before this point
GLuint shaderProgram;
int shaderLoadResult = LoadBasicShaders(shaderProgram, "../res/vert.shader", "../res/frag.shader");
Use the GLFW error callback
Bullet-proof your shader loader
Use ARB_debug_output or KHR_debug
Request an explicit GL version and profile (Core/Compatibility) via glfwWindowHint()
All together (this is what I meant by posting a MCVE):
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <cstdlib>
struct GlDebugOutput
{
static void Install()
{
if( !glewIsSupported( "GL_ARB_debug_output" ) )
{
std::cerr << "GL_ARB_debug_output not supported" << std::endl;
return;
}
glEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB );
glDebugMessageCallbackARB( DebugCallback, 0 );
glDebugMessageControlARB( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE );
}
private:
static const char* Source( GLenum source )
{
switch( source )
{
case GL_DEBUG_SOURCE_API_ARB : return "API";
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB : return "WINDOW_SYSTEM";
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB : return "SHADER_COMPILER";
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB : return "THIRD_PARTY";
case GL_DEBUG_SOURCE_APPLICATION_ARB : return "APPLICATION";
case GL_DEBUG_SOURCE_OTHER_ARB : return "OTHER";
default : return "Unknown source";
}
}
static const char* Type( GLenum type )
{
switch( type )
{
case GL_DEBUG_TYPE_ERROR_ARB : return "ERROR";
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB : return "DEPRECATED_BEHAVIOR";
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB : return "UNDEFINED_BEHAVIOR";
case GL_DEBUG_TYPE_PORTABILITY_ARB : return "PORTABILITY";
case GL_DEBUG_TYPE_PERFORMANCE_ARB : return "PERFORMANCE";
case GL_DEBUG_TYPE_OTHER_ARB : return "OTHER";
default : return "Unknown type";
}
}
static const char* Severity( GLenum severity )
{
switch( severity )
{
case GL_DEBUG_SEVERITY_HIGH_ARB : return "HIGH";
case GL_DEBUG_SEVERITY_MEDIUM_ARB : return "MEDIUM";
case GL_DEBUG_SEVERITY_LOW_ARB : return "LOW";
default : return "Unknown severity";
}
}
static void APIENTRY DebugCallback
(
GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam
)
{
std::cerr << "GL_DEBUG"
<< ": " << Source( source )
<< ": " << Type( type )
<< ": " << Severity( severity )
<< ": " << message
<< std::endl;
}
};
struct Program
{
static GLuint Load( const char* vert, const char* geom, const char* frag )
{
GLuint prog = glCreateProgram();
if( vert ) AttachShader( prog, GL_VERTEX_SHADER, vert );
if( geom ) AttachShader( prog, GL_GEOMETRY_SHADER, geom );
if( frag ) AttachShader( prog, GL_FRAGMENT_SHADER, frag );
glLinkProgram( prog );
CheckStatus( prog );
return prog;
}
private:
static void CheckStatus( GLuint obj )
{
GLint status = GL_FALSE;
if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
GLchar log[ 1 << 15 ] = { 0 };
if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
std::cerr << log << std::endl;
exit( EXIT_FAILURE );
}
static void AttachShader( GLuint program, GLenum type, const char* src )
{
GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader );
glAttachShader( program, shader );
glDeleteShader( shader );
}
};
#define GLSL(version, shader) "#version " #version "\n" #shader
const char* vert = GLSL
(
330,
layout( location = 0 ) in vec4 position;
void main()
{
gl_Position = position;
}
);
const char* frag = GLSL
(
330,
out vec4 outputColor;
void main()
{
outputColor = vec4( 1.0, 1.0, 1.0, 1.0 );
}
);
GLuint VAO;
GLuint VBO;
GLuint prog;
void init()
{
glGenVertexArrays( 1, &VAO );
glBindVertexArray( VAO );
glGenBuffers( 1,&VBO );
glBindBuffer( GL_ARRAY_BUFFER, VBO );
float verts[] =
{
-1.0, -1.0,
1.0, -1.0,
0.0, 1.0,
};
glBufferData( GL_ARRAY_BUFFER, sizeof( verts ), verts, GL_STATIC_DRAW );
prog = Program::Load( vert, NULL, frag );
glUseProgram( prog );
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, 0 );
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT );
glUseProgram( prog );
glBindVertexArray( VAO );
glDrawArrays( GL_TRIANGLES, 0, 3 );
}
void glfwErrorCallback( int error, const char* description )
{
std::cerr << "GLFW error: " << description << std::endl;
}
int main( int argc, char** argv )
{
glfwSetErrorCallback( glfwErrorCallback );
if( GL_FALSE == glfwInit() )
{
return EXIT_FAILURE;
}
std::cout << "GLFW version : " << glfwGetVersionString() << std::endl;
glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE );
glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE );
GLFWwindow* window = glfwCreateWindow( 640, 480, "Test", NULL, NULL );
if( NULL == window )
{
glfwTerminate();
return EXIT_FAILURE;
}
glfwMakeContextCurrent( window );
glfwSwapInterval( 1 );
glewExperimental = GL_TRUE;
const GLenum glewErr = glewInit();
if( GLEW_OK != glewErr )
{
std::cerr << "glewInit() failed: " << glewGetErrorString( glewErr ) << std::endl;
glfwTerminate();
return EXIT_FAILURE;
}
// consume spurious GL error from GLEW init
glGetError();
GlDebugOutput::Install();
init();
while( !glfwWindowShouldClose( window ) )
{
glfwPollEvents();
int w, h;
glfwGetFramebufferSize( window, &w, &h );
glViewport( 0, 0, w, h );
display();
glfwSwapBuffers( window );
}
return EXIT_SUCCESS;
}
If anything is even just a little bit off with your OpenGL implementation and/or shaders that program should scream bloody murder to stderr and exit.
Sorry for the very slow update, I've been busy with other things.
Anyways, the problem was that while writing the code, I had included the line
program = glCreateProgram();
but at some point, while tidying up, I accidentally deleted it. That's why the shaders were compiling but weren't linking, they weren't being linked to a program object.