OpenGL shader笔记
目录
- https://www.khronos.org/registry/OpenGL-Refpages/
- 着色器程序先编译链接好,然后启用,使用完毕后调用glUseProgram(0);因为OpenGL是状态机,会保存状态。
- 将顶点数据传入显卡缓存区,着色器使用完后 glDisableClientState
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(3,GL_FLOAT,sizeof(Vertex),rect); glColorPointer(3,GL_FLOAT,sizeof(Vertex),&rect[0].r);
- 调用着色器干活:
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY);
uniform
- 全局变量
const char* vs = "void main()\ {\ gl_Position = ftransform();\ }"; const char* ps = "uniform vec4 _color;\ void main()\ {\ gl_FragColor = _color;\ }"; createProgram(vs, ps); _color = glGetUniformLocation(_program,"_color");
- 设置值:
glUniform4f(_shader._color,0,1,0,1);
varying
- 着色器之间传递数据
const char* vs = "uniform vec4 _color;\ varying vec4 outColor;\ void main()\ {\ outColor = _color;\ gl_Position = ftransform(); }"; const char* ps = " varying vec4 outColor;\ void main()\ {\ gl_FragColor = outColor;\ }"; createProgram(vs, ps); _color = glGetUniformLocation(_program,"_color");
访问顶点
- gl_ModelViewProjectionMatrix * gl_Vertex
- 模型视图投影矩阵 乘以 顶点矩阵 (均为内置变量)
const char* vs = "uniform vec4 _color;\ varying vec4 outColor;\ void main()\ {\ outColor = _color;\ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\ //gl_Position = ftransform();\ }"; const char* ps = " varying vec4 outColor;\ void main()\ {\ gl_FragColor = outColor;\ }";
访问顶点--颜色
- 一个顶点支持多个颜色
- gl_Color gl_SecondaryColor 内置变量
const char* vs = "varying vec4 outColor0;\ varying vec4 outColor1;\ void main()\ {\ outColor0 = gl_Color;\ outColor1 = gl_SecondaryColor;\ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\ }"; const char* ps = "varying vec4 outColor0;\ varying vec4 outColor1;\ void main()\ {\ gl_FragColor = (outColor1 + outColor0);\ }";
- 使用:
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_SECONDARY_COLOR_ARRAY); _shader.begin(); glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), rect); glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(Vertex), &rect[0].r0); glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), &rect[0].r1); glDrawArrays(GL_TRIANGLE_STRIP,0,4); _shader.end(); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
访问顶点属性--法线 gl_Normal
const char* vs = "varying vec4 outColor;\ void main()\ {\ outColor = vec4(gl_Normal,1);\ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\ }"; const char* ps = "varying vec4 outColor;\ void main()\ {\ gl_FragColor = outColor;\ }";
- 使用:
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(Vertex), rect); glNormalPointer(GL_FLOAT, sizeof(Vertex), &rect[0].nx); _shader.begin(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); _shader.end(); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);
访问顶点--纹理坐标
- 关键词:
- gl_TexCoord[0] = gl_MultiTexCoord0;
- uniform sampler2D _texture;
- vec4 color = texture2D(_texture, gl_TexCoord[0].st);
- glEnable(GL_TEXTURE_2D); //启用纹理0
- glBindTexture(GL_TEXTURE_2D,_texure);//绑定纹理0
- glUniform1i(_shader._texture,0);//给纹理0填充纹理数据
- glTexCoordPointer(2,GL_FLOAT, sizeof(Vertex), &rect[0].u); //告诉显卡纹理坐标
const char* vs = "uniform vec4 _color;\ varying vec4 outColor;\ void main()\ {\ outColor = _color;\ gl_TexCoord[0] = gl_MultiTexCoord0;\ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\ }"; const char* ps = "varying vec4 outColor;\ uniform sampler2D _texture;\ void main()\ {\ vec4 color = texture2D(_texture,gl_TexCoord[0].st);\ gl_FragColor = color;\ }"; createProgram(vs, ps); _color = glGetUniformLocation(_program,"_color"); _texture= glGetUniformLocation(_program,"_texture");
glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,_texure); glUniform4f(_shader._color,1,1,1,1); glUniform1i(_shader._texture,0); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(Vertex), rect); glTexCoordPointer(2,GL_FLOAT, sizeof(Vertex), &rect[0].u); _shader.begin(); glDrawArrays(GL_TRIANGLE_STRIP,0,4); _shader.end();
attribute
- 关键词:
- glGetAttribLocation glEnableVertexAttribArray
- glVertexAttribPointer glDisableVertexAttribArray
class ShaderVertex :public GLSLProgram { public: typedef int attribute; public: uniform _ucolor; attribute _position; attribute _color; public: virtual void initialize() { const char* vs = "attribute vec3 _position;\n\ attribute vec3 _color;\n\ varying vec3 _outColor;\n\ void main()\n\ {\n\ _outColor = _color;\n\ gl_Position = gl_ModelViewProjectionMatrix * vec4(_position,1.0);\n\ }"; const char* ps = "uniform vec4 _color;\n\ varying vec3 _outColor;\n\ void main()\n\ {\n\ gl_FragColor = vec4(_outColor,1);\n\ }"; createProgram(vs, ps); _ucolor = glGetUniformLocation(_program, "_color"); _position = glGetAttribLocation(_program, "_position"); _color = glGetAttribLocation(_program, "_color"); } }
glUniform4f(_shader._ucolor, 0, 1, 0, 1); glEnableVertexAttribArray(_shader._position); glVertexAttribPointer(_shader._position, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), rect); glEnableVertexAttribArray(_shader._color); glVertexAttribPointer(_shader._color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), &rect[0].r); _shader.begin(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); _shader.end(); glDisableVertexAttribArray(_shader._position);
- 【注】对于颜色
struct Vertex { float x, y, z; unsigned char r, g, b; };
- 其顶点数据为:
Vertex rect[] = { {10, 10, 0, 255, 0, 0}, {110, 10, 0, 0, 255, 0}, {10, 110, 0, 0, 0, 255}, {110, 110, 0, 255, 0, 255}, };
- 为了归一化,glVertexAttribPointer(_shader._color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), &rect[0].r); 使用 GL_TRUE,将0-255,转为着色器可识别的0-1的float类型
in 与 out
- in 可以通过外部给当前阶段输入
- out 当前阶段vs对下一阶段ps的输出
- 下一阶段(ps)用in,变量名称类型保持不变
- 注:这个阶段的输出,一定是下一个阶段的输入
- 获取和使用还是和atrribute属性一样,建议使用 in out 做声明。
const char* vs = "#version 130\n\ in vec3 _position;\n\ in vec3 _color;\n\ out vec3 _outColor;\n\ void main()\n\ {\n\ _outColor = _color;\n\ gl_Position = gl_ModelViewProjectionMatrix * vec4(_position,1.0);\n\ }"; const char* ps = "in vec3 _outColor;\n\ void main()\n\ {\n\ gl_FragColor = vec4(_outColor,1);\n\ }"; createProgram(vs, ps); _color = glGetAttribLocation(_program,"_color"); _position = glGetAttribLocation(_program, "_position");
- 注:
- 返回值 _color为0 _position为1,这些就是程序当中用到的一些索引,通过这些索引给显卡或者这些变量传递值。
- uniform是全局变量,每次只能传一个,而atrribute 可以传一个数组,数组大小是由,如glDrawArrays最后一个值决定,个数不定。
Layout 关键字的使用
- _position _color这些值是通过程序glGetAttribLocation去获取到的,有没有办法统一?
- 可以不使用glGetAttribLocation获取,使用layout
layout(location = 0) in vec3 _position;\n\ layout(location = 1) in vec3 _color;\n\
这个里面location是多少,对应的glVertexAttribPointer第一个参数就给多少。
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(Vertex),rect); glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,sizeof(Vertex),&rect[0].r);
- #version 330 core == #version 330 加不加core一样,除非加compatibility
- #version 330 compatibility 兼容老的版本(gl_ModelViewProjectionMatrix)可用
- 在新的版本中没有gl_ModelViewProjectionMatrix ,所有采用传入矩阵
- 下面这些新的版本不提供了:
//! 指定以下的操作针对投影矩阵 glMatrixMode(GL_PROJECTION); //! 将投影矩阵清空成单位矩阵 glLoadIdentity(); glOrtho(0,_width,_height,0,-100,100);
- 自己创建矩阵传入着色器程序
CELL::matrix4 prj = CELL::ortho<float>(0,_width,_height,0,-100,100); glUniformMatrix4fv(_shader._mvp,1,GL_FALSE,prj.data()); //GL_FALSE 不做转置
Layout 关键字修饰out(至少需要410这个版本)
- 之前 in 和 out 配合使用需要变量名称一样,现在只需要layout(location = )中的值一致就可以了,名称不需要一致了
- layout 值有上限
Layout 关键字修饰uniform(至少需要430这个版本)
const char* vs = "#version 430 \n\ layout(location = 0) in vec3 _position;\n\ layout(location = 1) in vec3 _color;\n\ layout(location = 2) in vec2 _uv;\n\ layout(location = 0) uniform mat4 _mvp;\n\ layout(location = 0) out vec3 _outColor;\n\ layout(location = 1) out vec2 _outUV;\n\ void main()\n\ {\n\ _outColor = _color;\n\ _outUV = _uv;\n\ gl_Position = _mvp * vec4(_position,1.0);\n\ }"; const char* ps = "#version 430 \n\ layout(location = 0) in vec3 _inColor;\n\ layout(location = 1) in vec2 _inUV;\n\ layout(location = 1) uniform sampler2D _tex;\n\ void main()\n\ {\n\ vec4 color = texture2D(_tex,_inUV);\n\ gl_FragColor = color * vec4(_inColor,1);\n\ }";
struct Vertex { float x,y,z; float r,g,b; float u,v; }; _shader.begin(); glUniform1i(_shader._tex,0); glUniformMatrix4fv(0,1,GL_FALSE,prj.data()); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(Vertex),rect); glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,sizeof(Vertex),&rect[0].r); glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,sizeof(Vertex),&rect[0].u); glDrawArrays(GL_TRIANGLE_STRIP,0,4); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); _shader.end();
多个shader
_shader.begin(); { glUniform1i(_shader._tex, 0); glUniformMatrix4fv(0, 1, GL_FALSE, prj.data()); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), rect); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), &rect[0].r); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &rect[0].u); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); } _shader.end(); _shader1.begin(); { glUniformMatrix4fv(0, 1, GL_FALSE, prj.data()); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), rect); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), &rect[0].r); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &rect[0].u); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); } _shader1.end();
优化:链接完生成可执行程序后删除中间文件
//链接程序 glLinkProgram(_program); glGetProgramiv(_program, GL_LINK_STATUS, &status); if (status == GL_FALSE) { glGetProgramInfoLog(_program, sizeof(compileLog), 0, compileLog); break; } result = true; if (_vHandle != -1) { glDeleteShader(_vHandle); _vHandle = -1; } if (_pHandle != -1) { glDeleteShader(_pHandle); _pHandle = -1; }
attribute数组数据的使用
- 例如:颜色和位置合并为一个数组
const char* vs = "#version 430 \n\ layout(location = 0) in vec3 _posAndColor[4];\n\ layout(location = 1) in vec2 _uv;\n\ layout(location = 0) uniform mat4 _mvp;\n\ layout(location = 0) out vec3 _outColor;\n\ layout(location = 1) out vec2 _outUV;\n\ void main()\n\ {\n\ _outColor = _posAndColor[1] + _posAndColor[2] + _posAndColor[3];\n\ _outUV = _uv;\n\ gl_Position = _mvp * vec4(_posAndColor[0],1.0);\n\ }"; //获取 _position = glGetAttribLocation(_program,"_posAndColor[0]"); _color = glGetAttribLocation(_program,"_posAndColor[1]"); _uv = glGetAttribLocation(_program,"_uv");
- layout(location = 0 in vec3 _posAndColor[4]
- 如果使用过程中只使用了两个,那么编译时就会优化掉未使用的两个,则uv为2,如果_posAndColor[4]四个都使用,则uv为4。
- 如果使用layout,要会算下一个layout的索引值。
- 所有的属性值加起来不能超过16个
attribute结构体数据的使用
- 不能直接通过结构体名称获取结构体,需要通过结构体字段获取
- _position = glGetAttribLocation(_program,"_vert"); //_position 为 -1
const char* vs = "#version 430 \n\ struct VertAttr\n\ {\n\ vec3 _pos;\n\ vec3 _color;\n\ float _test[4];\n\ };\n\ in VertAttr _vert;\n\ in vec2 _uv;\n\ layout(location = 0) uniform mat4 _mvp;\n\ layout(location = 0) out vec3 _outColor;\n\ layout(location = 1) out vec2 _outUV;\n\ void main()\n\ {\n\ _outColor = _vert._color * _vert._test[0] * _vert._test[1] * _vert._test[2] *_vert._test[3];\n\ _outUV = _uv;\n\ gl_Position = _mvp * vec4(_vert._pos,1.0);\n\ }"; const char* ps = "#version 430 \n\ layout(location = 0) in vec3 _inColor;\n\ layout(location = 1) in vec2 _inUV;\n\ layout(location = 1) uniform sampler2D _tex;\n\ void main()\n\ {\n\ vec4 color = texture2D(_tex,_inUV);\n\ gl_FragColor = color * vec4(_inColor,1);\n\ }"; _position = glGetAttribLocation(_program,"_vert._pos"); //0 _color = glGetAttribLocation(_program,"_vert._color"); //1 _color = glGetAttribLocation(_program,"_vert._test[0]"); //2 _uv = glGetAttribLocation(_program,"_uv"); //6
- 注:VertAttr 占6个索引,如果其中某些在着色器程序的代码中没有使用,就会被编译器优化掉。
uniform结构体和数组的使用
- uniform最多有1024个
- 传100个矩阵给GPU也是耗时的,将矩阵数据直接存储到显卡当中,直接访问,使用UBO技术
const char* vs = "#version 430 \n\ struct VertAttr\n\ {\n\ vec3 _pos;\n\ vec3 _color;\n\ };\n\ struct MVP\n\ { \n\ mat4 _mat;\n\ float _scaler;\n\ };\n\ in VertAttr _vert;\n\ in vec2 _uv;\n\ uniform MVP _mvp;\n\ layout(location = 0) out vec3 _outColor;\n\ layout(location = 1) out vec2 _outUV;\n\ void main()\n\ {\n\ _outColor = _vert._color * _mvp._scaler;\n\ _outUV = _uv;\n\ gl_Position = _mvp._mat * vec4(_vert._pos,1.0);\n\ }"; _mvp = glGetUniformLocation(_program,"_mvp._mat"); //从内存拷贝到显存,需要消耗CPU资源 GLuint s = glGetUniformLocation(_program,"_mvp._scaler");
block快实现多个shader共享数据
- 解决频繁的的从内存拷贝数据到显存
- 在不同多个shader之间共享一个变量(前面uniform是全局变量,只是针对程序之间的)
- 块声明,类似结构体
uniform/in/out MVP { mat4 _mat; }mvp;
- 块的名称:MVP 变量名称:mvp
- 不能用 glGetUniformLocation 访问,得用 glGetUniformBlockIndex,参数是块的名称(如MVP)
- 不能像之前 glUniformMatrix4fv(0,1,GL_FALSE,prj.data()); 直接传值
- 需要声明缓冲区。
const char* vs = "#version 430 \n\ struct VertAttr\n\ {\n\ vec3 _pos;\n\ vec3 _color;\n\ };\n\ uniform MVP\n\ { \n\ mat4 _mat;\n\ }mvp;\n\ in VertAttr _vert;\n\ in vec2 _uv;\n\ layout(location = 0) out vec3 _outColor;\n\ layout(location = 1) out vec2 _outUV;\n\ void main()\n\ {\n\ _outColor = _vert._color;\n\ _outUV = _uv;\n\ gl_Position = mvp._mat * vec4(_vert._pos,1.0);\n\ }"; const char* ps = "#version 430 \n\ layout(location = 0) in vec3 _inColor;\n\ layout(location = 1) in vec2 _inUV;\n\ layout(location = 1) uniform sampler2D _tex;\n\ void main()\n\ {\n\ vec4 color = texture2D(_tex,_inUV);\n\ gl_FragColor = color * vec4(_inColor,1);\n\ }"; createProgram(vs, ps); //_mvp = glGetUniformLocation(_program,"mvp._mat"); _mvp = glGetUniformBlockIndex(_program,"MVP"); _tex = glGetUniformLocation(_program,"_tex"); _position = glGetAttribLocation(_program,"_vert._pos"); _color = glGetAttribLocation(_program,"_vert._color"); _uv = glGetAttribLocation(_program,"_uv");
GLuint _ubo; // 创建uniform buffer object 【绑定进行操作后解绑(每次只能操作一块数据)】 glGenBuffers(1,&_ubo); //这个buffer不在任何显卡中间,只是一个名称 glBindBuffer(GL_UNIFORM_BUFFER,_ubo); //指明buffer类型为GL_UNIFORM_BUFFER glBufferData(GL_UNIFORM_BUFFER,sizeof(CELL::matrix4),0,GL_DYNAMIC_DRAW); //分配空间 GL_DYNAMIC_DRAW 动态向buffer传数据 glBindBuffer(GL_UNIFORM_BUFFER,0);//用完之后绑定为0,避免对后续操作产生影响 //缓存区填充投影矩阵数据 CELL::matrix4 prj = CELL::ortho<float>(0,_width,_height,0,-100,100); glBindBuffer(GL_UNIFORM_BUFFER,_ubo); glBufferSubData(GL_UNIFORM_BUFFER,0,sizeof(CELL::matrix4),prj.data()); //绑定点这个数字作为 shader中的block 和内存中创建的buffer的映射桥梁 glUniformBlockBinding(_shader._program,_shader._mvp,1); //绑定点的值,可以任意指定一个数字(0,1,2....) //告诉uniform block 数据从哪里来,从绑定点来,绑定点数据从_ubo来 glBindBufferBase(GL_UNIFORM_BUFFER,1,_ubo); //绑定点和创建的buffer关联起来
out 共享变量
- 在vs和ps之间做共享变量,但是不能在attribute也就是属性变量中使用它
out block { vec3 _color; vec2 _uv; }Out;
- 在vs和PS之间共享block变量
const char* vs = "#version 430 \n\ struct VertAttr\n\ {\n\ vec3 _pos;\n\ vec3 _color;\n\ };\n\ uniform MVP\n\ { \n\ mat4 _mat;\n\ }mvp;\n\ in VertAttr _vert;\n\ in vec2 _uv;\n\ out block\n\ {\n\ vec3 _color; \n\ vec2 _uv; \n\ }Out;\n\ void main()\n\ {\n\ Out._color = _vert._color;\n\ Out._uv = _uv;\n\ gl_Position = mvp._mat * vec4(_vert._pos,1.0);\n\ }"; const char* ps = "#version 430 \n\ in block\n\ {\n\ vec3 _color; \n\ vec2 _uv; \n\ }In;\n\ layout(location = 1) uniform sampler2D _tex;\n\ void main()\n\ {\n\ vec4 color = texture2D(_tex,In._uv);\n\ gl_FragColor = color * vec4(In._color,1);\n\ }";
- 注:对于in VertAttr _vert; in vec2 _uv;这种后面通过glGetUniformLocation,glGetAttribLocation,获取的变量不能声明为block。
block之内存布局
- 如果block存在矩阵,布尔值,整型等,会存在内存布局问题
- 目前存在这样几种
- shared(默认), packed(可选), std140(版本140), and std430
- 重点第一种和std140
- std140:
ayout (std140) uniform ExampleBlock { //base alignment aligned offset float value; // 4 // 0 vec3 vector; // 16 // 16 (must be multiple of 16) mat4 matrix; // 16 // 32 (column 0) // 16 // 48 (column 1) // 16 // 64 (column 2) // 16 // 80 (column 3) float values[3]; // 16 // 96 (values[0]) // 16 // 112 (values[1]) // 16 // 128 (values[2]) bool boolean; // 4 // 144 int integer; // 4 // 148 };
const char* vs = "#version 430 \n\ struct VertAttr\n\ {\n\ vec3 _pos;\n\ vec3 _color;\n\ };\n\ layout(std140) uniform MVP\n\ { \n\ mat4 _prj;\n\ mat4 _view;\n\ mat4 _model;\n\ float _iData;\n\ float _fData;\n\ float _data[2];\n\ float _bData;\n\ }mvp;\n\ in VertAttr _vert;\n\ in vec2 _uv;\n\ out block\n\ {\n\ vec3 _color; \n\ vec2 _uv; \n\ }Out;\n\ void main()\n\ {\n\ Out._color = _vert._color;\n\ Out._uv = _uv;\n\ Out._uv *= mvp._iData;\n\ Out._uv *= mvp._fData;\n\ Out._uv *= mvp._bData;\n\ Out._uv *= mvp._data[0];\n\ Out._uv *= mvp._data[1];\n\ gl_Position = mvp._prj* mvp._view * mvp._model* vec4(_vert._pos,1.0);\n\ }"; const char* ps = "#version 430 \n\ in block\n\ {\n\ vec3 _color; \n\ vec2 _uv; \n\ }In;\n\ layout(location = 1) uniform sampler2D _tex;\n\ void main()\n\ {\n\ vec4 color = texture2D(_tex,In._uv);\n\ gl_FragColor = color * vec4(In._color,1);\n\ }"; createProgram(vs, ps); //获取块 _mvp = glGetUniformBlockIndex(_program,"MVP"); //获取块大小 GLint blockSize; glGetActiveUniformBlockiv(_program, _mvp,GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize); //获取字段信息 char* names[] = {"MVP._prj","MVP._view","MVP._model","MVP._iData","MVP._fData","MVP._data","MVP._bData"}; GLuint indexs[7] = {0}; glGetUniformIndices(_program,7,names,indexs); //获取字段偏移信息 GLint offset[7]; glGetActiveUniformsiv(_program,7, indexs, GL_UNIFORM_OFFSET, offset); _tex = glGetUniformLocation(_program,"_tex"); _position = glGetAttribLocation(_program,"_vert._pos"); _color = glGetAttribLocation(_program,"_vert._color"); _uv = glGetAttribLocation(_program,"_uv");
无数据绘制-常量数组的使用 gl_VertexID
const char* vs = "#version 130\n\ uniform mat4 _mvp;\n\ const vec3 _pos[4]= vec3[](\n\ vec3(10,10,0),\n\ vec3(410,10,0),\n\ vec3(10,410,0),\n\ vec3(410,410,0));\n\ void main()\n\ {\n\ gl_Position = _mvp * vec4(_pos[gl_VertexID],1.0);\n\ }"; const char* ps = "void main()\n\ {\n\ gl_FragColor = vec4(1,0,0,1);\n\ }"; _mvp = glGetUniformLocation(_program,"_mvp");
_shader.begin(); glUniformMatrix4fv(_shader._mvp,1,GL_FALSE,prj.data()); glDrawArrays(GL_TRIANGLE_STRIP,0,4); //gl_VertexID 取值0-3 _shader.end();
深入理解gl_FragCoord内置变量的作用
- gl_FragCoord.x 屏幕坐标 左下角为0,0。
- discard 返回后面流水线不执行。
- 画一个图形画了两次,一次正面,一次背面。
const char* vs = "#version 130\n\ uniform mat4 _mvp;\n\ const vec3 _pos[4] = vec3[](\n\ vec3(10, 10, 0),\n\ vec3(410, 10, 0),\n\ vec3(10, 410, 0),\n\ vec3(410, 410, 0));\n\ void main()\n\ {\n\ gl_Position = _mvp * vec4(_pos[gl_VertexID],1.0);\n\ }"; const char* ps = "void main()\n\ {\n\ if(gl_FragCoord.x > 100) discard;\n\ //glEnable(GL_CULL_FACE);\n\ //glCullFace(GL_BACK);\n\ gl_FragColor = gl_FrontFacing ? vec4(1,0,0,1) : vec4(0,1,0,1);\n\ }"; createProgram(vs, ps); _mvp = glGetUniformLocation(_program,"_mvp");
virtual void onInitGL() { glewInit(); _shader.initialize(); //裁剪背面 glEnable(GL_CULL_FACE); glCullFace(GL_BACK); } //旋转观察 virtual void render() { static float angle = 0; angle += 0.1f; CELL::matrix4 matRot; matRot.rotateYXZ(angle,angle,angle); CELL::matrix4 prj = CELL::ortho<float>(0,_width,_height,0,-100,100); CELL::matrix4 mvp = prj * matRot; _shader.begin(); glUniformMatrix4fv(_shader._mvp,1,GL_FALSE,mvp.data()); glDrawArrays(GL_TRIANGLE_STRIP,0,4); _shader.end(); }
纹理动画
class ShaderVertex :public GLSLProgram { public: uniform _mvp; uniform _texture; uniform _uvOffset; attribute _pos; attribute _uv; public: virtual void initialize() { const char* vs = "#version 130\n\ uniform mat4 _mvp;\n\ in vec3 _pos;\n\ in vec2 _uv;\n\ out vec2 _outUV;\n\ void main()\n\ {\n\ _outUV = _uv;\n\ gl_Position = _mvp * vec4(_pos,1.0);\n\ }"; const char* ps = "uniform sampler2D _texture;\n\ uniform vec2 _uvOffset;\n\ in vec2 _outUV;\n\ void main()\n\ {\n\ gl_FragColor = texture2D(_texture,_outUV + _uvOffset);\n\ }"; createProgram(vs, ps); _mvp = glGetUniformLocation(_program,"_mvp"); _texture = glGetUniformLocation(_program,"_texture"); _uvOffset = glGetUniformLocation(_program,"_uvOffset"); _pos = glGetAttribLocation(_program,"_pos"); _uv = glGetAttribLocation(_program,"_uv"); } }
ShaderVertex _shader; GLuint _texure; CELL::float2 _uvOffset; //启用纹理 glEnable(GL_TEXTURE_2D); //创建纹理 unsigned createTexture(int w, int h, const void* data, GLenum type) { unsigned texId; glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, texId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexImage2D(GL_TEXTURE_2D, 0, type, w, h, 0, type, GL_UNSIGNED_BYTE, data); return texId; } _texure = createTextureFromImage(resPath); _uvOffset.x += 0.01f; _uvOffset.y -= 0.01f; CELL::matrix4 prj = CELL::ortho<float>(0,_width,_height,0,-100,100); //绑定纹理 glBindTexture(GL_TEXTURE_2D,_texure); _shader.begin(); glUniformMatrix4fv(_shader._mvp,1,GL_FALSE,prj.data()); //传入纹理数据 glUniform1i(_shader._texture,0); glUniform2f(_shader._uvOffset,_uvOffset.x,_uvOffset.y); glVertexAttribPointer(_shader._pos,3, GL_FLOAT,GL_FALSE,sizeof(Vertex),rect); glVertexAttribPointer(_shader._uv,2, GL_FLOAT,GL_FALSE,sizeof(Vertex),&rect[0].u); glDrawArrays(GL_TRIANGLE_STRIP,0,4); _shader.end();
纹理帧动画
_hasElasped += fElapsed; //累计运行多少时间 Vertex rect[] = { {10, 10, 0, 0, 0}, {410, 10, 0, 1, 0}, {10, 410, 0, 0, 1}, {410, 410, 0, 1, 1}, }; CELL::matrix4 prj = CELL::ortho<float>(0, _width, _height, 0, -100, 100); glBindTexture(GL_TEXTURE_2D, _texure); //_hasElasped 是double类型,取值如2.123325 int frame = int(_hasElasped * 16) % 16; //_hasElasped * 16 _hasElasped秒总共播放了多少帧,模16计算当前为哪帧 //int frame = int(_hasElasped * 12)%16; float2 uvSize(0.25f, 0.25f); //每张纹理大小 int row = frame / 4; //哪一行 int col = frame % 4; //哪一列 for (size_t i = 0; i < 4; ++i) //缩小UV,遍历原纹理,把原纹理的一部分贴到目标区域 { rect[i].u *= 0.25f; rect[i].v *= 0.25f; rect[i].u += 0.25 * col; //计算列位置 rect[i].v += 0.25 * row; //计算行位置 } _shader.begin(); glUniformMatrix4fv(_shader._mvp, 1, GL_FALSE, prj.data()); //给shader传值 glUniform1i(_shader._texture, 0); glUniform2f(_shader._uvOffset, _uvOffset.x, _uvOffset.y); glVertexAttribPointer(_shader._pos, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), rect); glVertexAttribPointer(_shader._uv, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &rect[0].u); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); _shader.end();
纹理帧动画GPU实现
_hasElasped += fElapsed; Vertex rect[] = { {10, 10, 0, 0, 1}, {410, 10, 0, 1, 1}, {10, 410, 0, 0, 0}, {410, 410, 0, 1, 0}, }; CELL::matrix4 prj = CELL::ortho<float>(0, _width, _height, 0, -100, 100); glBindTexture(GL_TEXTURE_2D, _texure); int frame = int(_hasElasped * 16) % 16; _shader.begin(); glUniformMatrix4fv(_shader._mvp, 1, GL_FALSE, prj.data()); glUniform1i(_shader._texture, 0); glUniform3f(_shader._animInfor, 4, 4, frame); //当前帧编号,这里4, 4指4纹理贴图4行4列 glVertexAttribPointer(_shader._pos, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), rect); glVertexAttribPointer(_shader._uv, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &rect[0].u); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); _shader.end();
const char* vs = "#version 130\n\ uniform mat4 _mvp;\n\ // x = col,y = row,z = frame\n\ uniform vec3 _animInfor;\n\ in vec3 _pos;\n\ in vec2 _uv;\n\ out vec2 _outUV;\n\ void main()\n\ {\n\ float uS = 1.0/_animInfor.x; // 纹理总宽单位1,每列占比多少\n\ float vS = 1.0/_animInfor.y; // 纹理总长单位1,每行占比多少\n\ int col = int(_animInfor.z)%int(_animInfor.x);\n\ int row = int(_animInfor.z)/int(_animInfor.y);\n\ _outUV = _uv * vec2(uS,vS);\n\ _outUV.x += float(col) * uS;\n\ _outUV.y += float(row) * vS;\n\ gl_Position = _mvp * vec4(_pos,1.0);\n\ }"; const char* ps = "uniform sampler2D _texture;\n\ in vec2 _outUV;\n\ void main()\n\ {\n\ gl_FragColor = texture2D(_texture,_outUV);\n\ }"; createProgram(vs, ps); _mvp = glGetUniformLocation(_program, "_mvp"); _texture = glGetUniformLocation(_program, "_texture"); _animInfor = glGetUniformLocation(_program, "_animInfor"); _pos = glGetAttribLocation(_program, "_pos"); _uv = glGetAttribLocation(_program, "_uv");