« AndroidのOpenGL ESでマウスイベント | トップページ | AndroidのCanvas.getPixels(int[]) »

AndroidのOpenGL ESでマウスピッキング 〜完結編〜

AndroidのOpenGL ESでのマウスピッキングについに成功しました。

前回の物では、マウス座標と3D空間の関連付けを自前の関数でやっていたのですが、 それにバグがあり、視点の位置によってはうまくいかないことがありました。

そこで利用したのがこの関数。

GLU.gluUnProject

これがもう便利べんり。あとはあたり判定は実装済みだったので、置き換えて完了。

使い方は大体以下の通り。

    	int[] bits = new int[16];
    float[] model = new float[16];
    float[] proj = new float[16];
    gl.glGetIntegerv(gl.GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES, bits, 0);
    for(int i = 0; i < bits.length; i++){
    model[i] = Float.intBitsToFloat(bits[i]);
    }
    ((GL11)gl).glGetIntegerv(gl.GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES, bits, 0);
    for(int i = 0; i < bits.length; i++){
    proj[i] = Float.intBitsToFloat(bits[i]);
    }
   
    float[] ret = new float[3];
    GLU.gluUnProject((float)curX, (float)curY, 0f, model, 0, proj, 0, new int[]{0, 0, getWidth(), getHeight()}, 0, ret, 0);
    int x = (int)(ret[0] * 0x10000);
    int y = (int)(ret[1] * 0x10000);
    int z = (int)(ret[2] * 0x10000);

これでx、y、zにクリックされた点の座標が格納されるので、それとカメラ位置を通る 直線の式を計算し、それがポリゴンと衝突するかを判定すればOK

以下あたり判定のソース

package net.chephes.opengl;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.opengles.GL10;

import net.chephes.math.Matrix3D;

public class Plane{
    protected ByteBuffer  mIndexBuffer;
    protected IntBuffer   mVertexBuffer;
    protected int x, y, z;
    protected int rotateX, rotateY, rotateZ;
    protected int width, height;

    protected int one = 0x10000;
    protected int vertices[] = {
           -one, one, 0,
            one, one, 0,
            one,  -one, 0,
           -one,  -one, 0,
        };
       
    protected byte indices[] = {
            0, 1, 2,    2, 3, 0
    };
   
    public Plane(){
    this(1, 1);
    }
   
    public Plane(int width, int height){
    for(int i = 0; i < vertices.length; i+=3){
    vertices[i] *= width;
    vertices[i+1] *= height;
    }
    mVertexBuffer = GLUtil.createIntBuffer(vertices);
    mIndexBuffer = GLUtil.createByteBuffer(indices);
    }
   
    public void setX(int x){
    this.x = x;
    for(int i = 0; i < vertices.length; i+=3){
        mVertexBuffer.put(i, vertices[i] + x);
    }
    }
   
    public void setY(int y){
    this.y = y;
    for(int i = 1; i < vertices.length; i+=3){
        mVertexBuffer.put(i, vertices[i] + y);
    }
    }
   
    public void setZ(int z){
    this.z = z;
    for(int i = 2; i < vertices.length; i+=3){
        mVertexBuffer.put(i, vertices[i] + z);
    }
    }
   
    public void setRotateX(int rotateX){
    this.rotateX = rotateX;
    double theta = rotateX * Math.PI / 0x10000;
    double cos = Math.cos(theta);
    double sin = Math.sin(theta);
    for(int i = 1; i < vertices.length; i+=3){
    double y = (double)(vertices[i]) / 0x10000;
    double z = (double)(vertices[i+1]) / 0x10000;
    int flagY = y > 0 ? 1 : -1;
    double r = Math.sqrt(y * y + z * z);
        mVertexBuffer.put(i,
        flagY * (int)(r * cos * 0x10000) + this.y);
        mVertexBuffer.put(i+1,
        - flagY * (int)(r * sin * 0x10000) + this.z);
    }
    }
   
    public void setRotateY(int rotateY){
    this.rotateY = rotateY;
    double theta = rotateY * Math.PI / 0x10000;
    double cos = Math.cos(theta);
    double sin = Math.sin(theta);
    for(int i = 0; i < vertices.length; i+=3){
    double x = (double)(vertices[i]) / 0x10000;
    double z = (double)(vertices[i+2]) / 0x10000;
    int flagX = x > 0 ? 1 : -1;
    double r = Math.sqrt(x * x + z * z);
        mVertexBuffer.put(i,
        flagX * (int)(r * cos * 0x10000) + this.x);
        mVertexBuffer.put(i+2,
        - flagX * (int)(r *sin * 0x10000) + this.z);
    }
    }
   
    public void setRotateZ(int rotateZ){
    this.rotateZ = rotateZ;
    double theta = rotateZ * Math.PI / 0x10000;
    double cos = Math.cos(theta);
    double sin = Math.sin(theta);
    for(int i = 0; i < vertices.length; i+=3){
    double x = (double)(vertices[i]) / 0x10000;
    double y = (double)(vertices[i+1]) / 0x10000;
    int flagX = x > 0 ? 1 : -1;
    double r = Math.sqrt(x * x + y * y);
        mVertexBuffer.put(i,
        flagX * (int)(r * cos * 0x10000) + this.x);
        mVertexBuffer.put(i+1,
        - flagX * (int)(r * sin * 0x10000) + this.y);
    }
    }
   
    public int getX(){return x;}
    public int getY(){return y;}
    public int getZ(){return z;}
    public int getRotateX(){return rotateX;}
    public int getRotateY(){return rotateY;}
    public int getRotateZ(){return rotateZ;}
   
    public void render(GL10 gl){
    synchronized(gl){
            gl.glColor4f(1f, 1f, 1f, 1f);
            gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer);
            gl.glDrawElements(gl.GL_TRIANGLES, 6, gl.GL_UNSIGNED_BYTE, mIndexBuffer);
    }

    }
   
    private boolean isInside(int[] x, int[] y, int[] p, int[] q, int[] r){
    float v[][] = new float[3][3];
    float inv[][];
    for(int i = 0; i < 3; i++){
        v[i][0] = (float)(x[i] - y[i]) / 0x10000;
        v[i][1] = (float)(q[i] - p[i]) / 0x10000;
        v[i][2] = (float)(r[i] - p[i]) / 0x10000;
    }
    try{
        inv = Matrix3D.invert(v);
    }catch(Exception e){
    return false;
    }

    float t = 0, s = 0, u = 0;
    for(int i = 0; i < 3; i++){
    t += inv[0][i] * (float)(x[i] - p[i]) / 0x10000;
    s += inv[1][i] * (float)(x[i] - p[i]) / 0x10000;
    u += inv[2][i] * (float)(x[i] - p[i]) / 0x10000;
    }
    return s >= 0 && u >= 0 && s + u <= 1;
    }
   
    public boolean isInside(int[] x, int[] y){
    int[] p = new int[3];
    int[] q = new int[3];
    int[] r = new int[3];
    for(int i = 0; i < 3; i++){
    p[i] = mVertexBuffer.get(i);
    q[i] = mVertexBuffer.get(3 + i);
    r[i] = mVertexBuffer.get(6 + i);
    }
    boolean ret = isInside(x, y, p, q, r);
    for(int i = 0; i < 3; i++){
    p[i] = mVertexBuffer.get(6 + i);
    q[i] = mVertexBuffer.get(9 + i);
    r[i] = mVertexBuffer.get(0 + i);
    }
   
    return ret || isInside(x, y, p, q, r);
    }
   
}

isInside関数のint[] x、int[] yはそれぞれカメラの座標とクリックされた点の座標。 pqrはそれぞれ三角形の頂点を表す。

なおこのplaneクラスは高レベルオブジェクトとして紹介した物と同一で、 setRotationXしてから移動するとrotationが台無しになるというバグ付き。そのうち直します。

|

« AndroidのOpenGL ESでマウスイベント | トップページ | AndroidのCanvas.getPixels(int[]) »

Android」カテゴリの記事

コメント

すばらしいソリューションで感激です。

カメラと三角の間に、ほかのオブジェクトがある場合は対応できますか。
ぜひ教えてください。

投稿: | 2009年7月 3日 (金) 00時29分


セ ク っ て 稼 げ るなら旅したついでにヤる事にしたんだけど、これウメェわwww
女の家に泊まるから宿代いらないし、旅先で稼げるから財布もイラねーwwww

とりあえず女の子と約束して、家に泊めてもらって、ハ メ て、諭 吉ゲットwww
楽勝すぎてすげぇ笑えるwwwww
儲 か る旅って最高ーーーwwwwwww

http://yuzo.plusnote.net/jHR1gR6/

投稿: 自由だーーーー!!!!!! | 2009年8月17日 (月) 23時15分


3日お風呂入らずに来て!!って言われたから
我慢してその通りにしたんだが、行為を始めた途端に
チ ン カ スだらけの俺のテ ィ ン コを咥えてキレイにしてくれたわwwww

とりあえずされるがままでフィニッシュしたんだが、
ボーナス付けるとかイミフな事言われて8 万ゲットしたよ(^^;ラッキー♪

http://okane.d-viking.com/vU1SbXg/

投稿: くっちゃいの! | 2009年8月23日 (日) 08時14分


スカート脱がして足開かせたらパ ン ツからモ ロに具がはみ出てたよwwwww
既にず ぶ 濡 れだしwwwwwwwww

常にヤ ル 気まんまんすぎな女だし、仕方ないから即 挿 入してやったら
30分で女の子満足しちゃった(^^;

俺的にはもっと楽しみたかったけど、6 万もくれたし欲張っちゃダメだよな?w

http://ketsu.arctries.com/drgsr3z/

投稿: ちょwwwwwwww | 2009年9月 5日 (土) 23時48分


もうねーメンドすぎんだよねー(^^;
こっちが一生懸命腰カクカク動かすとかww
最近はもっぱら騎 乗で女にまかせてますwwwwwww

なんか女も実は自分で攻めたかったらしく、
好き放題させてやったら超 興 奮されちゃって報 酬も倍に上がったわwwwww

やっぱ楽 し て 稼 い で な ん ぼだよなwwwwwwww

http://love.scantyend.com/74wignc/

投稿: 楽してなんぼ!!!!!! | 2009年9月12日 (土) 09時49分


うっひゃーはひー!!!!!!!!
初 体 験 は是非巨 乳ちゃんと決めてたけど
ましゃかほんとになるとわ思ってなかったわwwwwwwww

てかリアルに俺の顔じゃ一 生 童 貞だろって自覚してたけど
これ楽勝すぎーーwwwwwwwwwwww

http://paipai.f-forward.net/pr8c6yr/

投稿: ふぇあっだぁおおおおあwwwwwwww | 2009年9月18日 (金) 22時01分


ぼろ儲けーーーー!!!!!wwwwwww
別にいらないけど、ノリでセルシオ買ってしまったしwwwwwwwww

とりま、今日も10マンゲット行ってきあーすwwwwww
帰りは勿論パチで遊ぶっすよーwww

http://mesu.korakoracola.net/r14w0ag/

投稿: ふぁーーーーだふ!! | 2009年9月27日 (日) 10時15分


週3くらいで適当にやってもう半年くらいなんだが
久しぶりに通帳見たら500マン超えてた!!!!( ゜д゜)ぽかーん

節約とかめんどいし金使いまくってんだけどそれでもこの勢いwwwwww

ちょっと明日車買いに言ってくるわwwwwwwwwww

http://nuko.yarashiyo.com/-woj2pg/

投稿: 持っち持ちー♪♪♪♪ | 2009年10月 1日 (木) 18時48分


乙 パ イの心地良さに勝るものはありまへんwwwwwww
勢いでこれ始めたけど童帝脱出できたしバイト代入るし
マジやってよかったーーーー(´;ω;`)

これ内緒だけど、童帝って言ったら貰える金倍増するから
毎回「童帝なんでよろしく♪」って言ってるぉwwwwwwwww

http://nuko.yarashiyo.com/-ptwvd5/

投稿: パパぱあパパぱあああいいいい!!!!!!! | 2009年10月 9日 (金) 06時58分


亀 頭寸止めくらいまくってカウパー出まくりwwwww
イ ク瞬間「ぁぁぁああああああ!!!!!」って大声出してしまった(^^;
やっぱ経験無し男はお姉様が丁寧にエスコートしてくれまつねwwwwww
てか今回の事で寸止めプ レ イにハマってしまったww またお願いしようwww

http://hole.hotohototo.net/w83d9vq/

投稿: カウパー多めwwww | 2009年10月14日 (水) 06時51分

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/486213/9129336

この記事へのトラックバック一覧です: AndroidのOpenGL ESでマウスピッキング 〜完結編〜:

« AndroidのOpenGL ESでマウスイベント | トップページ | AndroidのCanvas.getPixels(int[]) »