【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)

简介: 【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)

需要源码请点赞关注收藏后评论区留言私信~~~

一、OpenGL ES简介

虽然OpenGL的三维制图功能非常强大,但是它主要为计算机设计的,对于嵌入式设备和移动端设备来说显得比较臃肿,所以业界又设计了专供嵌入式设备的OpenGL ES 它相当于OpenGL的精简版,因为嵌入式设备追求性价比,所以能不做的渲染操作尽量不做,以便优化整体的系统性能

OpenGL ES将所有的渲染过程划分为若干着色器,每个着色器只负责自己这块的渲染操作。

着色器的小程序保存在扩展名为glsl的配置文件中,它采用GLSL语言编写,语法框架类似于C语言

OpenGL ES 2.0与3.0之间的GLSL语法差异如下:

(1)对于ES 3.0来说,glsl文件开头多了一行“#version 300 es”,表示当前小程序使用ES 3.0; (2)取消了ES 2.0的限定符attribute和varying,取而代之的是in和out;

(3)删除了ES 2.0的内置变量gl_FragColor和gl_FragData,改为通过out声明相关输出参数; (4)ES 2.0内置的纹理方法texture2D和texture3D都被新方法texture所取代;

(5)ES 3.0新增修饰符layout,它允许指定变量的位置序号;

二、着色器实战效果

如下图所示 可以在下拉框中选择不同颜色填充

代码如下

Java类

package com.example.threed;
import androidx.appcompat.app.AppCompatActivity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;
import com.example.threed.util.GlUtil;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class EsShaderActivity extends AppCompatActivity {
    private final static String TAG = "EsShaderActivity";
    private GLSurfaceView glsv_content; // 声明一个图形库表面视图对象
    private int mProgramId; // 声明glsl小程序的编号
    private int mStyle; // 三角形样式
    // 三角形的顶点坐标数组
    private float mCoordArray[] = { // 默认按逆时针方向顺序绘制
            0.0f, 0.622008459f, 0.0f,   // 顶
            -0.5f, -0.311004243f, 0.0f,   // 左底
            0.5f, -0.311004243f, 0.0f    // 右底
    };
    // 三角形的顶点颜色数组(纯色)
    private float[] mColorPureArray = {
            1.0f, 0.0f, 0.0f, 1.0f,
            1.0f, 0.0f, 0.0f, 1.0f,
            1.0f, 0.0f, 0.0f, 1.0f
    };
    // 三角形的顶点颜色数组(彩色)
    private float[] mColorFullArray = {
            0.0f, 1.0f, 0.0f, 1.0f,
            1.0f, 0.0f, 0.0f, 1.0f,
            0.0f, 0.0f, 1.0f, 1.0f
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_es_shader);
        showEsVersion(); // 显示OpenGL ES的版本号
        initStyleSpinner(); // 初始化样式下拉框
        glsv_content = findViewById(R.id.glsv_content);
        // 声明使用OpenGL ES的版本号为3.0。使用ES30方法之前务必指定版本号
        glsv_content.setEGLContextClientVersion(3);
        // 给OpenGL的表面视图注册三维图形的渲染器
        glsv_content.setRenderer(new ShaderRender());
        // 设置渲染模式(关闭自动刷新)
        glsv_content.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    }
    // 显示OpenGL ES的版本号
    private void showEsVersion() {
        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        ConfigurationInfo info = am.getDeviceConfigurationInfo();
        String versionDesc = String.format("%08X", info.reqGlEsVersion);
        String versionCode = String.format("%d.%d", Integer.parseInt(versionDesc)/10000,
                Integer.parseInt(versionDesc)%10000);
        Toast.makeText(this, "系统的OpenGL ES版本号为"+versionCode, Toast.LENGTH_SHORT).show();
    }
    // 初始化样式下拉框
    private void initStyleSpinner() {
        ArrayAdapter<String> styleAdapter = new ArrayAdapter<>(this,
                R.layout.item_select, styleArray);
        Spinner sp_style = findViewById(R.id.sp_style);
        sp_style.setPrompt("请选择三角形样式");
        sp_style.setAdapter(styleAdapter);
        sp_style.setOnItemSelectedListener(new StyleSelectedListener());
        sp_style.setSelection(0);
    }
    private String[] styleArray = { "只画线条", "绘制纯色表面", "绘制彩色表面" };
    class StyleSelectedListener implements AdapterView.OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            mStyle = arg2;
            glsv_content.requestRender(); // 主动请求渲染操作
        }
        public void onNothingSelected(AdapterView<?> arg0) {}
    }
    // 定义一个三维图形的渲染器
    private class ShaderRender implements GLSurfaceView.Renderer {
        // 在表面创建时触发
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            // 设置白色背景。0.0f相当于00,1.0f相当于FF
            GLES30.glClearColor(1f, 1f, 1f, 1);
            // 初始化着色器
            mProgramId = GlUtil.initShaderProgram(EsShaderActivity.this, "shader_vertex.glsl", "shader_fragment.glsl");
        }
        // 在表面变更时触发
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            GLES30.glViewport(0, 0, width, height); // 设置输出屏幕大小
            // 开启剔除操作。开启之后才能调用glCullFace方法禁止光照、阴影和颜色等效果,以消除不必要的渲染计算。
            GLES30.glEnable(GLES30.GL_CULL_FACE);
        }
        // 执行框架绘制动作
        @Override
        public void onDrawFrame(GL10 gl) {
            // 清除屏幕和深度缓存
            GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);
            GLES30.glLineWidth(3); // 指定线宽
            drawTriangle(); // 绘制三角形
        }
    }
    // 绘制三角形
    private void drawTriangle() {
        FloatBuffer vertexBuffer = GlUtil.getFloatBuffer(mCoordArray);
        FloatBuffer colorBuffer;
        if (mStyle == 2) { // 绘制彩色表面
            colorBuffer = GlUtil.getFloatBuffer(mColorFullArray);
        } else { // 绘制纯色表面
            colorBuffer = GlUtil.getFloatBuffer(mColorPureArray);
        }
        // 获取顶点着色器的vPosition位置(来自shader_vertex.glsl)
        int positionLoc = GLES30.glGetAttribLocation(mProgramId, "vPosition");
        // 获取片段着色器的vColor位置(来自shader_vertex.glsl)
        int colorLoc = GLES30.glGetAttribLocation(mProgramId, "inColor");
        GLES30.glEnableVertexAttribArray(positionLoc); // 启用顶点属性数组
        GLES30.glEnableVertexAttribArray(colorLoc); // 启用顶点属性数组
        // 指定顶点属性数组的位置信息
        GLES30.glVertexAttribPointer(positionLoc, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer);
        // 指定顶点属性数组的颜色信息
        GLES30.glVertexAttribPointer(colorLoc, 4, GLES30.GL_FLOAT, false, 0, colorBuffer);
        if (mStyle == 0) { // 只绘制线条
            // 绘制物体的轮廓线条
            GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, mCoordArray.length/3);
        } else { // 也绘制表面
            // 绘制物体的轮廓表面
            GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, mCoordArray.length/3);
        }
        GLES30.glDisableVertexAttribArray(colorLoc); // 禁用顶点属性数组
        GLES30.glDisableVertexAttribArray(positionLoc); // 禁用顶点属性数组
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="right"
            android:text="三角形样式:"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <Spinner
            android:id="@+id/sp_style"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:spinnerMode="dialog" />
    </LinearLayout>
    <!-- 注意这里要使用控件的全路径android.opengl.GLSurfaceView -->
    <android.opengl.GLSurfaceView
        android:id="@+id/glsv_content"
        android:layout_width="match_parent"
        android:layout_height="400dp" />
</LinearLayout>

创作不易 觉得有帮助请点赞关注收藏~~~

相关文章
|
8月前
|
Android开发 数据安全/隐私保护 开发者
Android自定义view之模仿登录界面文本输入框(华为云APP)
本文介绍了一款自定义输入框的实现,包含静态效果、hint值浮动动画及功能扩展。通过组合多个控件完成界面布局,使用TranslateAnimation与AlphaAnimation实现hint文字上下浮动效果,支持密码加密解密显示、去除键盘回车空格输入、光标定位等功能。代码基于Android平台,提供完整源码与attrs配置,方便复用与定制。希望对开发者有所帮助。
149 0
|
11月前
|
JavaScript 前端开发 Android开发
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
406 13
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
6月前
|
存储 Android开发 数据安全/隐私保护
Thanox安卓系统增加工具下载,管理、阻止、限制后台每个APP运行情况
Thanox是一款Android系统管理工具,专注于权限、后台启动及运行管理。支持应用冻结、系统优化、UI自定义和模块管理,基于Xposed框架开发,安全可靠且开源免费,兼容Android 6.0及以上版本。
665 4
|
9月前
|
数据采集 JSON 网络安全
移动端数据抓取:Android App的TLS流量解密方案
本文介绍了一种通过TLS流量解密技术抓取知乎App热榜数据的方法。利用Charles Proxy解密HTTPS流量,分析App与服务器通信内容;结合Python Requests库模拟请求,配置特定请求头以绕过反爬机制。同时使用代理IP隐藏真实IP地址,确保抓取稳定。最终成功提取热榜标题、内容简介、链接等信息,为分析热点话题和用户趋势提供数据支持。此方法也可应用于其他Android App的数据采集,但需注意选择可靠的代理服务。
387 11
移动端数据抓取:Android App的TLS流量解密方案
|
8月前
|
XML 搜索推荐 Android开发
Android改变进度条控件progressbar的样式(根据源码修改)
本文介绍了如何基于Android源码自定义ProgressBar样式。首先分析了系统源码中ProgressBar样式的定义,发现其依赖一张旋转图片实现动画效果。接着分两步指导开发者实现自定义:1) 模仿源码创建一个旋转动画XML文件(放置在drawable文件夹),修改图片为自定义样式;2) 在UI控件中通过`indeterminateDrawable`属性应用该动画。最终实现简单且个性化的ProgressBar效果,附带效果图展示。
544 2
|
9月前
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码android版环境配置流程及功能明细
部署需基于 CentOS 7.9 系统,硬盘不低于 40G,使用宝塔面板安装环境,包括 PHP 7.3(含 Redis、Fileinfo 扩展)、Nginx、MySQL 5.6、Redis 和最新 Composer。Swoole 扩展需按步骤配置。2021.08.05 后部署需将站点目录设为 public 并用 ThinkPHP 伪静态。开发环境建议 Windows 操作系统与最新 Android Studio,基础配置涉及 APP 名称修改、接口域名更换、包名调整及第三方登录分享(如 QQ、微信)的配置,同时需完成阿里云与腾讯云相关设置。
|
11月前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
763 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
11月前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
441 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
11月前
|
数据采集 JavaScript Android开发
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
516 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
11月前
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
363 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex