herrh herrh - 2 months ago 11
C++ Question

Linker error in GLSL shader?

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;
}

Answer

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.