I made a quick demo to show one way to change normals. It sets the normals of all vertices to the same normal...while this improves the lighting in this little example, it might not be suitable for your game to do it this simple way, but i think you'll get the idea. Another option is to create the normals in a modeller, save the result in OBJ-format and set
http://www.jpct.net/doc/com/threed/jpct/Config.html#useNormalsFromOBJ to true before loading it.
If you start this program, it will render a 20*20 field of cubes with one light and the usual issues. Removing the comment from the call to changeNormals(...) will modify the normals and improve the lighting. It's still not 100% perfect, but it don't think that this will be noticable in an actual game with textures and such.
About the "collision for light rays" thing...no, this isn't the way lighting in OpenGL (or any low level 3d api) works. This kind of lighting happens per polygon, it doesn't take any other part of the scene into account. What you mean with "collision for light rays" is usually called "shadows"...
. jPCT has a ShadowHelper for simple shadow mapping, but i don't think that the results will fit the style of your game.
import org.lwjgl.opengl.Display;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.GenericVertexController;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Lights;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;
import com.threed.jpct.util.Light;
public class CubeWorld {
public static void main(String[] args) throws Exception {
FrameBuffer buffer = new FrameBuffer(1024, 768, FrameBuffer.SAMPLINGMODE_GL_AA_4X);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.enableRenderer(IRenderer.RENDERER_OPENGL);
World world = new World();
world.setAmbientLight(0, 0, 0);
world.getLights().setRGBScale(Lights.RGB_SCALE_2X);
Light light = new Light(world);
light.setIntensity(255, 0, 0);
light.setPosition(new SimpleVector(0, 0, 180));
light.setAttenuation(20);
Object3D cube = Primitives.getCube(5);
cube.rotateY((float) -Math.PI / 4f);
cube.rotateMesh();
cube.clearRotation();
cube.build();
// uncomment this to set new, unified normals
// changeNormals(cube, new SimpleVector(0, 0, -1));
cube.compile();
for (int x = 0; x < 20; x++) {
for (int y = 0; y < 20; y++) {
Object3D tmp = new Object3D(cube, true);
tmp.translate((x - 10) * 5, (y - 10) * 5, 200);
tmp.build();
tmp.compile();
tmp.shareCompiledData(cube);
world.addObject(tmp);
}
}
while (!Display.isCloseRequested()) {
buffer.clear();
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
Thread.sleep(10);
}
}
private static void changeNormals(Object3D obj, final SimpleVector newNormal) {
obj.getMesh().setVertexController(new GenericVertexController() {
private static final long serialVersionUID = 1L;
@Override
public void apply() {
SimpleVector[] dest = this.getDestinationNormals();
for (SimpleVector sv : dest) {
sv.set(newNormal);
}
}
}, true);
obj.getMesh().applyVertexController();
obj.getMesh().removeVertexController();
}
}