android openGL ES详解(一)

Android OpenGl 介绍(一) 阅读详情
AI摘要

本文深入探讨了OpenGL ES中的核心概念和技术,包括GLSurfaceView的工作原理、顶点数组的排列顺序、模型投影矩阵的使用、纹理加载与显示方法,以及屏幕、窗口、视口和裁剪区域的区别。

目录

1.GLSurfaceView和主线程,渲染线程的关系

渲染线程

GLSurfaceView

关系总结

2.顶点数组中元素排列顺序

3.OpenGL中物体构成

4.使Java层数据可以被OpenGL存取

5.顶点数据显示到屏幕上的过程

6.为什么使用着色器

7. OpenGL 怎样平滑地从一个点向另外一个点混合颜色

线性插值

8.GL_TRIANGLE_FAN三角形扇的原理介绍

 三角形扇和三角形带

三角形扇(Triangle Fan)

三角形带(Triangle Strip)

9.OpenGL 如何把坐标映射到屏幕

归一化设备坐标

10.正交投影矩阵——弥补屏幕的宽高比

概念

正交投影矩阵方法

11.透视投影矩阵

基本原理

投影矩阵

参数设置

投影过程

注意事项

12.模型投影矩阵

13.旋转矩阵

14.纹理

为什么使用纹理?

如何将纹理加载入OpenGL

如何显示纹理

15.屏幕、窗口、视口、裁剪区域概念区分


1.GLSurfaceView和主线程,渲染线程的关系

渲染线程与主线程之间的通信可以用如下方法:

在主线程中的 GLSurfaceView 实例可以调用queueEvent( )方法传递一个 Runnable 给后台渲染线程,渲染线程可以调用 Activity 的 runOnUIThread()来传递事件 (event) 给主线程。

GLSurfaceView和主线程,渲染线程的关系如下:

渲染线程

  • 定义:GLSurfaceView内部维护了一个专门的渲染线程(通常称为GL线程或EGL线程),该线程专门用于OpenGL ES的渲染工作。
  • 职责:
    • 执行OpenGL ES的渲染命令,绘制图形和图像。
    • 管理OpenGL ES的上下文(Context)和表面(Surface)。
    • 在需要时,根据Renderer的指示重新绘制场景。

GLSurfaceView

  • 定义:GLSurfaceView是Android提供的一个特殊View,用于在Android应用中嵌入OpenGL ES内容。它继承自SurfaceView,并实现了OpenGL ES的渲染功能。
  • 与主线程的关系:
    • GLSurfaceView的实例化、布局和生命周期管理(如onResume、onPause)通常在主线程中进行。
    • 主线程可以通过调用GLSurfaceView的queueEvent等方法,将需要在渲染线程中执行的任务放入队列中。
  • 与渲染线程的关系:
    • GLSurfaceView内部维护了一个渲染线程,专门用于OpenGL ES的渲染工作。
    • 开发者通过实现GLSurfaceView.Renderer接口,并调用GLSurfaceView的setRenderer方法,将自定义的渲染器设置给GLSurfaceView。
    • 渲染线程会不断调用渲染器的onSurfaceCreated、onSurfaceChanged和onDrawFrame等方法,以执行OpenGL ES的渲染命令。

关系总结

  • 主线程与GLSurfaceView:主线程负责GLSurfaceView的实例化、布局和生命周期管理,并通过特定方法(如queueEvent)与渲染线程进行通信。
  • 渲染线程与GLSurfaceView:渲染线程是GLSurfaceView内部维护的,专门用于执行OpenGL ES渲染命令的线程。渲染线程根据渲染器的指示,在需要时重新绘制场景。
  • 主线程与渲染线程:两者通过GLSurfaceView提供的机制(如queueEvent)进行通信,确保UI更新和渲染工作能够协调进行,避免阻塞主线程或造成渲染延迟。

通过这种方式,GLSurfaceView有效地将OpenGL ES的渲染工作与Android应用的UI绘制和用户交互任务分离开来,提高了应用的性能和响应速度。

2.顶点数组中元素排列顺序

当定义三角形的时候,总是以逆时针的顺序排列项点; 这称为卷曲顺序 ( winding order)。因为在任何地方都使用这种一致的卷曲顺序,可以优化性能: 使用卷曲顺序可以指出一个三角形属于任何给定物体的前面或者后面,OpenGL 可以忽略那些无论如何都无法被看到的后面的三角形。

3.OpenGL中物体构成

无论何时,如果想表示一个 OpenGL 中的物体,都要考虑如何用点、直线及三角形把它组合出来。

4.使Java层数据可以被OpenGL存取

在java层完成顶点的定义后,但是,在OpenGL可以存取它们之前,我们仍然需要完成另外一步。主要的问题是这些代码运行的环境与OpenGL运行的环境使用了不同的语言,我们需要理解如下两个主要的概念。
(1)当我们在模拟器或者设备上编译和运行Java代码的时候,它并不是直接运行在硬件上的;相反,它运行在一个特殊的环境上,即Dalvik虚拟机(Dalvik virtualmachine);运行在虚拟机上的代码不能直接访问本地环境(nativeenvironment),除非通过特定的API。
(2)Davik虚拟机还使用了垃圾回收(garbage collection)机制。这意味着,当虚拟机检测到一个变量、对象或者其他内存片段不再被使用时,就会把这些内存释放掉以备重用;它也能腾挪内存以提高空间使用效率。本地环境并不是这样工作的,它不期望内存块会被移来移去或者被自动释放。Android之所以这样设计,是因为开发者在开发程序的时候不必关心特定的CPU或者机器架构,也不必关心底层的内存管理。这通常都能工作得很好,除非要与本地系统交互比如OpenGL。OpenGL作为本地系统库直接运行在硬件上;没有虚拟机,也没有垃圾回收或内存压缩。

 从 Java 调用本地代码
Dalvik方案是Android的主要特点之一,但是,如果代码运行在虚拟机内部,那它怎么与OpenGL通信呢?有两种技术,第一种技术是使用Java本地接口(JNI),这个技术已经由 Android 软件开发包提供了;当调用android.opengl.GLES20包里的方法时,软件开发包实际上就是在后台使用JNI调用本地系统库的。

把内存从 Java 堆复制到本地堆

第二种技术是改变内存分配的方式,Java 有一个特殊的类集合,它们可以分配本地内存块,并且把 Java 的数据复制到本地内存。本地内存可以被本地环境存取,而不受垃圾回收器的管控。

FloatBuffer用来在本地内存中存储数据。

FloatBuffer vertexData =ByteBuffer
.allocateDirect(tableVerticesWithTriangles.length * BYTES PER FLOAT).order(Byte0rder.native0rder()).asFloatBuffer();

让我们看一下代码的每一个部分。首先,我们使用ByteBuffer.allocateDirect()分配了一块本地内存,这块内存不会被垃圾回收器管理。这个方法需要知道要分配多少字节的内存块;因为顶点都存储在一个浮点数组里,并且每个浮点数有4个字节,所以这块内存的大小应该是tableVerticesWithTriangles.length* BYTES PER FLOAT。

5.顶点数据显示到屏幕上的过程

6.为什么使用着色器

在着色器出现之前,OpenGL只能使用一个固定的方法集合控制很少而有限的事情比如场景里有多少光线或者加多少雾;这些固定的 API很容易使用,但是它们很难扩展。你只能实现API提供的效果,而且仅此而已;几乎不能添加如卡通着色一样的自定义效果。
      随着时间的推移,底层的硬件有了很大提高;设计OpenGL的人意识到这些API需要演进,并跟上这些变化。在OpenGLES2.0里,他们使用着色器加入了可编程API;为了保持简洁,他们把那些固定的API完全删除了,因此,用户必须使用着色器。现在用着色器控制每个顶点应该如何画到屏幕上,也控制所有点、直线和三角形上的每个片段应该如何绘制;这打开了一个新的、充满了无限可能的新世界。现在可以按每个像素实现光照和其他优美的效果,如卡通着色。只要可以用着色器语言表达出来,就可以加入任何理想的自定义效果。

7. OpenGL 怎样平滑地从一个点向另外一个点混合颜色

线性插值

直线:长度做线性插值

三角形:面积做线性插值

 直线颜色线性插值,示例如下

直线起始点坐标(-0.5,0),终点坐标(0.5,0)

片段着色器代码如下:
precision mediump float;
varying vec4 v_Color;
void main(){
if(gl_FragCoord.x>-0.5 && gl_FragCoord.x < 0.5){
gl_FragColor.r =  v_Color.r*(gl_FragCoord.x +0.5);
gl_FragColor.g =  v_Color.g*(gl_FragCoord.x +0.5);
gl_FragColor.b =  v_Color.b*(gl_FragCoord.x +0.5);
} else {
gl_FragColor =v_Color;
}
}

绘制直线如下:
glDrawArrays(GL_LINES, 18, 2)

8.GL_TRIANGLE_FAN三角形扇的原理介绍

GL_TRIANGLE_FAN三角形扇是OpenGL中用于绘制三角形的一种模式。在这种模式下,第一个顶点被作为公共中心点,之后每个新加入的顶点与前一次添加的最后两个顶点以及公共中心点一起定义一个新的三角形。也就是说,每增加一个新顶点,都会生成一个新的扇形区域,并且所有三角形都共享这个公共中心点。

具体来说,当你定义了一系列的顶点,OpenGL会按照以下方式绘制三角形:第一个三角形由公共中心点、第二个顶点和第三个顶点构成;第二个三角形由公共中心点、第三个顶点和第四个顶点构成;依此类推,每增加一个顶点,都会与公共中心点和前一个顶点形成一个新的三角形。

这种模式非常适合用于绘制扇面或圆盘等具有公共中心区域的图形。例如,你可以使用GL_TRIANGLE_FAN来绘制一个围绕某一点的旋转效果,或者创建一个以某点为中心的扇形区域。

需要注意的是,GL_TRIANGLE_FAN模式的绘制效果会受到顶点顺序的影响,因此你需要确保顶点的顺序是正确的,以便生成你想要的图形。

总的来说,GL_TRIANGLE_FAN原理基于公共中心点和新增顶点来定义并绘制一系列的三角形,实现具有公共中心区域的图形绘制。

代码示例如下:

    private var tabUeVerticesWithTriangles = floatArrayOf(
        //x,y,r,g,b
        //桌面三角形
        0.0f, 0.0f, 1.0f, 1.0f, 1.0f,//公共中心点
        
        -0.5f, -0.5f, 0.7f, 0.7f, 0.7f,
        -0.25f, -0.5f, 0.0f, 1.0f, 0.0f,
        0.0f, -0.5f, 1.0f, 0.0f, 0.0f,
        0.25f, -0.5f, 0.0f, 1.0f, 0.0f,
        0.5f, -0.5f, 0.7f, 0.7f, 0.7f,

        0.5f, -0.25f, 0.0f, 1.0f, 0.0f,
        0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
        0.5f, 0.25f, 0.0f, 1.0f, 0.0f,
        0.5f, 0.5f, 0.7f, 0.7f, 0.7f,

        0.25f, 0.5f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
        -0.25f, 0.5f, 0.0f, 1.0f, 0.0f,
        -0.5f, 0.5f, 0.7f, 0.7f, 0.7f,

        -0.5f, 0.25f, 0.0f, 1.0f, 0.0f,
        -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
        -0.5f, -0.25f, 0.0f, 1.0f, 0.0f,
        -0.5f, -0.5f, 0.7f, 0.7f, 0.7f,

        //桌面分割线
        -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
        0.5f, 0.0f, 0.0f, 1.0f, 0.0f,

        //木槌
        0.0f, -0.25f, 0.0f, 0.0f, 1.0f,
        0.0f, 0.25f, 1.0f, 0.0f, 0.0f,

        //冰球
        0.0f, 0.0f,0.0f,1.0f,1.0f
    )


override fun onDrawFrame(gl: GL10?) {
        glClear(GL_COLOR_BUFFER_BIT)
        glDrawArrays(GL_TRIANGLE_FAN, 0, 18)
        glDrawArrays(GL_LINES, 18, 2)
        glDrawArrays(GL_POINTS, 20, 1)
        glDrawArrays(GL_POINTS, 21, 1)
        glDrawArrays(GL_POINTS, 22, 1)
    }

运行截图如下:

 三角形扇和三角形带

三角形扇(Triangle Fan)

三角形扇是一种特殊的三角形绘制模式,它从一个中心点开始,将后续的点依次与中心点和前一个点相连,形成一系列的三角形。具体来说,假设顶点序列为V0, V1, V2, ..., Vn,则三角形扇的绘制方式如下:

  • 第一个顶点V0作为中心点。
  • 第二个顶点V1与V0相连,形成第一个三角形的第一条边。
  • 第三个顶点V2与V0和V1相连,形成第一个完整的三角形V0-V1-V2。
  • 接着,V3与V0和V2相连,形成第二个三角形V0-V2-V3,以此类推,直到Vn。

这种绘制方式的特点是,所有三角形都共享同一个顶点(即中心点),且每个新添加的顶点都会与中心点和前一个顶点形成一个新的三角形。三角形扇适用于绘制具有中心对称或辐射状图案的图形。三角形扇,如下图

三角形带(Triangle Strip)

三角形带是另一种高效的三角形绘制模式,它通过连续添加顶点来形成一系列相连的三角形。假设顶点序列为V0, V1, V2, ..., Vn,则三角形带的绘制方式如下:

  • 第一个和第二个顶点V0和V1形成第一个三角形的两个顶点。
  • 第三个顶点V2与V0和V1相连,形成第一个完整的三角形V0-V1-V2。
  • 然后,V3与V1和V2相连,形成第二个三角形V1-V2-V3(注意这里V0不再参与)。
  • 以此类推,每增加一个顶点,就与前两个顶点形成一个新的三角形,直到Vn。

三角形带的特点是,每增加一个顶点,就形成一个新的三角形,且这些三角形在顶点序列上是相连的。这种绘制方式适用于绘制一系列相邻的三角形,如网格或地形等。三角形带,如下图:

9.OpenGL 如何把坐标映射到屏幕

归一化设备坐标

无论是x还是y坐标,OpenG 都会把屏幕映射到[-1,1]的范围内。这就意味着屏幕的左边对应x轴的-1,而屏幕的右边对应 +1;屏幕的底边会对应y轴的-1,而屏幕的顶边就对应 +1,如图所示。
不管屏幕是什么形状和大小,这个坐标范围都是一样的,如果我们需要在屏幕上显示任何东西,都需要在这个范围内绘制它们。

10.正交投影矩阵——弥补屏幕的宽高比

概念

在Android OpenGL中,正交投影矩阵的主要作用是定义一个视景体(Viewing Volume),即一个三维空间中的长方体区域,它决定了哪些物体应该被渲染到屏幕上。这个长方体区域被称为正交投影体。

正交投影的一个关键特性是,无论物体距离观察点的远近如何,它们在投影后的二维图像中都会保持相同的尺寸和形状。这意味着,在正交投影下,物体的大小不会因为距离的远近而改变,这与透视投影不同,透视投影中物体的大小会随着距离的远近而发生变化。

在OpenGL中,正交投影矩阵通常用于渲染那些不需要考虑透视效果的场景,比如2D游戏、UI界面等。在这些场景中,我们更关心的是物体在屏幕上的精确位置和大小,而不是它们因为距离观察点远近而产生的视觉变化。

在OpenGL中设置正交投影矩阵时,通常需要指定一个近裁剪面和一个远裁剪面,以及投影体的左右、上下边界。这些参数定义了投影体的范围和形状,从而决定了哪些物体应该被包含在渲染结果中。

总之,正交投影矩阵在Android OpenGL中扮演着定义渲染区域和保持物体形状尺寸不变的重要角色。

使用正交投影,不管多远或多近,所有的物体看上去大小总是相同的。

从虚拟坐标回到归一化设备坐标
当我们使用正交投影把虚拟坐标变换回归一化设备坐标时,实际上定义了三维世界内部的一个区域。在这个区域内的所有东西都会显示在屏幕上,而区域外的所有东西都会被裁剪掉。在下面的图像中,我们能在一个封闭的立方体内看到一个简单的场景(见图1)。当我们使用一个正交投影矩阵把这个立方体映射到屏幕上时,就会看到如图2所示的正交投影。

正交投影矩阵会把所有在左右之间、上下之间和远近之间的事物映射到归一化设备坐标中从 -1到1的范围,在这个范围内的所有事物在屏幕上都是可见的。

利用正交投影矩阵改变立方体的大小,以使我们可以在屏幕上看到或多或少的场景我们也能改变立方体的形状弥补屏幕的宽高比的影响。

正交投影矩阵方法

orthoM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)

参数介绍

foat[]m:目标数组,这个数组的长度至少有16个元素,这样它才能存储正交投影矩阵;

int mOffset:结果矩阵起始的偏移值;

float left;x轴的最小范围;

float right:x轴的最大范围;

float bottom:y轴的最小范围;

float top:y轴的最大范围;

floatnear:z轴的最小范围;
float far:z轴的最大范围。

x,y轴放大或缩小实现:left,right,bottom,top乘以缩放比例即可。

x,y轴平移实现:left,right,bottom,top加减平移数值。

例如:

var aspectRatio: Float = 0.0f
        if (width > height) {//landscape
            aspectRatio = (width.toFloat() / height.toFloat())
        } else {//portrait
            aspectRatio = (height.toFloat() / width.toFloat())
        }
        if (width > height) {//landscape水平放大
            orthoM(projectionMatrix, 0, -aspectRatio*0.2f, aspectRatio*0.2f, -1f, 1f, -1f, 1f);
        } else {//portrait垂直方向平移
            orthoM(projectionMatrix, 0, -1f, 1f, -aspectRatio+0.5f, aspectRatio+0.5f, -1f, 1f);
        }

11.透视投影矩阵

Android OpenGL的透视投影是3D图形渲染中的关键技术之一,它模拟了人类视觉系统中物体远近大小变化的感知。将现实3D模型转到2D屏幕上显示,下面是对Android OpenGL透视投影的详细解析:

基本原理

透视投影是从一个虚拟的观察点(或称为相机位置)出发,将3D空间中的物体投影到2D平面上。这个过程中,物体距离观察点越近,其在投影平面上显得越大;距离越远,则显得越小。这种投影方式能够产生强烈的空间感和立体感。

投影矩阵

实现透视投影的关键是设置透视投影矩阵。这个矩阵定义了从3D世界坐标到2D裁剪坐标的映射关系。

对宽高比和视野进行调整
如下通用的投影矩阵,它允许我们调整视野以及屏幕的宽高比。

参数说明:
a:如果我们想象一个相机拍摄的场景,这个变量就代表那个相机的焦距。焦距是由1/tan(视野/2)(tan表示正切函数)计算得到的。这个视野必须小于180度。比如,一个90度的视野,它的焦距会被设置为1/tan(90°/2),也就是1/1或者1

aspect:屏幕的宽高比,它等于宽度/高度
f:到远处平面的距离,必须是正值且大于到近处平面的距离
n:到近处平面的距离,必须是正值。比如,如果此值被设为1,那近处平面就位于一个z值为-1处

参数设置

透视投影矩阵的设置通常涉及以下几个关键参数:

  • 视场角(Field of View, FOV):决定了观察者视野的大小,通常是以度为单位的夹角。较小的视场角会产生较大的放大效果,使得场景看起来更加紧凑;较大的视场角则会产生类似缩小的效果,是场景有较宽的视野。A为垂直视场角,B为水平视场角。

fov数值变化,引起场景变化。

  • 宽高比(Aspect Ratio):通常是视口的宽度与高度的比值。这个参数对于保持场景的比例正确性非常重要。
  • 近裁剪面(Near Clipping Plane)和远裁剪面(Far Clipping Plane):定义了视椎体的前后边界。位于这两个平面之间的物体才会被投影并渲染到屏幕上。

投影过程

  • 顶点变换:首先,3D物体的顶点坐标会经过模型视图变换,从局部坐标系转换到世界坐标系,再进一步转换到相机坐标系(或称为观察坐标系)。
  • 透视除法:在透视投影中,经过变换后的顶点坐标会进行透视除法。这一步是透视投影的关键,它确保了近处的物体在屏幕上显得大,远处的物体显得小。
  • 裁剪与归一化:经过透视除法的坐标会进入裁剪空间,并进行裁剪测试。在裁剪过程中,位于视椎体之外的部分会被裁剪掉。剩余的坐标会经过归一化处理,最终映射到标准设备坐标系(NDC)上,准备进行后续的光栅化过程。

注意事项

  • 深度测试:在透视投影中,深度测试是确保正确渲染物体顺序的关键。通过比较片元的深度值,可以确定哪些物体在前面,哪些在后面,从而避免错误的遮挡关系。
  • 优化性能:透视投影的计算相对复杂,可能会对性能产生影响。因此,在开发过程中需要注意优化算法和减少不必要的计算。

综上所述,Android OpenGL的透视投影通过模拟人类视觉系统的特点,实现了对3D场景的逼真渲染。掌握透视投影的原理和技巧对于创建高质量的3D图形应用至关重要。

12.模型投影矩阵

利用模型矩阵移动物体。

private val modelMatrix = FloatArray(16)

setIdentityM(modelMatrix,0);
translateM(modelMatrix,0,0f,0f,-2.5f);//平移物体

val temp = FloatArray(16)
multiplyMM(temp,0,projectionMatrix,0,modelMatrix,0);//透视投影矩阵乘以模型矩阵
System.arraycopy(temp,0,projectionMatrix,0,temp.size);

13.旋转矩阵

利用旋转矩阵,基于某个角度或者向量(如,围绕x,y,z轴))旋转物体。

private val modelMatrix = FloatArray(16)

setIdentityM(modelMatrix,0);
rotateM(modelMatrix,0,-60f,1f,0f,0f)//围绕x轴,旋转物体-60度

val temp = FloatArray(16)
multiplyMM(temp,0,projectionMatrix,0,modelMatrix,0);//透视投影矩阵乘以模型矩阵
System.arraycopy(temp,0,projectionMatrix,0,temp.size);

14.纹理

为什么使用纹理?

用顶点着色器和片段着色器完成了简单的图形和颜色工作。但是还缺了点什么:如果想在这些图形上绘画并加人精致的细节呢?像艺术家一样,可以从基本的图形和颜色开始,再使用纹理(texture)在其表面上加人额外的细节。简单来说,纹理就是一个图像或照片,它们可以被加载进 OpenGL 中。我们可以用纹理加入大量令人难以置信的细节。想想你最近可能玩过的一个精美的三维游戏。与任何其他三维程序一样,那个游戏的本质也只是使用了点、直线和三角形。然而,通过纹理添加的细节和一个熟练的艺术家的加工,这些三角形可以用纹理构建一个精美的三维场景。

如何将纹理加载入OpenGL

加载图片纹理到openGL,示例代码如下:

private var textureId = 0

textureId = loadTexture(mContext!!, R.mipmap.air_hockey_surface)

fun loadTexture(context: Context, resourceId: Int): Int {
    val textureObjectIds = IntArray(1)
    glGenTextures(1, textureObjectIds, 0)
    if (textureObjectIds[0] == 0) return 0
    var options = BitmapFactory.Options();
    options.inScaled = false
    var bitmap = BitmapFactory.decodeResource(context.resources, resourceId, options)
    if (bitmap == null) {
        Log.d(TAG, "resourceId could not be decoded.")
        glDeleteTextures(1, textureObjectIds, 0)
        return 0
    }
    glBindTexture(GL_TEXTURE_2D, textureObjectIds[0])
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    texImage2D(GL_TEXTURE_2D, 0, bitmap, 0)
    glGenerateMipmap(GL_TEXTURE_2D)
    bitmap.recycle()
    glBindTexture(GL_TEXTURE_2D, 0)
    return textureObjectIds[0]
}

如何显示纹理

创建纹理着色器->链接openGL程序program->设置uniform变量数值->绑定着色器属性值与顶点数组数据->设置顶点属性数据可用->绘制纹理数据,显示纹理。

15.屏幕、窗口、视口、裁剪区域概念区分

  • 屏幕:即计算机的整个屏幕大小。
  • 窗口:指的就是现实的界面,即屏幕中的某一个窗口,可放大放小和移动关闭。
  • 视口:通过glViewport()函数设置大小,视口指的就是窗口中用来显示图形的一块区域,它可以和窗口等大,也可以比窗口大或者小,不过只有绘制在视口区域中的图形才会被显示,如果图形其中一部分超出了视口区域,那么超出的部分是看不到的。如下图,不同大小的视口:

  • 裁剪区域:即在视口中让你看到的图形,即显示出来的那部分。指的就是视口矩形区域的最小最大X坐标(left,right)和最小最大Y坐标(bottom,top),而不是窗口的最小最大X坐标和Y坐标,通过glOrtho()函数设置,这个函数还需要指定最近最远Z坐标,形成一个立体的裁剪区域。如下图,裁剪区域:

关系:当要把图形绘制在屏幕之前,首先要建立图形的几何描述,即建模,这往往是在世界坐标系内进行的。而图形最终是要显示在屏幕上,即屏幕坐标系。在模型的二维区域内选择一个区域,映射到屏幕坐标系的指定区域(窗口)中。在这个映射过程中包括平移、旋转、缩放操作及删除位于显示区域范围以外的图形部分。也就是OpenGL绘制图形时,并不是把整个模型直接绘制在整个屏幕上,而是把模型的部分绘制在窗口内。窗口还可以分为若干个区域,称为视口。模型在裁剪窗口内的部分映射到显示窗口中的指定视口中。窗口选择显示模型的那个部分,而视口指定显示在窗口的什么位置。

参考:https://www.cnblogs.com/hitfire/articles/3163227.html

参考:计算机图形学---------屏幕、窗口、视口、裁剪区域概念区分_窗口,视区,裁剪-优快云博客

OpenGL ES入门指南(一) 想学OpenGL?想在手机端上实现酷炫效果?那还不快来了解OpenGL ES 阅读详情

相关推荐

第一章 OpenGL ES 基础-屏幕、纹理、顶点坐标

GL_TRIANGLE_STRIP:指定要绘制的基本图元类型为三角形条带,即每三个顶点定义一个三角形,但从第三个顶点开始,每个新顶点都与前两个顶点一起构成一个新的三角形。坐标系 的 左下点(-1, -1),右下角(1,-1) , 左上角(-1, 1) , 右上角(1 , 1)坐标系 的 左下点 (0, 0),右下角(1 , 0) , 左上角(0, 1 ), 右上角(1, 1)0:指定了要渲染的顶点数组的起始索引,这里表示从顶点数组的第一个顶点开始。使用第二个顶点作为三角形条带的第二个顶点。

u012836015的博客 3535

Android C++ OpenGL 教程

用纯C++实现Android的OpenGL渲染功能,包括EGL环境创建、EGL线程创建、OpenGL生命周期管理等,会结合SurfaceView和TextureView实现OpenGL的渲染,最终我们会实现一个YUV播放器实例,为音视频开发打下坚实的基础。

Android OpenGL ES(一)开发入门

早就听过大名鼎鼎的 OpenGL,却迟迟没有实践学习,有些惭愧。今天开始通过实践+博文方式学习掌握 OpenGL。此文对于 OpenGL 的学习分为以下部分: OpenGL 基础概念 OpenGL 坐标系理解 OpenGL 渲染管线 OpenGL 着色语言 OpenGL 基础概念 OpenGL OpenGL 即 Open Graphics Library,是一个功能强大、调用方便的底层图形库...

yhao的博客 2068

Android中的OpenGL使用初探

OpenGL ES在Android中的使用

wlxyhy的博客 5341

OpenGL ES 2.0 for Android教程(一)

本文是一系列OpenGL ES 2.0 for Android教程,基于Kotlin与一点点Compose来创建代码示例。通过本系列教程你可以从零开始一步步学习OpenGL ES。

重来的博客 7477

从波形图到参数调优:一次无感BLDC电机启动失败的深度解析

本文深入解析无感BLDC电机启动失败案例,通过波形分析揭示参数不匹配和IPM保护机制触发等关键问题。详细探讨了过零点检测、PWM周期设置及强拖参数调优的底层逻辑,并分享IPM模块保护机制与实战调优技巧,最终实现99.98%的启动成功率。

weixin_29182481的博客 819

android opengl版本,Android OpenGL ES(一)开发入门

早就听过大名鼎鼎的 OpenGL,却迟迟没有实践学习,有些惭愧。今天开始通过实践+博文方式学习掌握 OpenGL。此文对于 OpenGL 的学习分为以下部分:OpenGL 基础概念OpenGL 坐标系理解OpenGL 渲染管线OpenGL 着色语言OpenGL 基础概念OpenGLOpenGL 即 Open Graphics Library,是一个功能强大、调用方便的底层图形库,它定义了跨编程语言...

weixin_36479263的博客 3860

UE5高斯泼溅落地全链路:从PLY导入到实时渲染的工程实践

3D高斯泼溅(3D Gaussian Splatting)正从NeRF后处理技术演进为新一代隐式几何渲染范式,其核心在于以可微椭球体替代传统三角面片,通过协方差矩阵与球谐系数实现高质量体素化渲染。该技术突破点云精度瓶颈,但与UE5现有资产管线存在根本性不兼容——静态网格导入器无法解析scale/rot/sh系数等非标顶点语义,标准光栅化管线亦无法执行高斯核采样计算。XV3DGS-UEPlugin通过自定义资产类型、StructuredBuffer GPU数据流与专用材质节点,将高斯泼溅重构为可编辑、可LOD

weixin_33692177的博客 356

Android OpenGl Es 学习(一):创建一个OpenGl es程序

概述 这是一个新的系列,学习OpengGl Es,其实是《OpenGl Es 应用开发实践指南 Android卷》的学习笔记,感兴趣的可以直接看这本书,当然这个会记录自己的理解,以下只作为笔记,以防以后忘记 之后会对本书的前九章依次分析记录 Android OpenGl Es 学习(一):创建一个OpenGl es程序 Android OpenGl Es 学习(二):定义顶点和着色器 Android OpenGl Es 学习(三):编译着色器 Android OpenGl Es 学习(四):增填颜色 And

R.先森的博客 629

优雅谈大模型:“System2”与“System 1”

研究人员探索了三种System 2方法——RaR、S2A 和 BSM,这些方法已经成功提炼到新的LLM,这个新的模型与System 1相比,产生了更好的结果,而且成本低于System 2。然而这种方法是有局限性,只能适用于特定的任务。

鲁班模锤 5142

避坑指南:在Linux服务器上用Conda安装antiSMASH 5.2.0(解决Jinja2报错和Matplotlib权限问题)

本文详细介绍了在Linux服务器上使用Conda安装antiSMASH 5.2.0的避坑指南,重点解决了Jinja2报错和Matplotlib权限问题。通过创建专用conda环境、安装指定版本依赖包和配置缓存目录,帮助用户顺利完成antiSMASH的本地部署,适用于批量处理基因组分析任务。

weixin_26911099的博客 314

安卓 OpenGL ES 高级教程(一)

1985 年,我带回家一台崭新闪亮的海军准将 Amiga 1000,大约在它们发布一周后。它配备了巨大的 512K 内存、可编程色彩映射表、摩托罗拉 68K CPU 和现代多任务操作系统,写满了“令人敬畏”的字样。当然是打个比方。我想它可能会成为一个天文学项目的良好平台,因为我现在可以控制那些恒星的颜色,而不是不得不满足于像 Hercules 或 C64 这样的人强加给我的蹩脚的固定调色板。所以我编写了一个 24 行的基本程序来绘制一个随机的星域,关掉灯,心想,“哇!

龙哥盟 1931

9 HAL库驱动框架简述(STM32HAL库)

HAL库外设的使用步骤总结如下:1、定义并填充xxx外设句柄结构体。2、如果遵循HAL库规范,通过HAL_xxx_MspInit()函数,实现外设底层资源的初始化,包括但不限于GPIO、时钟、DMA、中断等资源的初始化。3、调用HAL库的对应外设初始化函数,形如:HAL_xxx_Init()。4、初始化完成,开始使用外设。5、使用方法具体查看对应外设的HAL库驱动包中的说明:补充:HAL库使用主线外设初始化外设使用。

qq_25218501的博客 1977

Android OpenGL ES(一):关于OpenGL ES

在学习Android OpenGL ES开发之前,你必须具备Java 语言开发经验和一些Android开发的基本知识,但并不需要有图形开发的经验,本教程也会涉及到一些基本的线性几何知识,如矢量,矩阵运算等。 此外Android SDK 中有关OpenGL ES API的开发文档 android.opengl javax.microedition.khronos.egl ja

jackie03的专栏 3378

带挂牵引车倒车运动模型推导及仿真实现

半挂牵引车在倒车时,由于鞍座主销的连接限制,其运动方式与乘用车有显著差异。例如,乘用车在右侧倒车入库时,只需确定泊车起点并将方向盘向右打死。相反,牵引车在倒车时需要先向左转方向盘,当铰接角达到防折叠的临界值时,再将方向盘向右转回,以调整牵引车与挂车至直线状态,完成泊车入库。本研究旨在建立一个基于牵引车带挂车倒车运动学模型,该模型基于以下假设: 道路在车辆行驶过程中保持平坦,无凹凸不平; 车辆以低速行驶,且在运行过程中车身不发生侧倾或俯仰; 行驶过程中,轮胎无变形,无侧向滑动,且不产

jianmo的博客 2697

WIN10环境下STK11.5(含Analyzer, EOIR, Scheduler插件)的安装与破解全攻略

本文提供了一份详细的WIN10环境下STK11.5软件及其核心插件(Analyzer, EOIR, Scheduler)的安装与破解全攻略。内容涵盖从安装包准备、系统环境检查,到基础版安装、插件部署、破解文件替换及许可证配置的完整步骤,并附有常见问题排错指南,旨在帮助用户免费搭建功能齐全的卫星仿真分析环境。

solidity8miner的博客 756

Android OpenGL ES一 ——入门

本文简介 OpenGL简介 正文 构建OpenGL ES 环境 在清单文件中申明使用OpenGL ES 版本 创建一个支持OpenGL ES的Activity 构建渲染器类 定义图形 定义三角形 定义正方形 绘制图形 初始化图形 绘制图形 朋友圈里大神发过的朋友圈:每天进步一小步,一年下来,你会发现你得到的远超你想象。只是极少有人愿意这么做,短时间无法得到积极回馈,足以...

SuperLi 904

Fluent动网格实战:5种区域运动类型详解与配置避坑指南

本文详细解析了Fluent动网格技术中的五种区域运动类型,包括固定、刚体、变形、用户自定义和系统耦合,并提供了配置技巧与避坑指南。通过实际案例和参数优化建议,帮助工程师有效解决网格变形、计算稳定性等常见问题,提升CFD仿真效率。

weixin_28339967的博客 413

Android OpenGL ES 学习(一)

package com.kingsoft.openglproject.util; import android.opengl.GLES20; import android.util.Log; public class ShaderHelper { public static final String TAG = "ShaderHelper"; private static int compileShader(int type, String shaderCode) {

wh义华的专栏 590

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

学习OpenGL ES for Android(一)

OpenGL是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API),而在嵌入式和移动平台的版本是OpenGL ES。Android最初就支持OpenGL ES的1.0版本,到现在已经支持到最新的3.2版本,下面的支持变化图 当然这个版本支持不是绝对的,还有看硬件是否支持,例如genymotion模拟器只有OpenGL ES 2.0版本,如果你使用了高版本的API会导致崩溃。...

chends 1602

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Android OpenGL ES视频渲染(一)GLSurfaceView

本文将使用GLSurfaceView+MediaPlayer实现播放,并通过OpenGL进行简单的滤镜处理,以此来说明如何使用GLSurfaceView。

myvest的专栏 4064

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Android OpenGL ES 应用(一)

Android OpenGL ES 基本应用,画2个三角形组成一个正方形

移动生活,幸福代码 3376

Android OpenGL ES (一)简介

OpenGL是什么 OpenGL是一个跨平台的软件接口语言,用于调用硬件的2D、3D图形处理器。 由于是只软件接口,所以具体底层实现依赖硬件设备制造商。 Android includes support for high performance 2D and 3D graphics with the Open Graphics Library (OpenGL®), specifical...

android开发笔记 516

Android OpenGL ES(一)OpenGL ES介绍

在学习Android OpenGL ES开发之前,你必须具备Java 语言开发经验和一些Android开发的基本知识,但并不需要有图形开发的经验,本教程也会涉及到一些基本的线性几何知识,如矢量,矩阵运算等。 此外Android SDK 中有关OpenGL ES API的开发文档 android.opengl javax.microedition.khronos.egl jav...

weixin_30888413的博客 103

Android OpenGL ES2.0从放弃到入门(一)—— 了解OpenGL

Android openGL ES从放弃到入门2.0(一)—— 了解openGL前言什么是openGLOpenGL ES版本OpenGL ES能做什么OpenGL ES中的概念顶点着色器片元着色器着色器语言坐标系投影光照纹理OpenGL ES2.0渲染过程 前言 恰逢要在公司做一次openGL的技术分享,所以弄个博客整理下。技术一般水平有限,仅供入门参考,如有错误,还望指正。此篇文档没有代码,都是...

weixin_39560693的博客 1140

Android OpenGL ES 开发(一)— 环境搭建

我的视频课程:《Android C++ OpenGL 教程》 对于Opengl/sl/cv/...系列相信大家也不陌生,我在前面博客也介绍了OpenSL ES的一些知识和使用方法,让我们对OpenSL ES有了一定的了解。从今天开始我将给大家带来一系列的Android中OpenGL ES的使用方法(主要是基于2D平面图形的)。 一、OpenGL ES是什么? 我总结的...

ywl5320的专栏 4732
上一篇: Android OOM问题定位、内存优化
下一篇: 如何将本地Android studio项目上传到GitHub
闲暇部落
博客等级 码龄12年 2775粉丝 215原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闲暇部落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值