OpenGLES2之Android&iOS跨平台开发教程(四)绘制矩形并显示纹理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/suwk1009/article/details/80931195

前言


前一篇介绍了三角形的绘制,这一篇我们来绘制矩形,并加载本地图片转换为纹理显示到矩形上。

正文


1.着色器

顶点着色器:

attribute vec4 aPosition;                  // 应用程序传入顶点着色器的顶点位置
attribute vec2 aTextureCoord;              // 应用程序传入顶点着色器的顶点纹理坐标
varying vec2 vTextureCoord;                // 用于传递给片元着色器的顶点纹理数据

void main() {
    gl_Position = aPosition;
    vTextureCoord = aTextureCoord;
}

片元着色器:

precision mediump float;       // 设置工作精度
varying vec2 vTextureCoord;    // 接收从顶点着色器过来的纹理坐标
uniform sampler2D uTexture;    // 纹理采样器,代表一幅纹理

void main() {
    gl_FragColor = texture2D(uTexture, vTextureCoord);// 进行纹理采样
}

第一步当然是把shader代码写好,相比上一篇,去掉了顶点颜色,加上了纹理坐标,在片元着色器里使用texture2D进行纹理采样。

2.矩形

Rectangle.h:

#ifndef OPENGLES_RECTANGLE_H
#define OPENGLES_RECTANGLE_H

#include "Platform.h"
#include "Shader.hpp"

class Rectangle {
public:
    GLuint program; // 着色器程序引用
    GLuint aPosition; // 顶点位置引用
    GLuint aTextureCoord; // 纹理坐标引用
    GLuint uTexture;    // 纹理引用
    GLuint textureId = 0;

    int vertexCount = 0; // 顶点数量

    float* vertices = NULL;
    float* uv = NULL;


    Rectangle(); // 构造函数
    ~Rectangle();
    void init();
    void draw();
    void setTexture(GLuint texId);

};

#endif //OPENGLES_RECTANGLE_H

在C++代码中添加着色器中对应的引用,添加了setTexture函数,用于设置纹理。
Rectangle.cpp:

#include "Rectangle.h"

Rectangle::Rectangle()
{
    init();
}

Rectangle::~Rectangle()
{
    delete [] vertices;
    delete [] uv;
}

void Rectangle::init()
{
    vertexCount = 4;
    // 顶点坐标
    vertices = new float[vertexCount * 3]
            {
                    -0.5, 0.5, 0,
                    -0.5, -0.5, 0,
                    0.5, -0.5, 0,
                    0.5, 0.5, 0,
            };

    // 纹理坐标
    uv = new float[vertexCount * 2]
            {
                    0, 0,
                    0, 1,
                    1, 1,
                    1, 0,
            };

    // 顶点着色器
    char vsh[] = "attribute vec4 aPosition;                  // 应用程序传入顶点着色器的顶点位置\n"
            "attribute vec2 aTextureCoord;              // 应用程序传入顶点着色器的顶点纹理坐标\n"
            "varying vec2 vTextureCoord;                // 用于传递给片元着色器的顶点纹理数据\n"
            "\n"
            "void main() {\n"
            "    gl_Position = aPosition;\n"
            "    vTextureCoord = aTextureCoord;\n"
            "}";
    // 片元着色器
    char fsh[] = "precision mediump float;       // 设置工作精度\n"
            "varying vec2 vTextureCoord;    // 接收从顶点着色器过来的纹理坐标\n"
            "uniform sampler2D uTexture;    // 纹理采样器,代表一幅纹理\n"
            "\n"
            "void main() {\n"
            "    gl_FragColor = texture2D(uTexture, vTextureCoord);// 进行纹理采样\n"
            "}";
    // 创建着色器程序
    program = createProgram(vsh, fsh);
    // 获取着色器中的属性引用
    aPosition = glGetAttribLocation(program, "aPosition");
    aTextureCoord = glGetAttribLocation(program, "aTextureCoord");
    uTexture = glGetUniformLocation(program, "uTexture");
    // 使用着色器程序
    glUseProgram(program);
    // 给着色器传递顶点坐标数据
    glVertexAttribPointer(aPosition, 3, GL_FLOAT, GL_FALSE, 0, vertices);
    glEnableVertexAttribArray(aPosition);
    // 给着色器传递纹理坐标数据
    glVertexAttribPointer(aTextureCoord, 2, GL_FLOAT, GL_FALSE, 0, uv);
    glEnableVertexAttribArray(aTextureCoord);
}

void Rectangle::draw()
{
    // 绘制三角形
    glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
}

void Rectangle::setTexture(GLuint texId)
{
    textureId = texId;
    // 激活纹理单元0
    glActiveTexture(GL_TEXTURE0);
    // 绑定纹理
    glBindTexture(GL_TEXTURE_2D, textureId);
    // 给着色器传递纹理数据
    glUniform1i(uTexture, 0);
}

顶点坐标有四个,按顺序分别是矩形的左上角、左下角、右下角、右上角,纹理坐标也是四个一一对应,注意由于屏幕的坐标系与OpenGL ES纹理坐标系不一样,屏幕坐标系原点在左上角,OpenGL ES纹理坐标系原点在左下角,即两个刚好Y轴是反的,所以顶点纹理坐标要按照屏幕坐标系来,否则显示出来得图像是倒的,可以看到顶点(-0.5, 0.5)对应的纹理坐标是(0, 0)…依此类推。
至于其余部分代码中的注释已经写得比较详细了,不再细述。

3.修改Renderer

Renderer中把绘制三角形的换成矩形,添加了一个setTexture接口函数

#include "Renderer.h"
#include "Platform.h"
#include "Triangle.h"
#include "Rectangle.h"

Triangle *triangle;
Rectangle *rectangle;

void surfaceCreated() {
    // 指定刷新颜色缓冲区的颜色
    glClearColor(1.0f, 0.0f, 0.0f, 0.0f);

    //triangle = new Triangle();
    rectangle = new Rectangle();
}

void surfaceChanged(int w, int h) {
    ESLog("viewport: %d, %d", w, h);
    // 设置视口
    glViewport(0, 0, w, h);
}

void drawFrame() {
    // 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);

    //triangle->draw();
    rectangle->draw();
}

void setTexture(unsigned int texId)
{
    rectangle->setTexture(texId);
}

4.Android端图片转纹理

Android端加载本地图片当然就使用Bitmap了,GLUtils中有将Bitmap转换为texture的方法,代码如下:

    public void loadImage(final String path) {
        queueEvent(new Runnable() {
            @Override
            public void run() {
                int[] textures = new int[1];
                GLES20.glGenTextures(1, textures, 0);
                int textureId = textures[0];
                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

                Bitmap bitmap = null;
                try {
                    bitmap = BitmapFactory.decodeFile(path);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (bitmap != null) {
                    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
                    setTexture(textureId);
                    bitmap.recycle();
                }
            }
        });
    }

queueEvent表示将当前操作插入GL线程运行,因为使用了OpenGL相关函数,必须在GL线程中运行,否则会报没有OpenGL上下文错误。

5.iOS端图片转纹理

iOS端图片转纹理更方便,使用GLKTextureLoader,代码如下:

- (void)loadImage:(NSString*)path
{
    NSError* error;
    GLKTextureInfo* texture = [GLKTextureLoader textureWithContentsOfFile:path options:nil error:&error];
    if (error)
    {
        NSLog(@"Texture Error:%@", error);
    } else {
        GLuint name = texture.name;
        setTexture(name);
    }
}

运行效果如下(左iOS 右Android):
result

后记


完整工程下载:https://download.csdn.net/download/suwk1009/10522664

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页