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」カテゴリの記事
- Androidでお電話(2008.02.22)
- AndroidSDK感想(2008.02.14)
- Androidがバージョンアップ!!(2008.02.14)
- まとめてみた-。(2008.01.31)
- Androidの非公式実機が登場!(2007.12.07)


コメント
すばらしいソリューションで感激です。
カメラと三角の間に、ほかのオブジェクトがある場合は対応できますか。
ぜひ教えてください。
投稿: | 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分