Google VR开发-Cardboard VR SDK反畸变实现
上一篇文章分析了Cardboard SDK的生命周期设计。
这里我们看下畸变部分的实现。
private static final float[] DEFAULT_COEFFICIENTS = { 250.0F, 50000.0F };private float[] mCoefficients;
public float distortionFactor(float radius){float rSq = radius * radius;return 1.0F + mCoefficients[0] * rSq + mCoefficients[1] * rSq * rSq;}public float distort(float radius){return radius * distortionFactor(radius);}public float distortInverse(float radius){float r0 = radius / 0.9F;float r1 = radius * 0.9F;float dr0 = radius - distort(r0);while (Math.abs(r1 - r0) > 0.0001D) {float dr1 = radius - distort(r1);float r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0));r0 = r1;r1 = r2;dr0 = dr1;}return r1;}
在CardboardDeviceParams的构造函数中会构造这个Distortion类,并提供了getDistortion()来获取这个Distortion对象。
WindowManager windowManager = (WindowManager)context.getSystemService("window");
DisplayMetrics metrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getRealMetrics(metrics);
mXMetersPerPixel = (0.0254F / metrics.xdpi);mYMetersPerPixel = (0.0254F / metrics.ydpi);public float getWidthMeters(){return mWidth * mXMetersPerPixel;}public float getHeightMeters(){return mHeight * mYMetersPerPixel;}
private EyeViewport initViewportForEye(EyeParams eye, float xOffsetM){//获取屏幕属性ScreenParams screen = mHmd.getScreen();//获取Cardboard设备属性CardboardDeviceParams cdp = mHmd.getCardboard();//计算出眼睛到屏幕的距离0.011+0.037float eyeToScreenDistanceM = cdp.getEyeToLensDistance() + cdp.getScreenToLensDistance();//根据视场角算出人眼可见的屏幕区域float leftM = (float)Math.tan(Math.toRadians(eye.getFov().getLeft())) * eyeToScreenDistanceM;float rightM = (float)Math.tan(Math.toRadians(eye.getFov().getRight())) * eyeToScreenDistanceM;float bottomM = (float)Math.tan(Math.toRadians(eye.getFov().getBottom())) * eyeToScreenDistanceM;float topM = (float)Math.tan(Math.toRadians(eye.getFov().getTop())) * eyeToScreenDistanceM;EyeViewport vp = new EyeViewport();//视场偏移量vp.x = xOffsetM;vp.y = 0.0F;//视场的宽vp.width = (leftM + rightM);//视场高vp.height = (bottomM + topM);//视场左上角坐标vp.eyeX = (leftM + xOffsetM);vp.eyeY = bottomM;//屏幕横向像素数2560/以米为单位的屏幕宽度0.13155563,得到每米像素数19459.447float xPxPerM = screen.getWidth() / screen.getWidthMeters();//屏幕纵向像素数1440/以米为单位的屏幕高度0.07425001,得到每米像素数19393.936float yPxPerM = screen.getHeight() / screen.getHeightMeters();//最终算出视场左上角的像素坐标和像素宽高eye.getViewport().x = Math.round(vp.x * xPxPerM);eye.getViewport().y = Math.round(vp.y * xPxPerM);eye.getViewport().width = Math.round(vp.width * xPxPerM);eye.getViewport().height = Math.round(vp.height * xPxPerM);return vp;}
public DistortionMesh(EyeParams eye, Distortion distortion, float screenWidthM, float screenHeightM, float xEyeOffsetMScreen, float yEyeOffsetMScreen, float textureWidthM, float textureHeightM, float xEyeOffsetMTexture, float yEyeOffsetMTexture, float viewportXMTexture, float viewportYMTexture, float viewportWidthMTexture, float viewportHeightMTexture){float mPerUScreen = screenWidthM;float mPerVScreen = screenHeightM;float mPerUTexture = textureWidthM;float mPerVTexture = textureHeightM;float[] vertexData = new float[8000];int vertexOffset = 0;Log.d(TAG,"screenWidthM="+screenWidthM+"\nscreenHeightM="+screenHeightM+"\nxEyeOffsetMScreen="+xEyeOffsetMScreen+"\nyEyeOffsetMScreen="+yEyeOffsetMScreen+"\ntextureWidthM="+textureWidthM+"\ntextureHeightM="+textureHeightM+"\nxEyeOffsetMTexture="+xEyeOffsetMTexture+"\nyEyeOffsetMTexture="+yEyeOffsetMTexture+"\nviewportXMTexture="+viewportXMTexture+"\nviewportYMTexture="+viewportYMTexture+"\nviewportWidthMTexture="+viewportWidthMTexture+"\nviewportHeightMTexture="+viewportHeightMTexture);for (int row = 0; row < 40; row++) {for (int col = 0; col < 40; col++){float uTexture = col / 39.0F * (viewportWidthMTexture / textureWidthM) + viewportXMTexture / textureWidthM;float vTexture = row / 39.0F * (viewportHeightMTexture / textureHeightM) + viewportYMTexture / textureHeightM;float xTexture = uTexture * mPerUTexture;float yTexture = vTexture * mPerVTexture;float xTextureEye = xTexture - xEyeOffsetMTexture;float yTextureEye = yTexture - yEyeOffsetMTexture;float rTexture = (float)Math.sqrt(xTextureEye * xTextureEye + yTextureEye * yTextureEye);float textureToScreen = rTexture > 0.0F ? distortion.distortInverse(rTexture) / rTexture : 1.0F;float xScreen = xTextureEye * textureToScreen + xEyeOffsetMScreen;float yScreen = yTextureEye * textureToScreen + yEyeOffsetMScreen;float uScreen = xScreen / mPerUScreen;float vScreen = yScreen / mPerVScreen;float vignetteSizeMTexture = 0.002F / textureToScreen;float dxTexture = xTexture - DistortionRenderer.clamp(xTexture, viewportXMTexture + vignetteSizeMTexture, viewportXMTexture + viewportWidthMTexture - vignetteSizeMTexture);float dyTexture = yTexture - DistortionRenderer.clamp(yTexture, viewportYMTexture + vignetteSizeMTexture, viewportYMTexture + viewportHeightMTexture - vignetteSizeMTexture);float drTexture = (float)Math.sqrt(dxTexture * dxTexture + dyTexture * dyTexture);float vignette = 1.0F - DistortionRenderer.clamp(drTexture / vignetteSizeMTexture, 0.0F, 1.0F);vertexData[(vertexOffset + 0)] = (2.0F * uScreen - 1.0F);vertexData[(vertexOffset + 1)] = (2.0F * vScreen - 1.0F);vertexData[(vertexOffset + 2)] = vignette;vertexData[(vertexOffset + 3)] = uTexture;vertexData[(vertexOffset + 4)] = vTexture;vertexOffset += 5;}}nIndices = 3158;int[] indexData = new int[nIndices];int indexOffset = 0;vertexOffset = 0;for (int row = 0; row < 39; row++) {if (row > 0) {indexData[indexOffset] = indexData[(indexOffset - 1)];indexOffset++;}for (int col = 0; col < 40; col++) {if (col > 0) {if (row % 2 == 0){vertexOffset++;}else {vertexOffset--;}}indexData[(indexOffset++)] = vertexOffset;indexData[(indexOffset++)] = (vertexOffset + 40);}vertexOffset += 40;}FloatBuffer vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();vertexBuffer.put(vertexData).position(0);IntBuffer indexBuffer = ByteBuffer.allocateDirect(indexData.length * 4).order(ByteOrder.nativeOrder()).asIntBuffer();indexBuffer.put(indexData).position(0);int[] bufferIds = new int[2];GLES20.glGenBuffers(2, bufferIds, 0);mArrayBufferId = bufferIds[0];mElementBufferId = bufferIds[1];GLES20.glBindBuffer(34962, mArrayBufferId);GLES20.glBufferData(34962, vertexData.length * 4, vertexBuffer, 35044);GLES20.glBindBuffer(34963, mElementBufferId);GLES20.glBufferData(34963, indexData.length * 4, indexBuffer, 35044);GLES20.glBindBuffer(34962, 0);GLES20.glBindBuffer(34963, 0);}
构建完这个类之后,还需要创建纹理:
private int createTexture(int width, int height) {int[] textureIds = new int[1];GLES20.glGenTextures(1, textureIds, 0);GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, width, height, 0,GLES20.GL_RGB, GLES20.GL_UNSIGNED_SHORT_5_6_5, null);return textureIds[0];}
private int setupRenderTextureAndRenderbuffer(int width, int height) {if (mTextureId != -1) {GLES20.glDeleteTextures(1, new int[] { mTextureId }, 0);}if (mRenderbufferId != -1) {GLES20.glDeleteRenderbuffers(1, new int[] { mRenderbufferId }, 0);}if (mFramebufferId != -1) {GLES20.glDeleteFramebuffers(1, new int[] { mFramebufferId }, 0);}mTextureId = createTexture(width, height);checkGlError("setupRenderTextureAndRenderbuffer: create texture");int[] renderbufferIds = new int[1];GLES20.glGenRenderbuffers(1, renderbufferIds, 0);GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderbufferIds[0]);GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, width, height);mRenderbufferId = renderbufferIds[0];checkGlError("setupRenderTextureAndRenderbuffer: create renderbuffer");int[] framebufferIds = new int[1];GLES20.glGenFramebuffers(1, framebufferIds, 0);GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebufferIds[0]);mFramebufferId = framebufferIds[0];GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, mTextureId, 0);GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER,renderbufferIds[0]);int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {throw new RuntimeException("Framebuffer is not complete: "+ Integer.toHexString(status));}GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);return framebufferIds[0];}
public void beforeDrawFrame(){GLES20.glGetIntegerv(GLES20.GL_FRAMEBUFFER_BINDING, mOriginalFramebufferId);GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFramebufferId);}
DistortionRenderer.afterDrawFrame()
public void afterDrawFrame(){GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mOriginalFramebufferId.array()[0]);GLES20.glViewport(0, 0, mHmd.getScreen().getWidth(), mHmd.getScreen().getHeight());GLES20.glGetIntegerv(GLES20.GL_VIEWPORT, mViewport);GLES20.glGetIntegerv(GLES20.GL_CULL_FACE, mCullFaceEnabled);GLES20.glGetIntegerv(GLES20.GL_SCISSOR_TEST, mScissorTestEnabled);GLES20.glDisable(GLES20.GL_SCISSOR_TEST);GLES20.glDisable(GLES20.GL_CULL_FACE);GLES20.glClearColor(0.0F, 0.0F, 0.0F, 1.0F);GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);GLES20.glUseProgram(mProgramHolder.program);GLES20.glEnable(GLES20.GL_SCISSOR_TEST);GLES20.glScissor(0, 0, mHmd.getScreen().getWidth() / 2, mHmd.getScreen().getHeight());renderDistortionMesh(mLeftEyeDistortionMesh);GLES20.glScissor(mHmd.getScreen().getWidth() / 2, 0, mHmd.getScreen().getWidth() / 2, mHmd.getScreen().getHeight());renderDistortionMesh(mRightEyeDistortionMesh);GLES20.glDisableVertexAttribArray(mProgramHolder.aPosition);GLES20.glDisableVertexAttribArray(mProgramHolder.aVignette);GLES20.glDisableVertexAttribArray(mProgramHolder.aTextureCoord);GLES20.glUseProgram(0);GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);GLES20.glDisable(GLES20.GL_SCISSOR_TEST);if (mCullFaceEnabled.array()[0] == 1) {GLES20.glEnable(GLES20.GL_CULL_FACE);}if (mScissorTestEnabled.array()[0] == 1) {GLES20.glEnable(GLES20.GL_SCISSOR_TEST);}GLES20.glViewport(mViewport.array()[0], mViewport.array()[1], mViewport.array()[2], mViewport.array()[3]);}
DistortionRenderer.onProjectionChanged()
public void onProjectionChanged(HeadMountedDisplay hmd, EyeParams leftEye, EyeParams rightEye, float zNear, float zFar){mHmd = new HeadMountedDisplay(hmd);mLeftEyeFov = new FieldOfView(leftEye.getFov());mRightEyeFov = new FieldOfView(rightEye.getFov());ScreenParams screen = mHmd.getScreen();CardboardDeviceParams cdp = mHmd.getCardboard();if (mProgramHolder == null) {mProgramHolder = createProgramHolder();}EyeViewport leftEyeViewport = initViewportForEye(leftEye, 0.0F);EyeViewport rightEyeViewport = initViewportForEye(rightEye, leftEyeViewport.width);leftEye.getFov().toPerspectiveMatrix(zNear, zFar, leftEye.getTransform().getPerspective(), 0);rightEye.getFov().toPerspectiveMatrix(zNear, zFar, rightEye.getTransform().getPerspective(), 0);float textureWidthM = leftEyeViewport.width + rightEyeViewport.width;float textureHeightM = Math.max(leftEyeViewport.height, rightEyeViewport.height);float xPxPerM = screen.getWidth() / screen.getWidthMeters();float yPxPerM = screen.getHeight() / screen.getHeightMeters();int textureWidthPx = Math.round(textureWidthM * xPxPerM);int textureHeightPx = Math.round(textureHeightM * yPxPerM);float xEyeOffsetMScreen = screen.getWidthMeters() / 2.0F - cdp.getInterpupillaryDistance() / 2.0F;float yEyeOffsetMScreen = cdp.getVerticalDistanceToLensCenter() - screen.getBorderSizeMeters();mLeftEyeDistortionMesh = createDistortionMesh(leftEye, leftEyeViewport, textureWidthM, textureHeightM, xEyeOffsetMScreen, yEyeOffsetMScreen);xEyeOffsetMScreen = screen.getWidthMeters() - xEyeOffsetMScreen;mRightEyeDistortionMesh = createDistortionMesh(rightEye, rightEyeViewport, textureWidthM, textureHeightM, xEyeOffsetMScreen, yEyeOffsetMScreen);setupRenderTextureAndRenderbuffer(textureWidthPx, textureHeightPx);}
Google VR开发-Cardboard VR SDK反畸变实现相关推荐
- Google VR开发-Cardboard VR SDK头部追踪实现(罗德里格旋转公式)
一.罗德里格旋转公式 可以参考百度百科和维基百科进行了解. 概括来说就是罗德里格旋转公式就是用来求旋转后新向量的公式: 而这个公式可以转换成矩阵形式: 公式各部分的几何意义和推导原理参考下图 这个图证 ...
- unity+Cardboard SDK VR开发Cardboard Unity SDK讲解
Cardboard Unity SDK Reference中文翻译版,水平有限请以英文版为准. Plugin Reference Package 内容 Unity插件包包含以下内容: 脚本 · ...
- VR开发基础—VR视频
1.导入谷歌官方提供的库: commonwidget.common.panowidget(全景图).videowidget(视频) 或者添加依赖: dependencies { compile pro ...
- 【获奖公布】走进VR开发世界——我们离开发一款VR大作还有多远?
此次征文比赛以分享VR开发经验为核心,在对所有参赛文章进行审核后,以"开发"为先,评选出一.二.三等奖,共9名. 获奖名单 奖项 文章 作者 评语 一等奖 <VR游戏交互开发 ...
- GOOGLE VR SDK开发VR游戏,VR播放器之二
之前简单说了CardBoardView的使用,这里写CardboardView.StereoRenderer的,使用上十分简单,和编写glsurface的Renderer一样导出有关的接口,使用OPG ...
- GOOGLE VR SDK开发VR游戏,VR播放器之一
最近一年来,VR虚拟现实和AR增强现实技术的宣传甚嚣尘上.其实VR,AR技术很早就有了,一直没有流行开来,不可否认价格是影响技术推广的最大壁垒.谷歌对VR最大的贡献是提供了廉价的谷歌眼镜,按照GOOG ...
- GOOGLE VR SDK开发VR游戏,VR播放器之中的一个
近期一年来,VR虚拟现实和AR增强现实技术的宣传甚嚣尘上.事实上VR,AR技术非常早就有了,一直没有流行开来.不可否认价格是影响技术推广的最大壁垒. 谷歌对VR最大的贡献是提供了便宜的谷歌眼镜,依照G ...
- 二、VR全景图显示器开发 ---- Android VR视频/Google VR for Android /VR Pano/VR Video
原文地址: http://blog.csdn.net/qq_24889075/article/details/52128463 http://www.jianshu.com/p/104251a3153 ...
- 一、初识GVR ---- Android VR视频/Google VR for Android /VR Pano/VR Video
原文链接: http://blog.csdn.net/qq_24889075/article/details/52118633 http://www.jianshu.com/p/09c0822b9d1 ...
最新文章
- [NOI2005]聪聪与可可(期望dp)
- python 栈实现 加减乘除_数据结构与算法(六):基于栈实现简单的四则运算
- Flutter开发之爬坑集合(五)
- 现代密码学3.1--定义计算安全的两种方法
- 徐雷FrankXu 内推 杭州 蚂蚁金服招聘 java开发工程
- Django-安装xadmin的方法及主要配置方法
- java oracle11g jar_oracle11g驱动jar包下载
- java案例2-7 随机抽取幸运观众
- 提升自己的认知-思维模型
- vue运行报错冒号问题,browser.js:158 Uncaught SyntaxError: Unexpected token ‘:‘
- Pr:旧版标题字幕设计器
- 优秀工程师应该具备哪些素质_优秀的工程师具有什么品质
- JS生成26个英文字母
- 瑞芯微RK3399六核-迅为3399开发板介绍
- TexturePacker入门记事
- [AHK]自动运行一键选股
- js visibility
- 二手车电商又多了一只独角兽?
- 【自学编程】自己写小例子的经验
- 小试debian-7.11.0-amd64+Plone5.1.2全文检索和预览中文WORD中文PDF
热门文章
- Azure Information Protection信息保护(AIP)/Azure Rights Management权限管理(RMS)
- Python pandas 筛选 Excel 特定行和列全集
- 使用pypcd读取pcd时ValueError: field ‘__0000‘ occurs more than once错误
- 自动驾驶IDM与MOBIL模型
- 笔记本计算机声音小,笔记本声音太小怎么加大 笔记本声音太小增大方法【详细介绍】...
- 海尔微型计算机云悦t3G276ia,没了海尔云悦miniA 迷你主机界尽失半壁江山
- 基于SpringBoot和Vue实现的个人博客网站快速搭建(已开源)
- esx linux 硬盘 扩容,ESX虚拟机添加新磁盘并扩容逻辑卷
- 网络时间同步设备(时钟同步产品)时钟系统应用技术介绍
- LSB文本水印的嵌入与提取