Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

gluLookAt is not available in OpenGLES 2. OpenGLES 2 is also using floats not doubles.

Taking the description on the gluLookAt man-page, I have implemented it like this:

void graphics_t::set_mvp_look_at(const vec_t& eye,const vec_t& centre,const vec_t& up) {
#if !defined(GL2) && !defined(NDEBUG)
    matrix_t check;
    const vec_t f((centre-eye).normalised()),
    const matrix_t m = {{
        s.x, s.y, s.z, 0,
        u.x, u.y, u.z, 0,
        -f.x, -f.y, -f.z, 0,
        0, 0, 0, 1
    set_mvp_matrix(matrix_t::translation(-eye).transposition() * (m.transposition() * pimpl->mvp)); // setter notifies shader
#if !defined(GL2) && !defined(NDEBUG)
    if(pimpl->mvp != check)
        std::cout << "WARNING! Error setting look-up: " << std::endl << pimpl->mvp << std::endl << " != " << std::endl << check << std::endl;

As you can see I have some inline unit-testing when building for a non-OpenGLES 2 target (that's my own GL2 define).

Now the code seems to work, although it feels somehow slightly wrong depth but I can't put my fingers on that.

However, the code is printing warnings all the time, e.g.:

WARNING! Error setting look-up: matrix_t<[4.79627,0,0.424102,-261.019],[0.243815,5.79255,-2.75737,51.5329],[0.158943,-0.862347,-1.79752,269.079],[0.0794715,-0.431174,-0.898762,350.119]> != matrix_t<[5.31579,0,0.470039,-289.291],[0.270225,6.41998,-3.05604,57.1149],[0.158943,-0.862347,-1.79752,269.079],[0.0794715,-0.431174,-0.898762,350.119]>

As you can see, the numbers are very nearly the same but not-quite.

My comparision function for my matrix class is fuzzy with if(fabs(f[i]-rhs.f[i])>0.001) return false;.

Is this error within expected bounds when using float precision instead of doubles? Or is there a bigger bug in my translation?

share|improve this question
add comment

1 Answer

up vote 4 down vote accepted

You need to normalise all base vectors. The purpose of the cross products is to get a direction, so there is no need to normalise before the cross product, but you need to do it afterwards. You can skip the step if you know the arguments were normalised and orthogonal to each other.

The following:

const vec_t f((centre-eye).normalised()),

should instead be:

const vec_t f((centre-eye).normalised()),
            s(f.cross(up).normalised()), /* <- only this line changes */

As for your question regarding floats instead of doubles, floats have a mantissa of 24 bits (32 minus 1 for the sign and 8 for the exponent, plus the implicit top mantissa value), which is approximately 7 decimal digits. So in general you should not get any precision loss before the 6th decimal, unless of course you do things like subtracting two very close numbers.

Edit: by construction, u doesn't need to be normalised; I removed the useless call.

share|improve this answer
What's that "implicit top mantissa value" about? –  David Gouveia Dec 16 '11 at 17:25
@DavidGouveia: you can always rewrite a non-zero floating point number so that its mantissa starts with 1. Since we know it's always 1, it's never encoded. The exception to this scheme is denormal values, but that's another story :-) –  Sam Hocevar Dec 16 '11 at 18:00
so very obvious when you explain it! I had copied the man-page without thinking it through. Thx :) –  Will Dec 16 '11 at 18:52
@Will: note that you can remove the extra normalise() call that I mistakenly introduced. I hope you now understand why! :-) –  Sam Hocevar Dec 17 '11 at 13:01
add comment

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.