Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411514 Posts in 69376 Topics- by 58431 Members - Latest Member: Bohdan_Zoshchenko

April 27, 2024, 12:45:43 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)The grumpy old programmer room
Pages: 1 ... 94 95 [96] 97 98 ... 295
Print
Author Topic: The grumpy old programmer room  (Read 738882 times)
bateleur
Level 10
*****



View Profile
« Reply #1900 on: March 16, 2011, 09:38:00 AM »

@Bateleur: what about storing position+orientation at each keystroke? It could avoid the buildup of small errors.

Good tip, but unfortunately I can't use this (or any of the other usual FPS tricks) because I have large numbers of objects all interacting under physics-based control including dynamic creation and destruction. (It's for this project.)
Logged

mcc
Level 10
*****


glitch


View Profile WWW
« Reply #1901 on: March 16, 2011, 10:01:45 AM »

In my experience for physics replays you generally need determinism, small differences will quickly build up.
Yeah the problem is that two physics simulations only have to diverge ONCE and then everything after that will be totally different.

This might not be so bad if the "replay" is some kind of angry birds thing that consists of an initial nudge and after that everything replays the same, but if you've got something like recorded keystrokes in a proper "game" over a period of time, then the "recorded" player is going to expect every single physics object it interacts with to be exactly the same. I had a record/replay feature way back in Jumpman (I used it to make a video) and ran into this problem (actually, this is why I never really exposed it for use by players), I had to be careful to only engage with the "physics-y" parts of the game late in the video and sometimes had to rerun the video renders more than once before the physics happened to have the same results, because it was VERY easy for something to diverge by one frame or one pixel and as a result Jumpman would spend the remaining 2 minutes of the video running into a corner and jumping repeatedly for no reason.
Logged

My projects:<br />Games: Jumpman Retro-futuristic platforming iJumpman iPhone version Drumcircle PC+smartphone music toy<br />More: RUN HELLO
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #1902 on: March 16, 2011, 12:56:45 PM »

There's a reason physics engines don't support determinism properly. It's because even if they did, it would be useless across architectures - floating point is not well enough specified (allegedly) to do that. The best fix is to use fixed point or per-frame rounding, but both of those are a big performance hit.

It's better just to record replays frame by frame - it's cheaper than it looks.
Logged
mcc
Level 10
*****


glitch


View Profile WWW
« Reply #1903 on: March 16, 2011, 01:19:02 PM »

It's because even if they did, it would be useless across architectures - floating point is not well enough specified (allegedly) to do that.
I can believe that. Stupid butterfly effect Sad
Logged

My projects:<br />Games: Jumpman Retro-futuristic platforming iJumpman iPhone version Drumcircle PC+smartphone music toy<br />More: RUN HELLO
bateleur
Level 10
*****



View Profile
« Reply #1904 on: March 16, 2011, 02:23:20 PM »

There's a reason physics engines don't support determinism properly. It's because even if they did, it would be useless across architectures - floating point is not well enough specified (allegedly) to do that.

This argument is bogus.

Firstly, it requires actively sloppy implementation to end up with nondeterminism on a single machine (at least in software - not sure about hardware PhysX). Secondly, whilst cross-machine determinism would obviously be lovely, single-machine determinism is extremely useful in its own right.

It's better just to record replays frame by frame - it's cheaper than it looks.

Erm... I don't understand. Are you saying I got the numerical calculation I didn't post anywhere wrong? Tongue

In case anyone's curious, a 1-frame snapshot of a moderately (but not extremely) complex game state is about 20K. Even if I only took a snapshot every 10th frame that would be over 3MB for a 1 minute replay. This could be reduced by (I estimate) about 75% if I used a less verbose data format, but that makes a lot of extra coding work.

Logged

Aquin
Level 10
*****


Aquin is over here.


View Profile WWW
« Reply #1905 on: March 16, 2011, 02:27:48 PM »

Nah, Boris is right.  I've been looking at recording replays, and it's clear that recording initial conditions and expecting the physics engine to reproduce all interactions properly is a fool's errand.

It's better to just record frame-by-frame positions of all relevant in-game objects.  It's pretty much guaranteed accuracy and you don't have to worry about anything going wrong.  Maybe the game hiccups because of another program, maybe the floats come with rounding errors on different hardware, maybe blah blah blah.

Screw the maybes, just record absolute values.  Cheesy
Logged

I'd write a devlog about my current game, but I'm too busy making it.
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #1906 on: March 16, 2011, 03:08:20 PM »

single-machine determinism is extremely useful in its own right.
For what exactly? I also take exception to "sloppy". Determinism as you say is not too bad, but people here have made it clear that you need to be able to resume a savepoint as well as restart from the beginning, which is more work.

In case anyone's curious, a 1-frame snapshot of a moderately (but not extremely) complex game state is about 20K.
So, 3d game, position + rotation = 7 floats = 28 bytes. So you have about 1000 objects, which are apparently all moving at the same time. And the real gains are from encoding frame-by-frame differences, rather than attempting to compress any given frame. Same as in video compression. Perhaps one could even store just the low bits, and rely on the simulation being roughly correct...

Edit: On reflection, I've put my foot in it. I've not done any serious work on replays, so don't take my word for it.
« Last Edit: March 16, 2011, 03:17:13 PM by BorisTheBrave » Logged
Glaiel-Gamer
Guest
« Reply #1907 on: March 16, 2011, 03:55:34 PM »

In case anyone's curious, a 1-frame snapshot of a moderately (but not extremely) complex game state is about 20K. Even if I only took a snapshot every 10th frame that would be over 3MB for a 1 minute replay. This could be reduced by (I estimate) about 75% if I used a less verbose data format, but that makes a lot of extra coding work.

store a snapshot once per 1-2 seconds and assume that 1-2 seconds of simulation will be roughly the same even with minor errors?

assume that 95% of physics objects in your scene are sleeping, so 95% of those objects would only need about 1 byte of data (unless they moved from the previous snapshot)?

1000 objects, 90% are in the same state as the previous frame, storing id + position + rotation + velocity + angular velocity = 13 floats + 1 short (3D), 6 floats + 1 short (2D) x 100 objects = 5k (3D), 2.5k (2D), x 60 = 300k / min (3D), 150k / min (2D) [once per 2 seconds halve those values, so 150k/min, 75k/min]

zlib it up (cut down by 50-75%) and an hour replay is 9mb

can probably also assume that non-sleeping objects with no collisions since the previous snapshot also don't need to be updated, could cut it down even more.


Obviously the most inefficient way to store things would make large filesizes for everything. Even storing just keystrokes, if you did it EVERY FRAME the ENTIRE STATE of the keyboard the filesize would be huge.
Logged
mcc
Level 10
*****


glitch


View Profile WWW
« Reply #1908 on: March 16, 2011, 04:04:04 PM »

Glaiel has some good ideas here
assume that 95% of physics objects in your scene are sleeping, so 95% of those objects would only need about 1 byte of data (unless they moved from the previous snapshot)?
And many engines will even tell you who is or isn't sleeping.

Quote
And the real gains are from encoding frame-by-frame differences, rather than attempting to compress any given frame

Are there any good standard ways to compress linear "DPCM" type data like this? I wouldn't expect zlib to give you good performance, I expect that to work better on symbolic data. This isn't the only context where I've wondered this, I've also wanted some simple way to do basic lossless compression of audio.
Logged

My projects:<br />Games: Jumpman Retro-futuristic platforming iJumpman iPhone version Drumcircle PC+smartphone music toy<br />More: RUN HELLO
wademcgillis
Guest
« Reply #1909 on: March 16, 2011, 05:00:01 PM »

 Hand Shake Left Mock Anger Hand Shake Right

 Angry Angry Angry Angry Angry Angry Angry Angry Angry

THE COLORS ALWAYS CHANGE.



We're supposed to put why we're mad at programming, right?
Logged
mcc
Level 10
*****


glitch


View Profile WWW
« Reply #1910 on: March 16, 2011, 05:04:19 PM »

We're supposed to put why we're mad at programming, right?
I think you did fine
Logged

My projects:<br />Games: Jumpman Retro-futuristic platforming iJumpman iPhone version Drumcircle PC+smartphone music toy<br />More: RUN HELLO
wademcgillis
Guest
« Reply #1911 on: March 16, 2011, 05:12:21 PM »

We're supposed to put why we're mad at programming, right?
I think you did fine

I don't understand what's wrong.
I even made the method output to a text file to manually check the colors, but it still happens even though the text file says everything is OK.
The only thing that fixes it is hardcoding the colors, which I don't want to do.

Code:
void CTools::DrawBlockModify(FLOAT xx1, FLOAT yy1, FLOAT zz1, FLOAT xx2, FLOAT yy2, FLOAT zz2, IDirect3DTexture9 *texture, FLOAT hrepeat, FLOAT vrepeat, BOOL left, BOOL back, BOOL right, BOOL front, BOOL top, BOOL bottom, D3DCOLOR awesome)
{
// THIS CULLS RIGHT (counterclockwise)
FLOAT x1 = min(xx1, xx2);
FLOAT x2 = max(xx1, xx2);
FLOAT y1 = min(yy1, yy2);
FLOAT y2 = max(yy1, yy2);
FLOAT z1 = min(zz1, zz2);
FLOAT z2 = max(zz1, zz2);
int numVertices = 0;
sVertex Verts[36];
unsigned char shade = 160;
D3DCOLOR lightcolor = awesome;//game->GetGraphics()->GetColor();
D3DCOLOR shadowcolor = awesome;//game->GetGraphics()->GetColor();
if (front)
{
// Front
Verts[numVertices] = MAKEVERTEX( x2, y2, z1, shadowcolor, hrepeat, 0.0f );
Verts[numVertices+1] = MAKEVERTEX( x2, y1, z1, shadowcolor, hrepeat, vrepeat );
Verts[numVertices+2] = MAKEVERTEX( x1, y1, z1, shadowcolor, 0.0f, vrepeat );
Verts[numVertices+3] = MAKEVERTEX( x1, y1, z1, shadowcolor, 0.0f, vrepeat );
Verts[numVertices+4] = MAKEVERTEX( x1, y2, z1, shadowcolor, 0.0f, 0.0f );
Verts[numVertices+5] = MAKEVERTEX( x2, y2, z1, shadowcolor, hrepeat, 0.0f );
numVertices += 6;
}
if (back)
{
// Back
Verts[numVertices] = MAKEVERTEX( x1, y1, z2, shadowcolor, hrepeat, vrepeat );
Verts[numVertices+1] = MAKEVERTEX( x2, y1, z2, shadowcolor, 0.0f, vrepeat );
Verts[numVertices+2] = MAKEVERTEX( x2, y2, z2, shadowcolor, 0.0f, 0.0f );
Verts[numVertices+3] = MAKEVERTEX( x1, y1, z2, shadowcolor, hrepeat, vrepeat );
Verts[numVertices+4] = MAKEVERTEX( x2, y2, z2, shadowcolor, 0.0f, 0.0f );
Verts[numVertices+5] = MAKEVERTEX( x1, y2, z2, shadowcolor, hrepeat, 0.0f );
numVertices += 6;
}
if (left)
{
// Left
Verts[numVertices] = MAKEVERTEX( x1, y2, z2, shadowcolor, 0.0f, 0.0f );
Verts[numVertices+1] = MAKEVERTEX( x1, y1, z1, shadowcolor, hrepeat, vrepeat );
Verts[numVertices+2] = MAKEVERTEX( x1, y1, z2, shadowcolor, 0.0f, vrepeat );
Verts[numVertices+3] = MAKEVERTEX( x1, y2, z2, shadowcolor, 0.0f, 0.0f );
Verts[numVertices+4] = MAKEVERTEX( x1, y2, z1, shadowcolor, hrepeat, 0.0f );
Verts[numVertices+5] = MAKEVERTEX( x1, y1, z1, shadowcolor, hrepeat, vrepeat );
numVertices += 6;
}
if (right)
{
// Right
Verts[numVertices] = MAKEVERTEX( x2, y2, z2, shadowcolor, hrepeat, 0.0f );
Verts[numVertices+1] = MAKEVERTEX( x2, y1, z2, shadowcolor, hrepeat, vrepeat );
Verts[numVertices+2] = MAKEVERTEX( x2, y1, z1, shadowcolor, 0.0f, vrepeat );
Verts[numVertices+3] = MAKEVERTEX( x2, y1, z1, shadowcolor, 0.0f, vrepeat );
Verts[numVertices+4] = MAKEVERTEX( x2, y2, z1, shadowcolor, 0.0f, 0.0f );
Verts[numVertices+5] = MAKEVERTEX( x2, y2, z2, shadowcolor, hrepeat, 0.0f );
numVertices += 6;
}
if (top)
{
//game->DebugString("Top:");
//game->DebugColor(shadowcolor);
// Top
Verts[numVertices] = MAKEVERTEX( x2, y2, z2, shadowcolor, hrepeat, 0.0f );
Verts[numVertices+1] = MAKEVERTEX( x2, y2, z1, shadowcolor, hrepeat, vrepeat );
Verts[numVertices+2] = MAKEVERTEX( x1, y2, z1, shadowcolor, 0.0f, vrepeat );
Verts[numVertices+3] = MAKEVERTEX( x1, y2, z1, shadowcolor, 0.0f, vrepeat );
Verts[numVertices+4] = MAKEVERTEX( x1, y2, z2, shadowcolor, 0.0f, 0.0f );
Verts[numVertices+5] = MAKEVERTEX( x2, y2, z2, shadowcolor, hrepeat, 0.0f );
numVertices += 6;
}
if (numVertices == 0)
return;
IDirect3DDevice9 *pD3DDevice = game->GetGraphics()->GetDirect3DDevice9();
IDirect3DVertexBuffer9 *pD3DVB = NULL;
pD3DDevice->CreateVertexBuffer(numVertices*sizeof(sVertex),0, VertexFVF, D3DPOOL_MANAGED, &pD3DVB, NULL);
BYTE *Ptr;
pD3DVB->Lock(0,numVertices*sizeof(sVertex),(void**)&Ptr,0);
memcpy(Ptr, Verts, numVertices*sizeof(sVertex));
pD3DVB->Unlock();
pD3DDevice->SetTexture(0,texture);
pD3DDevice->SetStreamSource(0, pD3DVB, 0, sizeof(sVertex));
pD3DDevice->SetFVF(VertexFVF);
pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,numVertices);
pD3DVB->Release();
}

For some reason, whenever I call
Code:
CTools::DrawBlockModify(0,0,0,m*collide->GetWidth(),m*collide->GetHeight(),m*collide->GetDepth(),game->GetTextureManager()->GetTextureFromName("Dragon"),1,1,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,game->GetGraphics()->MakeColorRGB(255,0,0));
and then in the next object,
Code:
CTools::DrawBlockModify(0,0,0,m*collide->GetWidth(),m*collide->GetHeight(),m*collide->GetDepth(),game->GetTextureManager()->GetTextureFromName("Stone"),1,1,left,back,right,front,TRUE,FALSE,game->GetGraphics()->MakeColorRGB(255,255,255));

The top of the next object is the color of the previous one.
Logged
bateleur
Level 10
*****



View Profile
« Reply #1912 on: March 17, 2011, 05:30:23 AM »

On reflection, I've put my foot in it. I've not done any serious work on replays, so don't take my word for it.

Your suggestions seem sensible to me, but that's starting to sound like a week or more of work for something I could otherwise implement in an hour or two.

assume that 95% of physics objects in your scene are sleeping

This is a very reasonable assumption, but won't be literally true because a lot of things are either kinematically controlled or are part of composite bodies. There will be some corresponding notion of "does not require re-serialization", but rather more awkward to code correctly. (For example: In Unity, two objects connected by a FixedJoint do not have invariant positions relative to one another.)
Logged

Draknek
Level 6
*


"Alan Hazelden" for short


View Profile WWW
« Reply #1913 on: March 17, 2011, 06:37:37 AM »

single-machine determinism is extremely useful in its own right.
For what exactly? I also take exception to "sloppy". Determinism as you say is not too bad, but people here have made it clear that you need to be able to resume a savepoint as well as restart from the beginning, which is more work.
As well as making replays a simple process rather than a painful one (as demonstrated here), single-machine determinism is also massively useful for debugging.

Also, relevant link for floating point determinism: http://gafferongames.com/networking-for-game-programmers/floating-point-determinism/ (won't actually be helpful in making PhysX deterministic)
Logged

increpare
Guest
« Reply #1914 on: March 17, 2011, 09:05:53 AM »

As3 docs define their atan2 function as

"Computes and returns the angle of the point y/x in radians, when measured counterclockwise from a circle's x axis (where 0,0 represents the center of the circle). The return value is between positive pi and negative pi."

Self-contradicting crap.  Angry
Logged
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #1915 on: March 17, 2011, 12:03:58 PM »

Seems reasonable to me. -Pi/2 measured clockwise is a valid rotation, it's the same thing as Pi/2 measured anticlockwise.
Logged
increpare
Guest
« Reply #1916 on: March 17, 2011, 12:57:53 PM »

Seems reasonable to me. -Pi/2 measured clockwise is a valid rotation, it's the same thing as Pi/2 measured anticlockwise.
Angular distance from an axis is never going to have a range of greater than Pi.
Logged
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #1917 on: March 17, 2011, 02:24:29 PM »

Only it's not measuring angular distance, which would have range [0,Pi] like you say. It simply says angle. That doesn't prevent negative angles, or angles greater than 2 Pi, in my understanding. Angle is a vector quantity, like displacement, not a scalar quantity, like distance. Or, even more accurately, it is the group S1, which cannot be unambiguously mapped to the reals without specifying a range.
Logged
increpare
Guest
« Reply #1918 on: March 17, 2011, 02:59:55 PM »

Only it's not measuring angular distance, which would have range [0,Pi] like you say. It simply says angle. That doesn't prevent negative angles, or angles greater than 2 Pi, in my understanding. Angle is a vector quantity, like displacement, not a scalar quantity, like distance. Or, even more accurately, it is the group S1, which cannot be unambiguously mapped to the reals without specifying a range.
I didn't say [0,Pi].  I mean that, assuming that it's continuous, you wouldn't expect atan2, by the (incorrect) definition given, to have a range of more than [x,x+Pi] (regardless of what exact range is chosen).  I note wikipedia says "positive X axis", which is correct.
Logged
increpare
Guest
« Reply #1919 on: March 17, 2011, 03:05:08 PM »

[ Being a bit anal : Angle is not a vector in the mathsy technical sense, because it doesn't obey vector transformation laws - it's invariant under scaling, for instance. ]
Logged
Pages: 1 ... 94 95 [96] 97 98 ... 295
Print
Jump to:  

Theme orange-lt created by panic