码迷,mamicode.com
首页 > 其他好文 > 详细

5.简单的2D纹理绘制

时间:2021-04-19 15:17:37      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:输入   char   单点   简单   img   http   def   备忘   需要   

5.简单的2D纹理绘制

概述

2D纹理是一个图像数据的二维数组,一个纹理的单独数据元素称作纹理像素(texture pixels)。

总体流程

技术图片

纹理的使用流程

1. 准备工作

// 设置数据传输模式
// void glPixelStorei (GLenum pname, GLint param);
// UNPACK:将图像数据从内存传输到GPU内存中
// PACK:将图像数据从GPU内存传输到内存中
// OpenGL ES默认是按4字节4字节的形式传输到GPU内存中的,但是GL_RGB格式只有3个字节,所以这里就改为按1个字节1个字节的形式将图像数据传输到GPU内存中
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

// 1. 创建一个纹理对象
// void glGenTextures (GLsizei n, GLuint *textures);
// n表示要生成的纹理对象数量;textures表示保存n个纹理对象ID的无符号整数数组
glGenTextures(1, &textureId);

// 2. 绑定纹理对象
// void glBindTexture (GLenum target, GLuint texture);
//target表示要绑定的纹理的类型;OpenGL ES中纹理有:2D纹理(GL_TEXTURE_2D),2D纹理数组(GL_TEXTURE_2D_ARRAY),3D纹理(GL_TEXTURE_3D)和立方图纹理(GL_TEXTURE_CUBE_MAP)
// texture为前面生成的纹理ID
glBindTexture(GL_TEXTURE_2D, textureId);

// 3. 加载图像数据
// void glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
// target就是2D纹理类型;level表示mip级别;internalformat表示纹理存储的内部格式,这里为GL_RGB格式
// width表示图像像素宽度;height表示高度;border为了兼容OpenGL桌面API,传0即可
// format表示输入的纹理数据格式,这里为GL_RGB;type表示输入像素数据的类型,这里为GL_UNSIGNED_BYTE;pixels表示图像的实际像素数据
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 3, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);

// 4. 设置采样器的参数
// void glTexParameteri (GLenum target, GLenum pname, GLint param);
// target表示要绑定的纹理的类型;pname表示设置参数;param表示参数值
// GL_TEXTURE_MIN_FILTER表示缩小过滤,就是屏幕上投影的多边形小于纹理尺寸的时候,图片分辨率过高;
// GL_TEXTURE_MAG_FILTER表示放大过滤,屏幕上投影的多边形大于纹理尺寸的时候,图片分辨率过低;
// GL_NEAREST从最靠近纹理坐标的纹理中取得单点样本
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

2. 使用

// 1. 绑定纹理单元
// void glActiveTexture (GLenum texture);
// texture表示需要激活的纹理单元:GL_TEXTURE0、GL_TEXTURE1 。。。 GL_TEXTURE31
glActiveTexture(GL_TEXTURE0);

// 2. 绑定纹理对象
glBindTexture(GL_TEXTURE_2D, userData->textureId);

// 3. 传递统一变量的值;0代表的是采样纹理单元0:GL_TEXTURE0
glUniform1i(userData->samplerLoc, 0);

// 4. 片段着色器中进行采样操作
// void texture(sampler2D sampler, vec2 coord[,float bias])
// sampler表示绑定到纹理单元的采样器,就是纹理数据
// coord表示纹理坐标;bias为可选参数
// texture函数返回一个代表从纹理贴图中读取颜色的vec4,代表颜色值
outColor = texture(s_texture, v_texCoord);

纹理数据和纹理坐标的对应关系

输入数据样式:
    GLubyte pixels[6*3] = {
            255, 0, 0,  // 红
            0, 0, 0,    // 黑
            0,255,0,    // 绿
            0,255,255,    // 青
            0, 0, 255,  // 蓝
            255, 255, 0 // 黄
    };
这是一个2x3的图片:
纹理数据的第一个数据对应坐标(0,0);然后第二个坐标横过去,对应坐标(1,0)
第三个数据向上,对应坐标(0,1);第四个数据横过来,对应坐标(1,1);以此类推。。。

技术图片

纹理坐标和顶点坐标之间的对应关系

首先把贴纹理,想象成贴照片到墙上就可以了。纹理坐标和顶点坐标之间要一一对应,不可以交叉
    GLfloat vVertices[] = {
            -0.5f, 0.5f, 0.0f,
            0.0f, 1.0f,
            -0.5f, -0.5f, 0.0f,
            0.0f, 0.0f,
            0.5f, -0.5f, 0.0f,
            1.0f, 0.0f,
            0.5f, 0.5f, 0.0f,
            1.0f, 1.0f
    };
(0,1)V0 -> (0,0)V1 -> (1,0)V2 -> (1,1)V3
这个顶点坐标和纹理坐标的效果图如上图所示

上面顶点的坐标在坐标系的位置,如下图所示:

技术图片

把纹理横过来贴:
	GLfloat vVertices[] = {
            -0.5f, 0.5f, 0.0f,
            0.0f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            1.0f, 0.0f,
            0.5f, -0.5f, 0.0f,
            1.0f, 1.0f,
            0.5f, 0.5f, 0.0f,
            0.0f, 1.0f
    };
(0,0)V0 -> (1,0)V1 -> (1,1)V2 -> (0,1)V3

技术图片

交叉贴图的情况:(1,1)本来在(0,0)对角位置的,现在把它贴到(0,0)旁边的顶点上,就会出现对角交叉情况
	GLfloat vVertices[] = {
            -0.5f, 0.5f, 0.0f,
            0.0f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            1.0f, 0.0f,
            0.5f, -0.5f, 0.0f,
            0.0f, 1.0f,
            0.5f, 0.5f, 0.0f,
            1.0f, 1.0f
    };
(0,0)V0 -> (1,0)V1 -> (0,1)V2 -> (1,1)V3

技术图片

源码解析

#include <stdlib.h>
#include "esUtil.h"

typedef struct
{
    GLuint programObject;
    GLint samplerLoc;
    GLuint textureId;
} myUserData;

GLuint CreateSimpleTexture2D()
{
    GLuint textureId;
    // 图片数据,6个像素
    GLubyte pixels[6*3] = {
            255, 0, 0,  // 红
            0, 0, 0,    // 黑
            0,255,0,    // 绿
            0,255,255,    // 青
            0, 0, 255,  // 蓝
            255, 255, 0 // 黄
    };
    // 设置数据传输模式
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    // 1. 创建一个纹理对象
    glGenTextures(1, &textureId);
    // 2. 绑定纹理对象
    glBindTexture(GL_TEXTURE_2D, textureId);
    // 3. 加载图像数据
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 3, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
    // 4. 设置采样器的参数
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    return textureId;
}

int Init(MYESContext *myesContext)
{
    myUserData *userData = (myUserData *)myesContext->userData;
    char vShaderStr[] =
            "#version 300 es \n"
            "layout(location = 0) in vec4 a_position; \n"
            "layout(location = 1) in vec2 a_texCoord; \n"
            "out vec2 v_texCoord; \n"
            "void main() \n"
            "{ \n"
            "   gl_Position = a_position; \n"
            "   v_texCoord = a_texCoord; \n"
            "} \n";
    char fShaderStr[] =
            "#version 300 es \n"
            "precision mediump float; \n"
            "in vec2 v_texCoord; \n"
            "layout(location = 0) out vec4 outColor; \n"
            "uniform sampler2D s_texture; \n"	// 采样器类型统一变量
            "void main() \n"
            "{ \n"
            "   outColor = texture(s_texture, v_texCoord); \n" // 4. 片段着色器中进行采样操作
            "} \n";
    userData->programObject = myesLoadProgram(vShaderStr, fShaderStr);
    userData->samplerLoc = glGetUniformLocation(userData->programObject, "s_texture");
    userData->textureId = CreateSimpleTexture2D();
    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
    return GL_TRUE;
}

void Draw(MYESContext *myesContext)
{
    myUserData *userData = (myUserData *)myesContext->userData;
    GLfloat vVertices[] = {
            -0.5f, 0.5f, 0.0f,
            0.0f, 1.0f,
            -0.5f, -0.5f, 0.0f,
            0.0f, 0.0f,
            0.5f, -0.5f, 0.0f,
            1.0f, 0.0f,
            0.5f, 0.5f, 0.0f,
            1.0f, 1.0f
    };
    GLushort indices[] = {0, 1, 2, 0, 2, 3};
    glViewport(0, 0, myesContext->width, myesContext->height);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(userData->programObject);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), vVertices);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), &vVertices[3]);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    // 1. 绑定纹理单元
    glActiveTexture(GL_TEXTURE0);
    // 2. 绑定纹理对象
    glBindTexture(GL_TEXTURE_2D, userData->textureId);
    // 3. 传递统一变量的值;0代表的是采样纹理单元0:GL_TEXTURE0
    glUniform1i(userData->samplerLoc, 0);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}

void ShutDown(MYESContext *myesContext)
{
    myUserData *userData = (myUserData *)myesContext->userData;
    // 删除纹理对象
    glDeleteTextures(1, &userData->textureId);
    glDeleteProgram(userData->programObject);
}


int myesMain(MYESContext *myesContext)
{
    myesContext->userData = malloc(sizeof(myUserData));
    myesCreateWindow(myesContext, "9_1_simple_texture2D", 320, 240, MY_ES_WINDOW_RGB);

    if (!Init(myesContext))
    {
        return GL_FALSE;
    }

    esRegisterDrawFunc(myesContext, Draw);
    esRegisterShutdownFunc(myesContext, ShutDown);

    return GL_TRUE;
}

参考

1. OpenGL常用命令备忘录(Part B) -- glPixelStore
http://www.zwqxin.com/archives/opengl/opengl-api-memorandum-2.html
2. Android OpenGL ES 系列连载:(02)纹理映射
https://zhuanlan.zhihu.com/p/115210823
3. glTexImage2D
http://docs.gl/es2/glTexImage2D

5.简单的2D纹理绘制

标签:输入   char   单点   简单   img   http   def   备忘   需要   

原文地址:https://www.cnblogs.com/pyjetson/p/14669256.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!