最近一年来,VR虚拟现实和AR增强现实技术的宣传甚嚣尘上。其实VR,AR技术很早就有了,一直没有流行开来,不可否认价格是影响技术推广的最大壁垒。谷歌对VR最大的贡献是提供了廉价的谷歌眼镜,按照GOOGLE提供的图纸,使用两个放大镜和一个披萨盒就能轻松DIY出自己的VR眼镜,同一时期谷歌推出来开源的VR SDK,使得开发者可以轻松构建VR游戏和VR播放器,使得几乎所有对这一切感兴趣的公司可以轻松的低成本的在技术上布局VR产业链。很多VR眼镜已经降到了几十块钱,毫无疑问,谷歌又借着廉价和开源改变了我们的世界。
研究谷歌的SDK,需要具备一定的OPENGL知识,要不理解这一切十分困难。VR的原理十分简单,人能够感受的立体或者3D的世界全依赖人的双眼,人的双眼看到的东西是不一样,存在一个视角差,看一个立体的物体,左右眼能同时看到物体中间的部分,不过左眼能看到比右眼更多一点的左边部分,右眼能看到比左眼更多一点右边部分,大脑对两只眼镜看到的东西分析处理合成来感受这个世界的,一些3D画可以恰当的利于光线和颜色组合达到视觉欺骗也是这个原理。如果对OPENGL熟悉的话,应该很容易知道3D建模中,Camera的位置不同,能显示出来的对象角度是不一样的,特别是使用透视效果时,人的两眼就相当于3D世界里摄像头,两个摄像头看到的东西和一个是不同的。一般来说,独眼的残疾人如果不动的话,看到的世界是平面的,不过他们可以通过摆头或者移动身体来从不同的角度观察世界,从而在大脑里合成立体的世界。所以VR的原理就是把一张图片或者视频分解两个,分别提供给左右眼看,从而达到欺骗眼睛的效果,最终达到虚拟现实的效果。
谷歌VR SDK使用十分简单,一般来说最好下载最新的google VR sdk,VR SDK包括unity版本和java版本,两个版本功能差不多,一个用于unity平台,一个用于android平台,一个用于游戏开发,一个用于应用开发,当然这不是绝对,有不少应用也是使用unity开发,也有不少游戏使用java开发,选择上感觉可以看自己使用习惯。java版本包括两个包,一个cardboard.jar提借VR视觉支持,一个audio.jar提供VR声音支持。
CardboardActivity是VRSDK的主类,要使开发的窗口支持VR,窗口需要派生于这个类。可以根据需要调用CardBoardView,支持各种调用,完整代码如下,不过完成后除了看到一个按钮,其他都是黑冬冬的,因为Renderer我们没有填充内容,是个空的glsurface,熟悉opgengl的,可以完善这个类,后面会添加一个立方体用于测试眼镜
public class TestActivity extends CardboardActivity{ /* @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(R.layout.activity_main); RajawaliCardboardView cv = (RajawaliCardboardView) findViewById(R.id.view2);//new CardboardView(this); //cv.setRestoreGLStateEnabled(false); //cv.setRenderer(rd); this.setCardboardView(cv); RajawaliCardboardRenderer renderer = new RajawaliCardboardRenderer(this){ @Override protected void initScene() { getCurrentScene().addChild(createSphereWithTexture(new Texture("photo", R.drawable.homepage))); getCurrentCamera().setPosition(Vector3.ZERO); getCurrentCamera().setFieldOfView(75); } @Override public void onNewFrame(HeadTransform headTransform) { super.onNewFrame(headTransform); } @Override protected void onRender(long ellapsedRealtime, double deltaTime) { super.onRender(ellapsedRealtime, deltaTime); } @Override public void onDrawEye(Eye eye) { super.onDrawEye(eye); } @Override public void onFinishFrame(Viewport viewport) { super.onFinishFrame(viewport); } @Override public void onSurfaceChanged(int width, int height) { super.onSurfaceChanged(width, height); } @Override public void onSurfaceCreated(EGLConfig config) { super.onSurfaceCreated(config); } @Override public void onRendererShutdown() { super.onRendererShutdown(); } @Override public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) { super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset, yPixelOffset); } @Override public void onTouchEvent(MotionEvent event) { super.onTouchEvent(event); } }; cv.setRenderer(renderer); cv.setSurfaceRenderer(renderer); } */ /* @Override protected void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); super.onCreate(savedInstanceState); LinearLayout ln = new LinearLayout(this); ln.setBackgroundColor(Color.RED); CardboardView cbView = new CardboardView(this); cbView.setBackgroundColor(Color.BLUE); cbView.setVRModeEnabled(true); //cbView.setAlpha(0); cbView.setAlignmentMarkerEnabled(true); //cbView.setRenderer(new VrRenderer(this)); VrRenderer renderer = new VrRenderer(this); cbView.setRenderer(renderer); cbView.setPreserveEGLContextOnPause(true); setContentView(cbView); cbView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onCardboardTrigger(); } }); //mHideButtonsThread.start(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); CardboardView cardboardView = (CardboardView) findViewById(R.id.view2); cardboardView.setRenderer(rd); setCardboardView(cardboardView); vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); imageLeft = (ImageView) findViewById(R.id.image_left); imageRight = (ImageView) findViewById(R.id.image_right); progressLeft = (ProgressBar) findViewById(R.id.progress_left); progressRight = (ProgressBar) findViewById(R.id.progress_right); statusLeft = (TextView) findViewById(R.id.status_text_left); statusRight = (TextView) findViewById(R.id.status_text_right); fadeInAnim = new AlphaAnimation(0.0f, 1.0f); fadeInAnim.setDuration(500); setProgress(true); setStatus(true, getString(R.string.status_finding_files)); // kick off our task to find all MPOs, which will in turn kick off showing the first one. new MpoFindTask().execute((Void) null); } */ private Renderer rd = new Renderer(){ @Override public void onDrawFrame(HeadTransform headTransform, Eye eye, Eye eye1) { } @Override public void onFinishFrame(Viewport viewport) { } @Override public void onSurfaceChanged(int i, int i1) { } @Override public void onSurfaceCreated(EGLConfig eglConfig) { } @Override public void onRendererShutdown() { } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); CardboardView mSurfaceView = new CardboardView(this); addContentView(mSurfaceView, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT)); mSurfaceView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar | View.SYSTEM_UI_FLAG_IMMERSIVE); mSurfaceView.setRenderer(rd); mSurfaceView.setVRModeEnabled(true); //mSurfaceView.addChildrenForAccessibility(); setCardboardView(mSurfaceView); } }
参考:http://www.programcreek.com/java-api-examples/index.php?api=com.google.vrtoolkit.cardboard.CardboardView