Yes, that would be too expensive...for keyframes, i'm interpolating normals in the same way as i do interpolate vertices, but i guess it's another story here...
Another question: I tried to render three models at a time, which works fine...unless i'm trying to do the animation processing in parallel in three threads. The models are all loaded and created individually (i.e. i've simply loaded the ninja three times), but if i call animateSkin(...) in parallel, all hell breaks loose and they start to look as if they had a severe car accident or something. If i synchronize the animation calls to some common object, all is fine again. Am i doing something wrong? Any ideas?
Here's my hacky test case (with multi threaded animations disabled...enable it with useMultipleThreads=true), if that helps:
package bones.samples;
import java.io.FileInputStream;
import org.lwjgl.opengl.Display;
import raft.jpct.bones.Animated3D;
import raft.jpct.bones.AnimatedGroup;
import raft.jpct.bones.BonesIO;
import com.threed.jpct.Camera;
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IPaintListener;
import com.threed.jpct.IRenderer;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.threading.WorkLoad;
import com.threed.jpct.threading.Worker;
import com.threed.jpct.util.Light;
public class SimpleBones implements IPaintListener {
private static final long serialVersionUID = 1L;
private Ninja ninja = null;
private Ninja anotherNinja = null;
private Ninja theLastNinja = null;
private FrameBuffer buffer = null;
private World world = null;
private int fps = 0;
private long time = System.currentTimeMillis();
private Worker worker = new Worker(3);
private WorkLoad[] loads = new WorkLoad[3];
private boolean useMultipleThreads = false;
private boolean compile = true;
public static void main(String[] args) {
SimpleBones sb = new SimpleBones();
sb.runIt();
}
public void runIt() {
config();
init();
loop();
}
public void finishedPainting() {
fps++;
if (System.currentTimeMillis() - time >= 1000) {
System.out.println(fps + "fps");
fps = 0;
time = System.currentTimeMillis();
}
}
public void startPainting() {
}
private void config() {
Config.useMultipleThreads = true;
}
private void loop() {
try {
while (!buffer.isInitialized()) {
Thread.sleep(100);
}
while (!Display.isCloseRequested()) {
if (!useMultipleThreads) {
for (WorkLoad wl : loads) {
wl.doWork();
}
} else {
for (WorkLoad wl : loads) {
worker.add(wl);
}
}
buffer.clear();
if (useMultipleThreads) {
worker.waitForAll();
}
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void init() {
buffer = new FrameBuffer(1024, 768, FrameBuffer.SAMPLINGMODE_GL_AA_2X);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.enableRenderer(IRenderer.RENDERER_OPENGL);
buffer.setPaintListener(this);
world = new World();
Texture texture = new Texture("./samples/data/ninja/nskingr.jpg");
TextureManager.getInstance().addTexture("ninja", texture);
ninja = new Ninja();
ninja.addToWorld(world);
anotherNinja = new Ninja();
anotherNinja.addToWorld(world);
theLastNinja = new Ninja();
theLastNinja.addToWorld(world);
if (compile) {
ninja.compile();
anotherNinja.compile();
theLastNinja.compile();
}
WorkLoad w0 = new WorkLoad() {
public void doWork() {
ninja.animate(1);
}
public void done() {
}
public void error(Exception arg0) {
}
};
WorkLoad w1 = new WorkLoad() {
public void doWork() {
anotherNinja.animate(2);
}
public void done() {
}
public void error(Exception arg0) {
}
};
WorkLoad w2 = new WorkLoad() {
public void doWork() {
theLastNinja.animate(5);
}
public void done() {
}
public void error(Exception arg0) {
}
};
loads[0] = w0;
loads[1] = w1;
loads[2] = w2;
anotherNinja.translate(new SimpleVector(-200, 0, 0));
theLastNinja.translate(new SimpleVector(200, 0, 0));
world.getCamera().moveCamera(Camera.CAMERA_MOVEIN, 600);
world.getCamera().moveCamera(Camera.CAMERA_MOVEUP, 200);
world.getCamera().lookAt(new SimpleVector(0, -200, 0));
Light light = new Light(world);
light.setIntensity(255, 255, 255);
light.setPosition(new SimpleVector(800, -400, 0));
light.setAttenuation(-1);
}
private static class Ninja {
private AnimatedGroup animatedGroup = null;
private float index = 0;
private long time = 0;
public Ninja() {
init();
}
public void compile() {
for (Animated3D o : animatedGroup) {
o.compile(true);
}
}
public void translate(SimpleVector trns) {
for (Animated3D o : animatedGroup) {
o.translate(trns);
}
}
public void animate(int seq) {
if (time == 0) {
time = System.nanoTime() / 1000000L;
}
long dt = (System.nanoTime() / 1000000L) - time;
time = dt + time;
index += dt / 1000f;
while (index > 1) {
index -= 1;
}
animatedGroup.animateSkin(index, seq);
}
public void addToWorld(World world) {
animatedGroup.addToWorld(world);
}
private void init() {
try {
FileInputStream fis = new FileInputStream("./samples/data/ninja/ninja.group.bones");
try {
AnimatedGroup skinnedGroup = BonesIO.loadGroup(fis);
for (Animated3D o : skinnedGroup) {
o.setTexture("ninja");
o.build();
o.discardMeshData();
o.setVisibility(true);
}
animatedGroup = skinnedGroup;
} finally {
fis.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}