hello,朋友们,我又来了,还记得上篇文章提到的事情否?没错,加载png只是第一步,接下来要实现用mask图扣掉png中不需要的部分。(也就是cocos2d-x中那个clipingnode的效果)。看教程和看源码都是第一时间想到用模板测试。。。奈何技术不精还是怎么,效果总是出不来,翻墙,看别人各种实现,中间各种曲折。。后来实在没有办法,发帖问,有个大牛说让我用shader试一下。瞬间云开见月!对啊,我怎么没想到呢。虽然本人opengl新手,比较怂可编程渲染管线这种东西,不过现在觉得可编程管线太强大了。。哈哈先玩一阵glsl再说~~~
以下是GLSL的极好入门例子。其他地址都是texture.h 各种shadermanager.h...ShaderLoader.h坑爹..虽然我知道前面一个来自蓝宝书,后面一个来自红宝书。可是对于新手,还是越简单越好。如果不满意 请继续搜关键词GLSL helloworld附上链接:http://johnhany.net/2014/01/environment-for-opengl-with-vs2010/
照他给的代码贴上去,完全无错,运行出现一个三角形。好了,成功了一半,但是我们的贴图是4边形,怎么办呢?接下来就看我一步步实现吧!
首先,顶点数组
static const GLfloat position_data[] = {
-1.0, -1.0,
1.0, -1.0,
1.0, 1.0,
-1.0, 1.0
};
然后 color数组。。其实我们不需要color,但是做事要一步步小成功,不要一下子做很多,然后直接失败。
static const GLfloat color_data[] = {
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 1.0, 1.0, 1.0
};
然后新的函数改成这样子
static void displayFunc(void)
{
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_QUADS, 4, GL_UNSIGNED_SHORT, (void*)0);
glutSwapBuffers();
}
原来画三角形现在变成4边形。运行。出现一个彩色4变形。
====================================================================
到了上面已经成功了一半,对于一个新手来说,加载一个位图都如此困难。。。。orz
好继续上代码,思路是创建图片坐标数组,并传给vs用(其实是vs传给ps)反正是position的依葫芦画瓢版
static struct {
GLuint vertex_buffer, element_buffer, color_buffer,textcoord_buffer;
GLuint vertex_shader, fragment_shader, program;
//用于保存CPU端的object名称
struct {
GLint position;
GLint inColor;
GLint textcoord;
} attributes;
//用于保存GPU端attribute变量的地址
} names;
static const GLfloat textcoord_data[] = {
0.0f,0.0f,//对应-1,-1 因为坐标是中心原点 左下自然是-1,-1
1.0f,0.0f,
1.0f,1.0f,
0.0f,1.0f
};
记得与position中的位置一一对应,别把纹理的脚放到头去了。。
然后画瓢
names.attributes.textcoord = glGetAttribLocation(names.program, "textcoord");
glGenBuffers(1, &names.textcoord_buffer);
glBindBuffer(GL_ARRAY_BUFFER, names.textcoord_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(textcoord_data), textcoord_data, GL_STATIC_DRAW);
glVertexAttribPointer(names.attributes.textcoord, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, (void*)0);
glEnableVertexAttribArray(names.attributes.textcoord);
好了,现在我们已经成功的把纹理坐标传进了VS,VS传到PS。当然,这里要先在vs.glsl中定义变量,我就不列举了。反正最后会有完整的文件贴上。
我已经懒得一步步写中间加载并显示单副纹理的过程了。直接上mask版本的代码吧
//纹理贴图
GLint t1 = glGetUniformLocation(names.program, "tex1");
GLint t2 = glGetUniformLocation(names.program, "tex2");
img = loadPNGTexture(".\\test.png");
mask_img = loadPNGTexture(".\\mask.png");
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, img);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, mask_img);
glUniform1i(t1, 0);
glUniform1i(t2, 1);
然后是vs.glsl
#version 130
attribute vec2 position;
attribute vec4 inColor;
attribute vec2 textcoord;
varying vec4 outColor;
varying vec2 TextCoord;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
outColor = inColor;
TextCoord=textcoord;
}
=====================
ps.glsl==opengl叫 fs不叫pS。。
#version 130
varying vec4 outColor;
varying vec2 TextCoord;
uniform sampler2D tex1;
uniform sampler2D tex2;
void main()
{
vec4 clr_tex1=texture2D(tex1, TextCoord);
vec4 clr_mask=texture2D(tex2, TextCoord);
gl_FragColor =clr_tex1*clr_mask.a;
}
=====================最后是原图及效果图
看,坑了我好几天的模板测试,最后在可编程管线下就是这么简单。。。。
最后给伸手党来完整代码。。至于 loadPNGTexture 以及png_hlper.h的问题。。。em....看我前面的文章就知道怎么做了
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <gl/glew.h>
#ifdef __APPLE__
# include <gl/glut.h>
#else
# include "glut.h"
#endif
#pragma warning (disable:4996)
#pragma comment (lib,"glew32.lib")
#include "png_help.h"
static struct {
GLuint vertex_buffer, element_buffer, color_buffer,textcoord_buffer;
GLuint vertex_shader, fragment_shader, program;
//用于保存CPU端的object名称
struct {
GLint position;
GLint inColor;
GLint textcoord;
} attributes;
//用于保存GPU端attribute变量的地址
} names;
static const GLfloat position_data[] = {
-1.0, -1.0,
1.0, -1.0,
1.0, 1.0,
-1.0, 1.0
};
static const GLfloat color_data[] = {
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 1.0, 1.0, 1.0
};
static const GLfloat textcoord_data[] = {
0.0f,0.0f,
1.0f,0.0f,
1.0f,1.0f,
0.0f,1.0f
};
static const GLushort element_data[] = { 0, 1, 2,3};
static void infoLog(GLuint object, PFNGLGETSHADERIVPROC glGet__iv, PFNGLGETSHADERINFOLOGPROC glGet__InfoLog)
{
GLint log_length;
char *log;
glGet__iv(object, GL_INFO_LOG_LENGTH, &log_length);
log = (char *)malloc(log_length);
glGet__InfoLog(object, log_length, NULL, log);
fprintf(stderr, "%s", log);
free(log);
}
void *readShader(const char *filename, GLint *length)
{
FILE *f = fopen(filename, "r");
void *buffer;
if (!f) {
fprintf(stderr, "Unable to open %s for reading\n", filename);
return NULL;
}
fseek(f, 0, SEEK_END);
*length = ftell(f);
fseek(f, 0, SEEK_SET);
buffer = malloc(*length+1);
*length = fread(buffer, 1, *length, f);
fclose(f);
((char*)buffer)[*length] = '\0';
return buffer;
}
static GLuint initShader(GLenum type, const char *filename)
{
GLint length;
GLchar *source = (GLchar *)readShader(filename, &length);
GLuint shader;
GLint shader_ok;
if (!source)
return 0;
shader = glCreateShader(type);
//创建shader object
glShaderSource(shader, 1, (const GLchar**)&source, &length);
//导入shader的代码
//count - string的行数
//length - 指向包含string每行字数的数组
free(source);
glCompileShader(shader);
//编译shader代码
glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
//查询shader的状态,导出可能的编译错误
if (!shader_ok) {
fprintf(stderr, "Failed to compile %s:\n", filename);
infoLog(shader, glGetShaderiv, glGetShaderInfoLog);
glDeleteShader(shader);
getchar();
}
return shader;
}
static void installShaders(void)
{
names.vertex_shader = initShader(GL_VERTEX_SHADER, "HelloWorld-vs.glsl");
names.fragment_shader = initShader(GL_FRAGMENT_SHADER, "HelloWorld-fs.glsl");
GLint program_ok;
names.program = glCreateProgram();
glAttachShader(names.program, names.vertex_shader);
glAttachShader(names.program, names.fragment_shader);
//把shader依附在同一个program上,以连接两个shader
glLinkProgram(names.program);
//链接program,在GPU端创建相应可执行文件,并初始化uniform变量及其地址
glGetProgramiv(names.program, GL_LINK_STATUS, &program_ok);
//查询program的状态,并导出可能的错误
if (!program_ok) {
fprintf(stderr, "Failed to link shader program:\n");
infoLog(names.program, glGetProgramiv, glGetProgramInfoLog);
glDeleteProgram(names.program);
getchar();
}
glUseProgram(names.program);
//激活program后才能为shader指定uniform变量的值
}
unsigned int img = 0;
unsigned int mask_img = 0;
static void initBuffers(void)
{
names.attributes.position = glGetAttribLocation(names.program, "position");
names.attributes.inColor = glGetAttribLocation(names.program, "inColor");
names.attributes.textcoord = glGetAttribLocation(names.program, "textcoord");
//获取GPU端attribute变量的地址保存在本地变量中,用于值的传递
glGenBuffers(1, &names.vertex_buffer);
//产生1个buffer object的名称,并分配显存空间
glBindBuffer(GL_ARRAY_BUFFER, names.vertex_buffer);
//把产生的buffer object与相应target绑定,以改变其值
glBufferData(GL_ARRAY_BUFFER, sizeof(position_data), position_data, GL_STATIC_DRAW);
//GL_STATIC_DRAW其他可用参数:
//STATIC - 长时间不更改的值 DYNAMIC - 需要频繁改变的值 STREAM - 需要偶尔重写整个buffer的值
//DRAW - 保存于GPU用于绘制的值 READ - 保存于CPU用于读取的值 COPY - 折衷
glVertexAttribPointer(names.attributes.position, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*2, (void*)0);
glEnableVertexAttribArray(names.attributes.position);
glGenBuffers(1, &names.color_buffer);
glBindBuffer(GL_ARRAY_BUFFER, names.color_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(color_data), color_data, GL_STATIC_DRAW);
glVertexAttribPointer(names.attributes.inColor, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, (void*)0);
glEnableVertexAttribArray(names.attributes.inColor);
glGenBuffers(1, &names.textcoord_buffer);
glBindBuffer(GL_ARRAY_BUFFER, names.textcoord_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(textcoord_data), textcoord_data, GL_STATIC_DRAW);
glVertexAttribPointer(names.attributes.textcoord, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, (void*)0);
glEnableVertexAttribArray(names.attributes.textcoord);
glGenBuffers(1, &names.element_buffer);
glBindBuffer(GL_ARRAY_BUFFER, names.element_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, names.element_buffer);
//纹理贴图
GLint t1 = glGetUniformLocation(names.program, "tex1");
GLint t2 = glGetUniformLocation(names.program, "tex2");
img = loadPNGTexture(".\\test.png");
mask_img = loadPNGTexture(".\\mask.png");
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, img);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, mask_img);
glUniform1i(t1, 0);
glUniform1i(t2, 1);
}
static void idleFunc(void)
{
}
static void displayFunc(void)
{
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_QUADS, 4, GL_UNSIGNED_SHORT, (void*)0);
glutSwapBuffers();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(400, 400);
glutCreateWindow("Hello World");
glutIdleFunc(&idleFunc);
glutDisplayFunc(&displayFunc);
glewInit();
if (!GLEW_VERSION_2_0) {
fprintf(stderr, "OpenGL 2.0 not available\n");
getchar();
}
//与glew扩展库相关的函数要在glewInit()后执行
installShaders();
initBuffers();
glutMainLoop();
return 0;
}
到此结束。
再次吐槽,国内要找点东西实在太难了。。。这种东西说简单不简单,说难不难。看完教程的人基本不在话下,像我这样边解决问题边学边做,走的弯路实在太多了。
有道是会者不难,不会的人急得掉头发。想想那个坑爹的模板测试把!