I'm just starting out using visual studios and C++ and I've been following along the examples in Ed Angel's Interactive Computer Graphics book. I've seem to come into a snag with the rotating RGB cube example. I followed along exactly and I have got it to run and display a cube but the cube is all black instead of colored. To my understanding everything is correct and I have haven't been able to find any suggestions or hints as to what went wrong from google searches. I was wondering if anyone here with much more experience than I have could help me figure out what happened or point me in the direction.
// Display a rotating color cube
#include "Angel.h"
typedef Angel::vec4 color4;
typedef Angel::vec4 point4;
const int NumVertices = 36;
point4 points[NumVertices];
color4 colors[NumVertices];
//Vertices of a unit cube centered at origin, sides aligned with axes
point4 vertices[8] = {
point4( -0.5, -0.5, 0.5, 1.0),
point4( -0.5, 0.5, 0.5, 1.0),
point4( 0.5, 0.5, 0.5, 1.0),
point4( 0.5, -0.5, 0.5, 1.0),
point4( -0.5, -0.5, -0.5, 1.0),
point4( -0.5, 0.5, -0.5, 1.0),
point4( 0.5, 0.5, -0.5, 1.0),
point4( 0.5, -0.5, -0.5, 1.0)
};
//RGBA colors
color4 vertex_colors[8] = {
color4( 0.0, 0.0, 0.0, 1.0), //black
color4( 1.0, 0.0, 0.0, 1.0), //red
color4( 1.0, 1.0, 0.0, 1.0), //yellow
color4( 0.0, 1.0, 0.0, 1.0), //blue
color4( 0.0, 0.0, 1.0, 1.0), //green
color4( 1.0, 0.0, 1.0, 1.0), //magenta
color4( 1.0, 1.0, 1.0, 1.0), //white
color4( 0.0, 1.0, 1.0, 1.0) //cyan
};
//Array of rotation angles (in degrees) for each coordinate axis
enum { Xaxis = 0, Yaxis = 1, Zaxis = 2, NumAxes = 3 };
int Axis = Xaxis;
GLfloat Theta[NumAxes] = { 0.0, 0.0, 0.0};
GLuint theta; //The location of the "theta" shader uniform variable
//----------------------------------------------------------------------------
//quad generates two triangles for each face and assigns colors to the vertices
int Index = 0;
void
quad( int a, int b, int c, int d)
{
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[b]; points[Index] = vertices[b]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[d]; points[Index] = vertices[d]; Index++;
}
//----------------------------------------------------------------------------
//generate 12 triangles: 36 vertices and 36 colors
void
colorcube( void )
{
quad( 1, 0, 3, 2);
quad( 2, 3, 7, 6);
quad( 3, 0, 4, 7);
quad( 6, 5, 1, 2);
quad( 4, 5, 6, 7);
quad( 5, 4, 0, 1);
}
//----------------------------------------------------------------------------
//OpenGL initialization
void
init( void )
{
colorcube();
//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) + sizeof(colors), NULL, GL_STATIC_DRAW );
glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(points), points );
glBufferSubData( GL_ARRAY_BUFFER, sizeof(points), sizeof(colors), colors );
//Load shaders and use the resulting shader program
GLuint program = InitShader( "vshader36.glsl", "fshader36.glsl" );
std::cout << "Program ID:" <<program;
glUseProgram ( program );
//set up vertex arrays
GLuint vPosition = glGetAttribLocation( program, "vPosition" );
glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(points)) );
theta = glGetUniformLocation( program, "theta" );
glEnable( GL_DEPTH_TEST );
glClearColor( 1.0, 1.0, 1.0, 1.0 );
}
//----------------------------------------------------------------------------
void
display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUniform3fv( theta, 1, Theta );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
glutSwapBuffers();
}
//----------------------------------------------------------------------------
void
keyboard( unsigned char key, int x, int y )
{
switch ( key ) {
case 033:
case 'q': case 'Q':
exit( EXIT_SUCCESS );
break;
}
}
//----------------------------------------------------------------------------
void
mouse( int button, int state, int x, int y )
{
if ( state == GLUT_DOWN ) {
switch( button ) {
case GLUT_LEFT_BUTTON: Axis = Xaxis; break;
case GLUT_MIDDLE_BUTTON: Axis = Yaxis; break;
case GLUT_RIGHT_BUTTON: Axis = Zaxis; break;
}
}
}
//----------------------------------------------------------------------------
void
idle( void )
{
Theta[Axis] += 0.01;
if ( Theta[Axis] > 360.0 ) {
Theta[Axis] -= 360.0;
}
glutPostRedisplay();
}
//----------------------------------------------------------------------------
int
main( int argc, char **argv )
{
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
glutInitWindowSize( 512, 512 );
glutCreateWindow( "Color Cube" );
glewInit();
init();
glutDisplayFunc( display );
glutKeyboardFunc( keyboard );
glutMouseFunc( mouse );
glutIdleFunc( idle );
glutMainLoop();
return 0;
}
fshader36.glsl
#version 150
in vec4 color;
out vec4 fColor;
void main()
{
fColor = color;
}
vshader36.glsl
#version 150
in vec4 vPosition;
in vec4 vColor;
out vec4 color;
uniform vec3 theta;
void main()
{
vec3 angles = radians( theta );
vec3 c = cos( angles );
vec3 s = sin( angles );
mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0,
0.0, c.x, -s.x, 0.0,
0.0, s.x, c.x, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 ry = mat4( c.y, 0.0, s.y, 0.0,
0.0, 1.0, 0.0, 0.0,
-s.y, 0.0, c.y, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 rz = mat4( c.z, -s.z, 0.0, 0.0,
s.z, c.z, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 );
color = vColor;
gl_Position = rz * ry * rx * vPosition;
}
You have to actually set vColor for it to have a valid value. Do the same thing that you did to set vPosition:
GLuint vColor= glGetAttribLocation( program, "vColor" );
glEnableVertexAttribArray( vColor);
glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(colors)) );
You don't actually pass any colour information to your shader.
Related
I have the sample code of drawing a cube. How can I draw other cubes at different positions (using translation matrices) to be able to draw a tetris of which's engine I have.
#include <glf.hpp>
#include <GL/freeglut.h>
#include <camera.h>
#define kEpsilon 1.0e-6f
#define kPI 3.1415926535897932384626433832795f
#define kHalfPI 1.5707963267948966192313216916398f
#define kTwoPI 2.0f*kPI
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
namespace
{
//path to shader files
std::string const SHADER_VERT_SOURCE("../GL3_init/Basic.vsh"); //// relative to
std::string const SHADER_FRAG_SOURCE("../GL3_init/Basic.fsh"); //// the executable path
//cube data
namespace cube {
// (6 faces)(2 triangles/face)(3 vertices/triangle)
const int NumVertices = 36;
glm::vec4 points[NumVertices];
glm::vec4 colors[NumVertices];
// Vertices positions of a unit cube centered at origin
glm::vec4 vertex_positions[8] = {
glm::vec4( -0.5, -0.5, 0.5, 1.0),
glm::vec4( -0.5, 0.5, 0.5, 1.0),
glm::vec4( 0.5, 0.5, 0.5, 1.0),
glm::vec4( 0.5, -0.5, 0.5, 1.0),
glm::vec4( -0.5, -0.5, -0.5, 1.0),
glm::vec4( -0.5, 0.5, -0.5, 1.0),
glm::vec4( 0.5, 0.5, -0.5, 1.0),
glm::vec4( 0.5, -0.5, -0.5, 1.0)
};
// RGBA colors
glm::vec4 vertex_colors[8] = {
glm::vec4( 0.0, 0.0, 0.0, 1.0),//black
glm::vec4( 1.0, 0.0, 0.0, 1.0),//red
glm::vec4( 1.0, 1.0, 0.0, 1.0),//yellow
glm::vec4( 0.0, 1.0, 0.0, 1.0),//green
glm::vec4( 0.0, 0.0, 1.0, 1.0),//blue
glm::vec4( 1.0, 0.0, 1.0, 1.0),//magenta
glm::vec4( 1.0, 1.0, 1.0, 1.0),//white
glm::vec4( 0.0, 1.0, 1.0, 1.0) //cyan
};
// quad() generates two triangles for each face and assigns colors to the vertices
int Index = 0;
void quad( int a, int b, int c, int d )
{
colors[Index] = vertex_colors[a]; points[Index] = vertex_positions[a]; Index++;
colors[Index] = vertex_colors[b]; points[Index] = vertex_positions[b]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertex_positions[c]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertex_positions[a]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertex_positions[c]; Index++;
colors[Index] = vertex_colors[d]; points[Index] = vertex_positions[d]; Index++;
}
// generate 12 triangles: 36 vertices and 36 colors
void colorcube()
{
quad( 1, 0, 3, 2 );
quad( 2, 3, 7, 6 );
quad( 3, 0, 4, 7 );
quad( 6, 5, 1, 2 );
quad( 4, 5, 6, 7 );
quad( 5, 4, 0, 1 );
}
}
//OpenGL Objects
GLuint vao;
GLuint buffer;
GLuint program;
//window
int width = 800;
int height = 600;
//MVP
glm::mat4 mProjection = glm::perspective(60.0f, float(width) / height, 0.1f, 1000.0f);
Camera camera(glm::vec3(0.0f, 1.0f,-3.0f), glm::vec3(0.0f,0.0f,0.0f), glm::vec3(0.0f,1.0f,0.0f), mProjection);
//uniform variables
GLuint uMVP;
}
//create, compile and link shaders
bool initProgram()
{
bool Validated(true);
GLuint VertShaderName = glf::createShader(GL_VERTEX_SHADER, SHADER_VERT_SOURCE);
GLuint FragShaderName = glf::createShader(GL_FRAGMENT_SHADER, SHADER_FRAG_SOURCE);
program = glCreateProgram();
glAttachShader(program, VertShaderName);
glAttachShader(program, FragShaderName);
glLinkProgram(program);
glDeleteShader(VertShaderName);
glDeleteShader(FragShaderName);
Validated = Validated && glf::checkProgram(program);
if(Validated)
{
glUseProgram(program);
//Associate uniforms
uMVP = glGetUniformLocation( program, "MVP");
Validated = Validated && glf::checkError("initProgram - stage");
}
}
// Create and initialize buffer object
bool initBuffer()
{
bool Validated(true);
glGenBuffers(1,&buffer);
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER, sizeof(cube::points) + sizeof(cube::colors),NULL,GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(cube::points), cube::points);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(cube::points), sizeof(cube::colors), cube::colors);
return Validated;
}
// Create and bind vertex array object. Set pointer to vertex attributes
bool initVertexArray()
{
bool Validated(true);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
GLuint vPosition = glGetAttribLocation( program,"vPosition" );
glEnableVertexAttribArray(vPosition);
glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, 0);
GLuint vColor = glGetAttribLocation( program, "vColor" );
glEnableVertexAttribArray( vColor );
glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(cube::points)) );
return Validated;
}
// Setup GL state
bool beginGL()
{
bool Validated(true);
//setup the cube
cube::colorcube();
Validated = initProgram();
if(Validated)
Validated = initBuffer();
if(Validated)
Validated = initVertexArray();
return Validated;
}
// Free memory
void endGL()
{
glDeleteBuffers(1,&buffer);
glDeleteProgram(program);
glDeleteVertexArrays(1, &vao);
}
///////////////////////////////////////////////////////////////////////////////
// Called to draw scene
void RenderScene(void)
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glClearBufferfv(GL_COLOR, 0, &glm::vec4(0.4f, 0.4f, 0.4f, 1.0f)[0]);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glEnable(GL_CULL_FACE);
glEnable(GL_MULTISAMPLE);
//glPolygonMode( GL_FRONT_AND_BACK, GL_LINE);
//setup Model View Projection
glm::mat4 mMVP = camera.getprojection()*camera.ViewMatrix();
glProgramUniformMatrix4fv(program, uMVP, 1, GL_FALSE, glm::value_ptr(mMVP));
//Draw Cube
glDrawArrays(GL_TRIANGLES,0,cube::NumVertices);
// Flush drawing commands
glutSwapBuffers();
// Refresh the Window
glutPostRedisplay();
glDisable(GL_MULTISAMPLE);
}
///////////////////////////////////////////////////////////////////////////////
// A normal ASCII key has been pressed.
// In this case, space bar is pressed
void KeyPressFunc(unsigned char key, int x, int y)
{
switch(key)
{
// controls for camera
// add up/down and left/right controls
case 'L': camera.slide(.2, 0, 0); break;// slide camera right
case 'L' + 32: camera.slide(-0.2, 0, 0); break; // slide camera left
case 'U': camera.slide(0, -0.2, 0); break;// slide camera down
case 'U' + 32: camera.slide(0, 0.2, 0); break; // slide camera up
case 'F': camera.slide(0,0, 0.2); break; // slide camera forward
case 'F' + 32: camera.slide(0,0,-0.2); break; //slide camera back
// add pitch controls
case 'P': camera.pitch(-1.0); break;
case 'P' + 32: camera.pitch( 1.0); break;
// add yaw controls
case 'Y': camera.yaw(-1.0); break;
case 'Y' + 32: camera.yaw( 1.0); break;
// add roll controls
case 'R': camera.roll(1.0); break;
case 'R' + 32: camera.roll(-1.0); break;
// close with Esc
case 27: exit(0); break;
}
}
//////////////////////////////////////////////////////////////////////////////
// Window has changed size, or has just been created. In either case, we need
// to use the window dimensions to set the viewport and the projection matrix.
void ChangeSize(int w, int h)
{
width = w; height = h;
glViewport(0, 0, w, h);
mProjection = glm::perspective(60.0f, float(width) / height, 0.1f, 1000.0f);
camera.setprojection(mProjection);
}
// Main entry point for GLUT based programs
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(width, height);
glutCreateWindow("3D Demo");
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return 1;
}
if(beginGL()){
glutReshapeFunc(ChangeSize);
glutKeyboardFunc(KeyPressFunc);
glutDisplayFunc(RenderScene);
glutCloseFunc(endGL);
glutMainLoop();
return 0;
}
return 1;
}
In RenderScene you can play with the following lines in order to draw multiple cubes :
glm::mat4 mMVP = camera.getprojection()*camera.ViewMatrix();
for(int i = 0; i < 10; i++)
{
glm::mat4 finalM = mMVP * a_function_that_creates_a_translation_matrix(x, y, z);
glProgramUniformMatrix4fv(program, uMVP, 1, GL_FALSE, glm::value_ptr(finalM));
glDrawArrays(GL_TRIANGLES,0,cube::NumVertices);
}
I've been slowly learning how to work with 3d graphics and C++ and I've been working with an RGBA using an example from Ed angels interactive computer graphics. When trying to change it to have a color on each side, I hit a wall in either my understanding or I'm not seeing something obvious. A snippet of the original example I used that created a RGBA cube is this:
const int NumVertices = 36;
point4 points[NumVertices];
color4 colors[NumVertices];
//Vertices of a unit cube centered at origin, sides aligned with axes
point4 vertices[8] = {
point4( -1.0, -1.0, 1.0, 1.0),
point4( -1.0, 1.0, 1.0, 1.0),
point4( 1.0, 1.0, 1.0, 1.0),
point4( 1.0, -1.0, 1.0, 1.0),
point4( -1.0, -1.0, -1.0, 1.0),
point4( -1.0, 1.0, -1.0, 1.0),
point4( 1.0, 1.0, -1.0, 1.0),
point4( 1.0, -1.0, -1.0, 1.0)
};
//RGBA colors
color4 vertex_colors[8] = {
color4( 0.0, 0.0, 0.0, 1.0), //black
color4( 1.0, 0.0, 0.0, 1.0), //red
color4( 1.0, 1.0, 0.0, 1.0), //yellow
color4( 0.0, 1.0, 0.0, 1.0), //blue
color4( 0.0, 0.0, 1.0, 1.0), //green
color4( 1.0, 0.0, 1.0, 1.0), //magenta
color4( 1.0, 1.0, 1.0, 1.0), //white
color4( 0.0, 1.0, 1.0, 1.0) //cyan
};
//Array of rotation angles (in degrees) for each coordinate axis
enum { Xaxis = 0, Yaxis = 1, Zaxis = 2, NumAxes = 3 };
int Axis = Xaxis;
GLfloat Theta[NumAxes] = { 0.0, 0.0, 0.0};
GLuint theta; //The location of the "theta" shader uniform variable
//----------------------------------------------------------------------------
//quad generates two triangles for each face and assigns colors to the vertices
int Index = 0;
void
quad( int a, int b, int c, int d)
{
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[b]; points[Index] = vertices[b]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[d]; points[Index] = vertices[d]; Index++;
}
//----------------------------------------------------------------------------
//generate 12 triangles: 36 vertices and 36 colors
void
colorcube( void )
{
quad( 1, 0, 3, 2);
quad( 2, 3, 7, 6);
quad( 3, 0, 4, 7);
quad( 6, 5, 1, 2);
quad( 4, 5, 6, 7);
quad( 5, 4, 0, 1);
}
Now all i thought I had to do from what I read was just change the all the parameters of vertex_colors in quad to a making them all the same like this:
int Index = 0;
void
quad( int a, int b, int c, int d)
{
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[b]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[d]; Index++;
}
But when I did this all the was generated was a blank white window. So what I'm confused on is there more then just changing the parameters or do I need to work with something else to get it working?
I can compile and run the program but it creates only a white windows with nothing in it when it is run. I've made sure that the shader files are in the same directory and still it produces nothing else than a window with a white background.
//
// Perspective view of a color cube using LookAt() and Frustum()
//
// Colors are assigned to each vertex and then the rasterizer interpolates
// those colors across the triangles.
//
#define _CRT_SECURE_NO_WARNINGS
#include "Angel.h"
typedef Angel::vec4 color4;
typedef Angel::vec4 point4;
const int NumVertices = 36; //(6 faces)(2 triangles/face)(3 vertices/triangle)
point4 points[NumVertices];
color4 colors[NumVertices];
// Vertices of a unit cube centered at origin, sides aligned with axes
point4 vertices[8] = {
point4( -0.5, -0.5, 0.5, 1.0 ),
point4( -0.5, 0.5, 0.5, 1.0 ),
point4( 0.5, 0.5, 0.5, 1.0 ),
point4( 0.5, -0.5, 0.5, 1.0 ),
point4( -0.5, -0.5, -0.5, 1.0 ),
point4( -0.5, 0.5, -0.5, 1.0 ),
point4( 0.5, 0.5, -0.5, 1.0 ),
point4( 0.5, -0.5, -0.5, 1.0 )
};
// RGBA olors
color4 vertex_colors[8] = {
color4( 0.0, 0.0, 0.0, 1.0 ), // black
color4( 1.0, 0.0, 0.0, 1.0 ), // red
color4( 1.0, 1.0, 0.0, 1.0 ), // yellow
color4( 0.0, 1.0, 0.0, 1.0 ), // green
color4( 0.0, 0.0, 1.0, 1.0 ), // blue
color4( 1.0, 0.0, 1.0, 1.0 ), // magenta
color4( 1.0, 1.0, 1.0, 1.0 ), // white
color4( 0.0, 1.0, 1.0, 1.0 ) // cyan
};
// Viewing transformation parameters
GLfloat radius = 1.0;
GLfloat theta = 0.0;
GLfloat phi = 0.0;
const GLfloat dr = 5.0 * DegreesToRadians;
GLuint model_view; // model-view matrix uniform shader variable location
// Projection transformation parameters
GLfloat left = -1.0, right = 1.0;
GLfloat bottom = -1.0, top = 1.0;
GLfloat zNear = 0.5, zFar = 3.0;
GLuint projection; // projection matrix uniform shader variable location
//----------------------------------------------------------------------------
// quad generates two triangles for each face and assigns colors
// to the vertices
int Index = 0;
void
quad( int a, int b, int c, int d )
{
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[b]; points[Index] = vertices[b]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[d]; points[Index] = vertices[d]; Index++;
}
//----------------------------------------------------------------------------
// generate 12 triangles: 36 vertices and 36 colors
void
colorcube()
{
quad( 1, 0, 3, 2 );
quad( 2, 3, 7, 6 );
quad( 3, 0, 4, 7 );
quad( 6, 5, 1, 2 );
quad( 4, 5, 6, 7 );
quad( 5, 4, 0, 1 );
}
//----------------------------------------------------------------------------
// OpenGL initialization
void
init()
{
colorcube();
// 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) + sizeof(colors),
NULL, GL_STATIC_DRAW );
glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(points), points );
glBufferSubData( GL_ARRAY_BUFFER, sizeof(points), sizeof(colors), colors );
// Load shaders and use the resulting shader program
GLuint program = InitShader( "vshader42.glsl", "fshader42.glsl" );
glUseProgram( program );
// set up vertex arrays
GLuint vPosition = glGetAttribLocation( program, "vPosition" );
glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(0) );
GLuint vColor = glGetAttribLocation( program, "vColor" );
glEnableVertexAttribArray( vColor );
glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(sizeof(points)) );
model_view = glGetUniformLocation( program, "model_view" );
projection = glGetUniformLocation( program, "projection" );
glEnable( GL_DEPTH_TEST );
glClearColor( 1.0, 1.0, 1.0, 1.0 );
}
//----------------------------------------------------------------------------
void
display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
point4 eye( radius*sin(theta)*cos(phi),
radius*sin(theta)*sin(phi),
radius*cos(theta),
1.0 );
point4 at( 0.0, 0.0, 0.0, 1.0 );
vec4 up( 0.0, 1.0, 0.0, 0.0 );
mat4 mv = LookAt( eye, at, up );
glUniformMatrix4fv( model_view, 1, GL_TRUE, mv );
mat4 p = Frustum( left, right, bottom, top, zNear, zFar );
glUniformMatrix4fv( projection, 1, GL_TRUE, p );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
glutSwapBuffers();
}
//----------------------------------------------------------------------------
void
keyboard( unsigned char key, int x, int y )
{
switch( key ) {
case 033: // Escape Key
case 'q': case 'Q':
exit( EXIT_SUCCESS );
break;
case 'x': left *= 1.1; right *= 1.1; break;
case 'X': left *= 0.9; right *= 0.9; break;
case 'y': bottom *= 1.1; top *= 1.1; break;
case 'Y': bottom *= 0.9; top *= 0.9; break;
case 'z': zNear *= 1.1; zFar *= 1.1; break;
case 'Z': zNear *= 0.9; zFar *= 0.9; break;
case 'r': radius *= 2.0; break;
case 'R': radius *= 0.5; break;
case 'o': theta += dr; break;
case 'O': theta -= dr; break;
case 'p': phi += dr; break;
case 'P': phi -= dr; break;
case ' ': // reset values to their defaults
left = -1.0;
right = 1.0;
bottom = -1.0;
top = 1.0;
zNear = 0.5;
zFar = 3.0;
radius = 1.0;
theta = 0.0;
phi = 0.0;
break;
}
glutPostRedisplay();
}
//----------------------------------------------------------------------------
void
reshape( int width, int height )
{
glViewport( 0, 0, width, height );
}
//----------------------------------------------------------------------------
int
main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
glutInitWindowSize( 512, 512 );
glutInitContextVersion( 3, 2 );
glutInitContextProfile( GLUT_CORE_PROFILE );
glutCreateWindow( "Color Cube" );
glewInit();
init();
glutDisplayFunc( display );
glutKeyboardFunc( keyboard );
glutReshapeFunc( reshape );
glutMainLoop();
return 0;
}
A few ideas:
Replace your glewInit(); with:
glewExperimental = GL_TRUE; // Added because of http://openglbook.com/glgenvertexarrays-access-violationsegfault-with-glew/
GLint GlewInitResult = glewInit();
if (GlewInitResult != GLEW_OK) {
printf("ERROR: %s\n", glewGetErrorString(GlewInitResult));
}
Also you should check for OpenGL errors using glGetError(). Read more details in my blog post: http://blog.nobel-joergensen.com/2013/01/29/debugging-opengl-using-glgeterror/ .
Some ideas:
you are requesting a context with support of OpenGL 3.2 but from the filenames of the shaders I assume you are #using GLSL 4.2? That could be an issue.
does InitShaders look for (compile-)errors?
Eliminate one possible source of errors after another. Draw a fullscreen-quad instead of your geometry, disable the shaders etc.
I simply want to map images as textures to the faces of a cube and display. Instead of having my images on it, the cube is totally black. My images are both 64x64 jpg's.
My application code is below. Originally it was a program that generated 2 checkerboard textures, displayed 1 at a time on all faces of the cube, allowing the user to switch between them. Instead of a checkerboard on all faces, I want an image. I've commented out their texture generation and texture loading code, replacing it with, most importantly, ilutGLLoadImage() (from DevIL): it's supposed to kill most image-texture loading birds with one stone. This happens in init(). The only console output is "1,2" (from my cout), which implies that the images were loaded and given valid texture ID's. Why is the cube black?
Application code (init() is a good place to start looking):
#include "Angel.h"
#include <IL\config.h>
#include <IL\ilut_config.h>
#include <IL\il.h>
#include <IL\ilu.h>
#include <IL\ilut.h>
#include <iostream>
using namespace std;
const int NumTriangles = 12; // (6 faces)(2 triangles/face)
const int NumVertices = 3 * NumTriangles;
const int TextureSize = 64;
typedef Angel::vec4 point4;
typedef Angel::vec4 color4;
// Texture objects and storage for texture image
//GLuint textures[2];
GLuint tex1;
GLuint tex2;
//GLubyte image[TextureSize][TextureSize][3];
//GLubyte image2[TextureSize][TextureSize][3];
// Vertex data arrays
point4 points[NumVertices];
//color4 quad_colors[NumVertices];
vec2 tex_coords[NumVertices];
// Array of rotation angles (in degrees) for each coordinate axis
enum { Xaxis = 0, Yaxis = 1, Zaxis = 2, NumAxes = 3 };
int Axis = Xaxis;
GLfloat Theta[NumAxes] = { 0.0, 0.0, 0.0 };
GLuint theta;
//----------------------------------------------------------------------------
int Index = 0;
void
quad( int a, int b, int c, int d )
{
point4 vertices[8] = {
point4( -0.5, -0.5, 0.5, 1.0 ),
point4( -0.5, 0.5, 0.5, 1.0 ),
point4( 0.5, 0.5, 0.5, 1.0 ),
point4( 0.5, -0.5, 0.5, 1.0 ),
point4( -0.5, -0.5, -0.5, 1.0 ),
point4( -0.5, 0.5, -0.5, 1.0 ),
point4( 0.5, 0.5, -0.5, 1.0 ),
point4( 0.5, -0.5, -0.5, 1.0 )
};
color4 colors[8] = {
color4( 0.0, 0.0, 0.0, 1.0 ), // black
color4( 1.0, 0.0, 0.0, 1.0 ), // red
color4( 1.0, 1.0, 0.0, 1.0 ), // yellow
color4( 0.0, 1.0, 0.0, 1.0 ), // green
color4( 0.0, 0.0, 1.0, 1.0 ), // blue
color4( 1.0, 0.0, 1.0, 1.0 ), // magenta
color4( 0.0, 1.0, 1.0, 1.0 ), // white
color4( 1.0, 1.0, 1.0, 1.0 ) // cyan
};
// bottom-left texture coord
// quad_colors[Index] = colors[a];
points[Index] = vertices[a];
tex_coords[Index] = vec2( 0.0, 0.0 );
Index++;
// top-left texture coord
// quad_colors[Index] = colors[a];
points[Index] = vertices[b];
tex_coords[Index] = vec2( 0.0, 1.0 );
Index++;
// top-right
// quad_colors[Index] = colors[a];
points[Index] = vertices[c];
tex_coords[Index] = vec2( 1.0, 1.0 );
Index++;
// bottom-left
// quad_colors[Index] = colors[a];
points[Index] = vertices[a];
tex_coords[Index] = vec2( 0.0, 0.0 );
Index++;
// top-right
// quad_colors[Index] = colors[a];
points[Index] = vertices[c];
tex_coords[Index] = vec2( 1.0, 1.0 );
Index++;
// bottom-right
// quad_colors[Index] = colors[a];
points[Index] = vertices[d];
tex_coords[Index] = vec2( 1.0, 0.0 );
Index++;
}
//----------------------------------------------------------------------------
void
colorcube()
{
quad( 1, 0, 3, 2 );
quad( 2, 3, 7, 6 );
quad( 3, 0, 4, 7 );
quad( 6, 5, 1, 2 );
quad( 4, 5, 6, 7 );
quad( 5, 4, 0, 1 );
}
//----------------------------------------------------------------------------
void
init()
{
colorcube();
ILuint devilError;
ilInit();
iluInit();
ilutInit();
devilError = ilGetError();
if (devilError != IL_NO_ERROR) {
printf ("Devil Error (ilInit: %s\n", iluErrorString(devilError));
exit (2);
}
ilutRenderer(ILUT_OPENGL);
GLuint openglID, openglError;
tex1 = ilutGLLoadImage("test1.jpg");
tex2 = ilutGLLoadImage("test2.jpg");
cout << tex1 << "," << tex2 << endl;
devilError = ilGetError();
if (devilError != IL_NO_ERROR) {
printf ("Error: %s\n", iluGetString (devilError));
exit (2);
}
if (openglError != GL_NO_ERROR) {
printf ("Opengl Error (ilutGLBindTexImage): %s\n", gluGetString (openglError));
exit (2);
}
// // Create a checkerboard pattern
// for ( int i = 0; i < 64; i++ ) {
// for ( int j = 0; j < 64; j++ ) {
// GLubyte c = (((i & 0x8) == 0) ^ ((j & 0x8) == 0)) * 255;
// image[i][j][0] = c;
// image[i][j][1] = c;
// image[i][j][2] = c;
// image2[i][j][0] = c;
// image2[i][j][1] = 0;
// image2[i][j][2] = c;
// }
// }
//
// // Initialize texture objects
//
// // Get unused texture identifiers
// glGenTextures( 2, textures );
//
glBindTexture( GL_TEXTURE_2D, tex1 );
//
// // Specify that 'image' is to be used as a two-dimensional texture
// glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, TextureSize, TextureSize, 0,
// GL_RGB, GL_UNSIGNED_BYTE, image );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
//
glBindTexture( GL_TEXTURE_2D, tex2 );
// glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, TextureSize, TextureSize, 0,
// GL_RGB, GL_UNSIGNED_BYTE, image2 );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glActiveTexture( GL_TEXTURE0 );
// Set the current texture object
glBindTexture( GL_TEXTURE_2D, tex1 );
// 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) + sizeof(quad_colors) + sizeof(tex_coords),
// NULL, GL_STATIC_DRAW );
glBufferData( GL_ARRAY_BUFFER,
sizeof(points) + sizeof(tex_coords),
NULL, GL_STATIC_DRAW );
// Specify an offset to keep track of where we're placing data in our
// vertex array buffer. We'll use the same technique when we
// associate the offsets with vertex attribute pointers.
GLintptr offset = 0;
glBufferSubData( GL_ARRAY_BUFFER, offset, sizeof(points), points );
offset += sizeof(points);
// glBufferSubData( GL_ARRAY_BUFFER, offset,
// sizeof(quad_colors), quad_colors );
// offset += sizeof(quad_colors);
glBufferSubData( GL_ARRAY_BUFFER, offset, sizeof(tex_coords), tex_coords );
// Load shaders and use the resulting shader program
GLuint program = InitShader( "vshader71.glsl", "fshader71.glsl" );
glUseProgram( program );
// set up vertex arrays
offset = 0;
GLuint vPosition = glGetAttribLocation( program, "vPosition" );
glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(offset) );
offset += sizeof(points);
// GLuint vColor = glGetAttribLocation( program, "vColor" );
// glEnableVertexAttribArray( vColor );
// glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0,
// BUFFER_OFFSET(offset) );
// offset += sizeof(quad_colors);
// Pass the texture coordinates as a vertex attribute with the identifier 'vTextCoord'
GLuint vTexCoord = glGetAttribLocation( program, "vTexCoord" );
glEnableVertexAttribArray( vTexCoord );
glVertexAttribPointer( vTexCoord, 2, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(offset) );
// Set the value of the fragment shader texture sampler variable
// ("texture") to the the appropriate texture unit. In this case,
// zero, for GL_TEXTURE0 which was previously set by calling
// glActiveTexture().
glUniform1i( glGetUniformLocation(program, "texture"), 0 );
theta = glGetUniformLocation( program, "theta" );
glEnable( GL_DEPTH_TEST );
glClearColor( 1.0, 1.0, 1.0, 1.0 );
}
void
display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUniform3fv( theta, 1, Theta );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
glutSwapBuffers();
}
//----------------------------------------------------------------------------
void
mouse( int button, int state, int x, int y )
{
if ( state == GLUT_DOWN ) {
switch( button ) {
case GLUT_LEFT_BUTTON: Axis = Xaxis; break;
case GLUT_MIDDLE_BUTTON: Axis = Yaxis; break;
case GLUT_RIGHT_BUTTON: Axis = Zaxis; break;
}
}
}
//----------------------------------------------------------------------------
void
idle( void )
{
Theta[Axis] += 0.01;
if ( Theta[Axis] > 360.0 ) {
Theta[Axis] -= 360.0;
}
glutPostRedisplay();
}
//----------------------------------------------------------------------------
void
keyboard( unsigned char key, int mousex, int mousey )
{
switch( key ) {
case 033: // Escape Key
case 'q': case 'Q':
exit( EXIT_SUCCESS );
break;
case '1':
glBindTexture( GL_TEXTURE_2D, tex1 );
break;
case '2':
glBindTexture( GL_TEXTURE_2D, tex2 );
break;
}
glutPostRedisplay();
}
//----------------------------------------------------------------------------
int
main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
glutInitWindowSize( 512, 512 );
glutInitContextVersion( 3, 2 );
glutInitContextProfile( GLUT_CORE_PROFILE );
glutCreateWindow( "Texture Cube" );
glewExperimental = GL_TRUE;
glewInit();
init();
glutDisplayFunc( display );
glutKeyboardFunc( keyboard );
glutMouseFunc( mouse );
glutIdleFunc( idle );
glutMainLoop();
return 0;
}
Vertex shader:
#version 150
in vec4 vPosition;
in vec2 vTexCoord;
out vec4 color;
out vec2 texCoord;
uniform vec3 theta;
void main()
{
const float DegreesToRadians = 3.14159265 / 180.0;
vec3 c = cos( DegreesToRadians * theta );
vec3 s = sin( DegreesToRadians * theta );
mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0,
0.0, c.x, -s.x, 0.0,
0.0, s.x, c.x, 0.0,
0.0, 0.0, 0.0, 1.0);
mat4 ry = mat4( c.y, 0.0, s.y, 0.0,
0.0, 1.0, 0.0, 0.0,
-s.y, 0.0, c.y, 0.0,
0.0, 0.0, 0.0, 1.0 );
// Workaround for bug in ATI driver
ry[1][0] = 0.0;
ry[1][1] = 1.0;
mat4 rz = mat4( c.z, -s.z, 0.0, 0.0,
s.z, c.z, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 );
// Workaround for bug in ATI driver
rz[2][2] = 1.0;
texCoord = vTexCoord;
gl_Position = rz * ry * rx * vPosition;
}
Fragment shader:
#version 150
in vec2 texCoord;
out vec4 fColor;
uniform sampler2D texture;
void main()
{
fColor = texture2D( texture, texCoord );
}
Sinewave distortion of a 2D image is a classic visual effect: taking a 2D image and warping it along either the X or the Y axis by shifting pixels according to a sine wave. It ends up looking something like this:
I've seen a few examples of code for it, and the standard way to do this with OpenGL seems to be, for a an image of dimensions (x, y):
for each column from 0 to X
draw a single quad one pixel wide and y pixels high, offset by a sine wave value
Of course, this involves a lot of work on the client-side. Is there any way to draw a single quad and offload the distortion work to the GPU with shaders? Only vertex and fragment shaders; I'm using OpenGL 2, so there are no geometry shaders available.
I know I could use a fragment shader to sample texture coordinates that are offset by a sine wave, but getting them to place at locations outside the original box defined by the quad would be tricky, and I'd prefer not to have the output be clipped like in the sample picture. Is there any way around this problem?
Yes, this can be done using shaders. Using a vertex shader you can apply a sine distortion on a grid. A fragment shader can modulate the texture coordinate, but not the target pixel location; fragment shaders are gatherers and can not do data scattering.
Update
Working example for texture coordinate modulation:
#include <stdlib.h>
#include <stdio.h>
#include <GL/glew.h>
#include <GL/glfw.h>
static void pushModelview()
{
GLenum prev_matrix_mode;
glGetIntegerv(GL_MATRIX_MODE, &prev_matrix_mode);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMatrixMode(prev_matrix_mode);
}
static void popModelview()
{
GLenum prev_matrix_mode;
glGetIntegerv(GL_MATRIX_MODE, &prev_matrix_mode);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(prev_matrix_mode);
}
static const GLchar *vertex_shader_source =
"#version 130\n"
"void main()"
"{"
" gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;"
" gl_TexCoord[0] = gl_MultiTexCoord0;"
" gl_FrontColor = gl_Color;"
" gl_BackColor = gl_Color;"
"}\0";
GLuint shaderVertex = 0;
static const GLchar *fragment_shader_source =
"#version 130\n"
"uniform sampler2D texCMYK;\n"
"uniform sampler2D texRGB;\n"
"uniform float T;\n"
"const float pi = 3.14159265;\n"
"void main()\n"
"{\n"
" float ts = gl_TexCoord[0].s;\n"
" vec2 mod_texcoord = gl_TexCoord[0].st + vec2(0, 0.5*sin(T + 1.5*ts*pi));\n"
" gl_FragColor = -texture2D(texCMYK, mod_texcoord) + texture2D(texRGB, gl_TexCoord[0].st);\n"
"}\n\0";
GLuint shaderFragment = 0;
GLuint shaderProgram = 0;
#define TEX_CMYK_WIDTH 2
#define TEX_CMYK_HEIGHT 2
GLubyte textureDataCMYK[TEX_CMYK_WIDTH * TEX_CMYK_HEIGHT][3] = {
{0x00, 0xff, 0xff}, {0xff, 0x00, 0xff},
{0xff, 0xff, 0x00}, {0x00, 0x00, 0x00}
};
GLuint texCMYK = 0;
#define TEX_RGB_WIDTH 2
#define TEX_RGB_HEIGHT 2
GLubyte textureDataRGB[TEX_RGB_WIDTH * TEX_RGB_HEIGHT][3] = {
{0x00, 0x00, 0xff}, {0xff, 0xff, 0xff},
{0xff, 0x00, 0x00}, {0x00, 0xff, 0x00}
};
GLuint texRGB = 0;
GLfloat cube_vertices[][8] = {
/* X Y Z Nx Ny Nz S T */
{-1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0}, // 0
{ 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0}, // 1
{ 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0}, // 2
{-1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0}, // 3
{ 1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0},
{-1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 0.0},
{-1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 1.0},
{ 1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 1.0},
{-1.0, -1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0},
{-1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 1.0, 0.0},
{-1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0, 1.0},
{-1.0, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 1.0},
{ 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 0.0},
{ 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0},
{ 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0},
{ 1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 1.0},
{ 1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0},
{-1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 1.0, 0.0},
{-1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, 1.0},
{ 1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0},
{-1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0},
{ 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0},
{ 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0},
{-1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0},
};
static void draw_cube(void)
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(GLfloat) * 8, &cube_vertices[0][0]);
glNormalPointer(GL_FLOAT, sizeof(GLfloat) * 8, &cube_vertices[0][3]);
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat) * 8, &cube_vertices[0][6]);
glDrawArrays(GL_QUADS, 0, 24);
}
static void bind_sampler_to_unit_with_texture(GLchar const * const sampler_name, GLuint texture_unit, GLuint texture)
{
glActiveTexture(GL_TEXTURE0 + texture_unit);
glBindTexture(GL_TEXTURE_2D, texture);
GLuint loc_sampler = glGetUniformLocation(shaderProgram, sampler_name);
glUniform1i(loc_sampler, texture_unit);
}
static void display(double T)
{
int window_width, window_height;
glfwGetWindowSize(&window_width, &window_height);
if( !window_width || !window_height )
return;
const float window_aspect = (float)window_width / (float)window_height;
glDisable(GL_SCISSOR_TEST);
glClearColor(0.5, 0.5, 0.7, 1.0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, window_width, window_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-window_aspect, window_aspect, -1, 1, 1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -5);
pushModelview();
glRotatef(T * 0.1 * 180, 0., 1., 0.);
glRotatef(T * 0.1 * 60, 1., 0., 0.);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glUseProgram(shaderProgram);
glUniform1f(glGetUniformLocation(shaderProgram, "T"), T);
bind_sampler_to_unit_with_texture("texCMYK", 0, texCMYK);
bind_sampler_to_unit_with_texture("texRGB", 1, texRGB);
draw_cube();
popModelview();
glfwSwapBuffers();
}
static int open_window(void)
{
#if 0
glfwWindowHint(GLFW_OPENGL_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_OPENGL_VERSION_MINOR, 0);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
#endif
if( glfwOpenWindow(0, 0, /* default size */
8, 8, 8, /* 8 bits per channel */
8, 24, 8, /* 8 alpha, 24 depth, 8 stencil */
GLFW_WINDOW) != GL_TRUE ) {
fputs("Could not open window.\n", stderr);
return 0;
}
if( glewInit() != GLEW_OK ) {
fputs("Could not initialize extensions.\n", stderr);
return 0;
}
return 1;
}
static int check_extensions(void)
{
if( !GLEW_ARB_vertex_shader ||
!GLEW_ARB_fragment_shader ) {
fputs("Required OpenGL functionality not supported by system.\n", stderr);
return 0;
}
return 1;
}
static int check_shader_compilation(GLuint shader)
{
GLint n;
glGetShaderiv(shader, GL_COMPILE_STATUS, &n);
if( n == GL_FALSE ) {
GLchar *info_log;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &n);
info_log = malloc(n);
glGetShaderInfoLog(shader, n, &n, info_log);
fprintf(stderr, "Shader compilation failed: %*s\n", n, info_log);
free(info_log);
return 0;
}
return 1;
}
static int init_resources(void)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glGenTextures(1, &texCMYK);
glBindTexture(GL_TEXTURE_2D, texCMYK);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, TEX_CMYK_WIDTH, TEX_CMYK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, textureDataCMYK);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenTextures(1, &texRGB);
glBindTexture(GL_TEXTURE_2D, texRGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, TEX_RGB_WIDTH, TEX_RGB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, textureDataRGB);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
shaderVertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(shaderVertex, 1, (const GLchar**)&vertex_shader_source, NULL);
glCompileShader(shaderVertex);
if( !check_shader_compilation(shaderVertex) )
return 0;
shaderFragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(shaderFragment, 1, (const GLchar**)&fragment_shader_source, NULL);
glCompileShader(shaderFragment);
if( !check_shader_compilation(shaderFragment) )
return 0;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, shaderVertex);
glAttachShader(shaderProgram, shaderFragment);
glLinkProgram(shaderProgram);
return 1;
}
static void main_loop(void)
{
glfwSetTime(0);
while( glfwGetWindowParam(GLFW_OPENED) == GL_TRUE ) {
display(glfwGetTime());
}
}
int main(int argc, char *argv[])
{
if( glfwInit() != GL_TRUE ) {
fputs("Could not initialize framework.\n", stderr);
return -1;
}
if( !open_window() )
return -1;
if( !check_extensions() )
return -1;
if( !init_resources() )
return -1;
main_loop();
glfwTerminate();
return 0;
}
The fragment shader part is this:
#version 130
uniform sampler2D texCMYK;
uniform sampler2D texRGB;
uniform float T;
const float pi = 3.14159265;
void main()
{
float ts = gl_TexCoord[0].s;
vec2 mod_texcoord = gl_TexCoord[0].st + vec2(0, 0.5*sin(T + 1.5*ts*pi));
gl_FragColor = -texture2D(texCMYK, mod_texcoord) + texture2D(texRGB, gl_TexCoord[0].st);
};
Update – a shader that "expands":
uniform sampler2D texCMYK;
uniform sampler2D texRGB;
uniform float T;
const float pi = 3.14159265;
void main()
{
float ts = gl_TexCoord[0].s;
vec2 mod_texcoord = gl_TexCoord[0].st*vec2(1., 2.) + vec2(0, -0.5 + 0.5*sin(T + 1.5*ts*pi));
if( mod_texcoord.t < 0. || mod_texcoord.t > 1. ) { discard; }
gl_FragColor = -texture2D(texCMYK, mod_texcoord) + texture2D(texRGB, gl_TexCoord[0].st);
};
For a given input quad render a quad 2 * max_amplitude taller (maybe with a vertex shader?) and in your pixel shader discard pixels that aren't currently being sin()'d onto.
That way you can reach "outside" your original quad.