如何使用 Processing for Android 在 Google Cardboard 设备中显示立体图像?
How do you use Processing for Android to display a stereoscopic image in a Google Cardboard device?
Processing 旨在让 Java 绘图变得更容易。 Android 的处理具有其桌面兄弟的强大功能以及来自传感器的信息。将这些东西放在一起,显示立体图像并像 Oculus Rift 或 Google Cardboard 那样在其周围移动不是很容易吗?
下面的代码在两个视口中显示图像 - 一个用于左眼,一个用于右眼。结果是从 Google Cardboard 设备观看时图像看起来是 3D。加速度计和陀螺仪数据用于在头部四处移动时移动 3D 图像。唯一的错误是在横向模式下处理 Android 如果您不在此模式下启动它,程序会崩溃。我正在使用 Processing 2.0.3 和 Android 4.3,所以这个问题可能已经在当前版本中得到解决。 (尽管我确实看到它在 Github 上的 Processing-Bugs 讨论中仍然是一个悬而未决的问题)。纹理图像是一个最喜欢的卡通人物的 100 x 100 像素图像。您可以使用任何您想要的 - 只需将图像存储在数据文件夹中。
//Scott Little 2015, GPLv3
//pBoard is Processing for Cardboard
import android.os.Bundle; //for preventing sleep
import android.view.WindowManager;
import ketai.sensors.*; //ketai library for sensors
KetaiSensor sensor;
float ax,ay,az,mx,my,mz; //sensor variables
float eyex = 50; //camera variables
float eyey = 50;
float eyez = 0;
float panx = 0;
float pany = 0;
PGraphics lv; //left viewport
PGraphics rv; //right viewport
PShape s; //the object to be displayed
//********************************************************************
// The following code is required to prevent sleep.
//********************************************************************
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// fix so screen doesn't go to sleep when app is active
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
//********************************************************************
void setup() {
sensor = new KetaiSensor(this);
sensor.start();
size(displayWidth,displayHeight,P3D); //used to set P3D renderer
orientation(LANDSCAPE); //causes crashing if not started in this orientation
lv = createGraphics(displayWidth/2,displayHeight,P3D); //size of left viewport
rv = createGraphics(displayWidth/2,displayHeight,P3D);
PImage img = loadImage("jake.jpg"); //texture image
s = createShape();
TexturedCube(img, s, 50, 50);
}
void draw(){
//draw something fancy on every viewports
panx = panx-mx*10;
pany = 0;
eyex = 0;
eyey = -20*az;
ViewPort(lv, eyex, eyey, panx, pany, -15); //left viewport
ViewPort(rv, eyex, eyey, panx, pany, 15); //right viewport
//add the two viewports to your main panel
image(lv, 0, 0);
image(rv, displayWidth/2, 0);
}
//sensor data
void onAccelerometerEvent(float x, float y, float z){
ax = x;
ay = y;
az = z;
}
void onGyroscopeEvent(float x, float y, float z){
mx = x;
my = y;
mz = z;
}
//
void ViewPort(PGraphics v, float x, float y, float px, float py, int eyeoff){
v.beginDraw();
v.background(102);
v.lights();
v.pushMatrix();
v.camera(x+eyeoff, y, 300, px, py, 0, 0.0, 1.0, 0.0);
v.noStroke();
//v.box(100);
v.shape(s);
v.popMatrix();
v.endDraw();
}
//put a texture on PShape object, 6 faces for a cube
void TexturedCube(PImage tex, PShape s, int a, int b) {
s.beginShape(QUADS);
s.texture(tex);
// +Z "front" face
s.vertex(-a, -a, a, 0, b);
s.vertex( a, -a, a, b, b);
s.vertex( a, a, a, b, 0);
s.vertex(-a, a, a, 0, 0);
// -Z "back" face
s.vertex( a, -a, -a, 0, 0);
s.vertex(-a, -a, -a, b, 0);
s.vertex(-a, a, -a, b, b);
s.vertex( a, a, -a, 0, b);
// +Y "bottom" face
s.vertex(-a, a, a, 0, 0);
s.vertex( a, a, a, b, 0);
s.vertex( a, a, -a, b, b);
s.vertex(-a, a, -a, 0, b);
// -Y "top" face
s.vertex(-a, -a, -a, 0, 0);
s.vertex( a, -a, -a, b, 0);
s.vertex( a, -a, a, b, b);
s.vertex(-a, -a, a, 0, b);
// +X "right" face
s.vertex( a, -a, a, 0, 0);
s.vertex( a, -a, -a, b, 0);
s.vertex( a, a, -a, b, b);
s.vertex( a, a, a, 0, b);
// -X "left" face
s.vertex(-a, -a, -a, 0, 0);
s.vertex(-a, -a, a, b, 0);
s.vertex(-a, a, a, b, b);
s.vertex(-a, a, -a, 0, b);
s.endShape();
}
很容易显示不好的立体图像。 Oculus 团队花了这么长时间才实现它是有原因的 ;)
首先,您需要知道人们会不同程度地交叉双眼,以将视线聚焦在 near/far 远离他们的物体上。如果您将相机完全平行设置,那么只有当用户聚焦于无限远时,一切才会看起来不错。如果你以固定的方式稍微转动每个相机,没有眼动追踪,你会得到 3D 电影中使用的内束立体声,但会受到梯形失真效应的影响。如果没有适当的眼动追踪,最好的办法是 使用倾斜的相机平截头体 - 离轴投影 。有关更多信息,请参见 here.
还有其他问题。例如,当你转动头部时,你不仅改变了你的眼睛方向——你还改变了它们在 3D 中的绝对位置 space。如果您只是将 phones 旋转应用于您的相机,效果将会关闭。这就是为什么您应该 至少使用一个头部模型。当前版本的 CardboardSDK 支持对颈部进行建模,以在观察时考虑垂直平移up/down。
还有许多其他问题,例如由于耳机镜头导致的图像枕形失真、头部跟踪、将所有内容校准到特定phone、耳机、镜头,用户 InterPupillaryDistance... 列表还在继续。
总而言之,不,VR不是一件小事或简单的事情。问题是,如果做得不好,它不会立即显现出来。用户可能不会有意识地知道出了什么问题,但他们的大脑会知道。他们一生都在训练它了解周围的现实,而且它很擅长知道什么时候出了问题。做得不好的虚拟现实应用程序可能会导致迷失方向、头痛、眼睛疲劳、恶心,或者只是提供不满意的体验。 VR 世界的一些大玩家担心许多做得不好的 VR 应用程序会给很多人带来糟糕的体验,吓跑他们远离这项技术并阻止它流行。
总而言之,如果你想做 VR,要么确保你真的知道自己在做什么,要么使用 SDK/framework专家制作.
Processing 旨在让 Java 绘图变得更容易。 Android 的处理具有其桌面兄弟的强大功能以及来自传感器的信息。将这些东西放在一起,显示立体图像并像 Oculus Rift 或 Google Cardboard 那样在其周围移动不是很容易吗?
下面的代码在两个视口中显示图像 - 一个用于左眼,一个用于右眼。结果是从 Google Cardboard 设备观看时图像看起来是 3D。加速度计和陀螺仪数据用于在头部四处移动时移动 3D 图像。唯一的错误是在横向模式下处理 Android 如果您不在此模式下启动它,程序会崩溃。我正在使用 Processing 2.0.3 和 Android 4.3,所以这个问题可能已经在当前版本中得到解决。 (尽管我确实看到它在 Github 上的 Processing-Bugs 讨论中仍然是一个悬而未决的问题)。纹理图像是一个最喜欢的卡通人物的 100 x 100 像素图像。您可以使用任何您想要的 - 只需将图像存储在数据文件夹中。
//Scott Little 2015, GPLv3
//pBoard is Processing for Cardboard
import android.os.Bundle; //for preventing sleep
import android.view.WindowManager;
import ketai.sensors.*; //ketai library for sensors
KetaiSensor sensor;
float ax,ay,az,mx,my,mz; //sensor variables
float eyex = 50; //camera variables
float eyey = 50;
float eyez = 0;
float panx = 0;
float pany = 0;
PGraphics lv; //left viewport
PGraphics rv; //right viewport
PShape s; //the object to be displayed
//********************************************************************
// The following code is required to prevent sleep.
//********************************************************************
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// fix so screen doesn't go to sleep when app is active
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
//********************************************************************
void setup() {
sensor = new KetaiSensor(this);
sensor.start();
size(displayWidth,displayHeight,P3D); //used to set P3D renderer
orientation(LANDSCAPE); //causes crashing if not started in this orientation
lv = createGraphics(displayWidth/2,displayHeight,P3D); //size of left viewport
rv = createGraphics(displayWidth/2,displayHeight,P3D);
PImage img = loadImage("jake.jpg"); //texture image
s = createShape();
TexturedCube(img, s, 50, 50);
}
void draw(){
//draw something fancy on every viewports
panx = panx-mx*10;
pany = 0;
eyex = 0;
eyey = -20*az;
ViewPort(lv, eyex, eyey, panx, pany, -15); //left viewport
ViewPort(rv, eyex, eyey, panx, pany, 15); //right viewport
//add the two viewports to your main panel
image(lv, 0, 0);
image(rv, displayWidth/2, 0);
}
//sensor data
void onAccelerometerEvent(float x, float y, float z){
ax = x;
ay = y;
az = z;
}
void onGyroscopeEvent(float x, float y, float z){
mx = x;
my = y;
mz = z;
}
//
void ViewPort(PGraphics v, float x, float y, float px, float py, int eyeoff){
v.beginDraw();
v.background(102);
v.lights();
v.pushMatrix();
v.camera(x+eyeoff, y, 300, px, py, 0, 0.0, 1.0, 0.0);
v.noStroke();
//v.box(100);
v.shape(s);
v.popMatrix();
v.endDraw();
}
//put a texture on PShape object, 6 faces for a cube
void TexturedCube(PImage tex, PShape s, int a, int b) {
s.beginShape(QUADS);
s.texture(tex);
// +Z "front" face
s.vertex(-a, -a, a, 0, b);
s.vertex( a, -a, a, b, b);
s.vertex( a, a, a, b, 0);
s.vertex(-a, a, a, 0, 0);
// -Z "back" face
s.vertex( a, -a, -a, 0, 0);
s.vertex(-a, -a, -a, b, 0);
s.vertex(-a, a, -a, b, b);
s.vertex( a, a, -a, 0, b);
// +Y "bottom" face
s.vertex(-a, a, a, 0, 0);
s.vertex( a, a, a, b, 0);
s.vertex( a, a, -a, b, b);
s.vertex(-a, a, -a, 0, b);
// -Y "top" face
s.vertex(-a, -a, -a, 0, 0);
s.vertex( a, -a, -a, b, 0);
s.vertex( a, -a, a, b, b);
s.vertex(-a, -a, a, 0, b);
// +X "right" face
s.vertex( a, -a, a, 0, 0);
s.vertex( a, -a, -a, b, 0);
s.vertex( a, a, -a, b, b);
s.vertex( a, a, a, 0, b);
// -X "left" face
s.vertex(-a, -a, -a, 0, 0);
s.vertex(-a, -a, a, b, 0);
s.vertex(-a, a, a, b, b);
s.vertex(-a, a, -a, 0, b);
s.endShape();
}
很容易显示不好的立体图像。 Oculus 团队花了这么长时间才实现它是有原因的 ;)
首先,您需要知道人们会不同程度地交叉双眼,以将视线聚焦在 near/far 远离他们的物体上。如果您将相机完全平行设置,那么只有当用户聚焦于无限远时,一切才会看起来不错。如果你以固定的方式稍微转动每个相机,没有眼动追踪,你会得到 3D 电影中使用的内束立体声,但会受到梯形失真效应的影响。如果没有适当的眼动追踪,最好的办法是 使用倾斜的相机平截头体 - 离轴投影 。有关更多信息,请参见 here.
还有其他问题。例如,当你转动头部时,你不仅改变了你的眼睛方向——你还改变了它们在 3D 中的绝对位置 space。如果您只是将 phones 旋转应用于您的相机,效果将会关闭。这就是为什么您应该 至少使用一个头部模型。当前版本的 CardboardSDK 支持对颈部进行建模,以在观察时考虑垂直平移up/down。
还有许多其他问题,例如由于耳机镜头导致的图像枕形失真、头部跟踪、将所有内容校准到特定phone、耳机、镜头,用户 InterPupillaryDistance... 列表还在继续。
总而言之,不,VR不是一件小事或简单的事情。问题是,如果做得不好,它不会立即显现出来。用户可能不会有意识地知道出了什么问题,但他们的大脑会知道。他们一生都在训练它了解周围的现实,而且它很擅长知道什么时候出了问题。做得不好的虚拟现实应用程序可能会导致迷失方向、头痛、眼睛疲劳、恶心,或者只是提供不满意的体验。 VR 世界的一些大玩家担心许多做得不好的 VR 应用程序会给很多人带来糟糕的体验,吓跑他们远离这项技术并阻止它流行。
总而言之,如果你想做 VR,要么确保你真的知道自己在做什么,要么使用 SDK/framework专家制作.