2010年6月30日水曜日

影行列をJOGLでやってみた

動機
これに影とかつけたいなー.
OpenGLでどうやるんだろうー.影行列っていうのをつかうみたいだなー.
解説サンプルが載ってる.
JOGLでやってみよう!.


感謝
解説サンプル掲載ありがとうございます!



やってみた
JOGLの環境については以前のモノ等を参照してください.

上記サイトのサンプルの設定
光源位置(7, 5, 5)、平面の方程式 y + 1 = 0とした時に、
物体を描画し、平面「y + 1 = 0」に影を描画せよ。

これをJOGLでやってみたい.


ただここでは描画対象を球に変更し,光源を高さ(y)5の平面上の半径8の円周上でグルグル回しています.
tの上限とか見てないぐらい'てきとー'

コード
import java.awt.Frame;
import java.awt.Insets;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.FloatBuffer;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.media.opengl.glu.GLUquadric;
import com.sun.opengl.util.FPSAnimator;

public class Sample implements GLEventListener {

private final static int SCREEN_X = 640;
private final static int SCREEN_Y = 480;
float ShadowMatrix_ary[] = new float[16];
float plane_ary[] = { 0.0f, 1.0f, 0.0f, 1.0f };
float light_pos_ary[] = { 8.0f, 5.0f, 0.0f, 1.0f };
FloatBuffer light_pos = FloatBuffer.wrap(light_pos_ary);
float OffsetFactor = 1.0f;
float OffsetUnit = 0.0f;
float floorcolor_ary[] = { 0.8f, 0.8f, 0.8f, 1.0f };
FloatBuffer floorcolor = FloatBuffer.wrap(floorcolor_ary);
float red_ary[] = { 0.8f, 0.2f, 0.2f, 1.0f };
FloatBuffer red = FloatBuffer.wrap(red_ary);
private FPSAnimator animator;
private double t;

public Sample() {
Frame frame = new Frame("Sample JOGL");
frame.setVisible(true);
Insets ins = frame.getInsets();
frame.setSize(SCREEN_X + ins.left + ins.right, SCREEN_Y + ins.top
+ ins.bottom);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
GLCanvas canvas = new GLCanvas();
frame.add(canvas);
canvas.addGLEventListener(this);
canvas.setBounds(ins.left, ins.top, SCREEN_X, SCREEN_Y);
}

public void init(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
{
gl.glEnable(GL.GL_LIGHTING);
gl.glEnable(GL.GL_LIGHT0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_pos);
gl.glEnable(GL.GL_DEPTH_TEST);
}
CalcShadowMatrixf(plane_ary, light_pos_ary, ShadowMatrix_ary);
animator = new FPSAnimator(drawable, 60);
animator.start();
t = 0.0f;
}

public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
GL gl = drawable.getGL();
GLU glu = new GLU();
gl.glViewport(0, 0, w, h);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(30.0, (double) w / (double) h, 1.0, 100.0);
gl.glMatrixMode(GL.GL_MODELVIEW);
}

public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
GLU glu = new GLU();
light_pos_ary[0] = Double.valueOf(9.0 * Math.cos(t)).floatValue();
light_pos_ary[2] = Double.valueOf(9.0 * Math.sin(t)).floatValue();
t+= 0.01;
CalcShadowMatrixf(plane_ary, light_pos_ary, ShadowMatrix_ary);

gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
glu.gluLookAt(6.0, 7.0, 8.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
float xAngle = 0f;
float yAngle = 0f;
gl.glRotated(xAngle, 1, 0, 0);
gl.glRotated(yAngle, 0, 1, 0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_pos);
{
// 床を描画
gl.glEnable(GL.GL_POLYGON_OFFSET_FILL);
gl.glPushMatrix();
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, floorcolor);
gl.glPolygonOffset(OffsetFactor, OffsetUnit);
if (true) {
gl.glTranslatef(0, -1, 0);
gl.glRotatef(90, -1, 0, 0);
gl.glNormal3d(0, 0, 1);
gl.glRectf(-5, 5, 5, -5);
}
gl.glPopMatrix();
gl.glDisable(GL.GL_POLYGON_OFFSET_FILL);
}
{
// 通常の描画
gl.glPushMatrix();
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, red);
if (true) {
GLUquadric qobj0 = glu.gluNewQuadric();
glu.gluQuadricDrawStyle(qobj0, GLU.GLU_FILL);
glu.gluQuadricNormals(qobj0, GLU.GLU_SMOOTH);
glu.gluSphere(qobj0, 0.8f, 20, 20);
// glutSolidTeapot(1);
}
gl.glPopMatrix();
}
{
// 影の描画
gl.glDisable(GL.GL_LIGHTING);
gl.glDisable(GL.GL_LIGHT0);
gl.glPushMatrix();
gl.glMultMatrixf(ShadowMatrix_ary, 0);
gl.glColor3d(0, 0, 0);
if (true) {
GLUquadric qobj0 = glu.gluNewQuadric();
glu.gluQuadricDrawStyle(qobj0, GLU.GLU_FILL);
glu.gluQuadricNormals(qobj0, GLU.GLU_SMOOTH);
glu.gluSphere(qobj0, 0.8f, 20, 20);
// glutSolidTeapot(1);
}
gl.glPopMatrix();
gl.glEnable(GL.GL_LIGHTING);
gl.glEnable(GL.GL_LIGHT0);
}
}

void CalcShadowMatrixf(float[] planeAry, float[] lightPosAry,
float[] shadowMatrixAry) {
float dot = 0.0f;
for (int i = 0; i < 4; i++) {
dot += planeAry[i] * lightPosAry[i];
}
for (int loopY = 0; loopY < 4; ++loopY) {
for (int loopX = 0; loopX < 4; ++loopX) {
shadowMatrixAry[loopY * 4 + loopX] = -planeAry[loopY]
* lightPosAry[loopX];
if (loopX == loopY) {
shadowMatrixAry[loopY * 4 + loopX] += dot;
}
}
}
}


@Override
public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) {
//
}

public static void main(String[] args) {
new Sample();
}
}




結果


0 件のコメント: