OpenGL ES案例04_3-GLSL索引绘图添加纹理颜色混合

2020-09-01  本文已影响0人  卡布奇诺_95d2

本案例是在OpenGL ES案例04_1-GLSL使用索引绘图基础上增加纹理颜色混合。
最终效果如下:

最终效果
本案例与之前案例最大的区别是增加了纹理颜色混合。其它绘制流程一致,可参考之前案例描述或文末的完整代码。接下来描述一下如何增加纹理颜色混合。

顶点着色器

在顶点着色器中,需要增加纹理坐标属性,并且将纹理坐标传递给片元着器

attribute vec4 position;
attribute vec4 positionColor;
attribute vec2 textCoor;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;

varying lowp vec2 vTextCoor;
varying lowp vec4 varyColor;

void main(){
    vTextCoor = textCoor;
    varyColor = positionColor;
    gl_Position = projectionMatrix * modelViewMatrix * position;
}

片元着色器

  1. 设置float为高精度。在代码中去掉该行,无法正常绘制图片。
  2. 增加获取纹理坐标的属性,该属性与在顶点着色器中必须一模一样
  3. 使用texture2D函数,通过采样器,获取当前纹理坐标的颜色值。
  4. 对传入的顶点颜色值和纹理坐标对应的颜色值进行混合计算。
  5. 将最终计算的颜色值赋值给gl_FragColor。
precision highp float;

varying lowp vec2 vTextCoor;
varying lowp vec4 varyColor;
uniform sampler2D colorMap;

void main(){
    vec4 weakMask = texture2D(colorMap, vTextCoor);
    vec4 mask = varyColor;
    float alpha = 0.3;

    vec4 tempColor = mask * (1.0 - alpha) + weakMask * alpha;
    
    gl_FragColor = tempColor;
}

读取纹理数据

  1. 解压缩png/jpg图片,将UIImage转换为CGImageRef。
CGImageRef image = [[UIImage imageNamed:@"nn.jpg"] CGImage];
  1. 根据CGImageRef属性获取图片的宽和高,并开辟一段空间用于存放解压缩后的位图信息。
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
GLubyte* spriteData = (GLubyte*)calloc(width*height*4, sizeof(GLubyte));
  1. 创建CGContextRef上下文
CGContextRef context = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(image), kCGImageAlphaPremultipliedLast);
    CGRect rect = CGRectMake(0, 0, width, height);
  1. 在CGContextRef上将图片绘制出来,调用CGContextDrawImage函数,使用默认方式绘制,这样就得到了纹理数据。
CGContextDrawImage(context, rect, image);
  1. 得到纹理数据之后就不需要CGContextRef上下文了,可以将CGContextRef这个上下文释放掉。
CGContextRelease(context);
  1. 绑定一个纹理ID,默认纹理ID为0。
glBindTexture(GL_TEXTURE_2D, 0);
  1. 设置纹理的参数。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  1. 载入纹理数据。
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (float)width, (float)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
  1. 释放位图信息
free(spriteData);
  1. 设置纹理采样器
    主要是用来获取纹理中对应像素点的颜色值,即纹素。此处使用glUniform1i函数告诉采样器,要获取纹理ID为0的纹素。
glUniform1i(glGetUniformLocation(self.myProgram, "colorMap"), 0);

设置纹理坐标

由于添加了纹理,因此,在设置顶点坐标的时候需要添加纹理坐标。

  1. 获取顶点着色器中定义纹理坐标属性通道。
  2. 打开纹理坐标属性通道。
  3. 将数据传入纹理坐标属性。
-(void)setupVertexData{
    //(1)顶点数组 前3顶点值(x,y,z),后3位颜色值(RGB)
    GLfloat attrArr[] = {
        -0.5f, 0.5f, 0.0f,      0.0f, 0.0f, 0.5f,       0.0f, 1.0f,//左上
        0.5f, 0.5f, 0.0f,       0.0f, 0.5f, 0.0f,       1.0f, 1.0f,//右上
        -0.5f, -0.5f, 0.0f,     0.5f, 0.0f, 1.0f,       0.0f, 0.0f,//左下
        0.5f, -0.5f, 0.0f,      0.0f, 0.0f, 0.5f,       1.0f, 0.0f,//右下
        0.0f, 0.0f, 1.0f,       1.0f, 1.0f, 1.0f,       0.5f, 0.5f,//顶点
    };
    
    GLuint bufferID;
    glGenBuffers(1, &bufferID);
    glBindBuffer(GL_ARRAY_BUFFER, bufferID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
    
    GLuint position = glGetAttribLocation(self.myProgram, "position");
    glEnableVertexAttribArray(position);
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), NULL);
    
    GLuint positionColor = glGetAttribLocation(self.myProgram, "positionColor");
    glEnableVertexAttribArray(positionColor);
    glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), (GLfloat*)NULL+3);
    
    GLuint textCoor = glGetAttribLocation(self.myProgram, "textCoor");
    glEnableVertexAttribArray(textCoor);
    glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), (GLfloat*)NULL+6);
}

到此,整个Demo完成。具体代码请看GLSL三角形变换_纹理颜色混合

上一篇下一篇

猜你喜欢

热点阅读