0

2D オブジェクトのみを含む OpenGL ES 2.0 シーンがあります。次の 2 つの行列を適用しています。

width = 600;

CC3GLMatrix * projection = [CC3GLMatrix matrix];
height = width * self.frame.size.height / self.frame.size.width;
[projection populateFromFrustumLeft:-width/2 andRight:width/2 andBottom:-height/2 andTop:height/2 andNear:4 andFar:10];
glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);

CC3GLMatrix * modelView = [CC3GLMatrix matrix];
[modelView populateFromTranslation:CC3VectorMake(xTranslation ,yTranslation, -7)];
glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);

タッチ開始メソッドでは、タッチポイント座標を OpenGL ES 2.0 シーン座標にマッピングしようとしています。

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"Touches Began");
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self];

float differentialWidth = (768-width)/2; //Accounts for if OpenGL view is less than iPad width or height.
float differentialHeight = (1024-height)/2;
float openGlXPoint = ((touchPoint.x - differentialWidth) - (width/2));
float openGlYPoint = ((touchPoint.y - differentialHeight) - (width/2));
NSLog(@"X in Scene Touched is %f", openGlXPoint);

CGPoint finalPoint = CGPointMake(openGlXPoint, openGlYPoint);

for (SquareObject * square in squareArray) {
    if (CGRectContainsPoint(stand.bounds, finalPoint)) {
        NSString * messageSquare = (@"Object name is %@", square.Name);
        UIAlertView *message = [[UIAlertView alloc] initWithTitle:@"Touched"
                                                          message:messageSquare
                                                         delegate:nil
                                                cancelButtonTitle:@"OK"
                                                otherButtonTitles:nil];
        [message show];
    }
}
}

このコードは、OpenGL 座標を返すという点で機能します。たとえば、画面の中央をクリックすると、0,0 が返されます。ただし、問題は (私が思うに) シーンのズーム スケールを何らかの形で考慮する必要があることです。150,0 の原点で描画されたオブジェクトは、iPad でクリックした場所 (112,0 を返す) と一致しないためです。上記のコードを使用します)。誰かがこれを修正する方法を提案できますか?

ありがとう !

4

1 に答える 1

2

これは 2D アプリではやり過ぎかもしれませんが、3D アプリで通常これを行う方法は、「遠点」と「近点」の 2 つのベクトルを作成し、GLKUnproject またはその他の数学ライブラリを使用して両方をアンプロジェクションすることです。必要に応じて、遠点から近点を差し引いてオブジェクト座標の光線を取得します。これを使用して、投影やモデル ビュー マトリックスを気にすることなく、ジオメトリのみを使用して交差をテストできます。これが例です

bool testResult;
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);

GLKVector3 nearPt = GLKMathUnproject(GLKVector3Make(tapLoc.x, tapLoc.y, 0.0), modelViewMatrix, projectionMatrix, &viewport[0] , &testResult);

GLKVector3 farPt = GLKMathUnproject(GLKVector3Make(tapLoc.x, tapLoc.y, 1.0), modelViewMatrix, projectionMatrix, &viewport[0] , &testResult);

farPt = GLKVector3Subtract(farPt, nearPt);
//now you can test if the farPt ray intersects the geometry of interest, perhaps
//using a method like the one described here http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf

あなたの場合、projectionMatrix はおそらく 2 次元で作業しているため ID であり、modelViewMatrix はオブジェクトに適用したスケール、変換、回転、せん断などです。

また、ご存じないかもしれませんが、あなたが尋ねていることは「ピッキング」と呼ばれることが多く、「OpenGL ピッキング」と入力すると、Google に「OpenGL ピッキング」と入力すると、以前に「座標を変換します。」

于 2013-10-18T17:05:21.567 に答える