問題
私の主な目標は、デバイス上のタッチのモデル座標を取得して、何をタッチしたかを確認することです。私は大規模なモデルを扱っており、多くのものを描画する必要があり、それらにも触れることができなければなりません。
これを実現するには、2 つの方法が考えられます。1 つは、レイ キャスティングを実行し、カメラのポインティング ベクトルをモデルと交差させる方法です。これをメモリのどこかに保存する必要があります。一方、それが私がやろうとしていることですが、古い方法でそれを行うことができます:
function gluUnProject(winx, winy, winz: TGLdouble;
const modelMatrix: TGLMatrixd4;
const projMatrix: TGLMatrixd4;
const viewport: TGLVectori4;
objx, objy, objz
画面座標をモデル座標に変換します。私はここまで正しいですか?opengl アプリでのタッチ処理の他の方法を知っていますか? 関数がパラメーターとして winz を取ることがわかるように、これは画面座標でのフラグメントの高さであり、この情報は通常深度バッファーから取得されます。「通常の」openglで可能なように、opengl-es 2.0が内部的に使用される深度バッファへのアクセスを提供しないことはすでに認識しています。では、どうすればこの情報を入手できますか?
Appleは 2 つの可能性を提供します。深度がアタッチされたオフスクリーン フレーム バッファーを作成するか、深度情報をテクスチャにレンダリングします。悲しいことに、このマニュアルには、情報を iOS に読み戻す方法が示されていません。glReadPixels を使用して読み返す必要があると思います。見つけたものはすべて実装しましたが、どのように設定しても、オフスクリーン フレーム バッファまたはテクスチャからの高さに対して正しい結果が得られません。z値でGL_FLOATを取得することを期待しています。
z:28550323
r:72 g:235 b:191 [3]:1 <-- 常にこれ
コード
gluUnProject
glu ライブラリは iOS では利用できないので、コードを調べて、このソースに基づいて次のメソッドを実装しました: link . GLKVector2 画面入力変数は画面上の X、Y 座標であり、UITabGestureRecognizer によって読み取られます
-(GLKVector4)unprojectScreenPoint:(GLKVector2)screen {
//get active viewport
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
NSLog(@"viewport [0]:%d [1]:%d [2]:%d [3]:%d", viewport[0], viewport[1], viewport[2], viewport[3]);
//get matrices
GLKMatrix4 projectionModelViewMatrix = GLKMatrix4Multiply(_modelViewMatrix, _projectionMatrix);
projectionModelViewMatrix = GLKMatrix4Invert(projectionModelViewMatrix, NULL);
//in ios Y is inverse
screen.v[1] = viewport[3]-screen.v[1];
NSLog(@"screen: [0]:%.2f [1]:%.2f", screen.v[0], screen.v[1]);
//read from the depth component of the last rendererd offscreen framebuffer
/*
GLubyte z;
glBindFramebuffer(GL_FRAMEBUFFER, _depthFramebuffer);
glReadPixels(screen.v[0], screen.v[1], 1, 1, GL_DEPTH_COMPONENT16, GL_UNSIGNED_BYTE, &z);
NSLog(@"z:%c", z);
*/
//read from the last rendererd depth texture
Byte rgb[4];
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _depthTexture);
glReadPixels(screen.v[0], screen.v[1], 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &z);
glBindTexture(GL_TEXTURE_2D, 0);
NSLog(@"r:%d g:%d b:%d [3]:%d", rgb[0], rgb[1], rgb[2], rgb[3]);
GLKVector4 in = GLKVector4Make(screen.v[0], screen.v[1], 1, 1.0);
/* Map x and y from window coordinates */
in.v[0] = (in.v[0] - viewport[0]) / viewport[2];
in.v[1] = (in.v[1] - viewport[1]) / viewport[3];
/* Map to range -1 to 1 */
in.v[0] = in.v[0] * 2.0 - 1.0;
in.v[1] = in.v[1] * 2.0 - 1.0;
in.v[2] = in.v[2] * 2.0 - 1.0;
GLKVector4 out = GLKMatrix4MultiplyVector4(projectionModelViewMatrix, in);
if(out.v[3]==0.0) {
NSLog(@"out.v[3]==0.0");
return GLKVector4Make(0.0, 0.0, 0.0, 0.0);
}
out.v[0] /= out.v[3];
out.v[1] /= out.v[3];
out.v[2] /= out.v[3];
return out;
}
描画中に生成される深度バッファまたは深度テクスチャからデータを読み取ろうとします。このコードが非常に非効率的であることはわかっていますが、最初に実行してからクリーンアップする必要があります。
追加のフレーム バッファ (ここでコメント アウト) のみ、タイルのみに描画しようとしましたが、成功しませんでした。
描く
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glUseProgram(_program);
//http://stackoverflow.com/questions/10761902/ios-glkit-and-back-to-default-framebuffer
GLint defaultFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &defaultFBO);
GLint defaultRBO;
glGetIntegerv(GL_RENDERBUFFER_BINDING_OES, &defaultRBO);
//GLint defaultDepthRenderBuffer;
//glGetIntegerv(GL_Depth_B, &defaultRBO);
GLuint width, height;
//width = height = 512;
width = self.view.frame.size.width;
height = self.view.frame.size.height;
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
/* method offscreen framebuffer
GLuint depthRenderbuffer;
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
*/
//method render to texture
glActiveTexture(GL_TEXTURE1);
//https://github.com/rmaz/Shadow-Mapping
//http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html
GLuint depthTexture;
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// we do not want to wrap, this will cause incorrect shadows to be rendered
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// set up the depth compare function to check the shadow depth
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_EXT, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_EXT, GL_COMPARE_REF_TO_TEXTURE_EXT);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8_OES, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
if(status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(@"failed to make complete framebuffer object %x", status);
}
GLenum glError = glGetError();
if(GL_NO_ERROR != glError) {
NSLog(@"Offscreen OpenGL Error: %d", glError);
}
glClear(GL_DEPTH_BUFFER_BIT);
//glCullFace(GL_FRONT);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glUniform1i(_uniforms.renderMode, 1);
//
//Drawing calls
//
_depthTexture = depthTexture;
//_depthFramebuffer = depthRenderbuffer;
// Revert to the default framebuffer for now
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO);
// Render normally
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(0.316f, 0.50f, 0.86f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glCullFace(GL_BACK);
glUniform1i(_uniforms.renderMode, 0);
[self update];
//
//Drawing calls
//
}
}
z の値は、異なるタイプのものである可能性があります。float データ型に戻す必要があるのは単なる float ですか?
ご協力ありがとうございました!パテ
1.編集
レンダリングしたテクスチャからも RGBA を取得します。これを実現するために、描画中に個別のフレーム バッファーをアクティブにしますが、深度拡張はアクティブにせず、それにテクスチャを接続します。上記のコードを編集しました。今、私は次の値を取得しています:
screen: [0]:604.00 [1]:348.00
r:102 g:102 b:102 [3]:255
screen: [0]:330.00 [1]:566.00
r:73 g:48 b:32 [3]:255
screen: [0]:330.00 [1]:156.00
r:182 g:182 b:182 [3]:255
screen: [0]:266.00 [1]:790.00
r:80 g:127 b:219 [3]:255
screen: [0]:548.00 [1]:748.00
r:80 g:127 b:219 [3]:255
ご覧のとおり、rgba 値が読み取られます。良いニュースは、モデルがもういない空に触れているとき、値は常に同じであり、モデルに触れている間は変化することです. だから、テクスチャは正しいはずだと思います。しかし、どうすればこの 4 バイトから実際の値を再構築し、それを gluUnProject に渡すことができるでしょうか? フロートにキャストすることはできません。