opengl es 教程翻译5---一个带纹理的shader

来源:互联网 发布:js 对象属性名是变量 编辑:程序博客网 时间:2024/05/16 15:00
////  OpenGLView.m//  OpenGLES22////  Created by stephen.xing on 13/6/14.//  Copyright (c) 2014 IDREAMSKEY. All rights reserved.//#import "OpenGLView.h"#import "CC3GLMatrix.h"/*typedef struct {    float Position[3];    float Color[4];} Vertex;*/// Add texture coordinates to Vertex structure as followstypedef struct {    float Position[3];    float Color[4];    float TexCoord[2]; // New} Vertex;/*const Vertex Vertices[] = {    {{1, -1, 0}, {1, 0, 0, 1}},    {{1, 1, 0}, {0, 1, 0, 1}},    {{-1, 1, 0}, {0, 0, 1, 1}},    {{-1, -1, 0}, {0, 0, 0, 1}}}; // 每个顶点的信息 2.0 可以让我们方便的组织顶点的数据 方式不限了const GLubyte Indices[] = {    0, 1, 2,    2, 3, 0}; // 数据有了,,下面我们需要把他们传递给openGL*//*const Vertex Vertices[] = {    {{1, -1, 0}, {1, 0, 0, 1}},    {{1, 1, 0}, {1, 0, 0, 1}},    {{-1, 1, 0}, {0, 1, 0, 1}},    {{-1, -1, 0}, {0, 1, 0, 1}},    {{1, -1, -1}, {1, 0, 0, 1}},    {{1, 1, -1}, {1, 0, 0, 1}},    {{-1, 1, -1}, {0, 1, 0, 1}},    {{-1, -1, -1}, {0, 1, 0, 1}}};*/#define MAX_TEXTURE_COORD 4const Vertex Vertices[] = {    {{1, -1, 0}, {1, 0, 0, 1}, {MAX_TEXTURE_COORD, 0}},    {{1, 1, 0}, {1, 0, 0, 1}, {MAX_TEXTURE_COORD, MAX_TEXTURE_COORD}},    {{-1, 1, 0}, {0, 1, 0, 1}, {0, MAX_TEXTURE_COORD}},    {{-1, -1, 0}, {0, 1, 0, 1}, {0, 0}},    {{1, -1, -1}, {1, 0, 0, 1}, {MAX_TEXTURE_COORD, 0}},    {{1, 1, -1}, {1, 0, 0, 1}, {MAX_TEXTURE_COORD, MAX_TEXTURE_COORD}},    {{-1, 1, -1}, {0, 1, 0, 1}, {0, MAX_TEXTURE_COORD}},    {{-1, -1, -1}, {0, 1, 0, 1}, {0, 0}}};const GLubyte Indices[] = {    // Front    0, 1, 2,    2, 3, 0,    // Back    4, 6, 5,    4, 7, 6,    // Left    2, 7, 3,    7, 6, 2,    // Right    0, 4, 1,    4, 1, 5,    // Top    6, 2, 1,    1, 6, 5,    // Bottom    0, 3, 7,    0, 7, 4};// 1) Add to top of file   贴小鱼需要的 顶点const Vertex Vertices2[] = {    {{0.5, -0.5, 0.01}, {1, 1, 1, 1}, {1, 1}},    {{0.5, 0.5, 0.01}, {1, 1, 1, 1}, {1, 0}},    {{-0.5, 0.5, 0.01}, {1, 1, 1, 1}, {0, 0}},    {{-0.5, -0.5, 0.01}, {1, 1, 1, 1}, {0, 1}},};const GLubyte Indices2[] = {    1, 0, 2, 3}; @implementation OpenGLView- (void)setupDisplayLink {    // 注册刷新屏幕时候的回调    // render 函数必须有一个CADisplayLink* 类型的参数    CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render:)];    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];}- (GLuint)setupTexture:(NSString *)fileName {    // 得到image的引用  使用文件名为参数的 构造函数构造UIImage对象 然后拿到CGImage 属性就是图片的引用了    CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;    if (!spriteImage) {        NSLog(@"Failed to load image %@", fileName);        exit(1);    }        // 为了创建bitmap 上下未能我们必须自己分配空间 得到图片的长宽    size_t width = CGImageGetWidth(spriteImage);    size_t height = CGImageGetHeight(spriteImage);        // *4 是因为每个像素占用4个字节 RGBA    GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));        // 参数8 代表每个 成分占用多少字节    CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,                                                       CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);        // 把图片绘制到context中去    CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage); // 实际的填充spriteData 空间        CGContextRelease(spriteContext);        // 下面是将像素数据传递到OpenGL中去    GLuint texName;    glGenTextures(1, &texName); // 创建OpenGL对象,,去一个唯一的名字    glBindTexture(GL_TEXTURE_2D, texName); // 绑定,以后我说 TEXTURE_2D 就是说 texName 了        // 设置纹理的参数    // TEXTURE_MIN_FILTER: 对于远处的物体需要收缩纹理    // NEAREST: 绘制一个顶点的时候选择相关纹理上面距离最近的那个像素的颜色    // 如果不是使用mipmaps都必须使用 GL_TEXTURE_MIN_FILTER 参数 我们的例子就不是mipmaps    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);        // 将图片数据发送给gpu    glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);        free(spriteData);    // CPU这边的内存可以释放了 openGL会在gpu那边替我们存储这些数据    return texName;    // 返回tex的唯一标示}// 这里解释一个增加了纹理之后我们的vertex shader的变化// 为每一个顶点指定它对应的纹理坐标---输入参数//attribute vec2 TexCoordIn; // New// varying类型的变量是OpenGL 将会在调用fragment shader之前,为我们做插值处理// 例如 左下角是(0,0) 右下角是(1,0) 那么达到frament shader的时候 他们中间一点的纹理坐标 TexCoordOut的值将会是(0.5, 0)//varying vec2 TexCoordOut; // New//TexCoordOut = TexCoordIn; // New//// 这里解释一下 fragment shader 的变化//varying lowp vec2 TexCoordOut; // New//uniform sampler2D Texture; // New// gl_FragColor = DestinationColor;  顶点是什么颜色,中间的像素就根据顶点颜色插值// 下面的方式// 我们用顶点插值得到的颜色的基础上 乘以 像素对应的纹理坐标上面的纹理的颜色// texture2D 是一个内建函数   为我们从Texture纹理上面得到TexCoordOut坐标上面的颜色值//gl_FragColor = DestinationColor * texture2D(Texture, TexCoordOut); // New- (id)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self) {        // Initialization code        [self setupLayer];        [self setupContext];        [self setupDepthBuffer];        [self setupRenderBuffer];        [self setupFrameBuffer];                [self compileShaders];        [self setupVBOs];                // [self render];        [self setupDisplayLink]; // 改掉只渲染一次为 开启一个CADisplayLink的刷新定时器                        // 生成两个纹理 并且拿到纹理的名字        _floorTexture = [self setupTexture:@"tile_floor.png"];        _fishTexture = [self setupTexture:@"item_powerup_fish.png"];    }    return self;}/*// Only override drawRect: if you perform custom drawing.// An empty implementation adversely affects performance during animation.- (void)drawRect:(CGRect)rect{    // Drawing code}*/// 修改view绑定layer的类型+ (Class)layerClass { // 我们通过重写这个方法就能保证View的layer是一种特殊类型的layer CAEAGLLayer    return [CAEAGLLayer class];}// 是指layer为 不透明- (void)setupLayer { // 默认情况下CAEAGLLayer是透明的,但是那样影响性能,所以我们设置为不透明    _eaglLayer = (CAEAGLLayer*) self.layer;    _eaglLayer.opaque = YES;}// 创建 context对象- (void)setupContext { // context 用于管理iOS使用OpenGl所需要的所有信息    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2; // context是和版本号有关的    _context = [[EAGLContext alloc] initWithAPI:api];    if (!_context) {        NSLog(@"Failed to initialize OpenGLES 2.0 context");        exit(1);    }        if (![EAGLContext setCurrentContext:_context]) {        NSLog(@"Failed to set current OpenGL context");        exit(1);    }}// create render buffer 颜色缓冲区- (void)setupRenderBuffer {    glGenRenderbuffers(1, &_colorRenderBuffer); // 用于产生一个缓冲区对象,该函数为_colorRenderBuffer赋值        // 以后我说GL_RENDERBUFFER指的就_colorRenderBuffer    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);        // 为渲染缓冲区非配存储空间,通过context对象的renderbufferStorage函数生成这个对象    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];}// 深度缓冲区 开启- (void)setupDepthBuffer {    glGenRenderbuffers(1, &_depthRenderBuffer);    glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderBuffer);    //  注意申请内存的方式和render/color 缓冲区不同  不是使用context对象来分配内存了    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, self.frame.size.width, self.frame.size.height);}// create frame buffer- (void)setupFrameBuffer {    GLuint framebuffer; // 帧缓冲区 包含 渲染缓冲区和颜色缓冲区 蒙版缓冲区    glGenFramebuffers(1, &framebuffer);    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);        // 将renderbuffer 附着到 framebuffer的GL_COLOR_ATTACHMENT0    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,                              GL_RENDERBUFFER, _colorRenderBuffer);        // 将 代表深度的缓冲区 和 帧缓冲区的GL_DEPTH_ATTACHMENT 关联起来    // 可见 帧缓冲区真的包含着一系列 的其他类型的缓冲区    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,                              GL_RENDERBUFFER, _depthRenderBuffer);}- (GLuint) compileShader:(NSString*) shaderName withType:(GLenum) shaderType{        NSString* shaderFileExt = [[NSString alloc] initWithFormat:@"%@", @"vs"];    if( shaderType == GL_FRAGMENT_SHADER){        shaderFileExt  = [[NSString alloc] initWithFormat:@"%@", @"fs" ];    } // 不同shader 的后缀名不同        // 把shader文件的内存读取出来 保存到shaderString 这个字符串中    NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName                                                           ofType:shaderFileExt];    NSError* error;    NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath                                                       encoding:NSUTF8StringEncoding error:&error];    if (!shaderString) {        NSLog(@"Error loading shader: %@", error.localizedDescription);        exit(1);    }        // 创建一个代表shader的OpenGL对象,传入参数需要说明是 vs 还是 fs    GLuint shaderHandle = glCreateShader(shaderType);        // 把shader 的内容传递给 OpenGL    const char * shaderStringUTF8 = [shaderString UTF8String];    int shaderStringLength = [shaderString length];    glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);        // 让OpenGL为我们编译shader    glCompileShader(shaderHandle);        // 如果编译失败就输出失败原因--方便我们修改shader,,失败就退出    GLint compileSuccess;    glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);    if (compileSuccess == GL_FALSE) {        GLchar messages[256];        glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);        NSString *messageString = [NSString stringWithUTF8String:messages];        NSLog(@"%@", messageString);        exit(1);    }        return shaderHandle; // 成功则返回shader的句柄    }// 编译通过了,我们还需要几个步骤// 1. 链接shader// 2. 让OpenGL真正的使用这些shader// 3. 得到传入参数(attribute)的指针,然后将输入参数传递进去- (void)compileShaders {        // 分别编译 vertex shader 和 fragment shader    GLuint vertexShader = [self compileShader:@"SimleAddTexture" //@"SimpleWithoutComment"                                     withType:GL_VERTEX_SHADER];    GLuint fragmentShader = [self compileShader:@"SimleAddTexture" //@"SimpleWithoutComment"                                       withType:GL_FRAGMENT_SHADER];        // 链接    GLuint programHandle = glCreateProgram();    glAttachShader(programHandle, vertexShader);    glAttachShader(programHandle, fragmentShader);    glLinkProgram(programHandle);        // 如果链接失败则输出失败原因 并退出程序    GLint linkSuccess;    glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);    if (linkSuccess == GL_FALSE) {        GLchar messages[256];        glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);        NSString *messageString = [NSString stringWithUTF8String:messages];        NSLog(@"%@", messageString);        exit(1);    }        // 让OpenGL开始使用这个shader    glUseProgram(programHandle);        // 得到输入参数的指针,以便传值进去    _positionSlot = glGetAttribLocation(programHandle, "Position");    _colorSlot = glGetAttribLocation(programHandle, "SourceColor");    // 使OpenGL 允许我们向输入参数传值    glEnableVertexAttribArray(_positionSlot);    glEnableVertexAttribArray(_colorSlot);        _projectionUniform = glGetUniformLocation(programHandle, "Projection");    // 拿到 投影矩阵的 指针 句柄        _modelViewUniform = glGetUniformLocation(programHandle, "Modelview");        // 从opengl中拿到输入变量的指针    _texCoordSlot = glGetAttribLocation(programHandle, "TexCoordIn");    glEnableVertexAttribArray(_texCoordSlot);    _textureUniform = glGetUniformLocation(programHandle, "Texture");}// 我们在compileShaders 后面马上调用render 所以用的是同一个program- (void)render:(CADisplayLink*) displayLink {        // 使小鱼和边缘的黑色和 瓷砖纹理 混合起来    // GL_ONE : 源颜色 全部都要取       小鱼是源颜色    // GL_ONE_MINUS_SRC_ALPHA: 目标颜色 如果源颜色没有设置 取全部的目标颜色 小鱼躯干以外---取瓷砖底色    //                                  如果源颜色设置了 目标颜色不要去   小鱼的躯干 -----小鱼已经设置了,不再取瓷砖颜色    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);    glEnable(GL_BLEND);            glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0); // 设置清屏色    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // 执行真正的清屏动作--只是清空 rendre/color buffer    glEnable(GL_DEPTH_TEST);        // 生成投影矩阵    CC3GLMatrix *projection = [CC3GLMatrix matrix];    float h = 4.0f * self.frame.size.height / self.frame.size.width;    [projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:4 andFar:10];    // openGL默认是向z轴的负方向观察的    glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);        // 生成模型视图矩阵    CC3GLMatrix *modelView = [CC3GLMatrix matrix];    // CACurrentMediaTime 得到当前时间,根据这个时间左右移动模型    [modelView populateFromTranslation:CC3VectorMake(0 /*sin(CACurrentMediaTime())*/, 0, -7)];// 移动我们将会绘制的东西    // 在移动的基础上添加旋转效果    _currentRotation += displayLink.duration * 90;    [modelView rotateBy:CC3VectorMake(_currentRotation, _currentRotation, 0)];    // 模型视图矩阵传递到openGL    glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);        // 我们在UIView的多大比例中渲染,这里我们全UIView进行渲染,我们也可以指渲染一部分    glViewport(0, 0, self.frame.size.width, self.frame.size.height);        // 说明是 立方体的顶点缓冲区    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);        // 把当前的顶点值 传递给shader的输入参数    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE,                          sizeof(Vertex), 0);    // 参数解析:    // shader输入参数的 句柄 glGetAttribLocation 得到的    // 每个顶点的Position 参数是一个3元组    // 3元组的每个元素是float类型    // 每个顶点的数据结构的 内存大小    // 顶点结构中 位置信息 距离结构开始的偏移量    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE,                          sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));        // 向纹理坐标传递至 到opengl    glVertexAttribPointer( _texCoordSlot, 2, GL_FLOAT, GL_FALSE,                          sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));            /*GLuint _floorTexture;    glGenTextures(1, &_floorTexture);    glBindTexture(GL_TEXTURE_2D, _floorTexture);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);    glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);//spriteData是cpu中的图像数据     */    //    glActiveTexture(GL_TEXTURE0);    glBindTexture(GL_TEXTURE_2D, _floorTexture); // cpu 里面的纹理的名字    glUniform1i(_textureUniform, 0); // gpu 里面需要的纹理的指针        // 把最终的图形画出来    glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]),                   GL_UNSIGNED_BYTE, 0);    // 参数解释:    // 绘制的方式  点 线 三角形    // 顶点数目    // 顶点下标数组的数据类型 byte    //        //////////////////////////////////////////////////////////////////    //////////////////////////////////////////////////////////////////    //////////////////////////////////////////////////////////////////        // 绘制小鱼    // 绑定顶点缓冲区    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer2);        // 加载小鱼纹理    glActiveTexture(GL_TEXTURE0);    glBindTexture(GL_TEXTURE_2D, _fishTexture);    glUniform1i(_textureUniform, 0);        // 模型视图矩阵不需要改变,,所以下面这句话可用可不用    //glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);        glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));    glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));        glDrawElements(GL_TRIANGLE_STRIP, sizeof(Indices2)/sizeof(Indices2[0]), GL_UNSIGNED_BYTE, 0);                [_context presentRenderbuffer:GL_RENDERBUFFER]; // render/color buffer 指的是一个buffer}// 向OpenGL传值的最好方式 叫做定点缓冲区对象 VBO// VBO 是OpenGL中为我们存储顶点数据的缓冲区 我们可以通过函数调用将顶点信息从cpu ---> gpu// VBO 有两种 1保存的是每个顶点的信息 2保存的是顶点的序号信息- (void)setupVBOs {        /*    GLuint vertexBuffer;    glGenBuffers(1, &vertexBuffer);    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);        GLuint indexBuffer;    glGenBuffers(1, &indexBuffer);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);     */        // 顶点缓冲区的 变量不再是局部变量而是 成员变量了    glGenBuffers(1, &_vertexBuffer);    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);        glGenBuffers(1, &_indexBuffer);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);        glGenBuffers(1, &_vertexBuffer2);    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices2), Vertices2, GL_STATIC_DRAW);        glGenBuffers(1, &_indexBuffer2);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer2);    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices2), Indices2, GL_STATIC_DRAW);    }// 默认情况下 OpenGL 是2维的----右上角(1,1) 左下角(-1, -1)// 如果我们要在2D屏幕上达到 3D的效果 需要使用投影矩阵// 投影矩阵的主要概念是 近平面和远平面  物体越接近近平面我们把它缩的越小 物体越接近远平面 我们把它放的越大- (void) dealloc{   // arc 不需要 手工释放内存,,编译器替我们干了}@end


////  OpenGLView.h//  OpenGLES22////  Created by stephen.xing on 13/6/14.//  Copyright (c) 2014 IDREAMSKEY. All rights reserved.////#import <UIKit/UIKit.h>////@interface OpenGLView : UIView////@end#import <UIKit/UIKit.h> #import <QuartzCore/QuartzCore.h> #include <OpenGLES/ES2/gl.h> #include <OpenGLES/ES2/glext.h>   @interface OpenGLView : UIView{    CAEAGLLayer* _eaglLayer;    EAGLContext* _context;    GLuint _colorRenderBuffer;            GLuint _positionSlot;    GLuint _colorSlot;        GLuint _projectionUniform;    GLuint _modelViewUniform;        float _currentRotation;        // 我们绘制的立方体看起来怪怪的,有时候可以看到正方体的内部    // 我们可以通过开启深度测试修正这个问题-----    // 深度测试的意思---只有这个物体是离我们的眼睛最近的我们才绘制    GLuint _depthRenderBuffer;        GLuint _floorTexture;    GLuint _fishTexture;    GLuint _texCoordSlot; // vertex shader 中的TexCoordIn    GLuint _textureUniform; // fragment shader 中的 Texture        // 为小鱼贴图新增的    // 以前我们只有一个 顶点以及序号的缓冲区,所以我们不需要 拿到他们    // 现在我们我们将有两个 顶点以及序号的缓冲区了(1个是原来的立方体 1个是需要绘制小鱼平面),所以我们需要 索引去拿到他们    GLuint _vertexBuffer;    GLuint _indexBuffer;    GLuint _vertexBuffer2;    GLuint _indexBuffer2;}@end


attribute vec4 Position;attribute vec4 SourceColor;varying vec4 DestinationColor;uniform mat4 Projection;uniform mat4 Modelview;attribute vec2 TexCoordIn; // Newvarying vec2 TexCoordOut; // Newvoid main(void) {    DestinationColor = SourceColor;    gl_Position = Projection * Modelview * Position;    TexCoordOut = TexCoordIn; // New}

varying lowp vec4 DestinationColor;varying lowp vec2 TexCoordOut; // Newuniform sampler2D Texture; // Newvoid main(void) {    gl_FragColor = DestinationColor * texture2D(Texture, TexCoordOut); // New}


0 0
原创粉丝点击