Show Posts
|
|
Pages: [1]
|
|
1
|
Java Game APIs & Engines / Java Sound & OpenAL / Listener has no effect...
|
on: 2008-11-27 09:51:35
|
Hi, might it be that the listener position has no effect? Simple example: In the joal tutorial LoopingAndFadeAway the sound source is shifted at linear speed in z-direction. The sound gets quieter. If instead the source is fixed and the listener is shifted at linear speed in (-z)-direction nothing happens. Here is the tutorial source with the commented block at line 130. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
import java.nio.ByteBuffer;
import net.java.games.joal.AL; import net.java.games.joal.ALC; import net.java.games.joal.ALFactory; import net.java.games.joal.util.ALut;
public class LoopingAndFadeaway {
static int[] buffer = new int[1]; static int[] source = new int[1]; static float[] sourcePos = { 0.0f, 0.0f, 0.0f }; static float[] sourceVel = { 0.0f, 0.0f, 0.1f }; static float[] listenerPos = { 0.0f, 0.0f, 0.0f }; static float[] listenerVel = { 0.0f, 0.0f, -0.1f }; static float[] listenerOri = { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f }; static AL al; static ALC alc;
static int loadALData() { if (al.alGetError() != AL.AL_NO_ERROR) { return AL.AL_FALSE; }
int[] format = new int[1]; int[] size = new int[1]; ByteBuffer[] data = new ByteBuffer[1]; int[] freq = new int[1]; int[] loop = new int[1];
al.alGenBuffers(1, buffer, 0); if (al.alGetError() != AL.AL_NO_ERROR) return AL.AL_FALSE;
ALut.alutLoadWAVFile( "wavdata/Footsteps.wav", format, data, size, freq, loop); al.alBufferData(buffer[0], format[0], data[0], size[0], freq[0]); System.out.println("bufferID " + buffer[0]);
al.alGenSources(1, source, 0); System.out.println("sourceID " + source[0]); al.alSourcei(source[0], AL.AL_BUFFER, buffer[0]); al.alSourcef(source[0], AL.AL_PITCH, 1.0f); al.alSourcef(source[0], AL.AL_GAIN, 1.0f); al.alSourcefv(source[0], AL.AL_POSITION, sourcePos, 0); al.alSourcefv(source[0], AL.AL_POSITION, sourceVel, 0); al.alSourcei(source[0], AL.AL_LOOPING, AL.AL_TRUE);
if (al.alGetError() != AL.AL_NO_ERROR) { return AL.AL_FALSE; }
return AL.AL_TRUE; }
static void setListenerValues() { al.alListenerfv(AL.AL_POSITION, listenerPos, 0); al.alListenerfv(AL.AL_VELOCITY, listenerVel, 0); al.alListenerfv(AL.AL_ORIENTATION, listenerOri, 0); }
static void killAllData() { al.alDeleteBuffers(1, buffer, 0); al.alDeleteSources(1, source, 0); }
public static void main(String[] args) { try { ALut.alutInit(); al = ALFactory.getAL(); } catch(Exception e) { e.printStackTrace(); return; }
if(loadALData() == AL.AL_FALSE) { System.exit(1); }; al.alSourcePlay(source[0]); long startTime = System.currentTimeMillis(); long elapsed = 0; long ticker = 0; long lastTime = 0; while (elapsed < 10000) { elapsed = System.currentTimeMillis() - startTime; if (ticker > 100) { ticker = 0; listenerPos[0] += listenerVel[0]; listenerPos[1] += listenerVel[1]; listenerPos[2] += listenerVel[2]; al.alListenerfv(AL.AL_POSITION, listenerPos, 0); } ticker += System.currentTimeMillis() - lastTime; lastTime = System.currentTimeMillis(); } ALut.alutExit(); } }
|
What did I not mention? The listener position is always at default vec3(0.0)... Any suggestions? Thanks, Achilleos.
|
|
|
|
|
2
|
Java Game APIs & Engines / JOGL Development / Re: cubemap gl.glTexImage2D texture
|
on: 2008-11-17 08:46:30
|
You only create one texture and upload image data 6 times. To activate the cubemap just activate the only texture you created. Have a look at this working code brick: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| id = createOpenGLID();
gl.glBindTexture(texType, id);
gl.glTexParameteri(texType, GL.GL_TEXTURE_MIN_FILTER, minFilter); gl.glTexParameteri(texType, GL.GL_TEXTURE_MAG_FILTER, magFilter); gl.glTexParameteri(texType, GL.GL_TEXTURE_WRAP_S, wrapMode_s); gl.glTexParameteri(texType, GL.GL_TEXTURE_WRAP_T, wrapMode_t); gl.glTexParameteri(texType, GL.GL_TEXTURE_WRAP_R, wrapMode_r); if(anisotropicFiltering != 0) gl.glTexParameterf(texType, GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropicFiltering);
gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, internalFormat, width, height, 0, internalFormat, pixelFormat, posxData.getBuffer()); gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, internalFormat, width, height, 0, internalFormat, pixelFormat, posyData.getBuffer()); gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, internalFormat, width, height, 0, internalFormat, pixelFormat, poszData.getBuffer()); gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, internalFormat, width, height, 0, internalFormat, pixelFormat, negxData.getBuffer()); gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, internalFormat, width, height, 0, internalFormat, pixelFormat, negyData.getBuffer()); gl.glTexImage2D(GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, internalFormat, width, height, 0, internalFormat, pixelFormat, negzData.getBuffer()); |
Remember that you have to use a specific texture matrix to generate "correct" reflections using the cubemap: (the texType is "GL.GL_TEXTURE_CUBE_MAP") 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| gl.glEnable(texType); gl.glBindTexture(texType, id);
gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_COMBINE); gl.glTexEnvfv(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_COLOR, refl.getValues(), 0); gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_COMBINE_RGB, GL.GL_INTERPOLATE); gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_SRC0_RGB, GL.GL_TEXTURE); gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_OPERAND0_RGB, GL.GL_SRC_COLOR); gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_SRC1_RGB, GL.GL_PREVIOUS); gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_OPERAND1_RGB, GL.GL_SRC_COLOR); gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_SRC2_RGB, GL.GL_CONSTANT); gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_OPERAND2_RGB, GL.GL_SRC_ALPHA);
gl.glGetDoublev(GL.GL_MODELVIEW_MATRIX, mvmatrix);
double[] tex = texmatrix.array(); double[] mv = mvmatrix.array();
tex[0] = mv[0]; tex[1] = mv[4]; tex[2] = mv[8]; tex[3] = mv[12];
tex[4] = mv[1]; tex[5] = mv[5]; tex[6] = mv[9]; tex[7] = mv[13];
tex[8] = mv[2]; tex[9] = mv[6]; tex[10] = mv[10]; tex[11] = mv[14];
tex[12] = -mv[0]*mv[3] -mv[4]*mv[7] -mv[8]*mv[11]; tex[13] = -mv[1]*mv[3] -mv[5]*mv[7] -mv[9]*mv[11]; tex[14] = -mv[2]*mv[3] -mv[6]*mv[7] -mv[10]*mv[11]; tex[15] = mv[15];
gl.glMatrixMode(GL.GL_TEXTURE); gl.glLoadMatrixd(texmatrix); gl.glMatrixMode(GL.GL_MODELVIEW); |
|
|
|
|
|
6
|
Java Game APIs & Engines / JOGL Development / How to cleanup on java finalization?
|
on: 2008-11-03 14:07:14
|
|
Hi,
on Windows machines the JVM calls destroy() when an applet gets closed (Browser or Tab). The other threads seem to finish their current run as well. That way its possible to set the Renderer-Class to "shutdown" and wait for the FPSAnimator to call the display-method. Within the display-method the gl-context is present and its save to delete the gl-objects (textures, lists, shader,...). On Mac OS X and Linux the FPSAnimator never calls the display-method once the applet gets closed. And the display-method even does not run when triggered by hand. I see no way to wait for the user to "shutdown" the engine, it has to be triggered by hand (by clicking a button).
Is their another way to run the gl finialization on mac and linux?
Greetings, Achilleos.
|
|
|
|
|
7
|
Java Game APIs & Engines / JOGL Development / Re: How to update the world?
|
on: 2008-10-09 18:40:22
|
No i didn't check it. I though this is what the function does. But actualy you seem right. The API says: Returns the current time in milliseconds. Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the underlying operating system and may be larger. For example, many operating systems measure time in units of tens of milliseconds.
I will try nanoTime tomorrow. I tell you about the results. But some comments earlier someone said that there is a problem with nanoTime on AMD cpus...
|
|
|
|
|
9
|
Java Game APIs & Engines / JOGL Development / Re: How to update the world?
|
on: 2008-10-08 14:53:20
|
Well i made the changes and as expected: It doesn't change a thing. As promissed i made a little test applet. Here comes the source: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| package test;
import java.awt.Container;
import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCanvas; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLEventListener; import javax.swing.JApplet;
import com.sun.opengl.util.FPSAnimator;
public class Engine extends JApplet implements GLEventListener { private static final long serialVersionUID = 4056777684480799564L; protected Container frame = null; protected GLAutoDrawable canvas = null; protected FPSAnimator fpsAnim = null; protected long currentTimestamp = System.currentTimeMillis(); protected GL gl = null;
@Override public void init() { frame = this; frame.setName("Test"); this.setSize(10, 10); GLCapabilities glCaps = new GLCapabilities(); glCaps.setHardwareAccelerated(true); glCaps.setNumSamples(4); glCaps.setSampleBuffers(true); canvas = new GLCanvas(glCaps); canvas.addGLEventListener(this); frame.add((GLCanvas)canvas);
fpsAnim = new FPSAnimator(canvas, 60, true); }
@Override public void start(){ fpsAnim.start(); }
@Override public void stop(){ fpsAnim.stop(); }
@Override public void destroy(){ }
@Override public void display(GLAutoDrawable arg0){ long newTime = System.currentTimeMillis(); long deltaTime = newTime - currentTimestamp; currentTimestamp = newTime; System.out.println(deltaTime); }
@Override public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2){ }
@Override public void init(GLAutoDrawable drawable){ gl = drawable.getGL(); }
@Override public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3, int arg4){ }
} |
I have uploaded a webpage which runs the applet. Just follow this link: http://www.informatik.uni-bremen.de/~pachur/index.html
You see nearly nothing. Just a 10x10 px sized rectangle in the upper left corner of the page. The interesting part (the deltaTime between 2 calls) is outputted to the java console. While there is nothing drawn nor anything difficult happens, the deltaTime varys from 15 milliseconds up to 32 milliseconds. But the FPSAnimator class is well set up and calls 60 times per second the display function. Just taking the deltaTimings and update the world produces jerky animations, because there are no frames that needed additional time. The buffer swaping just seems to delay itself. As a result there are frames that forward the ingame time. Help is still needed. Maybe there is something i forgot. Achilleos
|
|
|
|
|
10
|
Java Game APIs & Engines / JOGL Development / Re: gl and OOP
|
on: 2008-10-08 08:49:19
|
|
You can have a one time made reference to the gl context and use this whenever you want as long as you are within the drawing thread and the gl context. The FPSAnimator or a class provided by you calls the display or repaint function of the drawable. The drawable itself will call a display method, which has to be implemented by you. From within this method you are save to draw everything you want.
You might want to provide some interface "Renderable" with a function "public void render(GL gl)" and pass the gl reference when calling your objectsto render themselves from within the display method. You grab the reference when "init(GLAutoDrawable drawable)" is called by "gl = drawable.getGL()". Another way is to give all your renderable objects the gl reference in advance.
|
|
|
|
|
11
|
Java Game APIs & Engines / JOGL Development / Re: How to update the world?
|
on: 2008-10-08 08:38:18
|
|
I agree that a fixed dt is more robust than a dynamic dt. Maybe sometimes a physics engine will be used in the project. Thats why i will change my code to use the algorithm provided above. But there will be some changes that have to be done in addition to make this work. Making these changes will take some time (cause i have other things to finish in advance). I will post again when i have finished them and tell you about the result.
But i do not guess that this will fix my problem. If it does not, i will provide a little applet (about 100 lines of code) which demonstrates the problem. Cause the problem does not come from using a dynamic dt but from the devices which delay images. Currently i guess that using swapBuffers() is the problamtic part. Using autoSwapBuffers seems not to produce this error.
Thanks so far, Achilleos.
|
|
|
|
|
12
|
Java Game APIs & Engines / JOGL Development / Re: How to update the world?
|
on: 2008-10-07 22:17:55
|
you can only make a jump with a certain framerate. There should be no difference when using a fixed dt. If the framerate is to low, you can have a 100 undetached animation updates, you wont see the jump. Player presses "Up"... tick 0 start jump.... tick 20 animated model is in the air... tick 40 animated model is back on the ground... tick ... tick... render. The problem of old arcade games had been, that absolutly no dt was used. Update -> Render -> Update -> Render. Old hardware, slow unplayable game, new hardware, extremly fast unplayable game. From the point on where you start considering the time passed you do not have this problem. A fixed dt is as good as a dynamic dt. Integrating a physics engine takes this to a new level... but i have no physics engine, thats why i want to make as few world updates as possible. And that is one update per rendering.
|
|
|
|
|
13
|
Java Game APIs & Engines / JOGL Development / Re: How to update the world?
|
on: 2008-10-07 21:47:38
|
Damn it. I just remembered a problem. Lets talk about this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| float t = 0.0f; const float dt = 0.01f;
float currentTime = time(); float accumulator = 0.0f;
State previous; State current;
while (!quit) { float newTime = time(); float deltaTime = newTime - currentTime; currentTime = newTime;
accumulator += deltaTime;
while (accumulator>=dt) { previousState = currentState; integrate(currentState, t, dt); t += dt; accumulator -= dt; }
const float alpha = accumulator / dt;
State state = currentState*alpha + previousState*(1.0f-alpha);
render(state); } |
I do something similar. I do not accumulate time calculated by the "animating enigne part" but i calculate a factor for scaling the "dt". That way i only need to make 1 step in animating the world, which is fine since i have no physics engine running. Making one animation update followed by an render call is just fine if you keep track of the time past and therefore so offset the animations. The problem comes from the devices or interfaces itself. If the graphics hardware buffers images there is no chance of making "non-jerky" animations. Take a look at the timings 2 posts before. If there is a complete engine tick, which happened in less than a milliseconds the world should not update. But if the graphics hardware delays the buffer swaping of something else, the world should have updated. The problem comes from measuring the time past. The graph with the white dots shows it. Some frames take time, some not (the scene does not change). That way the world does not update for about 5 frames and afterwards updates the time passed for 10 frames within the next 5 frames... I am not sure with this, but i have tried a lot of things. If i somehow start to measure time and consider the time passed for the world update and render/bufferswaping call, all animations start to have this subtle visual non-smoothness. If i say: "hey, vsync is on, 60 fps are okay, just make the world update", then everything is smooth.
|
|
|
|
|
15
|
Java Game APIs & Engines / JOGL Development / Re: How to update the world?
|
on: 2008-10-07 20:14:58
|
|
The delta time is not usable. Thats my point. Take an empty scene. Take the default FPSAnimator with scheduled animation of 60 fps. Take your lines of code and just make an additional System.out.println(delta);.
I got this (for example): 16 16 16 15 16 31 16 16 15 32 16 0 15 15 16 16
And thats the problem. Taking a mean value of delta is incorrect too, since measured over a second the render rate is still okay. But you cannot take a mean value of a second since this results into slow update time corrections. Currently i made the following, which works quite fine: Take the last 5 deltas, sort them in a list, take the middle.
(By the way: i have to correct myself. I took another look at the source of the animator classes and saw that drawable.display() was used with autoSwapBufferMode(true))
And another "by the way": this seems only to occur on windows xp. windows vista produces constant values. linux and mac os x system also seem to have this problem. -> all tested only with nvidia cards. Oh, another "by the way": ATI cards sometimes only render 30 frames while the display method is called 60 times...
|
|
|
|
|
16
|
Java Game APIs & Engines / JOGL Development / How to update the world?
|
on: 2008-10-07 17:41:11
|
Hi, i got a problem: I currently only using a single selfmade Animator-Class (like the FPSAnimator) to update the world and render the scene. This works almost fine... I call the drawable.display(); followed by the drawable.swapBuffers(); method to call for a new frame. The time needed for displaying is measured and results in a time-scale-factor for the world update. I want to draw 60 frames per second, that means i have 16,6 milliseconds for drawing a single frame. If the rendering needs more time, the time-scale-factor grows and the world updates offsets the game time a bit more. If less time was needed, the thread may sleep some time. The problem comes from the display and swap buffers methods, which are not invoked as i call them, but any time they want to. The little image shows an ingame gui. The first line shows the current fps and a graph of the last 10 seconds. The second line show the measured mspf (milliseconds per frame). The green graph show the mean values for 10 seconds and the dotted white graph the last 30 values (the values for a half second). The last line shows the tsf (time scale factor) and the difference between the last 2 mean values. The dottle lines shows my problem. In most of the display, swapBuffers calls i need nearly 0 ms and for some calls i need 16.6 ms. One can imagine that this comes from the vsync option (setSwapInterval) but in both cases this is how it looks like. It seems that the interface / device buffers the render requests and waits some time before it just renders all buffered requests. But how can you gain a steady world update with this? The FPSAnimator class produces a steady framerate and render call rate, but while using drawable.repaint() with autoswap buffer mode you have no chance to measure the time past or the framerate reached. If you want to reach 60 fps and the machine can only produce 10 fps the worlds time passes in slow-motion... Has anyone an idea to help me with this problem? Greeting, Achilleos. 
|
|
|
|
|
|
Add your game by posting it in the WIP section,
or publish it in Showcase.
The first screenshot will be displayed as a thumbnail.
|
|