首页 > 其他分享 >OpenGL ES通过缩小GLSurfaceView来解决纹理贴图变形的问题

OpenGL ES通过缩小GLSurfaceView来解决纹理贴图变形的问题

时间:2024-09-09 16:49:19浏览次数:11  
标签:贴图 1.0 mSurfaceHeight mSurfaceWidth OpenGL GLSurfaceView var GL GLES30

一、概述

  在使用OpenGL ES做纹理贴图的时候,图片有小有大。默认情况下纹理是撑满整个屏幕的。

  这就导致大图会被压扁、小图会被拉伸。这种体验相当不好。

  解决此问题的其中一种方式是:通过缩小GLSurfaceView的宽或高来解决问题。ps:公式可以看做是固定的,直接使用即可。

  1.根据屏幕及图像的宽高分别计算出宽高比

 var bitmapScaleRadio = bitmapWidth.toFloat() / bitmapHeight.toFloat()//bitmap的宽高比
        var viewScaleRadio = mSurfaceWidth.toFloat() / mSurfaceHeight.toFloat()//视图的宽高比

  2.根据屏幕及图像宽高比来计算视口的实际使用宽高(即缩小或放大到多少才不会导致图像变形)

if (bitmapScaleRadio > viewScaleRadio) {//需要缩小
            mViewWidth = mSurfaceWidth
            mViewHeight = (mSurfaceWidth / bitmapScaleRadio).toInt()
        } else if (bitmapScaleRadio < viewScaleRadio) {
            mViewHeight = mSurfaceHeight
            mViewWidth = (mSurfaceHeight * bitmapScaleRadio).toInt()
        } else {
            mViewWidth = mSurfaceWidth
            mViewHeight = mSurfaceHeight
        }

  3.把计算结果交给glViewport

override fun onSurfaceChanged(width: Int, height: Int) {
        mSurfaceWidth = width
        mSurfaceHeight = height
        var mViewBean =
            calculateViewport(mSurfaceWidth, mSurfaceHeight, bitmapSrc.width, bitmapSrc.height)
        //设置最终视口的大小
        var mStartX = (mSurfaceWidth - mViewBean.mViewWidth) / 2
        var mStartY = (mSurfaceHeight - mViewBean.mViewHeight) / 2
        GLES30.glViewport(mStartX, mStartY, mViewBean.mViewWidth, mViewBean.mViewHeight)
    }

 

 

二、代码示例(完整代码)

  1.calculateViewPort方法

/**
     * 通过缩小视口,让视口尽量接近图片宽高,从而使图片不变形
     * @param mSurfaceWidth 屏幕的宽度
     * @param mSurfaceHeight 屏幕宽度
     * @param imageWidth 图片宽度
     * @param imageHeight 图片高度
     * @return 返回视口要缩小到指定值的宽高。也就是最终视口的宽高
     */
    fun calculateViewport(
        mSurfaceWidth: Int,
        mSurfaceHeight: Int,
        imageWidth: Int,
        imageHeight: Int
    ): ViewPortAttribute {
        var mViewWidth: Int = 0
        var mViewHeight: Int = 0
        var bitmapWidth = imageWidth
        var bitmapHeight = imageHeight
        var bitmapScaleRadio = bitmapWidth.toFloat() / bitmapHeight.toFloat()//bitmap的宽高比
        var viewScaleRadio = mSurfaceWidth.toFloat() / mSurfaceHeight.toFloat()//视图的宽高比
        if (bitmapScaleRadio > viewScaleRadio) {//需要缩小
            mViewWidth = mSurfaceWidth
            mViewHeight = (mSurfaceWidth / bitmapScaleRadio).toInt()
        } else if (bitmapScaleRadio < viewScaleRadio) {
            mViewHeight = mSurfaceHeight
            mViewWidth = (mSurfaceHeight * bitmapScaleRadio).toInt()
        } else {
            mViewWidth = mSurfaceWidth
            mViewHeight = mSurfaceHeight
        }
        return ViewPortAttribute(mViewWidth, mViewHeight)
    }

  2.ScaleViewTextureShader.kt,这是一个shader,将其放入GLSurfaceView的回调方法中即可运行

package com.yw.filter.shader

import android.content.Context
import android.graphics.Bitmap
import android.opengl.GLES30
import com.yw.filter.R
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import java.nio.IntBuffer

class ScaleViewTextureShader(var context: Context, var bitmapSrc: Bitmap) : BaseShader() {
    private var vertices = floatArrayOf(//在android上纹理坐标需要上下颠倒之后才能够正确显示,否则会出现镜像、颠倒等问题
        //     ---- 位置 ----    - 纹理坐标 -
        1.0f, 1.0f, 0.0f, 1.0f, 0.0f,   // 右上
        1.0f, -1.0f, 0.0f, 1.0f, 1.0f,   // 右下
        -1.0f, -1.0f, 0.0f, 0.0f, 1.0f,   // 左下
        -1.0f, 1.0f, 0.0f, 0.0f, 0.0f    // 左上
    )
    private var indices = intArrayOf(
        0, 1, 3,//第一个三角形
        1, 2, 3 // 第二个三角形
    )
    private var vertexBuffer: FloatBuffer? = null
    private var indicesBuffer: IntBuffer? = null
    private var mSurfaceWidth: Int = 0
    private var mSurfaceHeight: Int = 0

    private var VAO = IntArray(1)
    var textureId: Int = 0
    override fun onSurfaceCreate() {
        //分配空间填充数据
        vertexBuffer = ByteBuffer
            .allocateDirect(vertices.size * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
        vertexBuffer?.put(vertices)
        vertexBuffer?.position(0)
        indicesBuffer = ByteBuffer
            .allocateDirect(indices.size * 4)
            .order(ByteOrder.nativeOrder())
            .asIntBuffer()
        indicesBuffer?.put(indices)
        indicesBuffer?.position(0)

        //创建并绑定VAO
        GLES30.glGenVertexArrays(1, VAO, 0)
        GLES30.glBindVertexArray(VAO[0])
        //创建并绑定VBO
        var VBO = IntArray(1)
        GLES30.glGenBuffers(1, VBO, 0)
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, VBO[0])
        GLES30.glBufferData(
            GLES30.GL_ARRAY_BUFFER,
            vertices.size * 4,
            vertexBuffer,
            GLES30.GL_STATIC_DRAW
        )

        //创建EBO
        var EBO = IntArray(1)
        GLES30.glGenBuffers(1, EBO, 0)
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, EBO[0])
        GLES30.glBufferData(
            GLES30.GL_ELEMENT_ARRAY_BUFFER,
            indices.size * 4,
            indicesBuffer,
            GLES30.GL_STATIC_DRAW
        )

        //告知显卡如何解析顶点数据
        GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 4 * 5, 0)
        GLES30.glEnableVertexAttribArray(0)
        //告知显卡如何解析纹理数据
        GLES30.glVertexAttribPointer(1, 2, GLES30.GL_FLOAT, false, 4 * 5, 4 * 3)
        GLES30.glEnableVertexAttribArray(1)

        //销毁
        GLES30.glBindVertexArray(0)
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0)
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0)

        textureId = getTextureId(bitmapSrc, GLES30.GL_RGBA)
        loadProgram(context, R.raw.texture_vert, R.raw.texture_frag)
    }

    override fun onDrawFrame() {
        GLES30.glClearColor(0.0f, 0.0f, 1.0f, 1.0f)
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
        GLES30.glBindVertexArray(VAO[0])
        GLES30.glUseProgram(programId)
        GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId)
        var vTextureLocation = GLES30.glGetUniformLocation(programId, "vTexture")
        GLES30.glUniform1i(vTextureLocation, 0)
        GLES30.glDrawElements(GLES30.GL_TRIANGLES, 6, GLES30.GL_UNSIGNED_INT, 0)

        GLES30.glBindVertexArray(0)
    }

    override fun onSurfaceChanged(width: Int, height: Int) {
        mSurfaceWidth = width
        mSurfaceHeight = height
        var mViewBean =
            calculateViewport(mSurfaceWidth, mSurfaceHeight, bitmapSrc.width, bitmapSrc.height)
        //设置最终视口的大小
        var mStartX = (mSurfaceWidth - mViewBean.mViewWidth) / 2
        var mStartY = (mSurfaceHeight - mViewBean.mViewHeight) / 2
        GLES30.glViewport(mStartX, mStartY, mViewBean.mViewWidth, mViewBean.mViewHeight)
    }

}

 

标签:贴图,1.0,mSurfaceHeight,mSurfaceWidth,OpenGL,GLSurfaceView,var,GL,GLES30
From: https://www.cnblogs.com/tony-yang-flutter/p/18404832

相关文章

  • OpenGL ES使用正交投影来解决图像变形的问题
    一、概述上一节实践了,通过改变GLSurfaceView的宽高来解决图像变形的问题。本节将通过正交投影的方式解决图像变形的问题。分三步:1.计算屏幕的宽高比及图像的宽高比varscreenRatio=screenWidth.toFloat()/screenHeightvarimgRat......
  • 在虚幻引擎(UE5)中使用HDR贴图_UE5教程
    一共有两种文件格式,推荐使用hdr格式,先讲hdr格式先创建一个材质,名称随意双击打开,把着色模型改为无光照拖入hdr贴图,此时会报错创建三维向量转换为参数,此时已经可以正常显示了,但是增加一些可调节参数一个对比度一个光照强度,转换为参数创建材质实例,双击打开打开双面材质创建......
  • 【小沐学OpenGL】Ubuntu环境下OpenGL的安装和使用
    文章目录1、简介1.1OpenGL简介1.2Linux上的窗体系统1.3Linux中的显示服务器1.4xrandr命令2、Xlib开发2.1创建空白窗口2.2打印文字2.3键盘响应3、OpenGL开发3.1绘制矩形结语1、简介1.1OpenGL简介OpenGL作为图形界的工业标准,其仅仅定义了一组2D和3D图形接......
  • AWTK 如何用 OpenGL 绘制图形
    在有GPU的情况下,AWTK使用OpenGL绘制图形。但是你会发现,如果自己在paint事件中使用OpenGL绘制图形,图形是无法显示的。原因是,AWTK采用nanovg绘制图形,而nanovg并不是在绘制时立即执行的,而是在整个界面绘制完成(EndFrame中)集中提交给GPU执行的。所以,如果在paint事......
  • 富文本编辑器 实现CTRL+V粘贴图片并上传、WORD粘贴带图片
    编辑器:百度ueditor前端:vue2,vue3,vue-cli,html5需求:复制粘贴word内容图片,word图片转存交互要求:开源,免费,技术支持用户体验:Ctrl+V快捷键操作该说不说,最近这块应该也是挻火的,今天早上又有网友加我微信私聊,说是想了解一下这块的技术和方案。实际我的微信号之前就已经在网上......
  • WebGL_0020:threejs 加载glb模型,加载图片贴图,加载canvas贴图,创建精灵模型并贴图
    1,import*asTHREEfrom'three';importtype{MapViewer}from'@/utils/map3d/mapViewer';import{STATIC_URL}from'@/config';import{GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader';constgetSpri......
  • C++和OpenGL实现3D游戏编程【连载7】——文字和汉字的显示
    1、本节实现的内容上一节我们讨论了纹理在二维平面内不规则图形贴图的相关基础操作,本节我们开始了解游戏里文字以及汉字的显示方法。本节课我们将从基本的ASCII字符显示,拓展到中文字符的显示,最后再讲到纹理字符的显示,并对各种文字显示方法的优缺点和使用场景进行分析,这节课......
  • LearnOpenGL学习笔记
    LearnOpenGL学习笔记入门认识OpenGL核心模式和立即渲染模式扩展状态机对象创建窗口视口渲染循环释放资源输入事件渲染你好,三角形基本概念顶点输入顶点着色器编译着色器片段着色器链接顶点属性顶点数组对象索引缓冲对象着色器GLSL数据类型输入与输出Uniform纹理基本知......
  • Learn OpenGL In Qt之系列简介
    竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~个人主页:rainInSunny | 个人专栏:C++那些事儿、LearnOpenGLInQt文章目录传送门写在前面为什么是OpenGL和Qt能学到什么能做点什么国漫女神炫酷进度冷酷机器人传送门LearnOpenGLInQt之系列简介LearnOpe......
  • OpenGL32.dll找不到入口点?快速修复指南及常见故障排除技巧
    在使用某些基于OpenGL的应用程序或游戏时,用户可能会遇到“OpenGL32.dll找不到入口点”的错误消息。这类问题通常会阻止应用程序正常运行,给用户带来不便。本文将详细介绍这一问题的原因以及如何有效地解决它。OpenGL32.dll找不到入口点的原因文件损坏或丢失:OpenGL32.dll文件......