ã¯ããã«
Oculus Riftåãã®å
¬å¼ã«å¯¾å¿ãã¦ããéçºç°å¢ã¯Unity Proã§ãããä»ã¯Trialçãåºã¦ããããã触ã£ã¦ããããæ¹ãå¤ãã¨æãã¾ãã
ãããç§ã¯ãã¯ãããããã®ã½ããã¯ä½¿ããã¨ãèãã¦ã¯ãã¾ããã§ãããããã§ããªãã¨ããè¦ããããã«ãªãã¾ããã®ã§ã解説ããã¦è¡ãããã¨æãã¾ãã
éç¼ã¢ãã«ã¹ã¯ãªã¼ã³ã«ã¤ãã¦
人éã®ç®ã¯ãå å¦ã¬ã³ãºã¨ãã¦ã®è½åã«å¿ å®ã§ãããOculus Riftããã®æ§è³ªãçããã¦è¨è¨ããã¦ãã¾ãã ã¾ããéç¼ã¢ãã«ã§ã¯ã人éã®ç®ã«å¯¾ãã¦ãåçç¶ã®æå½±ã¹ã¯ãªã¼ã³ãæå½±ãã¦ããç¶æ ã¨åãã§ããOculus Riftã¯å¹³é¢ã¢ãã«ã®æ¶²æ¶ãæã£ã¦ãã¾ããããããã¬ã³ãºã§ãã¾ãå å·¥ãã¦ç®ã®åã«åçç¶ã®æå½±ã¹ã¯ãªã¼ã³ãç½®ãã¦ããããã«è¦ãããã¦ãã¾ãã
極座æ¨ç³»ã¸ã®å¤æ
å³ä¸ã®éãé¨åã¯CGã§ã®æ®åé¢ãã¤ã¾ãæ åãã®ãã®ã§ããã赤ãé¨åã¯éç¼ã¢ãã«ã§ã®æ®åé¢ã¨ãªãã¾ããã«ã¡ã©ã¯æ¬æ¥ã赤ãé¨åã®æ®åé¢ãå¹³é¢ã«å°å½±ãããããå å¦çãªæªã¿ãæã£ã¦ãã¾ãããã¬ã³ãºã®æ§è³ªãã½ããã¦ã§ã¢ã§ãã®æªã¿ãç¡ããå¦çãããã¦ãã¾ããOculus Riftã§ã¯ããã®æªã¿ã®ç¶æ ãåç¾ããå¿ è¦ãããã¾ãã ãæ®åé¢ã®å¤§ãããwã¨ããæãè¨ç®ããããã®æ®åé¢ãw=2uã¨ãããéç¼ã¢ãã«ã®æ®åé¢ä½ç½®ã«å¯¾å¿ããå¹³é¢ã¢ãã«ã®ä½ç½®ãè¨ç®ãã¾ãã
å¹³é¢ã¢ãã«ã®åä½ã§ãã1uã¯ç´äº¤åº§æ¨ç³»ãéç¼ã¢ãã«ã®åä½ã§ãã1ucã¯æ¥µåº§æ¨ç³»ã®ããã対å¿ç¹ãè¦ã¤ããã«ã¯åº§æ¨å¤æãããå¿ è¦ãããã¾ããå³ä¸ã®ç¹pã¯3次å 空éä¸ã®ç¹ãç¹p'ã¯CGæ åãåçã§æ®åãããé¢ã§ã®å¯¾å¿ç¹ã«ãªãã¾ããOculusRiftã§ã¯ãp''ã対å¿ããç¹ã¨ãªãã¾ãã
ããã§ã®è§£èª¬ã¯ãp''ã®ä½ç½®ã«å¯¾å¿ããp'ãæ±ããããã®æ¹æ³ã«ã¤ãã¦è§£èª¬ãã¾ããã¾ãã¯focal legnthãè¨ç®ãã¾ããããã§ã®ç¦ç¹è·é¢ã®å®ç¾©ã¯ãã«ã¡ã©å å¦ã¨åæ§ã«ç¦ç¹ããæ®åé¢ã¾ã§ã®ãã¨ãå·®ãã¾ãã
focal lengthã1ãè¦éè§ã®è§åº¦ãθã¨ããæãæ®åé¢ã®å¤§ããã¯Tan(θ/2)ã¨ãªãã¾ããTanã®æ§è³ªä¸ã90°ã¯æ±ããããªããããç®åºã§ããè¦éè§ã¯1°~189°ã¾ã§ã¨ãªãã¾ããããã§ãæ®åé¢ã®å¤§ãããåä½æ°(1u)ã«ããå ´åãfocal length㯠Cot(θ/2)*u = 1/Tan(θ/2)*uã§æ±ãããã¨ãã§ãã¾ããããã«ãã£ã¦ã1uã«å¯¾ããæ¯çã¨ãã¦focal lengthãå¾ããã¨ãã§ãã¾ãã
1ucã¯ç»é¢ä¸å¿ããã®è¦éã®æ大è§ã®åä½ï¼ã©ã¸ã¢ã³ï¼ã¨ãªããè¦éè§ãθã¨ããã¨ã1uc = θ/2ã¨ãªãã¾ããã¤ã¾ããåçä¸ã®æ¥µåº§æ¨ç¹ p''㯠-θ/2<=p<=θ/2ã®åºéã§è¡¨ããã¨ãã§ãã¾ãã
ãã£ã¦p''ã®ã«å¯¾å¿ããp'ã®ä½ç½®ã¯p'= f * Tan((θ/2) * p'')ã¨ãªãã¾ããè¦éè§ã110°ã¨ãã¦å®æ°ã«ç´ãã¨ãf * Tan(55° * p'')ã«ãªãã¾ããp''ã1ucã®æãTan(55°) * f = 1uã¨ãªããããã«ãããåçåã®æ®åé¢ä¸ã®ç¹ããå¹³é¢åã®æ®åé¢ã§ã®å¯¾å¿ç¹ãæ±ã¾ãã¾ãã
æ®åé¢ã®å¤å½¢
ã¾ããéç¼ã¢ãã«ã®åº§æ¨ç³»ã¯æ¥µåº§æ¨ç³»ãªã®ã§ã常ã«ç¦ç¹ããæ®åé¢ã¾ã§ã®è·é¢ãä¸å®ã«ããå¿
è¦ãããã¾ããããã«ã¯æ®åé¢ãå¤å½¢ãããå¿
è¦ãããã¾ãã
æ°´å¹³é¨å(y軸ã®å¤ã0)ã§ã¯å
ã»ã©ã®ã¢ãã«ãéç¨ãã¾ãããããã§ãã¬ã³ãºã¢ãã«ã極座æ¨ç³»ãªã®ã§ã極座æ¨ç³»ããç´äº¤åº§æ¨ç³»ã«å¤æããæã«æ¨½åã®æªã¿ãçãã¾ãã
極座æ¨ç³»ã§ã¯ç»åä¸å¿ããã®è·é¢ã¨è§åº¦ã«ãã£ã¦è¡¨ããããããpââ(θ,l)ã®æ¥µåº§æ¨ç³»ã®å¯¾å¿ç¹ãpâ(x,y)ã¨ããã¨ãx^2+y^2 = l^2ã¨ãªããpâ=(cos(θ)*l,sin(θ)*l)ã§è¨ç®ããäºãã§ãã¾ãããã ããããã¯æ°´å¹³è¦éè§ãåç´è¦éè§ããããã180°ã®æã«ãªãã¾ãã®ã§ãOculusRiftã§ã¯æ°´å¹³è¦éè§ã120°ãåç´è¦éè§ã90°ã§ãããè¨ç®ãè¤éã«ãªã£ã¦ãã¾ãã¾ãã
樽åã«æªã¾ããé¢æ°ã¨ãã¦ãå³å¯ã«æ¥µåº§æ¨ç³»ããç´äº¤åº§æ¨ç³»ã®å¼ãå°å
¥ããå¿
è¦ããªãå ´åã¯ãç°¡ç¥å¼ã§æ¸ã¾ãã¦ãã¾ãã¾ãããã ãããã®æ¹æ³ã¯xã¨yããããã-1ãã1ã¾ã§ã®ç¯å²ãåãããã«ããã¸ã§ã¯ã·ã§ã³å¤æãããå¿
è¦ãããã¾ãã
xâ = cos(y*åç´è¦éè§(ã©ã¸ã¢ã³)*æªæ²å¼·åº¦ )* x;
yâ = cos(x*æ°´å¹³è¦éè§(ã©ã¸ã¢ã³)*æªæ²å¼·åº¦ )* y;
cos(0)=1ãcos(180°)=0ãªã®ã§ãå¼ãè¦ãããã«ã yã®å¤ã大ããã¨ãã¯xã®å¤ãå°ãããªãããã«ãªããxã®å¤ã大ããã¨ãã¯yã®å¤ãå°ãããªãããã«è¨ç®ããã¾ãã
ãã ããå³å¯çã«è¨¼æãã¦ãã訳ã§ã¯ãªãã®ã§ãæªæ²å¼·åº¦ã®ãã©ã¡ã¼ã¿ãããã£ã¦èª¿æ´ããå¿
è¦ãããã¾ãã
ãã®äºã¤ã®æ¹æ³ã«ãããæ¬ä¼¼çã§ããOculusRiftã®ãã¹ãããã»ãã·ã³ã°ãåç¾ããäºãã§ãã¾ãã
GPUã«ããå¦çã³ã¼ã(GLSL)
æå¾ã«QuartzComposerä¸ã§æ¸ããGLSLã³ã¼ããç´¹ä»ãã¾ããä¸ã«ã¯è§£èª¬ã«ç»å ´ããªãã£ãå¤æ°ãåºã¦ãã¾ãããdistãdistTXãdistTYãã¯1ãã調æ´ããxshiftã¯0ãxscaleãyscaleã¯1ãããoffsetxã0ããã§èª¿æ´ãã¦ããã°å ·åãè¯ãã¨æãã¾ããåèã«ãªãã°å¹¸ãã§ãã
textureã¯ã¬ã³ããªã³ã°ããã¤ã¡ã¼ã¸(æ°´å¹³è¦éè§110°ãåç´è¦éè§90°以ä¸ã§ã¬ã³ããªã³ã°ãããã®)ããã¤ã³ãããVertexShaderã®ã¡ãã·ã¥ã¯-1ãã1ã«ã¹ã±ã¼ãªã³ã°ãããã°ãªããã使ã£ã¦ãã¾ããåå²ããã¦ããã°ããã¦ããã»ã©ç¶ºéºã«ã¬ã³ãºç¶ã«ãªãã¾ãã
----ããããVertex Shader----
const float PI = 3.14159265358979323846264; //Constant Pi
uniform float fovX; //Field of View X
uniform float fovY; //Field of View Y
uniform float dist; //lens distortion(1.0~)
uniform float distTX; //another distortion(~1.0) horizontal texture magnification
uniform float distTY; //another distortion(~1.0) vertical texture magnification
uniform float xshift; //horizontal gaze shifthing(default value is 0)
uniform float xscale; //horizontal scale
uniform float yscale; //vertical scale
uniform float offsetx;//horizontal offset(a margin between both images)
//float fovX = 55.0; //Field of View X
//float fovY = 45.0; //Field of View Y
//float dist = 1.4; //lens distortion(min value is 1.0)
void main()
{
//focal legnth = 1.0/2.0*cot(fov/180.0*PI) = 0.5/tan(fov/180.0*PI)
//float focalX = 0.35010376910485486; //110(55) Degree focal length
//float focalY = 0.5; //90(45) Degree focal length
float focalX = 0.5/tan(fovX/180.0*PI);
float focalY = 0.5/tan(fovY/180.0*PI);
//vec4 pos = gl_Vertex * gl_ModelViewProjectionMatrix;
vec4 pos = gl_Vertex;
vec4 tpos = gl_TextureMatrix[0] * gl_MultiTexCoord0;
//vec4 tpos = gl_MultiTexCoord0;
float px = pos.x;
float py = pos.y;
float tx = (tpos.x - 0.5)*2.0;
float ty = (tpos.y - 0.5)*2.0;
float dx = cos(dist*py*fovY/180.0*PI)*px;
float dy = cos(dist*px*fovX/180.0*PI+xshift/180.0*PI)*py;
float ox = focalX*tan(distTX*tx*fovX/180.0*PI);
float oy = focalY*tan(distTY*ty*fovY/180.0*PI);
gl_Position.x = dx*xscale+0.5+offsetx;
gl_Position.y = dy*2.0*yscale;
gl_Position.z = 0.0;
//gl_Position = pos;
gl_TexCoord[0].x = ox+0.5;
gl_TexCoord[0].y = oy+0.5;
//gl_TexCoord[0] = tpos;
//Forward current color and texture coordinates after applying texture matrix
gl_FrontColor = gl_Color;
}
----ããã¾ã§Vertex Shader----
----ããããPixel Shader----
uniform sampler2D texture;
void main()
{
//Multiply color by texture
gl_FragColor = gl_Color * texture2D(texture, gl_TexCoord[0].xy);
}
----ããã¾ã§Pixel Shader----
ã»ããä¸è¨ã®ã³ã¼ãã使ã£ãåèåç»