PDA

View Full Version : Efficent Camera Movement



ribblem
07-08-2000, 12:07 PM
I am looking for an efficent way to move the camera around in a first person perspective(including Z ie the person can fly). My method right now uses lots of sin and cos calls and I figure there must be a much more efficent way to do it. Perhaps using gluLookAt and some dot products, but my head just couldn't think of a good way. Anyone out there got some good way to do this?

ngill
07-08-2000, 01:08 PM
here's what I use... I don't know if it's right or wrong... but it seems perfectly ok...

x,y,z = your pos...
this lets you look around freely given the x angle = 0 when looking straight ahead...
and yangle=0 looking straight ahead, yangle is + as you go up... xangle is + as you go to the right...

static GLfloat lookx(0.0f), looky(0.0f), lookz(0.0f);
static GLfloat upx(0.0f), upy(1.0f), upz(0.0f), dist(5.0f);

lookx=x+dist*sinf(xangle)*cosf(yangle);
looky=y+dist*sinf(yangle);
lookz=z+(-1*dist*cosf(xangle)*cosf(yangle)); // I know x+(-y) = x-y

if (yangle>PI/2.0) yangle=PI/2.0;
if (yangle<-PI/2.0) yangle=-PI/2.0;

gluLookAt(x,y,z,lookx,looky,lookz,upx,upy,upz);

the movement is:


ytheta+=6.28f/20.0f;
x+=cosf(xangle)*speed;
z+=sinf(xangle)*speed;
y=sinf(ytheta)*0.03f;

//don't confuse the ytheta with yangle, ytheta is for bumping you
// up and down as you move...


adding some equations so you can fly shouldn't be hard at all fromt his point... by the way, I would rederive all the equations by yourself and then check... =), it's more fun that way!! http://www.opengl.org/discussion_boards/ubb/smile.gif


[This message has been edited by ngill (edited 07-08-2000).]

[This message has been edited by ngill (edited 07-08-2000).]

07-09-2000, 07:40 AM
Calling sin, cos, etc is not inefficient. Why?

Sin, etc are just coefficients, or numbers multiplied by whatever parameter you specify.

As they functions are inlined I doubt there is any function call overhead when the code is compiled.

ribblem
07-09-2000, 08:33 AM
I'm pretty sure that sin and cos are pretty expensive. I suppose I could run a little benchmark. I've seen replacement sine and cosine routines that use a table lookup to speed up these computations, that makes me think the default versions are slow. I know dot products are super fast so that is why I'd like to find a way to replace my current method with a dot product method. In the mean time I think I'll put together a little bench mark. Talk to ya latter

ribblem
07-09-2000, 08:53 AM
Ok I made the following benchmark.

#include <iostream>
#include <cmath>

#include "bmark.h"

using namespace std;

void main()
{

float bob = 3.14f;
float holder;
Benchmark theBmark;

for(unsigned long int i=0; i<123456789; ++i)
{
holder=bob*i;
}
cerr << theBmark.bTime() << endl;

Benchmark theBmark2;
for(unsigned long int j=0; j<123456789; ++j)
{
holder=cosf(bob);
}
cerr << theBmark2.bTime()<< endl;
}

From this code I get the multiplies taking 6.64 seconds. And the cosine taking 57.02 seconds.

MikeC
07-10-2000, 02:41 AM
ribblem, that's 57 seconds for 123 million cosines! Exactly how many times per frame do you expect to be moving your camera? Might the answer be "one"? Meaning that your "inefficient" trig code must be costing you, ooh, a few millionths of a second per frame at the very least. Time to break out the assembler, boys.

You're wasting your time optimizing this code for speed. You should be concentrating on keeping it clear and maintainable, and focusing your optimization efforts on the bits that'll actually benefit.

As Donald Knuth said, "premature optimization is the root of all evil".

Blza
07-10-2000, 04:08 AM
Ok ngill.
but how can i find the angles(xangle, yangle, zangle ) ?

sorry my stupid question...

cya

DFrey
07-10-2000, 04:50 AM
You don't have to "find" them. You can just "get" them from an input device for user input or key framing code for predefined camera path and events. For input devices just simply scale the input device values (relative offsets from previous device position) by some user configurable scale value.

phlake
07-10-2000, 08:54 AM
i have to agree with MikeC... trig functions are quite fast. i've got a program performing 30 to 40 trig functions, assorted divisions and multiplications, etc, and i'm getting nearly 200fps. your GL state will affect you alot more. worry about efficient OpenGL code long before you worry about your math.

Blza
07-10-2000, 11:58 AM
OK DFrey..
So those angle are just variable that i can inc or dec following the keyboard input, for example ?? ahhh nice....

and phlake, how did you get 200 FPS man ????
i`m fighting my machine to get 40...
so poor...

a magic ??
heheh

thanx...

DFrey
07-10-2000, 01:19 PM
Yeah, right. For user input, I generally would use the input values to affect an applied force (linear or angular) and then derive the velocites and displacements. Though things are a bit more complicated when collision detection is considered but I digress, that is off topic.

[This message has been edited by DFrey (edited 07-10-2000).]

phlake
07-10-2000, 01:53 PM
Blza: well, first and foremost: not very many polygons. i'm building a tetris clone. 2nd: i have a geForce DDR. that probably helps. using detonator2 drivers, win2k, and a celeron overclocked to something like 472.6...

i'll have source available in a week or two. (unfortunately, i've got some dns problems right now... emailing me will be difficult... temporarily, you may use nate@24.31.244.201)

Blza
07-10-2000, 03:03 PM
No DFrey...
thats not off topic..

i dont know how uses those variables to simulate phisics laws man..

i mean, gravity, friction on body-to-body, etc...
is it hard ???

ribblem
07-10-2000, 03:12 PM
I suppose the preformance hit isn't too bad now that I look at it. But I'm definantly talking about more than 1 or 2 trig calls. To obtain free movement in all axis I currently need 6 calls per camera. And since I'm working on realistic shadows and mirrors I need multiple cammeras. It all adds up... You guys are definently right thought that my state has much more effect.

Noah
07-12-2000, 09:11 PM
This is what I use...It's written in Visual Basic, but i'm sure you fancy C++ programmers can figure it out:

angle=(Xangle)*(3.1415926/180) // calculate this for movement
angle2=(Zangle)*(3.1415926/180)

GLtranslate(-SavedX,-SavedY,-SavedZ) // translate the scene back to the origin

// Yaw
if keyboard.asynckeyDown(&h56) then
glRotate(2.0, 0.0, 0.0, 1.0)
Xangle=Xangle+2.0
elseif keyboard.asynckeyDown(&h58) then
glRotate(2.0, 0.0, 0.0, -1.0)
Xangle=Xangle-2.0
end if
//

// pitch
if keyboard.asynckeyDown(&h5B) then
glrotate(1.0, cos(angle), sin(-angle), 0)
Zangle=Zangle+1
elseif keyboard.asynckeyDown(&h54) then
glrotate(1.0, -cos(angle), -sin(-angle), 0)
Zangle=Zangle-1
end if
//

GLtranslate(SavedX,SavedY,SavedZ) // put the scene bakc where it was

Vert = Cos(angle2)
gltranslate (MySpeed*sin(angle))*Vert, (MySpeed*cos(angle))*Vert, MySpeed*-sin(angle2) // move the scene in the XYZ direction that the player is facing by the increment MySpeed (which, if you haven't guessed, is the speed at which the player is moving)

SavedX=SavedX+MySpeed*sin(angle)*Vert // store the values of where the scene is positioned
SavedY=SavedY+MySpeed*cos(angle)*Vert
SavedZ=SavedZ+MySpeed*-sin(angle2)

FYI:
Keyboard.asyncKeydown(&h-whatever) polls the keyboard for the state of the key code passed, in case you were wondering what the heck that was for.

I hope this helps,
-Noah Desch

[This message has been edited by Noah (edited 07-12-2000).]

07-16-2000, 03:38 PM
The sin function code body looks like this:

return parameter * sin_constant;

Any trig function is simple multiplication. Sin is a constant. You see? http://www.opengl.org/discussion_boards/ubb/wink.gif

Because peeps don't know what trig is they assume it is slow... for a human, yes, but for a computer, no.

ngill
07-16-2000, 08:28 PM
umm... if there was a constant... that would mean that sin, cos would be a linear trig functions!! and they certainly aren't so... I could see it as a 6+ degree polynomial, which has a period... but that's different that's 6 mutliplications, instead of 1!

Siwko
07-17-2000, 07:32 AM
Easiest optimaization for this -

On construction of your class, app or whatever... build a trig lookup table. That way you're only doing your "expensive" calls only once during the entire app, at initialization.

Old programming trick... http://www.opengl.org/discussion_boards/ubb/smile.gif

MikeC
07-17-2000, 08:01 AM
... old programming trick, which will unfortunately often slow you down on newer systems.

Read just about any book on optimization, and chances are it'll tell you the same thing. Assume your processor is infinitely fast. It's memory access that kills you.

ribblem
07-17-2000, 12:00 PM
When I started this thread I was sure the trig functions use some infinite series to produce the results and I'm still pretty certain that is what is being done. If anyone knows which infinate series is used I'd appricate it if you'd tell me, just so I know.

After seeing how fast these operations are done I would agree with MiceC that the long used trig lookup tables just might be dead since with processors being as fast as they are even a Cache 1 lookup costs many clock cycles.

pbrisk
07-17-2000, 02:26 PM
[QUOTE]Originally posted by ribblem:
[B]When I started this thread I was sure the trig functions use some infinite series to produce the results and I'm still pretty certain that is what is being done. If anyone knows which infinate series is used I'd appricate it if you'd tell me, just so I know.

I don't know if these series are what are used in computers, but here is what I got from my CRC tables of Mathematical Formulae:
Ch. 1, p.41,

Infinite Series:

(the result of taking the Maclaurin series for the funtion )

sinx = x - (x^3/3!) + (x^5/5!) - (x^7/7!) + ...

cosx = 1 - (x^2/2!) + (x^4/4!) - (x^6/6!) + ...


There are also formulas that use infinite products (like a summation, but using multiplication instead of addition).

Hope that helps.

pbrisk
07-17-2000, 02:35 PM
Here are some formulas that may help you out:

DOT PRODUCT:

A . B = |A&#0124; &#0124;B|cosx, where x is the angle between vectors A and B. (remember |X| is the magnitude of vector X).

This gives us a simple formula for the angle between two vectors

cosx = (A . B)/(|A&#0124; &#0124;B|)

|A x B| = |A&#0124; &#0124;B|sinx.

So sinx = (|A x B|)/(|A&#0124; &#0124;B|).

Cross products are somewhat more costly than dot products, but should be easier than using series.


Originally posted by ribblem:
I'm pretty sure that sin and cos are pretty expensive. I suppose I could run a little benchmark. I've seen replacement sine and cosine routines that use a table lookup to speed up these computations, that makes me think the default versions are slow. I know dot products are super fast so that is why I'd like to find a way to replace my current method with a dot product method. In the mean time I think I'll put together a little bench mark. Talk to ya latter

pbrisk
07-17-2000, 02:47 PM
[QUOTE]Originally posted by Blza:
[B]No DFrey...
thats not off topic..

i dont know how uses those variables to simulate phisics laws man..

i mean, gravity, friction on body-to-body, etc...
is it hard ???

--------------------------------------------

Simulating physics should not be that hard. Mechanics really isn't that difficult (at least for me). Physics gets bad when it comes to wave motion, electricity and magnetism, optics, relativity, and quantum.

Look at a basic mechanics textbook. Serway is a good author. Most of the formulas are polynomial or trigonometric, and calculus is only necessary to derive the formulas (once you've got them, you can simply plug and chug).

Good luck

Siwko
07-18-2000, 04:26 AM
Lets see... Lookup table (cached) versus complex number operations... if your code is well ordered, the lookup table will ALWAYS yield better results in the long run over intensive calculations, save the case of optimized insturction sets, ie: AMD's math libraries for the K7.

Suffice it to say, its still a very fast optimization that can be made.