私は iPhone 4 OpenGL ES アプリで不可解な問題を抱えており、このサイトでいくつかの本当に有用で興味をそそるヒントや提案にもかかわらず、ここ数か月オンとオフに取り組んでおり、行き詰まりに陥っています。
ブロックを単純に描画し、ユーザーがブロックをさまざまな配置に移動できるようにする 3D ゲームを作成しています。アプリの大部分は C++ で記述されています。
私の問題は、ここでソースコードを見つけたGLuUnprojectを使用しようとしていることです:
http://webcvs.freedesktop.org/mesa/Mesa/src/glu/mesa/project.c?view=markup
ユーザーが選択した3Dポイント(したがってブロック)を解釈して移動および回転させ、倍精度ではなく浮動小数点に変換しました。
このソースをネット上の他のバージョンと比較したところ、一貫しているように見えることに注意してください。
次のコードを使用して光線ベクトルを取得します。
Ray RenderingEngine::GetRayVector( vec2 winPos ) const
{
// Get the last matrices used
glGetFloatv( GL_MODELVIEW_MATRIX, __modelview );
glGetFloatv( GL_PROJECTION_MATRIX, __projection );
glGetIntegerv( GL_VIEWPORT, __viewport );
// Flip the y coordinate
winPos.y = (float)__viewport[3] - winPos.y;
// Create vectors to be set
vec3 nearPoint;
vec3 farPoint;
Ray rayVector;
//Retrieving position projected on near plan
gluUnProject( winPos.x, winPos.y , 0,
__modelview, __projection, __viewport,
&nearPoint.x, &nearPoint.y, &nearPoint.z);
//Retrieving position projected on far plan
gluUnProject( winPos.x, winPos.y, 1,
__modelview, __projection, __viewport,
&farPoint.x, &farPoint.y, &farPoint.z);
rayVector.nearPoint = nearPoint;
rayVector.farPoint = farPoint;
//Return the ray vector
return rayVector;
}
返された光線をニア プレーンからファー プレーンにトレースするためのベクトル コードは簡単で、画面の下部近くのブロックは正しく識別されていることがわかりますが、画面を上に移動すると、報告された値の不一致が大きくなるようです。選択したポイントの y 値と期待される y 値。
また、GLuProject を使用して、次のようにワールド座標に対してどのスクリーン座標が生成されているかを手動で確認しようとしました。
vec3 RenderingEngine::GetScreenCoordinates( vec3 objectPos ) const
{
// Get the last matrices used
glGetFloatv( GL_MODELVIEW_MATRIX, __modelview );
glGetFloatv( GL_PROJECTION_MATRIX, __projection );
glGetIntegerv( GL_VIEWPORT, __viewport );
vec3 winPos;
gluProject(objectPos.x, objectPos.y, objectPos.z ,
__modelview, __projection, __viewport,
&winPos.x, &winPos.y, &winPos.z);
// Swap the y value
winPos.y = (float)__viewport[3] - winPos.y;
return winPos;
}
繰り返しになりますが、結果は、ユーザーが画面の上をクリックするにつれて GLuProjected の y 座標がますます間違っていくという点で、レイ トレーシング アプローチと一致しています。
たとえば、touchesBegan イベントによって直接報告されたクリック位置が (246,190) の場合、計算された位置は (246, 215) であり、不一致は 25 です。
touchesBegan イベントによって直接報告されたクリックされた位置が (246,398) の場合、計算された位置は (246, 405) であり、不一致は 7 です。
x座標は正しいようです。
ビューポートの高さが 480 (全画面の高さ) に設定されている場合、layer.bounds.size.height が 436 と報告されることに気付きました。レイヤー境界の幅は、ビューポートの幅でもある 320 として報告されます。
436 という値は、使用するビューポートのサイズに関係なく、ウィンドウの上部にステータス スクリーンを表示するかどうかに関係なく固定されているようです。
次の呼び出しの前に、bounds.size.height を 480 に設定しようとしました。
[my_context
renderbufferStorage:GL_RENDERBUFFER
fromDrawable: eaglLayer];
しかし、これは無視されているようで、高さは後で呼び出しで 436 として報告されます。
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
GL_RENDERBUFFER_HEIGHT_OES, &height);
ポイントとピクセルの違いとスケーリングの必要性についての議論を見てきましたが、その違いは iPhone 4 の Retina ディスプレイ解像度によるものであり、異なるスケーリングが必要になることを示唆していたため、その情報を有効に使用するのに苦労しました。シミュレータと実際のデバイス。ただし、私が知る限り、シミュレーターとデバイスは一貫して動作しています。
2011 年 8 月 30 日 これに関するフィードバックが得られないので、質問をより扱いやすくするために提供できる情報はありますか?
2011 年 8 月 31 日 OpenGL のセットアップと表示コードは次のとおりです。
- (id) initWithCoder:(NSCoder*)coder
{
if ((self = [super initWithCoder:coder]))
{
// Create OpenGL friendly layer to draw in
CAEAGLLayer* eaglLayer = (CAEAGLLayer*) self.layer;
eaglLayer.opaque = YES;
// eaglLayer.bounds.size.width and eaglLayer.bounds.size.height are
// always 320 and 436 at this point
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES1;
m_context = [[EAGLContext alloc] initWithAPI:api];
// check have a context
if (!m_context || ![EAGLContext setCurrentContext:m_context]) {
[self release];
return nil;
}
glGenRenderbuffersOES(1, &m_colorRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
[m_context
renderbufferStorage:GL_RENDERBUFFER
fromDrawable: eaglLayer];
UIScreen *scr = [UIScreen mainScreen];
CGRect rect = scr.applicationFrame;
int width = CGRectGetWidth(rect); // Always 320
int height = CGRectGetHeight(rect); // Always 480 (status bar not displayed)
// Initialise the main code
m_applicationEngine->Initialise(width, height);
// This is the key c++ code invoked in Initialise call shown here indented
// Setup viewport
LowerLeft = ivec2(0,0);
ViewportSize = ivec2(width,height);
// Code to create vertex and index buffers not shown here
// …
// Extract width and height from the color buffer.
int width, height;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
GL_RENDERBUFFER_WIDTH_OES, &width);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
GL_RENDERBUFFER_HEIGHT_OES, &height);
// Create a depth buffer that has the same size as the color buffer.
glGenRenderbuffersOES(1, &m_depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES,
width, height);
// Create the framebuffer object.
GLuint framebuffer;
glGenFramebuffersOES(1, &framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES,
GL_RENDERBUFFER_OES, m_colorRenderbuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES,
GL_RENDERBUFFER_OES, m_depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
// Set up various GL states.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
// ...Back in initiWithCoder
// Do those things which need to happen when the main code is reset
m_applicationEngine->Reset();
// This is the key c++ code invoked in Reset call shown here indented
// Set initial camera position where
// eye=(0.7,8,-8), m_target=(0,4,0), CAMERA_UP=(0,-1,0)
m_main_camera = mat4::LookAt(eye, m_target, CAMERA_UP);
// ...Back in initiWithCoder
[self drawView: nil];
m_timestamp = CACurrentMediaTime();
// Create timer object that allows application to synchronise its
// drawing to the refresh rate of the display.
CADisplayLink* displayLink;
displayLink = [CADisplayLink displayLinkWithTarget:self
selector:@selector(drawView:)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
}
return self;
}
- (void) drawView: (CADisplayLink*) displayLink
{
if (displayLink != nil) {
// Invoke main rendering code
m_applicationEngine->Render();
// This is the key c++ code invoked in Render call shown here indented
// Do the background
glClearColor(1.0f, 1.0f, 1.0f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// A set of objects are provided to this method
// for each one (called visual below) do the following:
// Set the viewport transform.
glViewport(LowerLeft.x, LowerLeft.y, ViewportSize.x, ViewportSize.y);
// Set the model view and projection transforms
// Frustum(T left, T right, T bottom, T top, T near, T far)
float h = 4.0f * size.y / size.x;
mat4 modelview = visual->Rotation * visual->Translation * m_main_camera;
mat4 projection = mat4::Frustum(-1.5, 1.5, h/2, -h/2, 4, 14);
// Load the model view matrix and initialise
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLoadMatrixf(modelview.Pointer());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glLoadMatrixf(projection.Pointer());
// Draw the surface - code not shown
// …
// ...Back in drawView
[m_context presentRenderbuffer:GL_RENDERBUFFER];
}
}