Saturday, November 04, 2006

Puyo puyo - A puzzle game written in java

Just published a puzzle game called "Puyo Puyo". The project is hosted using google's project hosting service and written in java. The license is LGPL.Currently it has a simple project homepage at http://limingchina.googlepages.com/puyopuyo.

If you have NetBeans 5.5 installed, you can check out all the files under /trunk/puyo and directly open it using the IDE. Of course if you are familiar with Java SDK, it should be easy to only check out the essential source code and compile and run it using the command line tools provided by the SDK.

The look and feel is rather primitive at the moment. But it could be improved over time. If you have interest, you can also drop me a line and we can do it together.

The first release (version 0.1) can be downloaded here. If you already have java run time environment installed on your machine, simply double click the jar file starts the game.

Have fun with it!

Wednesday, November 01, 2006

Raytraced balls with refraction using FX Composer

I've tweaked a little bit the raytrace.fxproj shipped with FX Composer 1.8 from NVidia. Originally the raytracer support only reflection. I tried to show refraction (Figure 1) instead of reflection (Figure 2).



Figure 1. Raytraced balls with refraction





Figure 2. Raytraced balls with reflection


The following gives some details about the tweak.

First of all, we need to specify a transmittance coefficient to describe how much light can be refracted. We give a name Kt.

struct Sphere {
float3 centre;
float rad2; // radius^2
float4 color;
float Kd, Ks, Kr, Kt;
~~~ //this variable is added
};

Then we need a function to compute the direction of refracted ray given the incoming ray and a refraction index. You can find the function and explanation in the Cg Tutorial book sample chaper. The formula behind it can be also found on the Snell's law on wikipedia.


float3 refract(float3 i, float3 n, float eta)
{
float cosi = dot(-i, n);
float cost2 = 1.0 - eta * eta * (1.0 - cosi*cosi);
float3 t = eta*i + ((eta*cosi - sqrt(abs(cost2))) * n);
return t * float3(cost2 > 0.0, cost2>0.0, cost2 > 0.0);
}

Finally, in the RayTracePS function, we comment out the reflection part and add a similar part for refraction:

// shoot reflection ray
/*
float3 r = reflect(eyeray.d, n);
Ray reflray;
reflray.o = i;
reflray.d = r;
float3 ri = NearestHit(reflray, hitobj2, hit);
if (hit) {
n = SphereNormal(object[hitobj2], ri);
c += Shade(ri, n, reflray.d, hitobj2) * object[hitobj].Kr;
} else {
c += backgroundColor;
}
*/

// shoot refraction ray
float3 t = refract(eyeray.d, n, 0.9);
Ray refrray;
refrray.o = i;
refrray.d = t;
float3 ti = NearestHitExcludeObj(refrray, hitobj, hitobj2, hit);
if (hit) {
n = SphereNormal(object[hitobj2], ti);
c += Shade(ti, n, refrray.d, hitobj2) * object[hitobj].Kt;
} else {
c += backgroundColor;
}

Note that everything is similar except the routine for computing the nearest hit point for the refracted ray:
NearestHitExcludeObj(refrray, hitobj, hitobj2, hit).

This function computes a hit obj (hitobj2) but excluding the current hit obj (hitobj). This is because the refracted ray starts from the current hit obj. If we don't exclude it, the function will return "no hit" result since the ray intersects the current obj at the very origin point of the ray and the parameter t of the ray is then 0 and below the error threshold.

// find nearest hit returns intersection point. The excludeobj will be excluded.

float3 NearestHitExcludeObj(Ray ray, int excludeobj,
out int hitobj, out bool anyhit)
{
float mint = 1e10;
hitobj = -1;
anyhit = false;
for(int i=0; i < NOBJECTS; i++) {
bool hit;
float t = SphereIntersect(object[i], ray, hit);
if (hit && i!=excludeobj) {
if (t < mint) {
hitobj = i;
mint = t;
anyhit = true;
}
}
}
return ray.o + ray.d*mint;
}