一个简单的GLSL Shader例子

本例子选自OpenGL Shading Language中的第一个Shader例子,使用颜色平滑地表示一个表面的温度。温度及其颜色的范围在应用程序中进行设置。
//先看顶点着色器temp.vert:
uniform float CoolestTemp;
uniform float TempRange;
attribute float VertexTemp;//每个定点都对应一个温度值
varying float Temperature;//传递到片段处理器进行后续处理
void main(void)
{
//进行插值
Temperature = (VertexTemp - CoolestTemp) / TempRange;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
//片段着色器temp.frag:
uniform vec3 CoolestColor;
uniform vec3 HottestColor;
varying float Temperature;
void main(void)
{
//通过温度值寻找一个相应的颜色,位于最冷和最热之间
vec3 color = mix(CoolestColor, HottestColor,Temperature);
gl_FragColor = vec4(color,1.0);
}
下面看看如何将着色器和应用程序进行链接(第一步是创建着色器对象,指定着色器源代码,进行编译,并程序对象和着色器进行绑定和链接),同时指定了一些一致变量的值
/*public*/
int installShaders(const GLchar *Vertex, const GLchar *Fragment)
{
GLint vertCompiled, fragCompiled;
// status values
GLint linked;
// Create a vertex shader object and a fragment shader object
VertexShaderObject = glCreateShader(GL_VERTEX_SHADER);
FragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER); /
/ Load source code strings into shaders
glShaderSource(VertexShaderObject, 1, &Vertex, NULL);
glShaderSource(FragmentShaderObject, 1, &Fragment, NULL);
// Compile the brick vertex shader, and print out
// the compiler log file.
glCompileShader(VertexShaderObject);
glGetShaderiv(VertexShaderObject, GL_COMPILE_STATUS, &vertCompiled);
// Compile the brick vertex shader, and print out
// the compiler log file.
glCompileShader(FragmentShaderObject);
glGetShaderiv(FragmentShaderObject, GL_COMPILE_STATUS, &fragCompiled);
if (!vertCompiled || !fragCompiled)
return 0;
// Create a program object and attach the two compiled shaders
ProgramObject = glCreateProgram();
glAttachShader(ProgramObject, VertexShaderObject);
glAttachShader(ProgramObject, FragmentShaderObject);
// Link the program object and print out the info log
glLinkProgram(ProgramObject);
glGetProgramiv(ProgramObject, GL_LINK_STATUS, &linked);
if (!linked)
return 0;
// Install program object as part of current state
glUseProgram(ProgramObject);
// Set up initial uniform values
glUniform1f(glGetUniformLocation(ProgramObject, "CoolestTemp"), 0.0f);
glUniform1f(glGetUniformLocation(ProgramObject, "TempRange"), 1.0f);
glUniform3f(glGetUniformLocation(ProgramObject, "CoolestColor"), 0.0, 0.0, 1.0);
glUniform3f(glGetUniformLocation(ProgramObject, "HottestColor"), 1.0, 0.0, 0.0);
return 1;
}
这其中用到了一些读取外部着色器代码的函数,顶点着色器后缀自定义为.vert,片段着色器自定义为.frag,我们也可以将着色器放在程序中存储在一个字符串中。
//Shader related functions static int shaderSize(char *fileName, EShaderType shaderType)
{
//返回顶点着色器或者片段着色器的大小
char name[100];
strcpy(name, fileName);
switch (shaderType)
{
case EVertexShader:
strcat(name, ".vert");
break;
case EFragmentShader:
strcat(name, ".frag");
break;
default:
printf("ERROR: unknown shader file type\n");
exit(1);
break;
}
int count = -1;
// Open the file, seek to the end to find its length
int fd = _open(name, _O_RDONLY);
if (fd != -1)
{
count = _lseek(fd, 0, SEEK_END) + 1;
_close(fd);
}
return count;
}

static int readShader(char *fileName, EShaderType shaderType, char *shaderText, int size)
{
// Reads a shader from the supplied file and returns the shader in the
// arrays passed in.
Returns 1 if successful, 0 if an error occurred.
// The parameter size is an upper limit of the amount of bytes to read.
// It is ok for it to be too big.
FILE *fh;
char name[100];
int count;
strcpy(name, fileName);
switch (shaderType)
{
case EVertexShader:
strcat(name, ".vert");
break;
case EFragmentShader:
strcat(name, ".frag");
break;
default:
printf("ERROR: unknown shader file type\n");
exit(1);
break;
}
// Open the file
fh = fopen(name, "r");
if (!fh)
return -1;
// Get the shader from a file.
fseek(fh, 0, SEEK_SET);
count = (int) fread(shaderText, 1, size, fh);
shaderText[count] = '\0';
if (ferror(fh))
count = 0;
fclose(fh);
return count;
}

/*public*/
int readShaderSource(char *fileName, GLchar **vertexShader, GLchar **fragmentShader)
{
int vSize, fSize;
// // Allocate memory to hold the source of our shaders.
vSize = shaderSize(fileName, EVertexShader);
fSize = shaderSize(fileName, EFragmentShader);
if ((vSize == -1) || (fSize == -1))
{
printf("Cannot determine size of the shader %s\n", fileName); return 0;
}
*vertexShader = (GLchar *) malloc(vSize);
*fragmentShader = (GLchar *) malloc(fSize);
// // Read the source code //
if (!readShader(fileName, EVertexShader, *vertexShader, vSize))
{
printf("Cannot read the file %s.vert\n", fileName);
return 0;
}
if (!readShader(fileName, EFragmentShader, *fragmentShader, fSize))
{
printf("Cannot read the file %s.frag\n", fileName);
return 0;
}
return 1;
}
这里我们只绘制一个简单的三角形,需要为每个顶点指定一个属性值,代表其温度值,着色器中我们对其进行了读取并插值。对于复杂的图形,应当使用顶点数组进行指定。
static void display(void)
{
glLoadIdentity();
glTranslatef(0.0, 0.0, -5.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//查询定点着色器属性变量VertexTemp,并对它进行设置,每个定点需要指定一个属性
GLint tempLoc = glGetAttribLocationARB(ProgramObject, "VertexTemp");
glBegin(GL_TRIANGLES);
glVertexAttrib1f(tempLoc, 0.0f);
glVertex3f(1.0f,0.0f,0.0f);
glVertexAttrib1f(tempLoc, 0.5f);
glVertex3f(-1.0f,0.0f,0.0f);
glVertexAttrib1f(tempLoc, 1.0f);
glVertex3f(0.0f,1.0f,0.0f);
glEnd();
glFlush();
glutSwapBuffers();
}
运行效果如下:

 
整个程序如下:

  

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <fcntl.h>

#include <io.h>

#define GLEW_STATIC 1

#include <GL/glew.h>

#include <GL/glu.h>

#include <GL/glut.h>

 

//窗口句柄

static GLint window;

 

GLuint ProgramObject = 0;                            //程序对象

GLuint VertexShaderObject = 0;                   //顶点着色器对象

GLuint FragmentShaderObject = 0;    //片段着色器对象

 

//Shader类型

typedef enum {

    EVertexShader,

         EFragmentShader,

} EShaderType;

 

//用来检查OpenGL版本,需要GLSL 2.0支持

void getGlVersion( int *major, int *minor )

{

    constchar* verstr = (constchar*)glGetString( GL_VERSION );

    if( (verstr == NULL) || (sscanf( verstr, "%d.%d", major, minor ) != 2) )

    {

        *major = *minor = 0;

        fprintf( stderr, "Invalid GL_VERSION format!!!\n" );

    }

}

 

staticvoid display(void)

{

    glLoadIdentity();

    glTranslatef(0.0, 0.0, -5.0);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 

         //查询定点着色器属性变量VertexTemp,并对它进行设置,每个定点需要指定一个属性

         GLint tempLoc = glGetAttribLocationARB(ProgramObject, "VertexTemp");

         glBegin(GL_TRIANGLES);

                   glVertexAttrib1f(tempLoc, 0.0f);         

                   glVertex3f(1.0f,0.0f,0.0f);

                   glVertexAttrib1f(tempLoc, 0.5f);

                   glVertex3f(-1.0f,0.0f,0.0f);

                   glVertexAttrib1f(tempLoc, 1.0f);

                   glVertex3f(0.0f,1.0f,0.0f);

         glEnd();

    glFlush();

    glutSwapBuffers();

}

 

staticvoid reshape(int wid, int ht)

{

    float vp = 0.8f;

    float aspect = (float) wid / (float) ht;

         

    glViewport(0, 0, wid, ht);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    //glOrtho(-1.0, 1.0, -1.0, 1.0, -10.0, 10.0);

    glFrustum(-vp, vp, -vp / aspect, vp / aspect, 3, 10.0);

         glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

}

 



//Shader related functions

staticint shaderSize(char *fileName, EShaderType shaderType)

{

         //返回顶点着色器或者片段着色器的大小

    char name[100];

    strcpy(name, fileName);

 

    switch (shaderType)

    {

        case EVertexShader:

            strcat(name, ".vert");

            break;

        case EFragmentShader:

            strcat(name, ".frag");

            break;

        default:

            printf("ERROR: unknown shader file type\n");

            exit(1);

            break;

    }

 

    int count = -1;

    // Open the file, seek to the end to find its length

    int fd = _open(name, _O_RDONLY);

    if (fd != -1)

    {

        count = _lseek(fd, 0, SEEK_END) + 1;

        _close(fd);

    }

    return count;

}

 



staticint readShader(char *fileName, EShaderType shaderType, char *shaderText, int size)

{

    //

    // Reads a shader from the supplied file and returns the shader in the

    // arrays passed in. Returns 1 if successful, 0 if an error occurred.

    // The parameter size is an upper limit of the amount of bytes to read.

    // It is ok for it to be too big.

    //

    FILE *fh;

    char name[100];

    int count;

 

    strcpy(name, fileName);

 

    switch (shaderType) 

    {

        case EVertexShader:

            strcat(name, ".vert");

            break;

        case EFragmentShader:

            strcat(name, ".frag");

            break;

        default:

            printf("ERROR: unknown shader file type\n");

            exit(1);

            break;

    }

 

    // Open the file

    fh = fopen(name, "r");

    if (!fh)

        return -1;

 

    // Get the shader from a file.

    fseek(fh, 0, SEEK_SET);

    count = (int) fread(shaderText, 1, size, fh);

    shaderText[count] = '\0';

 

    if (ferror(fh))

        count = 0;

 

    fclose(fh);

    return count;

}

 



/*public*/

int readShaderSource(char *fileName, GLchar **vertexShader, GLchar **fragmentShader)

{

    int vSize, fSize;

 

    //

    // Allocate memory to hold the source of our shaders.

    //

    vSize = shaderSize(fileName, EVertexShader);

    fSize = shaderSize(fileName, EFragmentShader);

 

    if ((vSize == -1) || (fSize == -1))

    {

        printf("Cannot determine size of the shader %s\n", fileName);

        return 0;

    }

 

    *vertexShader = (GLchar *) malloc(vSize);

    *fragmentShader = (GLchar *) malloc(fSize);

 

    //

    // Read the source code

    //

    if (!readShader(fileName, EVertexShader, *vertexShader, vSize))

    {

        printf("Cannot read the file %s.vert\n", fileName);

        return 0;

    }

 

    if (!readShader(fileName, EFragmentShader, *fragmentShader, fSize))

    {

        printf("Cannot read the file %s.frag\n", fileName);

        return 0;

    }

 

    return 1;

}

 



/*public*/

int installShaders(const GLchar *Vertex,

                        const GLchar *Fragment)

{

    GLint vertCompiled, fragCompiled;    // status values

    GLint linked;

 

    // Create a vertex shader object and a fragment shader object

 

    VertexShaderObject = glCreateShader(GL_VERTEX_SHADER);

    FragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER);

 

    // Load source code strings into shaders

 

    glShaderSource(VertexShaderObject, 1, &Vertex, NULL);

    glShaderSource(FragmentShaderObject, 1, &Fragment, NULL);

 

    // Compile the brick vertex shader, and print out

    // the compiler log file.

 

    glCompileShader(VertexShaderObject);

    glGetShaderiv(VertexShaderObject, GL_COMPILE_STATUS, &vertCompiled);

 

    // Compile the brick vertex shader, and print out

    // the compiler log file.

 

    glCompileShader(FragmentShaderObject);

    glGetShaderiv(FragmentShaderObject, GL_COMPILE_STATUS, &fragCompiled);

 

    if (!vertCompiled || !fragCompiled)

        return 0;

 

    // Create a program object and attach the two compiled shaders

 

    ProgramObject = glCreateProgram();

    glAttachShader(ProgramObject, VertexShaderObject);

    glAttachShader(ProgramObject, FragmentShaderObject);

 

    // Link the program object and print out the info log

 

    glLinkProgram(ProgramObject);

    glGetProgramiv(ProgramObject, GL_LINK_STATUS, &linked);

 

    if (!linked)

        return 0;

 

    // Install program object as part of current state

 

    glUseProgram(ProgramObject);

 

    // Set up initial uniform values

    glUniform1f(glGetUniformLocation(ProgramObject, "CoolestTemp"), 0.0f);

    glUniform1f(glGetUniformLocation(ProgramObject, "TempRange"), 1.0f);

    glUniform3f(glGetUniformLocation(ProgramObject, "CoolestColor"), 0.0, 0.0, 1.0);

    glUniform3f(glGetUniformLocation(ProgramObject, "HottestColor"), 1.0, 0.0, 0.0);

 

    return 1;

}

 

/******************************************************************************/

/*

/* Main

/*

/******************************************************************************/

int main( int argc, char **argv )

{

    int success = 0;

    int gl_major, gl_minor;

    GLchar *VertexShaderSource, *FragmentShaderSource;

         

    glutInit( &argc, argv );

    glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);

    glutInitWindowSize(500, 500);

    window = glutCreateWindow( "Temperature Shader");

         

    glutDisplayFunc(display);

    glutReshapeFunc(reshape);

         

    // Initialize the "OpenGL Extension Wrangler" library

    glewInit();

         

    // Make sure that OpenGL 2.0 is supported by the driver

    getGlVersion(&gl_major, &gl_minor);

    printf("GL_VERSION major=%d minor=%d\n", gl_major, gl_minor);

         

    if (gl_major < 2)

    {

        printf("GL_VERSION major=%d minor=%d\n", gl_major, gl_minor);

        printf("Support for OpenGL 2.0 is required for this demo...exiting\n");

        exit(1);

    }

         

    readShaderSource("temp", &VertexShaderSource, &FragmentShaderSource);

    success = installShaders(VertexShaderSource, FragmentShaderSource);

         

    if (success)

        glutMainLoop();

    

    return 0;

}


 

转载: http://blog.chinaunix.net/uid-20235103-id-1970751.html

你可能感兴趣的:(C++,OpenGL,GLSL)