Android OpenGL(六) 纹理

纹理

纹理是一个2D图片(甚至也有1D和3D的纹理),
它可以用来添加物体的细节;你可以想象纹理是一张绘有砖块的纸,无缝折叠贴合到你的3D的
房子上,这样你的房子看起来就像有砖墙外表了
在这里插入图片描述

纹理环绕方式

纹理坐标的范围通常是从(0, 0)到(1, 1),那如果我们把纹理坐标设置在范围之外会发生什么?
OpenGL默认的行为是重复这个纹理图像(我们基本上忽略浮点纹理坐标的整数部分),但
OpenGL提供了更多的选择:在这里插入图片描述在这里插入图片描述
使用方式类似:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

纹理过滤

纹理过滤:GL_NEAREST 、GL_LINEAR和多级渐远纹理

GL_NEAREST(也叫邻近过滤,Nearest Neighbor Filtering)是OpenGL默认的纹理过滤方
式。当设置为GL_NEAREST的时候,OpenGL会选择中心点最接近纹理坐标的那个像素。

GL_LINEAR(也叫线性过滤,(Bi)linear Filtering)它会基于纹理坐标附近的纹理像素,计算出
一个插值,近似出这些纹理像素之间的颜色。一个纹理像素的中心距离纹理坐标越近,那么这个
纹理像素的颜色对最终的样本颜色的贡献越大。

当进行放大(Magnify)和缩小(Minify)操作的时候可以设置纹理过滤的选项,比如你可以在纹理
被缩小的时候使用邻近过滤,被放大时使用线性过滤。我们需要使用glTexParameter*函数为
放大和缩小指定过滤方式。这段代码看起来会和纹理环绕方式的设置很相似:
多级

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

多级渐远纹理

过滤方式
GL_NEAREST_MIPMAP_NEAREST :使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样
GL_LINEAR_MIPMAP_NEAREST: 使用最邻近的多级渐远纹理级别,并使用线性插值进行采样
GL_NEAREST_MIPMAP_LINEAR 在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样
GL_LINEAR_MIPMAP_LINEAR 在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

纹理的使用

  1. 生成纹理GLES30.glGenTextures(1, textureIds, 0)

  2. 绑定纹理 GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds[0])

  3. 设置纹理环绕方式、纹理过滤 GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR) GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR)

  4. 载入图片数据

  GLUtils.texImage2D(GLES30.GL_TEXTURE_2D,
            0,
            GLES30.GL_RGBA,
            bitmap,
            0)
  1. 取消绑定纹理
   GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)

纹理加载

    private fun loadTexture() {
        GLES30.glGenTextures(1, textureIds, 0)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds[0])


        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,
            GLES30.GL_TEXTURE_MIN_FILTER,
            GLES30.GL_LINEAR)
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,
            GLES30.GL_TEXTURE_MAG_FILTER,
            GLES30.GL_LINEAR)
        // 加载bitmap到纹理中
        GLUtils.texImage2D(GLES30.GL_TEXTURE_2D,
            0,
            GLES30.GL_RGBA,
            bitmap,
            0)
        GLES30.glGenerateMipmap(GLES30.GL_TEXTURE_2D)
        bitmap.recycle()
        // 取消绑定纹理
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)
    }

纹理应用

展示图片
在这里插入图片描述
布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.opengl.GLSurfaceView
        android:id="@+id/glSurfaceView_img"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Activity

class OpenGlImgActivity : AppCompatActivity() {
    private var glSurfaceView: GLSurfaceView? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_opengl_img_demo)
        glSurfaceView = findViewById(R.id.glSurfaceView_img)
        glSurfaceView?.setEGLContextClientVersion(3)
        glSurfaceView?.setRenderer(GLImageViewRender(BitmapFactory.decodeResource(resources, R.drawable.flower)))
        glSurfaceView?.renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
    }
}

GLSurfaceView.Renderer


import android.graphics.Bitmap
import android.opengl.GLES30
import android.opengl.GLSurfaceView
import android.opengl.GLUtils
import android.opengl.Matrix
import android.util.Log
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class GLImageViewRender(val bitmap:Bitmap) : GLSurfaceView.Renderer {
    /*
     * 顶点位置程序
     */
    private val vertexShaderCode =
        "uniform mat4 uTMatrix;" +
        "attribute vec4 aPosition;" +
        "attribute vec2 aTexCoord;" +
        "varying vec2 vTexCoord;" +
        "void main() { " +
        "   gl_Position = uTMatrix * aPosition;" +
        "   vTexCoord = aTexCoord;" +
        "}"

    /**
     * 片元颜色程序
     */
    private val fragmentShaderCode =
        "precision mediump float;" +
        "uniform sampler2D uSampler;" +
        "varying vec2 vTexCoord;" +
        "void main() { " +
        "   gl_FragColor = texture2D(uSampler,vTexCoord);" +
        "}"

    /**
     * 三角形顶点位置
     */
    private val coodData = floatArrayOf(
        // 顶点坐标        纹理坐标
        -1f, 1f, 0.0f, 0f, 0f,   // 左上角
        -1f, -1f, 0.0f, 0f, 1f,  //左下角
        1f, 1.0f, 0.0f, 1f, 0f,   //右上角
        1f, -1f, 0.0f, 1f, 1f  //右下角
    )

    private var translateMatrix = FloatArray(16)
    private var program: Int = 0
    private var positionHandle: Int = -1
    private var texCoordHandle: Int = -1
    private var samplerHandle: Int = -1
    private var uMatrixHandle: Int = -1
    
    // vbo
    private var vboId = IntArray(1)
    // 纹理id array
    private var textureIds= IntArray(1)

    private lateinit var coordBuffer: FloatBuffer
    private lateinit var byteBuffer: ByteBuffer

    override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {
        // 设置背景颜色
        GLES30.glClearColor(1f, 0f, 0f, 1.0f)
        // 清理缓存
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
        // 顶点坐标内存申请
        createFloatBuffer()
        // 创建定点着色程序
        val vertexShader = loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode)
        // 创建片元着色程序
        val fragmentShader = loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode)
        if (vertexShader != 0 && fragmentShader != 0) {
            linkProgram(vertexShader, fragmentShader)
            GLES30.glDeleteShader(vertexShader)
            GLES30.glDeleteShader(fragmentShader)
            // 生成VBO
            GLES30.glGenBuffers(1, vboId, 0)
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboId[0])
            GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, byteBuffer.capacity(), byteBuffer, GLES30.GL_STATIC_DRAW)
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0)

            //
            Matrix.setIdentityM(translateMatrix, 0)

            // 将数据传递shader
            positionHandle = GLES30.glGetAttribLocation(program, "aPosition")
            GLES30.glEnableVertexAttribArray(positionHandle)

            texCoordHandle = GLES30.glGetAttribLocation(program, "aTexCoord")
            GLES30.glEnableVertexAttribArray(texCoordHandle)

            uMatrixHandle = GLES30.glGetUniformLocation(program, "uTMatrix")
            samplerHandle = GLES30.glGetUniformLocation(program, "uSampler")

            loadTexture()
        }
    }

    private fun linkProgram(vertexShader: Int, fragmentShader: Int) {
        // 创建空的opengl es 程序
        program = GLES30.glCreateProgram()
        program.let {
            // 将顶点着色器加入程序
            GLES30.glAttachShader(it, vertexShader)
            // 将片元着色器加入程序
            GLES30.glAttachShader(it, fragmentShader)
            // 链接到着色器程序
            GLES30.glLinkProgram(it)
            // 将程序加入到opengl30环境中
            GLES30.glUseProgram(it)
            val info = GLES30.glGetProgramInfoLog(it)
            // 打印链接程序日志
            Log.e("wdf", "info==" + info)
        }
    }

    private fun createFloatBuffer() {
        // 申请物理层空间
        byteBuffer = ByteBuffer.allocateDirect(coodData.size * 4).apply {
            this.order(ByteOrder.nativeOrder())
        }
        // 坐标数据转换
        coordBuffer = byteBuffer.asFloatBuffer()
        coordBuffer.put(coodData, 0, coodData.size)
        coordBuffer.position(0)
    }

    override fun onSurfaceChanged(p0: GL10?, width: Int, height: Int) {
        // 设置绘制窗口
        GLES30.glViewport(0, 0, width, height)
    }

    override fun onDrawFrame(p0: GL10?) {
        if (program <= 0) {
            return
        }
        GLES30.glUseProgram(program)
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboId[0])
        program?.let {
            GLES30.glVertexAttribPointer(positionHandle, 3, GLES30.GL_FLOAT, false, 5 * Float.SIZE_BYTES, 0)
            GLES30.glVertexAttribPointer(texCoordHandle, 2, GLES30.GL_FLOAT, false, 5 * Float.SIZE_BYTES, 3 * Float.SIZE_BYTES)

            GLES30.glUniformMatrix4fv(uMatrixHandle, 1, false, translateMatrix, 0)

            // 激活纹理单元
            GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
            // 绑定纹理单元
            GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds[0])
            // 第二个参数传递激活的纹理单元,因为激活的是GLES30.GL_TEXTURE0,因此传递0
            GLES30.glUniform1i(samplerHandle, 0)
            GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4)
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0)
        }

    }

    private fun loadTexture() {
        GLES30.glGenTextures(1, textureIds, 0)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds[0])


        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,
            GLES30.GL_TEXTURE_MIN_FILTER,
            GLES30.GL_LINEAR)
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,
            GLES30.GL_TEXTURE_MAG_FILTER,
            GLES30.GL_LINEAR)
        // 加载bitmap到纹理中
        GLUtils.texImage2D(GLES30.GL_TEXTURE_2D,
            0,
            GLES30.GL_RGBA,
            bitmap,
            0)
        GLES30.glGenerateMipmap(GLES30.GL_TEXTURE_2D)
        bitmap.recycle()
        // 取消绑定纹理
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)
    }

    /**
     * 创建shader,加载shader程序
     */
    private fun loadShader(type: Int, shaderCode: String): Int {
        val shader = GLES30.glCreateShader(type)
        GLES30.glShaderSource(shader, shaderCode)
        GLES30.glCompileShader(shader)
        return shader
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一文大白话讲清楚webpack基本使用——18——HappyPack

文章目录 一文大白话讲清楚webpack基本使用——18——HappyPack1. 建议按文章顺序从头看&#xff0c;一看到底&#xff0c;豁然开朗2. 啥是HappyPack3. 怎么使用HappyPack 一文大白话讲清楚webpack基本使用——18——HappyPack 1. 建议按文章顺序从头看&#xff0c;一看到底&a…

深入 Rollup:从入门到精通(二)Rollup简介

1. 简介 对于将rollup描述为一个打包工具&#xff0c;我觉得并不是很精准&#xff0c;稍有些笼统&#xff0c;未能完全展示它的功能。 我更倾向于将它定义为&#xff1a; 以模块化的方式加载你的 js 文件&#xff08;如果使用插件&#xff0c;也可以支持其他静态资源文件&…

【数据结构】_C语言实现不带头非循环单向链表

目录 1. 链表的概念及结构 2. 链表的分类 3. 单链表的实现 3.1 SList.h头文件 3.2 SList.c源文件 3.3 Test_SList.c测试文件 关于线性表&#xff0c;已介绍顺序表&#xff0c;详见下文&#xff1a; 【数据结构】_顺序表-CSDN博客 本文介绍链表&#xff1b; 基于顺序表…

HTML5 Web Worker 的使用与实践

引言 在现代 Web 开发中&#xff0c;用户体验是至关重要的。如果页面在执行复杂计算或处理大量数据时变得卡顿或无响应&#xff0c;用户很可能会流失。HTML5 引入了 Web Worker&#xff0c;它允许我们在后台运行 JavaScript 代码&#xff0c;从而避免阻塞主线程&#xff0c;保…

Excel 技巧21 - Excel中整理美化数据实例,Ctrl+T 超级表格(★★★)

本文讲Excel中如何整理美化数据的实例&#xff0c;以及CtrlT 超级表格的常用功能。 目录 1&#xff0c;Excel中整理美化数据 1-1&#xff0c;设置间隔行颜色 1-2&#xff0c;给总销量列设置数据条 1-3&#xff0c;根据总销量设置排序 1-4&#xff0c;加一个销售趋势列 2&…

手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion(原理介绍)

手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion&#xff08;原理介绍&#xff09; 目录 手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion&#xff08;原理介绍&#xff09;DDPM 原理图Stable Diffusion 原理Stable Diffusion的原理解释Stable Diffusion 和 Diffus…

倍频增量式编码器--角度插值法输出A,B(Aangular Interpolation)

问题是&#xff1a; 最大速度&#xff0c;周期刻度&#xff0c;最小细分刻度&#xff0c;可以计算得到&#xff1a; 结论&#xff1a; 按照最高速度采样&#xff1b;数字A,B输出间隔时间&#xff1a;按照计算角度 插入细分角度运算算时间&#xff08;最快速度&#xff09;&a…

基于微信小程序的助农扶贫系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

嵌入式C语言:结构体对齐

目录 一、对齐的原因 1.1. 硬件访问效率 1.2. 内存管理简化 1.3. 编译器优化 1.4. 代码示例 二、对齐规则 2.1. 基本数据类型对齐 2.2. 结构体成员对齐 2.3. 结构体整体对齐 2.4. 代码示例 三、对齐控制 3.1. 使用 #pragma pack 3.2. 使用 __attribute__((packed)…

网络工程师 (1)数据的表示

一、R进制的表示及互转 R进制是一种数制表示方法&#xff0c;其中R代表基数&#xff0c;采用R个基本符号&#xff08;0, 1, 2, …, R-1&#xff09;表示各位上的数字&#xff0c;并遵循“逢R进一”的运算规则。在R进制中&#xff0c;每一位上的数字均不超过R-1。R进制与十进制之…

coffee销售数据集分析:基于时间趋势分析的实操练习

**文章说明&#xff1a;**对coffee销售数据集的简单分析练习&#xff08;时间趋势分析练习&#xff09;&#xff0c;主要是为了强化利用python进行数据分析的实操能力。属于个人的练习文章。 **注&#xff1a;**这是我第一次使用md格式编辑博客文章&#xff0c;排版上还是不是很…

SQL在DBA手里-改写篇

背景 最近运营需要做月报汇总交易情况&#xff0c;之前一直是他们手工出的数据&#xff0c;他们想做成月初自动发送邮件&#xff0c;从而减轻他们的工作量。于是他们提供SQL我们在邮件服务器配置做定时发送任务。 表介绍&#xff08;表及字段已做脱敏处理&#xff09; trans…

vue3入门基础学习之搭建登录验证功能

环境准备&#xff1a;node.js、Visual Studio Code&#xff08;也可以是其他开发工具&#xff0c;选自己熟悉的就行&#xff09; 下载地址&#xff1a;https://nodejs.p2hp.com/https://code.visualstudio.com/ 新建一个vue3的项目&#xff0c;选一个文件夹执行以下命令 使用…

Scrapy如何设置iP,并实现IP重用, IP代理池重用

前置知识 1/3乐观锁 2/3 Scrapy流程(非全部) 3/3 关于付费代理 我用的"快代理", 1000个ip, 每个ip1min的有效期, 你用的时候, 把你的链接, 用户名填上去就行 设置代理IP &#x1f512; & 帮助文档: ①meta ②meta#proxy$ 语法: ①proxy的设置: Request对象中…

消息队列篇--通信协议篇--网络通信模型(OSI7层参考模型,TCP/IP分层模型)

一、OSI参考模型&#xff08;Open Systems Interconnection Model&#xff09; OSI参考模型是一个用于描述和标准化网络通信功能的七层框架。它由国际标准化组织&#xff08;ISO&#xff09;提出&#xff0c;旨在为不同的网络设备和协议提供一个通用的语言和结构&#xff0c;以…

开源智慧园区管理系统对比五款主流产品探索智能运营新模式

内容概要 在这个数字化迅速发展的时代&#xff0c;园区管理也迎来了全新的机遇和挑战。众所周知&#xff0c;开源智慧园区管理系统作为一种创新解决方案&#xff0c;正逐步打破传统管理的局限性。它的开放性不仅使得系统可以根据具体需求进行灵活调整&#xff0c;也为用户提供…

leetcode——删除链表的倒数第N个节点(java)

给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例 3&#xf…

WPS数据分析000009

一、函数与数据透视表统计数据时效率差异 函数 F4绝对引用 数据透视表 二、数据透视表基础操作 数据透视表&#xff1a;一个快速的生成报表的工具 显示详细信息 方式一; 方式二&#xff1a; 移动数据透视表 删除数据透视表 复制粘贴数据透视表 留足空间&#xff0c;否则拖动字…

【C++图论】1761. 一个图中连通三元组的最小度数|2005

本文涉及知识点 C图论 LeetCode1761. 一个图中连通三元组的最小度数 给你一个无向图&#xff0c;整数 n 表示图中节点的数目&#xff0c;edges 数组表示图中的边&#xff0c;其中 edges[i] [ui, vi] &#xff0c;表示 ui 和 vi 之间有一条无向边。 一个 连通三元组 指的是 …

ubuntu 更新24LTS中断导致“系统出错且无法恢复,请联系系统管理员”

22LTS to 24LTS 更新过程中手jian把更新程序controlC导致的。 解决 目前企图完成更新来恢复&#xff0c;重启后有软件包冲突&#xff0c;sudo apt upgrade报冲突。无法进行。 将原来source.list重新 sudo dpkg --configure -a sudo apt install -f 这些都不管用。还是显示gno…