1.把着色器写到文本文件中,以便在程序中读取调用shader.vert;shader.fragment
2.用读文件的方式把两个着色器中的代码读到字符串中
3.新建shader对象,判断创建是否成功glCreateShader()
4.将着色器字符串关联到shader对象glShaderSource()
5.编译着色器对象,判断编译是否成功,如果不成功,输出错误日志glCompileShader()
6.创建着色器程序,判断是否创建成功glCreateProgram()
7.关联着色器对象和着色器程序glAttachShader()
8.链接着色器程序,判断链接是否成功glLinkProgram()
9.使用着色器程序 即让着色器在主程序运行过程中发挥作用glUseProgram()
1234567见AddShader()函数
具体代码如下:
#include <stdio.h>
#include <string>
#include <iostream>
#include <glew.h>
#include <assert.h>
#include <freeglut.h>
#include "Utils.h"
#include "Vertex.h"
const char * pVS = "shader.vert";//已经用着色语言编辑好的着色器(其实就是文本文件)
const char * pFS = "shader.frag";
GLuint VBO;
GLuint gScaleLocation;
static void RenderSceneCB()
{
glClear(GL_COLOR_BUFFER_BIT);
static float Scale = 0.0f;
Scale += 0.001f;
glUniform1f(gScaleLocation,sinf(Scale));
glEnableVertexAttribArray(1);//设置是否启用与index索引相关联的顶点数组
glBindBuffer(GL_ARRAY_BUFFER,VBO);//第二次调用激活绑定到目标GL_ARRAY_BUFFER的缓存对象
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,3*4,0);//从缓冲区获取数据,传入到顶点着色器对应的in变量中(即给顶点着色器输入数据,即opengl将要处理的所有顶点数据)
glDrawArrays(GL_TRIANGLES,0,3);
glDisableVertexAttribArray(1);
glutSwapBuffers();
}
static void CreateVertexBuffer()
{
Vector3f Vertices[3];
Vertices[0] = Vector3f(-1.0f,-1.0f,0.0f);
Vertices[1] = Vector3f(1.0f,-1.0f, 0.0f);
Vertices[2] = Vector3f(0.0f,1.0f, 0.0f);
glGenBuffers(1,&VBO);//返回n个未使用的缓存对象名称,并保存到buffer数组中
glBindBuffer(GL_ARRAY_BUFFER,VBO);//第一次调用,创建一个与该名称相对应的新缓存对象(且将它作为当前对象),并真正地分配所需内存
glBufferData(GL_ARRAY_BUFFER,sizeof(Vertices), Vertices, GL_STATIC_DRAW);
}
static void AddShader(GLuint ShaderProgram,const char* shaderText, GLenum shaderType)
{
GLuint ShaderObj = glCreateShader(shaderType);
if (ShaderObj == 0)
{
ErrorOut();
exit(1);
}
const GLchar* p[1];
p[0]= shaderText;
GLint L[1];
L[0] = strlen(shaderText);
glShaderSource(ShaderObj,1,p,L);
glCompileShader(ShaderObj);
GLint success;
glGetShaderiv(ShaderObj,GL_COMPILE_STATUS,&success);
if (!success)
{
GLchar InfoLog[1024];
glGetShaderInfoLog(ShaderObj,1024,NULL,InfoLog);
fprintf(stderr,"Error compiling shader type %d:'%s'\n",shaderType,InfoLog);
exit(1);
}
glAttachShader(ShaderProgram,ShaderObj);
}
void CompileShaders()
{
string vs,fs;
if (!ReadFile(pVS,vs))
{
exit(1);
}
if (!ReadFile(pFS,fs))
{
exit(1);
}
//cout<<vs<<endl;
//cout<<fs<<endl;
GLuint ShaderProgram = glCreateProgram();
if (0 == ShaderProgram)
{
ErrorOut();
exit(1);
}
AddShader(ShaderProgram,vs.c_str(),GL_VERTEX_SHADER);
AddShader(ShaderProgram,fs.c_str(),GL_FRAGMENT_SHADER);
glLinkProgram(ShaderProgram);
GLint Success=0;
GLchar ErrorLog[1024] = {0};
glGetProgramiv(ShaderProgram,GL_LINK_STATUS,&Success);
if (Success == 0)
{
glGetProgramInfoLog(ShaderProgram,sizeof(ErrorLog),NULL,ErrorLog);
fprintf(stderr,"Error linking shader program:'%s'\n",ErrorLog);
exit(1);
}
gScaleLocation = glGetUniformLocation(ShaderProgram,"gScale");
//assert(gScaleLocation != OxFFFFFFFF);
glValidateProgram(ShaderProgram);
glGetProgramiv(ShaderProgram,GL_VALIDATE_STATUS,&Success);
if (Success == 0)
{
glGetProgramInfoLog(ShaderProgram,sizeof(ErrorLog),NULL,ErrorLog);
fprintf(stderr, "Error linking shader program:'%s'\n",ErrorLog);
exit(1);
}
glUseProgram(ShaderProgram);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA);
glutInitWindowSize(800, 600);
glutCreateWindow("tutorial 01");
GLenum res = glewInit();
if (GLEW_OK != res)
{
fprintf(stderr,"Error:%s",glewGetErrorString(res));
return 1;
}
glutDisplayFunc(RenderSceneCB);
glutIdleFunc(RenderSceneCB);
glClearColor(0.0f,1.0f,0.0f,0.0f);
CompileShaders();
CreateVertexBuffer();
glutMainLoop();
return 0;
}
附加:
(1)shader.vert :
#version 330
layout (location = 1) in vec3 Position;
unifor float gScale;
// varying
out vec3 color;
void main()
{
gl_Position = vec4(Position.x*gScale, Position.y*gScale, Position.z , 1.0);
color = vec3(Position.x*gScale,Position.y*gScale,Position.z);
}
(2) shader.frag:
#version 330
out vec4 FragColor;
uniform float gScale;
in vec3 color;
void main()
{
FragColor = vec4(color.x, color.y, color.z, 0.1);
}
(3)Vertex内容:
#pragma once
class Vector3f
{
public:
float x,y,z;
Vector3f(){}
Vector3f(float _x,float _y,float _z)
{
x = _x;
y = _y;
z = _z;
}
};
(4)Utis.h内容:
#pragma once
#include <iostream>
#include <string>
using namespace std;
//添加宏定义错误文件和位置
void error_out(string file,unsigned int linenum);
#define ErrorOut() error_out(__FILE__,__LINE__)
bool ReadFile(const char* fileName, string& outFile);
Utis.cpp内容:
#include "Utils.h"
#include <fstream>
void error_out(string file, unsigned int linenum)
{
cout<<file<<":"<<linenum<<endl;
}
bool ReadFile(const char* pFileName,string& outFile)
{
ifstream f(pFileName);
bool ret = false;
if (f.is_open())
{
string line;
while(getline(f,line))
{
outFile.append(line);
outFile.append("\n");
}
f.close();
ret = true;
}
else
{
ErrorOut();
}
return ret;
}