四、纹理显示图片

news2024/12/28 4:58:08

第一部分纹理基础

1)基础概念

在 OpenGLES 开发中,纹理除了用于装饰物体表面,还可以用来作为存储数据的容器。

纹理映射:纹理映射就是通过为图元的顶点坐标指定恰当的纹理坐标,通过纹理坐标在纹理图中选定特定的纹理区域,最后通过纹理坐标与顶点的映射关系,将选定的纹理区域映射到指定图元上。
纹理映射也称为纹理贴图,简单地说就是将纹理坐标(纹理坐标系)所指定的纹理区域,映射到顶点坐标(渲染坐标系或OpenGLES 坐标系)对应的区域。

纹理坐标【备注 opengles纹理坐真正的原点为左上角,向下为Y正方向,右为X正方向】

在这里插入图片描述

顶点坐标

在这里插入图片描述

这里在顶点数组编写的时候纹理坐标也需要对应。

绘制三角形:

编写代码的流程:

2)顶点着色器,片段着色器的修改

顶点数组中引入顶点索引位置+对应点的纹理坐标
float vertices[] = {
        //---- 位置 ----    - 纹理坐标 -
        0.5f,  0.5f, 0.0f,   1.0f, 1.0f,   // 右上
        0.5f, -0.5f, 0.0f,   1.0f, 0.0f,   // 右下
        -0.5f, -0.5f, 0.0f,  0.0f, 0.0f,   // 左下
        -0.5f,  0.5f, 0.0f,  0.0f, 1.0f    // 左上
};

顶点着色器

需要引入纹理属性,并传出out给片段着色器

#version 300 es
layout (location = 0) in vec4 vPosition;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

void main()
{
    gl_Position = vPosition;
    TexCoord = aTexCoord;
}

片段着色器

引入ourTexture 叠加顶点着色器传入的TexCoord组合成片段着色器传出的颜色。

#version 300 es
precision mediump float;
out vec4 fragColor;
in vec2 TexCoord;

//在调用glDrawElements之前绑定纹理了,它会自动把纹理赋值给片段着色器的采样器:
uniform sampler2D ourTexture;//纹理单元

void main()
{
	//texture 是OpenGL ES内置函数,称之为采样器,获取纹理上指定位置的颜色值。
    //ourTexture  绑定定义的纹理
    //TexCoord  由顶点坐标那边传来的纹理坐标
    //最后输出还可以把颜色也叠加上去
    fragColor = texture(ourTexture, TexCoord);
}

3)初始化时准备工作

索引数组

//索引数组 就是画矩形图片时对应的两个三角形坐标
unsigned int indices[] = {
        0, 1, 3, // first triangle
        1, 2, 3  // second triangle
};

绑定纹理相关

//将GL_ELEMENT_ARRAY_BUFFER缓冲区绑定到EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
//将索引坐标绑定到GL_ELEMENT_ARRAY_BUFFER
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

纹理属性绑定

1表示顶点着色器里面location里面的1属性,2表示从顶点数组取两个数据
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float ), (void *)(3*sizeof(float)));//这个与顶点数组的数据内容相关
glEnableVertexAttribArray(1);//启动

创建加载纹理

//创建纹理对象
glGenTextures(1, &texture);
//将纹理绑定到GL_TEXTURE_2D  纹理目标
glBindTexture(GL_TEXTURE_2D, texture);
//为当前绑定的纹理对象设定纹理环绕方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//重复纹理的填充方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//为当前绑定的纹理对象设定纹理过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//缩小时线性插值
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//放到就是线性

绑定纹理数据

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texturewidth, textureheight, 0, GL_RGB, GL_UNSIGNED_BYTE, texturedata);
LOGD("CreateProgram %s", texturedata);
glGenerateMipmap(GL_TEXTURE_2D);//为当前绑定的纹理自动生成所有需要的多级渐远纹理
LOGD("CreateProgram END");

4)绘画纹理

//指定使用的着色器程序
glUseProgram(program);

glBindTexture(GL_TEXTURE_2D, texture);
LOGD("glBindTexture");
//绑定顶点数组
glBindVertexArray(VAO);
//画纹理
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);

第二部分项目工程部分

以三、画三角形的区别为例

Java端没有区别,都是一致的。

C++端存在区别,需引入纹理相关的

1)加载assets资源文件下面的图片资源并解析bmp的图片数据

在ReadFileUtil.h中添加

unsigned char *DecodeBMP(unsigned char *bmpFileData, int &width, int &height) {
    if (0x4D42 == *((short *) bmpFileData)) { // 数据头是否为0x4D42 判断是否是 24 位的位图,
        // 读格式头
        int pixelDataOffset = *((int *) (bmpFileData + 10));// 取出像素数据在内存块的偏移地址
        width = *((int *) (bmpFileData + 18));
        height = *((int *) (bmpFileData + 22));
        LOGD("pixelDataOffset %d", pixelDataOffset);
        unsigned char *pixelData = bmpFileData + pixelDataOffset;
        // 位图像素数据是 BGR 排布的,所以更换 r b 的位置
        for (int i = 0; i < width * height * 3; i += 3) {
            char temp = pixelData[i];
            pixelData[i] = pixelData[i + 2];
            pixelData[i + 2] = temp;
        }
        return pixelData;
    }
    LOGD("DecodeBMP END");
    return nullptr;
}

unsigned char *ReadBMP(char *bmpPath, int &width, int &height) {

    unsigned char *bmpFileContent = const_cast<unsigned char *>(LoadFileContent(bmpPath));
    if (bmpFileContent == NULL) {
        return 0;
    }
    unsigned char *pixelData = DecodeBMP(bmpFileContent, width, height);
    LOGD("pixelData %d, width = %d, height = %d",pixelData, width, height);
    if (pixelData == NULL) {
        delete[] bmpFileContent;
        return 0;
    }
    LOGD("ReadBMP END");
    return bmpFileContent;
}

2)在Nativity.cpp中调用解析bmp数据并赋值到纹理类中

JNIEXPORT void JNICALL NativeImpl_init(JNIEnv *env, jobject instance)
{
   TextureDemo::GetInstance();
   int width = 0, height = 0;
   unsigned char *img = ReadBMP("awesomeface.bmp", width, height);//解析获取图片数据
   TextureDemo::GetInstance()->getTexturedata(img, width, height);
   TextureDemo::GetInstance()->CreateProgram(
         reinterpret_cast<const char *>(LoadFileContent("vertex.vs")),
         reinterpret_cast<const char *>(LoadFileContent("fragment.fs")));
}

3)纹理实现类

TextureDemo.h

//
// Created by CreatWall_zhouwen on 2023/4/13.
//

#ifndef TWODRAWTEXTURE_TEXTUREDEMO_H
#define TWODRAWTEXTURE_TEXTUREDEMO_H


#include <GLES3/gl3.h>

class TextureDemo {
public:
    TextureDemo(){
        program = 0;
        vertexShaderHandle = 0;
        fragShaderHandle = 0;
    };
    ~TextureDemo(){};
    void CreateProgram(const char *ver, const char *frag);
    void Draw();
    void getTexturedata(unsigned char *data, int width, int height);
    static TextureDemo* GetInstance();
    static void DestroyInstance();
private:
    GLuint program;
    GLuint vertexShaderHandle;
    GLuint fragShaderHandle;
    GLuint VBO, VAO, EBO;
    unsigned int texture;
    unsigned char *texturedata;
    int texturewidth, textureheight;
};



#endif //TWODRAWTEXTURE_TEXTUREDEMO_H

TextureDemo.cpp

//
// Created by CreatWall_zhouwen on 2023/4/13.
//

#include "TextureDemo.h"
#include "Util.h"
TextureDemo* m_pContext = nullptr;
#define TAG "DRAWTEXTURE"


float vertices[] = {
        //---- 位置 ----    - 纹理坐标 -
        0.5f,  0.5f, 0.0f,   1.0f, 1.0f,   // 右上
        0.5f, -0.5f, 0.0f,   1.0f, 0.0f,   // 右下
        -0.5f, -0.5f, 0.0f,  0.0f, 0.0f,   // 左下
        -0.5f,  0.5f, 0.0f,  0.0f, 1.0f    // 左上
};
//索引数组
unsigned int indices[] = {
        0, 1, 3, // first triangle
        1, 2, 3  // second triangle
};

void TextureDemo::CreateProgram(const char *ver, const char *frag)
{
    LOGD("CreateProgram Enter");
    //程序中加载编译顶点着色器
    vertexShaderHandle = glCreateShader(GL_VERTEX_SHADER);//创建顶点着色器
    glShaderSource(vertexShaderHandle, 1, &ver, NULL);
    glCompileShader(vertexShaderHandle);
    GLint compiled = 0;
    glGetShaderiv(vertexShaderHandle, GL_COMPILE_STATUS, &compiled);//
    if (!compiled){
        LOGD("glCompileShader vertexShaderHandle error");
        return;
    }

    //程序中加载编译片段着色器
    fragShaderHandle = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragShaderHandle, 1, &frag, NULL);
    glCompileShader(fragShaderHandle);
    glGetShaderiv(fragShaderHandle, GL_COMPILE_STATUS, &compiled);
    if(!compiled){
        LOGD("glCompileShader fragShaderHandle error");
        return;
    }

    //创建程序
    program = glCreateProgram();
    if (program)
    {
        //添加顶点着色器
        GLint AttachStatus = GL_FALSE;
        glAttachShader(program, vertexShaderHandle);
        glGetShaderiv(vertexShaderHandle, GL_ATTACHED_SHADERS, &AttachStatus);
        if(AttachStatus == 1){
            LOGD("glAttachShader vertexShaderHandle error");
            return;
        }

        //添加片段着色器
        glAttachShader(program, fragShaderHandle);
        glGetShaderiv(fragShaderHandle, GL_ATTACHED_SHADERS, &AttachStatus);
        if(AttachStatus == 2){
            LOGD("glAttachShader fragShaderHandle error");
            return;
        }

        //链接
        glLinkProgram(program);
        GLint linkStatus = GL_FALSE;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
        if (linkStatus != GL_TRUE){
            LOGD("glLinkProgram error");
            return;
        }

        //成功连接到程序之后就可以解绑删除
        glDetachShader(program, vertexShaderHandle);
        glDeleteShader(vertexShaderHandle);
        glDetachShader(program, fragShaderHandle);
        glDeleteShader(fragShaderHandle);
        vertexShaderHandle = 0;
        fragShaderHandle = 0;
    }
    LOGD("program success");
    /* -----顶点相关------ */
    //创建顶点数组
    glGenVertexArrays(1, &VAO);
    //创建顶点缓冲区
    glGenBuffers(1, &VBO);
    //绑定顶点数组
    glBindVertexArray(VAO);
    //将顶点缓冲区绑定为GL_ARRAY_BUFFER
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    //将定义的顶点数组绑定到GL_ARRAY_BUFFER这个缓存中,这个缓存对应顶点缓冲区数据
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    /* -----绑定纹理相关------ */
    //将GL_ELEMENT_ARRAY_BUFFER缓冲区绑定到EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    //将索引坐标绑定到GL_ELEMENT_ARRAY_BUFFER
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    //指定配置的顶点属性,第一个index参数对应顶点着色器的location值
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float ), (void *)0);
    //启用顶点属性
    glEnableVertexAttribArray(0);

    //纹理属性绑定
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float ), (void *)(3*sizeof(float)));
    glEnableVertexAttribArray(1);

    //将顶点数组和顶点缓冲区置空则不让其他修改
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    /* -----创建加载纹理------ */
    //创建纹理
    glGenTextures(1, &texture);
    //将纹理绑定到GL_TEXTURE_2D
    glBindTexture(GL_TEXTURE_2D, texture);
    //为当前绑定的纹理对象设定纹理环绕方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//重复纹理的填充方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    //为当前绑定的纹理对象设定纹理过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//缩小时线性插值
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//放到就是线性

    //绑定纹理数据
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texturewidth, textureheight, 0, GL_RGB, GL_UNSIGNED_BYTE, texturedata);
    LOGD("CreateProgram %s", texturedata);
    glGenerateMipmap(GL_TEXTURE_2D);//为当前绑定的纹理自动生成所有需要的多级渐远纹理
    LOGD("CreateProgram END");
}
void TextureDemo::Draw()
{
    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0.2f, 0.9f, 0.3f, 1.0f);
    //指定使用的着色器程序
    glUseProgram(program);

    glBindTexture(GL_TEXTURE_2D, texture);
    LOGD("glBindTexture");
    //绑定顶点数组
    glBindVertexArray(VAO);
    //画纹理
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

}
TextureDemo* TextureDemo::GetInstance()
{
    if (m_pContext == nullptr)
    {
        m_pContext = new TextureDemo();
    }
    return m_pContext;
}
void TextureDemo::DestroyInstance()
{
    if (m_pContext)
    {
        delete m_pContext;
        m_pContext = nullptr;
    }
}

void TextureDemo::getTexturedata(unsigned char *data, int width, int height)
{
    texturedata = data;
    texturewidth = width;
    textureheight = height;
}

安卓配置部分与三、画三角形一致。

引入资源与三、画三角形一致,只是多出一个解析bmp图片数据的接口

参考链接

OpenGL ES 3.0 开发之纹理贴图 https://blog.csdn.net/qq_39792615/article/details/113394702

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/617992.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

汽车电子AUTOSAR之Event

上文AUTOSAR基础篇之DTC中提到event是故障监控的基本单元&#xff0c;本文将从event的使能条件&#xff08;Enable Condition&#xff09;、上报方式、去抖动策略&#xff08;Debouncing Strategy&#xff09;、优先级&#xff08;Priority&#xff09;、Displacement、依赖关系…

解决SpringBoot配置文件项目重启出现乱码的情况

近日&#xff0c;在创建了SpringBoot项目后往配置文件中写了相关的系统配置&#xff0c;并且在上面加了中文注释&#xff0c;但是在重启项目或开机重启后遇到了注释乱码的情况&#xff0c;查询了各种相关资料&#xff0c;得以解决 发现问题 首先看到我在这个application.prope…

Golang每日一练(leetDay0089) 滑动窗口最大值、中位数

目录 239. 滑动窗口最大值 Sliding Window Maximum &#x1f31f;&#x1f31f;&#x1f31f; 480. 滑动窗口中位数 Sliding Window Median &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专…

chatgpt赋能python:Python安装FBProphet:绝佳的时间序列预测工具

Python安装FBProphet&#xff1a;绝佳的时间序列预测工具 随着时间序列数据应用场景的不断增加&#xff0c;越来越多的数据科学家和工程师开始使用FBProphet进行时间序列预测。FBProphet是由Facebook开发的一种开源预测工具&#xff0c;它使用先进的统计方法进行时间序列分析&…

案例40:基于Springboot疫苗预约系统开题报告设计

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

Day_41顺序查找与折半查找

目录 一. 顺序查找和折半查找的实现 1. 顺序查找 1.1 一般线性表的顺序查找 1.2 有序表的顺序查找 2. 折半查找 二. 代码实现 1. 内部节点 2. 类的构造函数 3. 顺序查找 4. 折半查找 三. 代码展示 四. 数据测试 五. 小结 一. 顺序查找和折半查找的实现 1. 顺序查找…

chatgpt赋能python:Python定义错误:什么是Python定义错误

Python定义错误&#xff1a;什么是Python定义错误 Python是一种强大的编程语言&#xff0c;被广泛用于各种领域&#xff0c;例如Web开发&#xff0c;数据分析&#xff0c;机器学习等。然而&#xff0c;即使是最有经验的Python开发人员也会犯一些常见的错误&#xff0c;其中之一…

在线教育机构的视频如何做防下载和防盗录?

在线教育平台付费课程、企业内训的培训课程&#xff0c;这类视频课程内容是如何做防下载和防盗录的&#xff1f; 1.AI隐形溯源水印 这个功能能够将水印隐藏在视频中&#xff0c;不会影响观看体验&#xff0c;但却能够帮助企业很好的视频版权保护。更重要的是&#xff0c;对于盗…

【ArcGIS Pro二次开发】(34):从字符串中提取中文、英文、数字与特殊符号

这是一个基于字段计算的工具。 有时候我们会遇到一些混杂着各种中文、英文、数字、特殊符号的文字&#xff0c;这个工具的目的是从这些复杂文字中提取出想要的特定文字。 比如说从CAD测绘图中可以读取到类似【混3】、【砖2】的文字&#xff0c;如果想要从中提取出层数或结构&…

chatgpt赋能python:Python宏变量——简介

Python宏变量——简介 Python是一种高级编程语言&#xff0c;具有易学易用、简洁清晰等优点。但我们在编写代码的时候&#xff0c;有时需要用到常量或者宏定义&#xff0c;这就需要用到宏变量。在Python中&#xff0c;宏变量是一种常见的编程方法&#xff0c;本文将详细介绍Py…

chatgpt赋能python:Python安装后怎么使用?

Python安装后怎么使用&#xff1f; Python是一种高级编程语言&#xff0c;被广泛用于Web开发、数据分析、人工智能和自动化等领域。下面我们将介绍安装Python后如何使用它。 步骤1 - 安装Python 首先&#xff0c;从官方网站下载并安装Python。在安装过程中&#xff0c;您可以…

chatgpt赋能python:Python中的构造方法是什么?

Python中的构造方法是什么&#xff1f; 当你开始学习 Python 编程时&#xff0c;你可能经常听到 “构造方法” 这个词。那么&#xff0c;什么是构造方法&#xff1f;为什么它在 Python 中很重要&#xff1f;本文将为您揭示构造方法的概念以及它们在 Python 中的作用。 什么是…

案例36:基于Springboot药店管理系统开题报告设计

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

chatgpt赋能python:Python程序员必知的Geany配置技巧

Python程序员必知的Geany配置技巧 如果你是一名Python程序员&#xff0c;并且正在寻找一个简单易用的代码编辑器&#xff0c;那么Geany是一个非常不错的选择。Geany是一款轻量级的集成开发环境&#xff08;IDE&#xff09;&#xff0c;除了Python&#xff0c;还支持许多其他编…

chatgpt赋能python:Python安装完后如何打开

Python安装完后如何打开 Python是一种高级的、解释性、交互式的编程语言&#xff0c;已经成为了广泛的编程应用领域中不可或缺的一部分&#xff0c;如网络编程、数据科学和人工智能等。Python的安装对于学习、开发和应用Python技术非常重要&#xff0c;但安装了Python后如何打…

案例38:基于Springboot电影评论网站开题报告设计

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

chatgpt赋能python:Python中的Gevent:安装和使用

Python 中的 Gevent: 安装和使用 Gevent 是 Python 生态系统中的一个流行的高性能网络库&#xff0c;它是基于 libev 的 Python 网络库&#xff0c;提供了非阻塞IO、协程和并发编程等方面的特性。Gevent 使得开发高性能的网络应用程序变得简单而易行。本文将介绍如何在 Python…

【Leetcode】78 子集 | 保存遍历路径上的所有节点 // 46 排列 | 使用辅助数组记录元素是否使用

78 子集 与组合问题相比&#xff0c;需要保存路上经过的所有节点。 写法1 分为选择第 i i i个元素和不选择第 i i i个元素两种情况递归。 每push进一个元素&#xff0c;代表进入了一个新的节点&#xff0c;就保存当前的路径。 import java.util.ArrayList; import java.uti…

JUC基础-0606

9.ReentrantReadWriteLock读写锁 9.1 锁的基本概念 悲观锁&#xff1a;不支持并发&#xff0c;效率低&#xff0c;但是可以解决所有并发安全问题 乐观锁&#xff1a;支持并发读&#xff0c;维护一个版本号&#xff0c;写的时候比较版本号进行控制&#xff0c;先提交的版本号…

chatgpt赋能python:Python配置指南:提高SEO效果的关键

Python配置指南&#xff1a;提高SEO效果的关键 Python作为一种高效、易学易用的编程语言&#xff0c;在数据科学、机器学习、网络编程等领域得到了广泛应用。作为一个网站管理员&#xff0c;如何让Python支持的应用程序尽可能地符合搜索引擎优化&#xff08;SEO&#xff09;的…