トップページ | 2007年12月 »

2007年11月

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が台無しになるというバグ付き。そのうち直します。

| | コメント (3) | トラックバック (0)

AndroidのOpenGL ESでマウスイベント

数日前からずっとチャレンジしていたOpenGL ESによるマウスイベントが、 ついにちょろっと動きました!

基本的なアイディアとしては、カメラの座標を通り、クリックされた方向に向かう 直線と、対象の三角形のある平面の交点の位置を取得するというもの。

具体的な手順は以下の通り

  • カメラ位置から注視点へ向かう直線の、z-x傾き、z-y傾きを得る
  • 視野角、アスペクト比から、クリックされた点とカメラ位置との相対z-x傾き、z-y傾きを計算する
  • tanの加法定理により、上記二つを合成し、絶対のz-x傾きz-y傾きを得る
  • 上で得られた傾きを持って、カメラ位置を通る直線を作る
  • カメラの位置ベクトルをxとし、その直線を通る、カメラ位置以外の任意の点の位置ベクトルをyとする
  • 当たり判定を行う三角形の三点の位置ベクトルをそれぞれp、q、rとする
  • p、q、rの三点からなる三角形内部を表すベクトルは、p+s(q-p)+u(r-p), s+u<=1, s>=0, u>=0であり、 設定したx、yを通る直線はt(y-x)+xで表されるので、これらを連立方程式として解く。

以下、x =(x1,x2,x3)とする


以上より、Aの逆行列を求めることで、sとtの値を求めることができる。

もとめたs,tの値がそれぞれ0以上であり、かつそれらの和が1以下であれば、 その三角形と直線は、共有点を持つことになる。


この方法で一応実装が8割ほど完了しました。以下動作ムービー

| | コメント (1) | トラックバック (0)

AndroidのLogクラス

Androidアプリをデバッグする際に非常に便利なのがLogクラスとLogCatですが、 たまにLogCatが全く反応しなくなってしまうときがあります。

eclipseを再起動してもなおるとも限らず、よくわからなくてとりあえず OSごと再起動する、なんてこともあるでしょう。

そんなときの為のメモ。

もしEmulatorが終了した等の理由でLogCatの反応がなくなったときは

  • エミュレータを終了する
  • eclipseを終了する
  • タスクマネージャー、またはアクティビティモニタからadbを強制終了
  • eclipse起動
  • エミュレータ起動

の順に復旧作業を行うと、無事またLogCatを利用することができます。

| | コメント (0) | トラックバック (0)

AndroidのOpenGLではまった後...

前回のソースですが、あのソース自体には特に問題がなさそうということが判明しました。 とりあえず現象の原因は、マルチスレッドによるテクスチャの読み込み処理でした。

現在は起動時に全てのテクスチャを読み込むように変更したのですが、 前段階では、テクスチャを描画しながら動的に読み出ししていた訳です。 そうすると、必然的にglTexImage2Dを実行する前にせっかくglBindTextureをしていても、 それとは別のスレッドでglBindTextureが呼び出されて、目的とは異なるテクスチャに 画像が読み出されることになると。以上が原因でした。

とりあえず抜け出せたので、それをもう少し発展させて何か完成したらまた 公開したいと思います。

| | コメント (0) | トラックバック (0)

AndroidのOpenGLでテクスチャにはまる

OpenGLの機能を使って、とりあえずWebからとってきた画像をテクスチャとして 利用しているんですが、なぜか一枚目のテクスチャが二枚目のテクスチャに上書きされてしまいます。 また、何かと思うように動いてくれなかったり‥。 バグなのかなんなのか不明。

//テクスチャ生成部
int a[] = new int[1];
gl.glGenTextures(1, a, 0);
gl.glBindTexture(gl.GL_TEXTURE_2D, a[0]);
gl.glTexParameterx (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT);
gl.glTexParameterx (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT);
int pixels[] = canvas.getPixels();
IntBuffer buffer = TexturePlane.createIntBuffer(pixels);
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA,
    canvas.getBitmapWidth(), canvas.getBitmapHeight(), 0,
gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, buffer);

//レンダリング部
gl.glEnable(gl.GL_TEXTURE_2D);
gl.glColor4f(1f, 1f, 1f, 1f);
gl.glBindTexture(gl.GL_TEXTURE_2D, texid);

gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer);
gl.glTexCoordPointer(2, gl.GL_FIXED, 0, mTextureBuffer);
gl.glDrawElements(gl.GL_TRIANGLES, 6, gl.GL_UNSIGNED_BYTE, mIndexBuffer);
gl.glDisable(gl.GL_TEXTURE_2D);

なにかわかる人は教えていただけると助かります。

| | コメント (0) | トラックバック (0)

AndroidのOpenGL ESで高レベルオブジェクト

少し前にPaperVision3Dを使って3D系の物を作っていたので、 OpenGL流の頂点がなんたらかんたら、という扱いが非常にめんどくさく感じる。

そこで、そこらへんをカプセル化して使えるオブジェクトを作ってみた。 イメージとしては、PaperVision3Dで言うところのPlaneが近い。

class TexturePlane{
    private ByteBuffer  mIndexBuffer;
    private IntBuffer   mVertexBuffer;
    private IntBuffer mTextureBuffer;
    private int texid;
    private int x, y, z;
    private int rotateX, rotateY, rotateZ;

    int one = 0x10000;
    int vertices[] = {
           -one, -one, 0,
            one, -one, 0,
            one,  one, 0,
           -one,  one, 0,
        };
       
    byte indices[] = {
            0, 1, 2,    2, 3, 0
    };
int textures[] = {
one, one,
0, one,
0, 0,
one, 0
};
   
    public TexturePlane(int texid){
    mVertexBuffer = createIntBuffer(vertices);
    mIndexBuffer = createByteBuffer(indices);
    mTextureBuffer = createIntBuffer(textures);
    this.texid = texid;
    }
   
    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;
    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 * Math.cos(rotateX * Math.PI / 0x10000) * 0x10000) + this.y);
        mVertexBuffer.put(i+1,
        - flagY * (int)(r * Math.sin(rotateX * Math.PI / 0x10000) * 0x10000) + this.z);
    }
    }
   
    public void setRotateY(int rotateY){
    this.rotateY = rotateY;
    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 * Math.cos(rotateY * Math.PI / 0x10000) * 0x10000) + this.x);
        mVertexBuffer.put(i+2,
        - flagX * (int)(r * Math.sin(rotateY * Math.PI / 0x10000) * 0x10000) + this.z);
    }
    }
   
    public void setRotateZ(int rotateZ){
    this.rotateZ = rotateZ;
    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 * Math.cos(rotateZ * Math.PI / 0x10000) * 0x10000) + this.x);
        mVertexBuffer.put(i+1,
        - flagX * (int)(r * Math.sin(rotateZ * Math.PI / 0x10000) * 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 int getTextureID(){return texid;}
   
    public void render(GL10 gl){
        gl.glColor4f(1f, 1f, 1f, 1f);

gl.glBindTexture(gl.GL_TEXTURE_2D, texid);

        gl.glTexCoordPointer(2, gl.GL_FIXED, 0, mTextureBuffer);
        gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer);
        gl.glDrawElements(gl.GL_TRIANGLES, 6, gl.GL_UNSIGNED_BYTE, mIndexBuffer);
    }
   
    public static IntBuffer createIntBuffer(int[] data){
    ByteBuffer buffer = ByteBuffer.allocateDirect(data.length * 4);
    buffer.order(ByteOrder.nativeOrder());
    IntBuffer ret = buffer.asIntBuffer();
    ret.put(data);
    ret.position(0);
   
    return ret;
    }

    public static FloatBuffer createFloatBuffer(float[] data){
    ByteBuffer buffer = ByteBuffer.allocateDirect(data.length * 4);
    buffer.order(ByteOrder.nativeOrder());
    FloatBuffer ret = buffer.asFloatBuffer();
    ret.put(data);
    ret.position(0);
   
    return ret;
    }
   
    public static ByteBuffer createByteBuffer(byte[] data){
    ByteBuffer buffer = ByteBuffer.allocateDirect(data.length);
    buffer.order(ByteOrder.nativeOrder());
    buffer.put(data);
    buffer.position(0);
    return buffer;
    }
}

使い方は、テクスチャを自前で生成して、そのテクスチャ番号を コンストラクタに与える。あとは適当にパラメータを設定して renderメソッドでレンダリング。

まだ拡大縮小をサポートしていなかったり、テクスチャを作るまでが 自前だったりするので、そこらへんを拡張予定。

| | コメント (1) | トラックバック (0)

AndroidのOpenGLで透視投影

とりあえずOpenGLをいろいろいじっているわけですが、 やっとこさ透視投影と陰面消去ができたのでお知らせします。

package net.chephes.graphics;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLU;

import android.app.Activity;
import android.os.Bundle;
import android.view.*;
import android.graphics.*;
import android.content.Context;
import android.content.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.Log;



public class Android3D extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        View view = new View3D(this);
        setContentView(view);
    }
   
    public static void trace(String message){
    Log.i("Android3D", message);
    }
}

class TexturePlane{
    private ByteBuffer  mIndexBuffer;
    private FloatBuffer   mVertexBuffer;
    private FloatBuffer mTextureBuffer;
    private int texid;
    private float x, y, z;

    float one = 1;
    float vertices[] = {
           -one, -one, 0,
            one, -one, 0,
            one,  one, 0,
           -one,  one, 0,
        };
       
    byte indices[] = {
            0, 1, 2,    2, 3, 0
    };
float textures[] = {
1, 1,
0, 1,
0, 0,
1, 0
};
   
    public TexturePlane(int texid){
    mVertexBuffer = createFloatBuffer(vertices);
    mIndexBuffer = createByteBuffer(indices);
    mTextureBuffer = createFloatBuffer(textures);
    this.texid = texid;
    }
   
    public void setX(float x){
    this.x = x;
    for(int i = 0; i < vertices.length; i+=3){
        mVertexBuffer.put(i, vertices[i] + x);
    }
    }
   
    public void setY(float y){
    this.y = y;
    for(int i = 1; i < vertices.length; i+=3){
        mVertexBuffer.put(i, vertices[i] + y);
    }
    }
   
    public void setZ(float z){
    this.z = z;
    for(int i = 2; i < vertices.length; i+=3){
        mVertexBuffer.put(i, vertices[i] + z);
    }
    }
   
    public float getX(){return x;}
    public float getY(){return y;}
    public float getZ(){return z;}
   
    public void render(GL10 gl){
        gl.glColor4f(1f, 1f, 1f, 0f);

gl.glBindTexture(gl.GL_TEXTURE_2D, texid);

        gl.glTexCoordPointer(2, gl.GL_FLOAT, 0, mTextureBuffer);
        gl.glVertexPointer(3, gl.GL_FLOAT, 0, mVertexBuffer);
        gl.glDrawElements(gl.GL_TRIANGLES, 6, gl.GL_UNSIGNED_BYTE, mIndexBuffer);
    }
   
    public static IntBuffer createIntBuffer(int[] data){
    ByteBuffer buffer = ByteBuffer.allocateDirect(data.length * 4);
    buffer.order(ByteOrder.nativeOrder());
    IntBuffer ret = buffer.asIntBuffer();
    ret.put(data);
    ret.position(0);
   
    return ret;
    }

    public static FloatBuffer createFloatBuffer(float[] data){
    ByteBuffer buffer = ByteBuffer.allocateDirect(data.length * 4);
    buffer.order(ByteOrder.nativeOrder());
    FloatBuffer ret = buffer.asFloatBuffer();
    ret.put(data);
    ret.position(0);
   
    return ret;
    }
   
    public static ByteBuffer createByteBuffer(byte[] data){
    ByteBuffer buffer = ByteBuffer.allocateDirect(data.length);
    buffer.order(ByteOrder.nativeOrder());
    buffer.put(data);
    buffer.position(0);
    return buffer;
    }
}

class View3D extends View{
private OpenGLContext glContext;
   
    private boolean isDraw = false;
    private TexturePlane plane, plane2;
   
    public View3D(Context context){
super(context);

glContext = new OpenGLContext(OpenGLContext.DEPTH_BUFFER);
GL10 gl = (GL10)(glContext.getGL());
       
        plane = new TexturePlane(createTexture(gl, loadImage(R.drawable.kirby_t, 128, 128)));
        plane.setZ(30);
        plane2 = new TexturePlane(createTexture(gl,
        loadImage(R.drawable.texture, 512, 512)));
        plane2.setZ(10);
       
isDraw = true;
Android3D.trace("start...");
}
   
    public int createTexture(GL10 gl, Canvas canvas){
int a[] = new int[1];
gl.glGenTextures(1, a, 0);
gl.glBindTexture(gl.GL_TEXTURE_2D, a[0]);

IntBuffer buffer = TexturePlane.createIntBuffer(canvas.getPixels());

gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA,
canvas.getBitmapWidth(), canvas.getBitmapHeight(), 0,
gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, buffer);

return a[0];
    }

public Canvas loadImage(int fileid, int width, int height) {
Resources r = this.getContext().getResources();
Bitmap bitmap = Bitmap.createBitmap(width, height, true);
Drawable drawable = r.getDrawable(fileid);
Canvas canvas = new Canvas(bitmap);

drawable.setBounds(0, 0, width, height);
drawable.draw(canvas);

return canvas;
}

private void setPerspective(GL10 gl, float fovy, float aspect, float zNear, float zFar){
        gl.glMatrixMode(gl.GL_PROJECTION);
        gl.glLoadIdentity();
        GLU.gluPerspective(gl, fovy, aspect, zNear, zFar);
}

private void setCamera(GL10 gl, float x, float y, float z, float vx, float vy, float vz){
        gl.glMatrixMode(gl.GL_MODELVIEW);
        gl.glLoadIdentity();
        GLU.gluLookAt(gl, x, y, z,
        vx, vy, vz,
        0f, 1f, 0f);

}

    @Override
    protected void onDraw(Canvas canvas) {
    if(!isDraw){ return;}

GL10 gl = (GL10)(glContext.getGL());
glContext.waitNative(canvas, this);
        gl.glViewport(0, 0, getWidth(), getHeight());
       
        setPerspective(gl, 10.0f, (float)getWidth() / getHeight(), 1f, 100f);
        setCamera(gl, 10f, 20f, 70f, 0, 0, 0);
       
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);

gl.glEnableClientState(gl.GL_VERTEX_ARRAY);
        gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY);
        gl.glEnable(gl.GL_TEXTURE_2D);
        gl.glDisable(gl.GL_CULL_FACE);

        gl.glEnable(gl.GL_DEPTH_TEST);
plane.render(gl);
        plane2.render(gl);
        gl.glDisable(gl.GL_DEPTH_TEST);

glContext.waitGL();
exe();
invalidate();
    }
   
    private void exe(){
plane.setZ(plane.getZ() - 0.1f);
    }
}

注目すべきはonDraw関数の中身。まず

glViewport

で表示箇所を設定し、

GLU.gluPerspective

で透視投影行列を設定しています。 そのとき、

glMatrixMode(GL10.GL_PROJECTION);

を呼び出して 投影用の行列を選択するのを忘れずに。 そして今度はカメラの設定。

glMatrixMode(GL10.GL_MODELVIEW);

で 行列を選んで、

GLU.gluLookAt

でカメラ位置を設定。 始めの3つのfloatはカメラの位置、次の3つは見る場所、最後の3つは どの方向を上とするか。 それができたらとりあえず

glClear

でいろいろ消して、

glEnable(GL10.GL_DEPTH_TEST);
//...処理
glDisable(GL10.GL_DEPTH_TEST);

の間でオブジェクトをいろいろ追加。最後は

waitGLを呼び出してレンダリング
完了。

まぁだいたいこんな流れです。OpenGLがシェルのような対話型の APIであることと、内部的に持ってる行列を選んだり、 どれを描くかを

glEnable

で選んだりするというのに気付くと 大分理解しやすいかと思います。

| | コメント (9) | トラックバック (0)

AndroidでSystem.out.println

アプリを開発する上で書かせないのがコンソール出力ですが、Androidでは いつもどおり

System.out.println("hoge");
と書いても出力されません。

そこで、Androidではandroid.util.Logクラスを利用して出力します。

eclipse上で結果を見るときはWindow > Show ViewからAndroidを選び、LogCatを表示するように 設定するだけで見れます。

動作イメージは以下

| | コメント (0) | トラックバック (0)

Androidでゲーム第二弾 ブロック崩し

これはあつい。Schlechte Weltさんがブロック崩しを作ったらしい。 これはもう動かしてみるしか無い、ということでサンプルムービー。

あとニュースといえば、NESエミュが動いたらしいですね。ソースも公開予定らしいので、 勉強になりそう。

| | コメント (1) | トラックバック (0)

AndroidのOpenGL ESでテクスチャ

OpenGL ES系のネタ。せっかくテクスチャも張れるということなので、 ためしに張ってみました。画像読み込み関連はいつものごとくSchlechte Weltさんを参考にしました。

以下サンプルソース

package net.chephes.graphics;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.os.Bundle;
import android.view.*;
import android.graphics.*;
import android.content.Context;
import android.content.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;


public class Android3D extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        View view = new View3D(this);
        setContentView(view);
    }
}

class View3D extends View{
private float angle = 0;
private OpenGLContext glContext;
    private ByteBuffer  mIndexBuffer;
    private IntBuffer   mVertexBuffer;
    private IntBuffer   mColorBuffer;
    private FloatBuffer mTextureBuffer;
    private int texid;
   
    private boolean isDraw = false;
   
    int one = 0x10000;
    int vertices[] = {
           -one, -one, -one,
            one, -one, -one,
            one,  one, -one,
           -one,  one, -one,
        };
       
    int colors[] = {
              0,    0,    0,  one,
            one,    0,    0,  one,
            one,  one,    0,  one,
              0,  one,    0,  one,
        };
    byte indices[] = {
            0, 1, 2,    2, 3, 0
    };

    public View3D(Context context){
super(context);

    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
    vbb.order(ByteOrder.nativeOrder());
    mVertexBuffer = vbb.asIntBuffer();
mVertexBuffer.put(vertices);
mVertexBuffer.position(0);

    ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
    cbb.order(ByteOrder.nativeOrder());
mColorBuffer = cbb.asIntBuffer();
mColorBuffer.put(colors);
mColorBuffer.position(0);

mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
mIndexBuffer.put(indices);
mIndexBuffer.position(0);
glContext = new OpenGLContext(0);
GL10 gl = (GL10)(glContext.getGL());
        gl.glEnable(gl.GL_TEXTURE_2D);
int a[] = new int[1];
gl.glGenTextures(1, a, 0);
texid = a[0];
gl.glBindTexture(gl.GL_TEXTURE_2D, texid);

Canvas canvas = loadImage(R.drawable.kirby, 128, 128);
a = canvas.getPixels();
ByteBuffer tb = ByteBuffer.allocateDirect(a.length * 4);
tb.order(ByteOrder.nativeOrder());
IntBuffer ib = tb.asIntBuffer();
ib.put(a);
ib.position(0);

gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, 128, 128, 0,
gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, ib);

tb = ByteBuffer.allocateDirect(256);
float b[] = {0, 0,
1, 0,
1, 1,
0, 1};
tb.order(ByteOrder.nativeOrder());
mTextureBuffer = tb.asFloatBuffer();
mTextureBuffer.put(b);
mTextureBuffer.position(0);
isDraw = true;
}

public Canvas loadImage(int fileid, int width, int height) {
Resources r = this.getContext().getResources();
Bitmap bitmap = Bitmap.createBitmap(width, height, true);
Drawable drawable = r.getDrawable(fileid);
Canvas canvas = new Canvas(bitmap);

drawable.setBounds(0, 0, width, height);
drawable.draw(canvas);

return canvas;
}

    @Override
    protected void onDraw(Canvas canvas) {
    if(!isDraw){ return;}

GL10 gl = (GL10)(glContext.getGL());
glContext.waitNative(canvas, this);

gl.glClear(gl.GL_COLOR_BUFFER_BIT);

        gl.glMatrixMode(gl.GL_MODELVIEW);
        gl.glLoadIdentity();
        gl.glTranslatef(0, 0, -3.0f);
        gl.glScalef(0.8f, 0.8f, 0.8f);
        gl.glRotatef(angle += 1.2f, 1, 1, 0);

        gl.glColor4f(1f, 1f, 1f, 1f);
        gl.glEnableClientState(gl.GL_VERTEX_ARRAY);
        gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY);

    gl.glTexEnvx(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE);

        gl.glDisable(gl.GL_CULL_FACE);

        gl.glTexCoordPointer(2, gl.GL_FLOAT, 0, mTextureBuffer);
        gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer);
        gl.glDrawElements(gl.GL_TRIANGLES, 6, gl.GL_UNSIGNED_BYTE, mIndexBuffer);
invalidate();
glContext.waitGL();

    }
}

どうやってもテクスチャがはれずに大ハマリしました。とりあえず報告なので、 細かい解説はのちのちやります。リソースは各自適当な物を用意してください。

また、上部にタイトルバーが若干のこってておかしいですが、それの直し方を 知ってる人がいたら、教えてくれると助かります。

11/18追記
requestWindowFeature(Window.FEATURE_NO_TITLE);
でタイトルバー問題は解決。ありがとうs_weltさん

| | コメント (2) | トラックバック (0)

Androidで作られたゲーム第一号

Schlechte WeltさんのGridViewで爆弾探すで、 多分日本で初めてのAndroidでできたゲームが完成した模様。

これを見たとき「マインスイーパ作れるじゃん!」と思いついた。 というわけで作ってみたがなかなか難しい。 現状は次の画像のとおり。いろいろおかしな部分はあるが一応動くには動く。

残念ながらソースの公開は無いそうだが、彼はGridViewと呼ばれるViewクラスのサブクラスを 使ってマインスイーパーを作ったそうだ。GridViewクラスは高レベルの画像表示用のクラスで、 大体イメージとしては画像をタイルのように並べることができるといった感じである。

これからもAndroid製のアプリを見つけたら逐次報告していきます。

| | コメント (0) | トラックバック (0)

AndroidのOpenGLで3D描画

AndroidではOpenGLを使って3Dを描画できるらしいので、早速使ってみた

以下はただ四角いポリゴンを書くだけの簡単なサンプルです。

OpenGLに関してはwisdomsoftのOpenGL入門を参考にしました。

package net.chephes.graphics;

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

import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.graphics.*;
import android.content.Context;

public class Android3D extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(new View3D(this));
    }
}

class View3D extends View{
private float angle = 0;
private OpenGLContext glContext;
    private ByteBuffer  mIndexBuffer;
    private IntBuffer   mVertexBuffer;
    private IntBuffer   mColorBuffer;
    int one = 0x10000;
    int vertices[] = {
           -one, -one, -one,
            one, -one, -one,
            one,  one, -one,
           -one,  one, -one,
        };
       
    int colors[] = {
              0,    0,    0,  one,
            one,    0,    0,  one,
            one,  one,    0,  one,
              0,  one,    0,  one,
        };
    byte indices[] = {
            0, 1, 2,    2, 3, 0
    };

    public View3D(Context context){
super(context);
glContext = new OpenGLContext(0);
    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
    vbb.order(ByteOrder.nativeOrder());
    mVertexBuffer = vbb.asIntBuffer();
mVertexBuffer.put(vertices);
mVertexBuffer.position(0);

    ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
    cbb.order(ByteOrder.nativeOrder());
mColorBuffer = cbb.asIntBuffer();
mColorBuffer.put(colors);
mColorBuffer.position(0);
mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
mIndexBuffer.put(indices);
mIndexBuffer.position(0);
}

    @Override
    protected void onDraw(Canvas canvas) {
GL10 gl = (GL10)(glContext.getGL());
glContext.waitNative(canvas, this);

gl.glClear(gl.GL_COLOR_BUFFER_BIT);

        gl.glMatrixMode(gl.GL_MODELVIEW);
        gl.glLoadIdentity();
        gl.glTranslatef(0, 0, -3.0f);
        gl.glScalef(0.5f, 0.5f, 0.5f);
        gl.glRotatef(angle += 1.2f, 0, 0, 1);

        gl.glColor4f(0.7f, 0.7f, 0.7f, 1.0f);
        gl.glEnableClientState(gl.GL_VERTEX_ARRAY);
        gl.glEnableClientState(gl.GL_COLOR_ARRAY);
        gl.glDisable(gl.GL_CULL_FACE);

gl.glFrontFace(gl.GL_CW);
        gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer);
        gl.glColorPointer(4, gl.GL_FIXED, 0, mColorBuffer);
        gl.glDrawElements(gl.GL_TRIANGLES, 6, gl.GL_UNSIGNED_BYTE, mIndexBuffer);
invalidate();
glContext.waitGL();
    }
}

OpenGLを以前から利用している人にとっては簡単そう。僕は今回が初めての利用だったので、 いろいろわからずとりあえずこれだけは書いてみた、という感じ。

3Dに関してはなかなか面白そうなので、また別のサンプルを作ったらソースを公開します。

| | コメント (1) | トラックバック (0)

Androidでメインループ

友人のSchlechte Weltさんのところで、 Androidでループする方法が紹介されている。

やはりループは必須である。ということでループの仕方。 普通の携帯アプリとかならwhile()ループを使って実現すると思う。 けどAndroidのサンプルを見てるとHandlerを使うのが普通みたい。 今回のはサンプルにあるSnakeと同様にHandlerを拡張して使っている。

どうやらHandlerと呼ばれるクラスを自作するといいらしい。

なるほどー。

で、そのHandlerのhandleMessageのなかで、ループさせる関数update()、およびinvalidate()を 呼び出していると。invalidate()を実行するとどうやら描画を再度行うそうだ。iアプリで言うところの repaint()みたいなもんか。

| | コメント (0) | トラックバック (0)

AndroidでWebページサムネイル

Androidのwebkitを使ってwebページサムネイル画像を作ってみる。

ポイントは、WebViewをaddContentViewして表示している状態にすること。

でもそれだとサムネイルの意味が無いので、

addContentView(view, new ViewGroup.LayoutParams(1, 1));

みたいに最後にちょろっと入れる感じで問題ない。

import android.webkit.WebView;
import android.content.Context;
import android.graphics.Bitmap;

public class ThumbCreator {

    public WebView web;
   
    public ThumbCreator(Context context){
        web = new WebView(context);
    }
   
    public void loadUrl(String url){
        web.loadUrl(url);
    }
   
    public Bitmap getThumbnail(int width, int height, float scale, boolean hasAlpha){
        return web.createSnapshot(width, height, scale, hasAlpha);
    }
}

| | コメント (0) | トラックバック (0)

Androidでドラッグイベント取得

Androidは基本的にタッチパネルも使える模様。しかも、使い方は一般的な マウスイベントの取り方とあんまり変わらないので超便利。

package net.chephes.androidtest;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;

import java.net.*;
import java.io.*;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.*;

public class AndroidTest extends Activity {
    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(new MyView(this));
    }
   
    public class MyView extends View {
        Bitmap mBitmap;
        Canvas mCanvas;
        private final Paint mPaint;
        private boolean curDown;
        private Drawable d;
        private int offsetX, offsetY;
        private int curX, curY;
        private int imgX, imgY;
        private int imgW, imgH;
      
        public MyView(Context c) {
            super(c);
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setARGB(255, 255, 255, 255);
            d = loadImage("http://www.google.com/images/google_sm.gif");
        }

        public Drawable loadImage(String str){
            Drawable d = null;
            try{
                URL url = new URL(str);
                HttpURLConnection http = (HttpURLConnection)url.openConnection();
                http.setRequestMethod("GET");
                http.connect();
                InputStream in = http.getInputStream();
                d = Drawable.createFromStream(in, "a");
                in.close();
            }catch(Exception e){
            }
            imgX = 20;
            imgY = 20;
            imgW = 143;
            imgH = 59;
            d.setBounds(imgX, imgY, imgX + imgW, imgY + imgH);
            return d;
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            int curW = mBitmap != null ? mBitmap.width() : 0;
            int curH = mBitmap != null ? mBitmap.height() : 0;
            if (curW >= w && curH >= h) {
                return;
            }
          
            if (curW < w) curW = w;
            if (curH < h) curH = h;
          
            Bitmap newBitmap = Bitmap.createBitmap(curW, curH, false);
            Canvas newCanvas = new Canvas();
            newCanvas.setDevice(newBitmap);
            if (mBitmap != null) {
                newCanvas.drawBitmap(mBitmap, 0, 0, null);
            }
            mBitmap = newBitmap;
            mCanvas = newCanvas;
        }
      
        @Override
        protected void onDraw(Canvas canvas) {
            if (mBitmap != null) {
                canvas.drawBitmap(mBitmap, 0, 0, null);
                d.draw(canvas);
            }
        }

        @Override
        public boolean onMotionEvent(MotionEvent event) {
            int action = event.getAction();
            curX = (int)event.getX();
            curY = (int)event.getY();
            if(action == MotionEvent.ACTION_DOWN){
                offsetX = curX - imgX;
                offsetY = curY - imgY;
                curDown = true;
            }else if(action == MotionEvent.ACTION_UP){
                curDown = false;
            }else if(curDown && action == MotionEvent.ACTION_MOVE){
                imgX = curX - offsetX;
                imgY = curY - offsetY;
                d.setBounds(imgX, imgY, imgX + imgW, imgY + imgH);
                invalidate();
            }
            return true;
        }
      
    }
}

とりあえず動くのができたのでアップしてみる。

いろいろと試しまくっているので、いらないimport文とか結構ありそうなので、 なんか見つけたら教えてください。

11/14追記

上記のプログラムは若干挙動に問題があります。画像以外の箇所をドラッグしても、画像が移動してしまいます。近いうちに修正版をアップするので、お待ちください。

| | コメント (0) | トラックバック (1)

Androidでブラウザを作る

Androidのライブラリにはwebkitを使った物があるそうなので、試しに使ってみる。

package com.chephes;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;

public class WebViewer extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        WebView view = new WebView(this);
        view.loadUrl("http://www.google.co.jp");
        setContentView(view);
    }
}

たったこんだけの記述でブラウザができるとは‥。少し読み込みが遅いので、しばらく待ってください。

どうやら高レベルのGUIたちがViewとか言われる奴らっぽい。そいつらを使うと簡単に 高機能な物が作れそう。基本の使い方はnew→setContentViewで設定。コンストラクタの引数には contentすなわちActivityを渡す。

しかもWebViewerのすごいところが、自分でサムネイル画像を生成できるらしい。すんげーなおい。

| | コメント (0) | トラックバック (1)

Androidでネットから画像を読み込んで表示

AndroidでネットからHTTPリクエストを使って画像を取得し、それをキャンバスに描くサンプル。

比較的すんなりできた。今のところはやり方がわからないので、サイズを自分で指定している。

11/14追記 nesukeさんがサイズの取得法を教えてくれました。コメント欄を参照package net.chephes;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.content.Context;
import android.graphics.*;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;

public class AndroidDraw extends Activity {

    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(new SampleView(this));
    }
   
    private static class SampleView extends View{
        private Drawable d;

        public SampleView(Context context) {
            super(context);
            d = loadImage("http://www.google.com/images/google_sm.gif");
        }
       
        public Drawable loadImage(String str){
        Drawable d = null;
        try{
        URL url = new URL(str);
        HttpURLConnection http = (HttpURLConnection)url.openConnection();
        http.setRequestMethod("GET");
        http.connect();
        InputStream in = http.getInputStream();
        d = Drawable.createFromStream(in, "a");
                in.close();
        }catch(Exception e){
        }
        d.setBounds(20, 20, 143, 59);
        return d;
        }
       
        @Override protected void onDraw(Canvas canvas) {
        d.draw(canvas);
        }
    }
}

アンドロイドすんげーな。ポイントはDrawableクラスのcreateFromStreamで、第二引数は リソース名らしいが、今のところよくわからないので適当。とりあえず表示されたので 気にしない。

| | コメント (2) | トラックバック (0)

Androidでネット接続 HTTP通信編

Android系ネタ

Android上でHTTP通信をすることに成功しました。

やり方はjavaでHTTP通信をするのとほぼ同じ方式。

百聞は一見にしかずということで、以下ソース

package net.chephes.androidtest;

import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
import java.net.*;
import java.io.*;

public class AndroidTest extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        TextView tv = new TextView(this);
        try{
            URL url = new URL("http://www.google.co.jp");
            HttpURLConnection http = (HttpURLConnection)url.openConnection();
            http.setRequestMethod("GET");
            http.connect();
            InputStream in = http.getInputStream();
            byte b[] = new byte[1024];
            in.read(b);
            in.close();
            http.disconnect();
            tv.setText(new String(b));
        }catch(Exception e){
            tv.setText(e.toString());
        }
        setContentView(tv);
    }
}

参考にしたのはJava で HTTP クライアントを作ってみよう (2)

ほぼ完全にjavaですね。iアプリとかと違って独自の通信方式ではない模様。

すると、大分いろんな物が作れそうな予感

| | コメント (1) | トラックバック (0)

AndroidSDKをインストールしてみる

GoogleのAndroidプラットフォーム SDK公開

これを聞いたからには、とりあえずインストールしてみる。 まずここからダウンロード

  • 同梱されていたドキュメントによると、とりあえず適当な箇所に配置して、toolsにパスを通す らしい
  • 導入にはeclipseが必須みたいなので、持ってない方はこちらからインストールしておく。
  • eclipseを起動し、Help > Software Updates > Find and Install...を選ぶと、ダイアログが出てくるので そこではSearch for new features to install (新しいのをインストール)を選択し次へ。
  •  

  • New Remote Site(新しいサイト)を選び、出てくるダイアログにはNameは適当に入力、 URLにはhttps://dl-ssl.google.com/android/eclipse/と入力する。
  • この作業が終わると、リストに上記のサイトが追加されるので、Finish(完了)を選ぶ。
  • しばらく放っておくと、eclipseがプラグインを見つけてくるので、Androidにチェックを入れて次へ進む。そしたらとりあえず同意して完了する
  • で次に出てくるダイアログではInstallAll(全部インストール)を実行し、終わったらeclipseを再起動する。
  • 再起動したら、eclipseにAndroidSDKのディレクトリを入力する。入力方法はWindow→Preference(設定?)終わったら適用する。※Macはeclipse→Preference

おめでとうございます。これでAndroidのインストールは完了です。

次はお待ちかね、HelloWorldだよ!

  • File > New > Projectより新しいAndroidプロジェクトを作成。
  • Project name, package name, Activity name, Application nameを決める。
  • そうするとメインのクラスとR.javaというファイルができる。

ちなみにmainの中身はこんな感じ

package net.chephes.androidtest;

import android.app.Activity;
import android.os.Bundle;

public class AndroidTest extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
    }
}

これを改造するらしい

import android.widget.TextView;
public class AndroidTest extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        TextView tv = new TextView(this);
        tv.setText("Hello, Android");
        setContentView(tv);
    }
}

こんな風に

次はいよいよ実行。RunからAndroid Applicationを選んで、project、Activityを選んだら実行。

ををををををおおおおお!!!!、動きましたね!!

| | コメント (0) | トラックバック (0)

ActionScript3.0のデバッグにFirebugを利用する

ActionScript3.0で開発を行っているときに最も苦労するのがデバッグであるが、 ここで非常に便利なのがFireBugである。

本来FireBugはjavascriptのデバッグ用であるが、これをActionScriptからExternalInterface経由で呼び出すことができる。具体的な利用法は以下の通り。

import flash.external.ExternalInterface;

ExternalInterface.call("console.log", 10, "abc");

これでトレースの代わりとして用いることができる。ここら辺をライブラリ化して便利に使えるようにしたのがThunderBoltである。まだ利用したことはないが、どうやら便利らしい。

| | コメント (0) | トラックバック (0)

ActionScriptでテルミン

最近大人の科学でテルミンを買ってみたら、マトリョミンとかっていう マトリョーシカにテルミンを内蔵したマトリョミンっていうのが載ってた。
Gizmodo Japan
テルミン+マトリョーシカ=マトリョミン(動画)
それに触発されて Webカメラを利用してテルミンっぽい感じに動くActionScriptを作ってみた。

大人の科学マガジンVol.17 テルミン (Gakken Mook) 大人の科学マガジンVol.17 テルミン (Gakken Mook)

著者:大人の科学マガジン編集部
販売元:学習研究社
Amazon.co.jpで詳細を確認する

このフラッシュは赤い物に反応するので、片手に赤い物を携えて演奏してください。

重いのでリンクに張り替え

特定の周波数成分の音を出す為に Onegameさんのページと、その先のhow to make actionscript 3 play generated pcm wave dataのライブラリ を参考にした。

ソースは以下に記述

Theremin.as

ThereminProvider.as

| | コメント (0) | トラックバック (0)

KViewer はてぶのhotentryを机の上でばらまいたように閲覧する

サムネイル作成APIとFlex2とjavascriptの連携を利用して、
はてぶを読み込んでそのサムネイルをばらまく
Flashを作ってみた。

サムネイルをドラッグすると場所を移動できて、
ダブルクリックでそのページを開く仕様。

サムネイルができてません的なメッセージがでたら
リロードしてください。

上の画像をクリックしてページへ飛びます

要望等ご意見ありましたらコメント欄にどうぞ

| | コメント (0) | トラックバック (0)

トップページ | 2007年12月 »