OpenGL.ES在Android上的简单实践:14-全景(惯性滑动球体)

2023-11-20

OpenGL.ES在Android上的简单实践:

14-全景(惯性滑动球体)

 

 

 

1、整理封装全景球

现在,我们的地球已经能正确的显示出来,我们来增加必要的交互,使得我们左右滑动屏幕的时候,地球能旋转起来,而且是像一个地球仪一样,手指离开屏幕后,能随着惯性的操作延后旋转。

第一步,我们现在测试页面PanoramaActivity添加对GLSurfaceView的触摸事件监听,并设置可以点击状态。

public class PanoramaActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        glSurfaceView = new GLSurfaceView(this);
        renderer = new PanoramaRenderer(PanoramaActivity.this);
        ... ...
        glSurfaceView.setClickable(true);
        glSurfaceView.setOnTouchListener(new GLViewTouchListener());
        setContentView(glSurfaceView);
    }

    private class GLViewTouchListener implements View.OnTouchListener {
        @Override
        public boolean onTouch(View view, MotionEvent event) { 
            if(event.getAction() == MotionEvent.ACTION_DOWN){
            ... ...
            }else if(event.getAction() == MotionEvent.ACTION_MOVE){
            ... ...
            }else if(event.getAction() == MotionEvent.ACTION_UP){
            ... ...
            }else {
                return false;
            }
            return true;
        }
    }
}


 

第二步,我们让渲染器PanoramaRenderer响应手指“滑动”这系列操作。这系列操作分别经过按下,滑动,抬起三个事件。所以我们这三个响应的事件中添加renderer的接口:

           if(event.getAction() == MotionEvent.ACTION_DOWN){
                final float x = event.getX();
                final float y = event.getY();
                glSurfaceView.queueEvent(new Runnable() {
                    @Override
                    public void run() {
                        renderer.handleTouchUp(x, y);
                    }
                });
            }else if(event.getAction() ==MotionEvent.ACTION_MOVE){
                final float x = event.getX();
                final float y = event.getY();
                    glSurfaceView.queueEvent(new Runnable() {
                        @Override
                        public void run() {
                            renderer.handleTouchDrag(x,y);
                        }
                    });
            }else if(event.getAction() == MotionEvent.ACTION_UP){
                final float x = event.getX();
                final float y = event.getY();
                glSurfaceView.queueEvent(new Runnable() {
                    @Override
                    public void run() {
                        renderer.handleTouchUp(x,y);
                    }
                });
            }

进入PanoramaRenderer 我们把响应请求传递給ball,让ball执行对应的操作。对于渲染器renderer,我们不好做太多逻辑的操作,把逻辑操作交给对应的模型内部维护,方便模型对象的管理。

// PanoramaRenderer.java
    ... ...
    public void handleTouchUp(float x, float y) {
        if(ball!=null){
            ball.handleTouchUp( x, y);
        }
    }

    public void handleTouchDrag(float x, float y) {
        if(ball!=null){
            ball.handleTouchDrag( x, y);
        }
    }

    public void handleTouchDown(float x, float y) {
        if(ball!=null){
            ball.handleTouchDown( x, y);
        }
    }

到这里,其实Renderer的三大glsurfaceview回调,我们也应该封装在模型对象中响应。下面我们更新PanoramaRenderer和Ball->PanoramaRenderer2和PanoramaBall。

public class PanoramaRenderer2 implements GLSurfaceView.Renderer{
    private final Context context;
    private PanoramaBall ball;

    public PanoramaRenderer(Context context) {
        this.context = context
        ball = new PanoramaBall(context);
    }

    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        if(ball!=null) ball.onSurfaceCreated(eglConfig);
    }

    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        if(ball!=null) ball.onSurfaceChanged(width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        if(ball!=null) ball.onDrawFrame();
    }

    public void handleTouchUp(float x, float y) {
        if(ball!=null) ball.handleTouchUp( x, y);
    }
    public void handleTouchDrag(float x, float y) {
        if(ball!=null) ball.handleTouchDrag( x, y);
    }
    public void handleTouchDown(float x, float y) {
        if(ball!=null) ball.handleTouchDown( x, y);
    }
}

我们从渲染器入手,更新后的渲染器相当简单。只起到一个渲染管理者的作用,实际的操作我们交给模型对象PanoramaBall。还有一点注意,我们是在PanoramaRenderer构造函数中调用PanoramaBall的构造,还记得之前我们说过,所以GL的接口方法必须在glsurfaceview的三大回调中调用吗?记住这点,下面我正式改造PanoramaBall:

public class PanoramaBall {   
    ... ...
    private float[] mProjectionMatrix = new float[16];// 投影矩阵
    private float[] mViewMatrix = new float[16]; // 摄像机位置朝向9参数矩阵
    private float[] mModelMatrix = new float[16];// 模型变换矩阵
    private float[] mMVPMatrix = new float[16];// 获取具体物体对象的MVP矩阵
    private float[] getFinalMatrix() {
        Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
        return mMVPMatrix;
    }

    public PanoramaBall(Context context){
        this.context = context;
        Matrix.setIdentityM(mProjectionMatrix, 0);
        Matrix.setIdentityM(mViewMatrix, 0);
        Matrix.setIdentityM(mModelMatrix, 0);
        Matrix.setIdentityM(mMVPMatrix, 0);
    }
    ... ...
}

第一步,我们抽取MVP矩阵的方法,记住三大矩阵是左乘的,具体原理分析请参考这里的第4节。接下来继续查看新增的扩展函数接口onSurfaceCreated / onSurfaceChanged / onDrawFrame。

    // 紧接着上面部分 ...
    public void onSurfaceCreated(EGLConfig eglConfig) {
        initVertexData();
        initTexture();
        buildProgram();
        setAttributeStatus();
        // 这些方法跟之前的一样,直接copy就ok
    }

    public void onSurfaceChanged(int width, int height) {
        GLES20.glViewport(0,0,width,height);
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
        MatrixHelper.perspectiveM(mProjectionMatrix, 45, (float)width/(float)height, 1f, 100f);
        Matrix.setLookAtM(mViewMatrix, 0,
                0f, 0f, 4f,
                0f, 0f, 0f,
                0f, 1f, 0f);
    }

    public void onDrawFrame() {
        GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
        ballShaderProgram.userProgram();
        ballShaderProgram.setUniforms(getFinalMatrix(),textureId);
        setAttributeStatus();
        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.getIndexBufferId());
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, numElements, GLES20.GL_UNSIGNED_SHORT, 0);
        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
    }

其实就是当初我们在renderer写的代码,只是我们封装在PanoramaBall中。一切都按照正确的方向前进中,现在我们可以测试页面PanoramaActivity替换渲染器看看是否和之前的一样效果?

 

2、滑动全景球

当我们用手指滑动屏幕的时候,全景球需要知道是向左还是向右滑动,以此作出正确的旋转。所以当全景球接受按压事件的时候,先记录当前的屏幕按压位置;之后在滑动的事件求出正确的移动步伐并旋转等量的角度;抬起事件则重置位置。

    private float mLastX;
    private float mLastY;

    public void handleTouchUp(float x, float y) {
        this.mLastX = 0;
        this.mLastY = 0;
    }

    public void handleTouchDown(float x, float y) {
        this.mLastX = x;
        this.mLastY = y;
    }

    public void handleTouchMove(float x, float y) {
        float offsetX = this.mLastX - x;
        float offsetY = this.mLastY - y;
        .. .. ..
    }

up和down都so easy。那么move的响应事件,我们该怎样令球旋转起来呢?我们自然想到android.opengl.Matrix的rotateM(float[] m, int mOffset, float a, float x, float y, float z)函数,调用这个函数我们需要什么?我们需要偏转角度a。得到偏转角度后,我们调用rotateM接口,得出偏转角度的旋转矩阵,然后把旋转的矩阵和模型矩阵运算求值,就得出了新的模型矩阵了,最后模型矩阵更新到MVP。搞定!

    private float mLastX;
    private float mLastY;
    private float rotationX = 0;
    private float rotationY = 0;
    private float[] mMatrixRotationX = new float[16];
    private float[] mMatrixRotationY = new float[16];

    public void handleTouchUp(float x, float y) {
        this.mLastX = 0;
        this.mLastY = 0;
    }

    public void handleTouchDown(float x, float y) {
        this.mLastX = x;
        this.mLastY = y;
    }

    public void handleTouchMove(float x, float y) {
        float offsetX = this.mLastX - x;
        float offsetY = this.mLastY - y;
        this.rotationY -= offsetX/10 ; // 注意! 屏幕横坐标的步伐,球应该是绕着Y轴旋转
        this.rotationX -= offsetY/10 ; // 注意! 屏幕纵坐标的步伐,球应该是绕着X轴旋转

        // 这部分代码是对球模型矩阵的操作,可以抽取成方法 updateBallMatrix,在onDrawFrame调用
        Matrix.setIdentityM(this.mModelMatrix, 0);
        Matrix.setIdentityM(mMatrixRotationX, 0);
        Matrix.setIdentityM(mMatrixRotationY, 0);
        Matrix.rotateM(mMatrixRotationY, 0, this.rotationY, 0, 1, 0);
        Matrix.rotateM(mMatrixRotationX, 0, this.rotationX, 1, 0, 0);
        Matrix.multiplyMM(this.mModelMatrix,0, mMatrixRotationX,0, mMatrixRotationY,0 );

        this.mLastX = x;
        this.mLastY = y;
    }

运行工程项目,是不是如下图所示能够动起来了?!         

但是大家有没发现,我们可以直接绕过顶部和底部...尴尬  要不大家加个角度的限制?

        

 

3、添加手指操作的惯性效果

现在我们是能够滑动球体了,接下来我们来实现惯性滑动,想象我们以前小时候玩地球仪那样大力滑动产生惯性的流畅自转。所以第一件事就是增加滑动事件的速度。这时我们用到Android的API——VelocityTracker。我们在测试页面PanoramaActivity增加VelocityTracker的使用:

public class PanoramaActivity extends Activity{
    private VelocityTracker mVelocityTracker = null;
    ... ...
    protected void onResume() { 
        ... ...
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        } else {
            mVelocityTracker.clear();
        }
    }

    protected void onPause() {
        if(null != mVelocityTracker) {
            mVelocityTracker.clear();
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }


    private class GLViewTouchListener implements View.OnTouchListener {
        
        @Override
        public boolean onTouch(View view, MotionEvent event) {
            if(event.getAction() == MotionEvent.ACTION_DOWN){
                // 增加速度
                if (mVelocityTracker == null) {
                    mVelocityTracker = VelocityTracker.obtain();
                } else {
                    mVelocityTracker.clear();
                }
                mVelocityTracker.addMovement(event);
                ... ...
            }else if(event.getAction() ==MotionEvent.ACTION_MOVE){
                mVelocityTracker.addMovement(event);
                mVelocityTracker.computeCurrentVelocity(1000);
                // 在获取速度之前总要进行以上两步
                ... ...
            }else if(event.getAction() == MotionEvent.ACTION_UP){
                final float x = event.getX();
                final float y = event.getY();
                final float xVelocity = mVelocityTracker.getXVelocity();
                final float yVelocity = mVelocityTracker.getYVelocity();
                glSurfaceView.queueEvent(new Runnable() {
                    @Override
                    public void run() {
                        renderer.handleTouchUp(x, y, xVelocity, yVelocity);
                        // 把速度当成参数传递
                    }
                });
            }else {
                return false;
            }
            return true;
        }
    }
}

当我们手抬起的时候,速度变量传递到渲染器,触发全景球的惯性操作。那么怎样实现惯性这一操作?其实就是使用这个速度变量通过一个线程逐渐递减,并逐渐增加球体的旋转分量,是不是很简单?下面我们继续更新代码:

    public void handleTouchUp(final float x, final float y,
                              final float xVelocity, final float yVelocity) {
        this.mLastX = 0;
        this.mLastY = 0;

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    handleGestureInertia(x, y, xVelocity, yVelocity);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    private void handleGestureInertia(float upX, float upY, float xVelocity, float yVelocity)
            throws InterruptedException {
        boolean gestureInertia_isStop = false;
        float mXVelocity = xVelocity;
        float mYVelocity = yVelocity;
        while(!this.gestureInertia_isStop){
//--------------------------------------------------------------------------------
            float offsetY = mYVelocity / 2000;
            this.rotationX = this.rotationX + offsetY;

            float offsetX = mXVelocity / 2000;
            this.rotationY = this.rotationY + offsetX;

            if(rotationX%360 > 90 ){
                this.rotationX = 90;
            }
            if(rotationX%360 < -90 ){
                this.rotationX = -90;
            }
//--------------------------------------------------------------------------------
            if(Math.abs(mYVelocity - 0.975f*mYVelocity) < 0.00001f
                    || Math.abs(mXVelocity - 0.975f*mXVelocity) < 0.00001f){
                this.gestureInertia_isStop = true;
            }
            mYVelocity = 0.975f*mYVelocity;
            mXVelocity = 0.975f*mXVelocity;
            Thread.sleep(5);
        }
    }

我们分析一下这个惯性操作方法,首先我们拿到速度变量,把它们先缩放指定倍数当做步伐(2000倍的缩放),然后把步伐增量添加到旋转角度上;我们还限制绕x轴的旋转角度不能超过顶部和底部。随后我们衰减速度变量,并加一个判断条件,衰减前后的差值小于0.00001f就可以视为惯性已经可以停止了。不要忘记惯性线程每一步伐要睡眠5~10(大家可以试下不睡眠的效果)这个和硬件显示的帧率是相关的,但不会相差很大。

由于篇幅关系,以上方法的具体数值都是我经过调试之后总结出来的,大家可以随便修改成适合自己的大小,加上自己的日志。

接下来,运行工程项目,看看以下效果是否如意?

     

工程代码:https://github.com/MrZhaozhirong/BlogApp

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenGL.ES在Android上的简单实践:14-全景(惯性滑动球体) 的相关文章

  • Mybatis框架解析

    一 Mybatis框架简介 MyBatis框架是一个开源的数据持久层框架 它的内部封装了通过JDBC访问数据库的操作 支持普通的SQL查询 存储过程和高级映射 几乎消除了所有的JDBC代码和参数的手工设置以及结果集的检索 MyBatis作为
  • PAM机制

    一 PAM简介 Linux PAM linux可插入认证模块 是一套共享库 使本地系统管理员可以随意选择程序的认证方式 换句话说 不用 重新编写和 重新编译一个包含PAM功能的应用程序 就可以改变它使用的认证机制 这种方式下 就算升级本地认
  • 无监督低照度图像增强网络ZeroDCE和SCI介绍

    目录 简介 Zero DCE 算法介绍 模型代码 无监督loss介绍 小结 Self Calibrated Illumination SCI 模型介绍 无监督loss介绍 小结 总结 简介 当前有较多深度学习的方法来做图像效果增强 但多数都
  • 量化投资学习-31:如何评判专家的战法是否真的有效还是瞎蒙?

    每逢牛市 都会冒出各种股神 各种专家 在牛市大趋势的东风下 各种专家鱼龙混杂 如何如何评判专家的战法是否真的有效还是瞎蒙 所谓牛市 就是高点越来越高 即使在任何一个时间点买入 短暂的亏损后 股价也再创新高 一样能赚钱 因此 在牛市的大势下
  • 三个闭环负反馈PID调节系统:电流环、速度环和位置环的关系

    三个闭环负反馈PID调节系统 电流环 速度环和位置环的关系 伺服电机为了达到生产的精准控制 电机一般采用三环控制 这主要是为了使伺服电机系统形成闭环控制 所谓三环就是3个闭环负反馈PID调节系统 电压映射电流变化 电流映射转矩大小 转矩大小
  • Sql语句中的DML语句

    一 什么是DML语句 DML语句就是数据库操作语句 二 DML语句的分类 Insert 插入 Update 修改更新 Delete 删除 Select 选择 三 insert语句 Delete from 表名名称 where 条件 DELE
  • windows下配置Mysql-5.7.9服务

    第一步 从官方网站下载 mysql 5 7 9 winx64 zip 第二步 解压缩 在根目录下复制my default ini 改名为my ini 第三步 初始化mysql目录 bin mysqld initialize user mys
  • 在渗透测试中,扫描器原理是什么

    在渗透测试中 扫描器原理是什么 渗透测试中的扫描器是一种自动化工具 用于识别目标系统中的漏洞 弱点或配置错误 扫描器通过发送特定的网络请求或使用其他技术手段来检查目标系统的安全性 并生成报告以供分析和修复 以下是扫描器的一般原理 1 信息收
  • 一眼看懂promise与async await的区别

    promise方法 let p1 new Promise resolve reject gt setTimeout gt resolve 我是p1 4000 let p2 new Promise resolve reject gt setT
  • 12.HTML5下一代的HTML标准介绍与初识尝试

    关注回复 学习交流群 加入 安全开发运维 答疑交流群 请朋友们 多多点击文中的广告 支持作者更新更多文章 目录 本文为作者原创文章 为尊重作者劳动成果禁止非授权转载 若需转载请在 全栈工程师修炼指南 公众号留言 或者发送邮件到 master
  • 运维之Linux发行版和容器镜像网站及开源软件收集

    关注 WeiyiGeek 公众号 将我设为 特别关注 每天带你玩转网络安全运维 应用开发 物联网IOT学习 0x00 概述 0x01 镜像源网站 国内镜像 国内高校 0x02 发行版官网 CentOS kail Debian Ubuntu
  • 客户机操作系统已禁用 CPU。请关闭或重置虚拟机。解决方法

    今天在用VMware安装CentOS7报了这个错误 在网上找半天都没解决 最后换一个地址下的镜像就能正常安装了 Index of centos 7 9 2009 isos x86 64
  • 12_Linux ARM架构_安装JDK8-银河麒麟V10(Kylin Linux Advanced Server V10 )操作系统

    12 Linux ARM架构 安装JDK8 银河麒麟V10 Kylin Linux Advanced Server V10 操作系统 1 官网下载aarch64架构jdk包 2 linux服务器中创建java文件夹 方便后期快速寻找 3 将
  • DevC++如何改成中文?

    DevC 如何改成中文 1 点击Tools工具 2 选择环境选项 3 选择简体中文 4 点击确定
  • 深入理解Google Cast(一)基本概念

    什么是google cast google cast允许用户将手机上的内容投影到TV上 然后用户可以将手机作为遥控器来控制TV上的媒体播放 Google cast SDK用于扩展你的app 使其支持google cast功能 一个Cast
  • 图像验证码识别(九)——训练和识别

    前面讲到已经把所有的字符经过去干扰 分割和归一化得到标准大小的单个字符 接下来要做的就是识别验证码了 现在要做的基本上也就和OCR没什么区别了 因为得到的字符已经是尽可能标准的了 下面的识别分为两个步骤 第一步先是特征值的提取 第二步是SV
  • ROC曲线绘制原理及如何用SPSS绘制ROC曲线

    本文同步发布于 脑之说 微信公众号 欢迎搜索关注 ROC曲线 Receiver operating characteristic curve 即受试者工作特征曲线 主要用来评价某个指标对两类被试 如病人和健康人 分类 诊断的效果 以及寻找最
  • 深入探索并发编程系列(五)-将内存乱序逮个正着

    当用C C 编写无锁代码时 一定要小心谨慎 以保证正确的内存顺序 不然的话 会发生一些诡异的事情 Intel在x86 x64体系结构手册的Volume 3 8 2 3 中列出了一些可能会发生的诡异的事情 这里介绍其中一个最简单的例子 假设在
  • autoware警告The ‘state_publisher‘ executable is deprecated. Please use ‘robot_state_publisher‘ instead

    在运行autoware官方demo autoware ai 的时候 启动my localization launch roslaunch autoware quickstart examples my localization launch

随机推荐

  • C++示例程序,演示如何将两个整数相加并打印结果

    include
  • iOS开发-国际化-配置App多语言

    作者 大慈大悲大熊猫 链接 http www jianshu com p 1edd4bda6fe5 來源 简书 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 基本设置 第一步 先在Project的info里添加所需要支
  • 使用Python对数据的操作转换

    1 列表加值转字典 在Python中 将列表的值转换为字典的键可以使用以下代码 myList name age location myDict k None for k in myList print myDict 输出 name None
  • 百度2012实习生校园招聘笔试题

    1 给一个单词a 如果通过交换单词中字母的顺序可以得到另外的单词b 那么b是a的兄弟单词 比如的单词army和mary互为兄弟单词 现在要给出一种解决方案 对于用户输入的单词 根据给定的字典找出输入单词有哪些兄弟单词 请具体说明数据结构和查
  • vue组件之间传值的几种方式

    这里写目录标题 vue组件传值 父传子 子传父 非父子组件传值 provide 和 inject 传值 事件总线传值 attrs listeners 使用 attrs listeners 进行子往上级传 vueX vue组件传值 父传子 父
  • Qt的基本语法及其使用(一)

    Qt的概念 Qt是通用的C 开发界面框架 C 图形用户界面 应用程序开发框架 既可以开发GUI程序也可以开发开发非GUI程序 Qt是面向对象的框架 使用特殊的代码生成扩展 Qt的历史 1991由QT公司研发 2008年被诺基亚收购 2012
  • C/C++ 引用作为函数的返回值

    语法 类型 函数名 形参列表 函数体 特别注意 1 引用作为函数的返回值时 必须在定义函数时在函数名前将 2 用引用作函数的返回值的最大的好处是在内存中不产生返回值的副本 代码来源 RUNOOB include
  • Microsoft Network Monitor 3.4简要说明

    第一次启动后是一个欢迎界面 左下角可以选择要监控的网络连接 在标签栏上点击右键 可以选择关闭这个页面 或者保留这个页面 关闭其他所有页面 点击工具栏第一个图标 NewCapture 就可以打开一个新的监控界面 点击工具栏上的 Start 按
  • RTSP,RTP,RTCP协议

    一 RTSP 1 简介 实时流传输协议 是一个应用层协议 TCP IP网络体系中 它是一个多媒体播放控制协议 主要用来使用户在播放流媒体时可以像操作本地的影碟机一样进行控制 即可以对流媒体进行暂停 继续 后退和前进等控制 RTSP体系结位于
  • 软件设计说明书模版(申请软件著作权可供参考)

    1 引言 1 1 编写目的 1 2 项目背景 1 2 项目概要 总体要求 2 1 系统功能概述 2 2 系统功能要求 软件开发 3 1 软件需求分析 3 2 软件的概要设计 3 2 1 软件概要设计说明 3 2 3 基本设计概念和处理流程
  • R 语言 基础教程 第6章 分类与预测建模(1)朴素贝叶斯分类,KNN算法,人工神经网络,CART算法,C4.5算法,决策树,回归分析,R语言数据分析

    关注公众号凡花花的小窝 收获更多的考研计算机专业编程相关的资料 分类与测分析是数据挖掘的主要技术手段之一 都属于分析数据的形式 至今已在理论和方法上取得了丰硕的研究成果 1 回归分析 数据分析概念 数据分析是指用适当的分析方法对收集来的大量
  • 液晶电视的MEMC(运动画质补偿技术)的优势不足

    MEMC Motion Estimate and Motion Compensation 即运动估计和运动补偿 液晶电视中用到的运动画质补偿技术 其原理是采用动态映像系统 在传统的两帧图像之间加插一帧运动补偿帧 将普通平板电视的50 60H
  • JDBC连接MySQL数据库

    开发工具与关键技术 IntelliJ IDEA java 撰写时间 2020年9月8日 一 JDBC简介 JDBC全称为 Java Data Base Connectivity java数据库连接 用Java语言操作数据库 可以为多种数据库
  • FPG—VGA显示器字符显示(附代码)

    目录 1 实操 1 1 字符取模 1 2 顶层模块 1 3 图像数据生成模块 1 3 1 模块框图 1 3 2 波形图绘制 1 3 3 代码编写 1 3 4 仿真验证 2 总结 本例程大部分与VGA显示驱动内容相同 只是显示部分改变了 故此
  • sublime text 3神奇的插件--snippet

    像之前用VS 做项目时 任意创建一个asp网页 都会自动出现一些基础的代码 毕竟是微软把大家养的太舒服 总感觉用sublime text时每次手敲一些重复代码时特别无辜 所以查阅了一下package control 终于发现了这一神器 创建
  • 斑马面试总结

    面试岗位 测试开发实习生 面试主要提问的是简历上的项目经历 测试相关的 给你一个视频软件 怎么测试 功能测试 黑盒测试 视频的封面正常 点击屏幕或播放键可以正常播放 视频时间倒计时显示正常 再次点击暂停 视频的声音 默认打开 无噪音 可以调
  • java连接sqlserver2005 tcp 有时超时,SQL Server 2005 出现到主机 的 TCP/IP 连接失败

    用jdbc连接SQL Server2005出现到主机 的 TCP IP 连接失败 java net ConnectException Connection refused connect 估计是因为sqlserver2005默认情况下是禁用
  • Elasticsearch 日志

    下载并安装 Filebeat 首次使用 Filebeat 请参阅入门指南 复制代码片段 curl L O https artifacts elastic co downloads beats filebeat filebeat 7 2 0
  • SpringBoot 整合slf4j 日志配置

    slf4j 即 Simple Logging Facade for Java 简单门面日志 它是对所有日志框架制定的一种规范 标准 接口 并不是一个框架的具体的实现 它只服务于各种各样的日志系统 slf4j提供了统一的记录日志的接口 对不同
  • OpenGL.ES在Android上的简单实践:14-全景(惯性滑动球体)

    OpenGL ES在Android上的简单实践 14 全景 惯性滑动球体 1 整理封装全景球 现在 我们的地球已经能正确的显示出来 我们来增加必要的交互 使得我们左右滑动屏幕的时候 地球能旋转起来 而且是像一个地球仪一样 手指离开屏幕后 能