1
\$\begingroup\$

So I have the following...

float s = 0.5f;

void renderFrameLine() {
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  GLfloat vVertices[] = { s, s, 0.0f, s, -s, 0.0f, -s, s,
    0.0f};
  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices);
  glEnableVertexAttribArray(0);
  glDrawArrays(GL_TRIANGLES, 0, 3);
}

This works great so now I want to add depth so I get ready by changing my vertex shader as following...

GLbyte vShaderStr[] =
"attribute vec4 vPosition;   \n"
"uniform mat4 Projection;   \n"
"void main()                 \n"
"{                           \n"
"     gl_Position = Projection * vPosition; \n"
"}                           \n";

And based on this code in GLM...

template <typename valType>
    GLM_FUNC_QUALIFIER detail::tmat4x4<valType> perspectiveFov
    (
            valType const & fov,
            valType const & width,
            valType const & height,
            valType const & zNear,
            valType const & zFar
    )
    {
#ifdef GLM_FORCE_RADIANS
            valType rad = fov;
#else
            valType rad = glm::radians(fov);
#endif
            valType h = glm::cos(valType(0.5) * rad) / glm::sin(valType(0.5) * rad);
            valType w = h * height / width; ///todo max(width , Height) / min(width , Height)?

            detail::tmat4x4<valType> Result(valType(0));
            Result[0][0] = w;
            Result[1][1] = h;
            Result[2][2] = - (zFar + zNear) / (zFar - zNear);
            Result[2][3] = - valType(1);
            Result[3][2] = - (valType(2) * zFar * zNear) / (zFar - zNear);
            return Result;
    }

I create the following function to create a perspective matrix...

void glFrustumf(float near, float far){
        float aspectRatio = .5;
        float DEG2RAD = 3.14159f / 180.0f;
        float fov = 90*DEG2RAD;
        float h = cosf(0.5f*fov)/sinf(0.5f*fov);
        float w = h * aspectRatio;
        float a =  - (near+far)/(near - far);
        float b = - ((2*far*near)/(far-near));

        float proj[16] = {
                        w, 0, 0, 0,
                        0, h, 0, 0,
                        0, 0, a, 1,
                        0, 0, b, 0
                    };
        GLint projectionUniform = glGetUniformLocation(programObject, "Projection");
        glUniformMatrix4fv(projectionUniform, 1, 0, &proj[0]);
}

This doesn't seem to work and instead returns a blank screen. Can anyone tell me what I am doing wrong?

Update

I also tried

void glFrustumf(float near, float far, float left, float right, float bottom, float top){
        float deltaX = right - left;
        float deltaY = top - bottom;
        float deltaZ = far - near;

        float a = 2.0f * near / deltaX;
        float b = 2.0f * near / deltaY;
        float c = (right + left) / deltaX;
        float d = (top + bottom) / deltaY;
        float e = -(near + far) / deltaZ;
        float f = -2.0f * near * far / deltaZ;

        float proj[16] = {
                        a, 0, 0, 0,
                        0, b, 0, 0,
                        c, d, e, -1.0f,
                        0, 0, f, 0
                    };
        GLint projectionUniform = glGetUniformLocation(programObject, "Projection");
        glUniformMatrix4fv(projectionUniform, 1, GL_FALSE, &proj[0]);
}

but no dice...

Per previous comment

Based on this line...

2 ⁢ nearVal right - left 0 A 0 0 2 ⁢ nearVal top - bottom B 0 0 0 C D 0 0 -1 0

A = right + left right - left

B = top + bottom top - bottom

C = - farVal + nearVal farVal - nearVal

D = - 2 ⁢ farVal ⁢ nearVal farVal - nearVal

I changed to this...

float proj[16] = {
                        a, 0, c, 0,
                        0, b, d, 0,
                        0, 0, e, f,
                        0, 0, -1, 0
};

But still just black...

Also tried...

void glFrustumf(float near, float far){
    float aspectRatio = .5;
    float DEG2RAD = 3.14159f / 180.0f;
    float fov = 90*DEG2RAD;
    float w = fov/aspectRatio;
    float a =  - (near+far)/(near - far);
    float b = - ((2*far*near)/(near - far));

    float proj[16] = {
                    w, 0, 0, 0,
                    0, fov, 0, 0,
                    0, 0, a, b,
                    0, 0, -1, 0
                };
    GLint projectionUniform = glGetUniformLocation(programObject, "Projection");
    glUniformMatrix4fv(projectionUniform, 1, 0, &proj[0]);
}

Also tried ...

void glFrustumf(float near, float far){
    float aspectRatio = .5;
    float DEG2RAD = 3.14159f / 180.0f;
    float fov = 90*DEG2RAD;
    float cot = (1 / (tanf(fov)/2));
    float cota = cot /aspectRatio;
    float a =  - (far+near)/(near - far);
    float b = - ((2*far*near)/(near-far));

    float proj[16] = {
                    cota, 0, 0, 0,
                    0, cot, 0, 0,
                    0, 0, a, b,
                    0, 0, -1, 0
                };
    GLint projectionUniform = glGetUniformLocation(programObject, "Projection");
    glUniformMatrix4fv(projectionUniform, 1, 0, &proj[0]);
}
\$\endgroup\$
3

2 Answers 2

3
\$\begingroup\$

I have had this exact problem. https://stackoverflow.com/questions/14713343/projection-theory-implimented-in-glsl

First thing I suggjest is getting a book called "3D Math Primer for Graphics and Game Development", which goes into detail on the clip matrix derives the whole formula for both OpenGL and DirectX projections. (There is a slight difference, oddly enough.)

Your matrix, in the first attempt, is actually correct. The error, or reason your screen is blank, is because your passing it to the Vertex Shader with glUniformMatrix4fv(projectUniform, 1, GL_FALSE, &proj[0]); That GL_FALSE, should be GL_TRUE. Giving glUniformMatrix4fv(projectUniform, 1, GL_TRUE, &proj[0]);

The projection matrices are as fallows (Row Major Format):

OpenGL:

| zoomX   0        0      0 |
|   0   zoomY      0      0 |
|   0     0   (f+n)/(f-n) 1 |
|   0     0   (2nf)/(n-f) 0 |

DirectX:

| zoomX   0        0      0 |
|   0   zoomY      0      0 |
|   0     0   (f+n)/(f-n) 1 |
|   0     0   (nf)/(n-f)  0 |

I'm also posting my implimentation. My implimentation automatically adjust's the row major format to column major format. So to pass a matrix in this format, you specify GL_FALSE. As opposed to your implimentation where you should specify GL_TRUE. Make shure you understand how to identify when to use GL_FALSE or GL_TRUE.

template <class type> struct mat4_t
{
    type m00, m10, m20, m30;
    type m01, m11, m21, m31;
    type m02, m12, m22, m32;
    type m03, m13, m23, m33;

    mat4_t();
    mat4_t(type, type, type, type,
           type, type, type, type,
           type, type, type, type,
           type, type, type, type);
};

template <class type> mat4_t<type>::mat4_t()
{
    m00 = 0; m01 = 0; m02 = 0; m03 = 0;
    m10 = 0; m11 = 0; m12 = 0; m13 = 0;
    m20 = 0; m21 = 0; m22 = 0; m23 = 0;
    m30 = 0; m31 = 0; m32 = 0; m33 = 0;
}

template <class type> mat4_t<type>::mat4_t(type n00, type n01, type n02, type n03,
                                           type n10, type n11, type n12, type n13,
                                           type n20, type n21, type n22, type n23,
                                           type n30, type n31, type n32, type n33)
{
    m00 = n00; m01 = n01; m02 = n02; m03 = n03;
    m10 = n10; m11 = n11; m12 = n12; m13 = n13;
    m20 = n20; m21 = n21; m22 = n22; m23 = n23;
    m30 = n30; m31 = n31; m32 = n32; m33 = n33;
}

typedef mat4_t<float> mat4;

mat4 ProjectionMatrix(float aspect, float fovy, float near, float far)
{
    float h = near * tan(radians(fovy));

    float fmn = far - near;
    return mat4(h * aspect, 0.0, 0.0,                0.0,
                0.0,        h,   0.0,                0.0,
                0.0,        0.0, (far + near) / fmn, 1.0,
                0.0,        0.0, (2*near*far) / fmn, 0.0);
}
\$\endgroup\$
7
  • \$\begingroup\$ Thanks a lot for showing your implementation! I will try to play around with it but from the documentation (Remember I am using GLES2.0) "Specifies whether to transpose the matrix as the values are loaded into the uniform variable. Must be GL_FALSE." So does this mean I just need to reverse the order of the variables? \$\endgroup\$
    – Jackie
    Jun 2, 2013 at 14:25
  • \$\begingroup\$ I tried maunally transposing to float proj[16] = { w, 0, 0, 0, 0, h, 0, 0, 0, 0, a, b, 0, 0, 1, 0 }; But still no dice \$\endgroup\$
    – Jackie
    Jun 2, 2013 at 14:47
  • \$\begingroup\$ adding GL_TRUE does cause an exception btw. \$\endgroup\$
    – Jackie
    Jun 2, 2013 at 14:58
  • \$\begingroup\$ Odd that GLES2.0 has that requirement, Though I guess we cant change that. Looking at your implimentation again, I see you have a = -(near+far)/(near-far) and then b = -(2*near*far)/(far-near). for one thing, there is'nt supposed to be a - in either equasion. You also have the denominators wrong. it should be a = (near+far)/(far-near) and b = (2*near*far)/(near-far) try changing that and see what happens. \$\endgroup\$ Jun 2, 2013 at 15:14
  • \$\begingroup\$ Or it could be a = (near+far)/(far-near) and b = -(2*near*far)/(far-near) I guess. so never mind, that should'nt change anything. \$\endgroup\$ Jun 2, 2013 at 15:15
1
\$\begingroup\$

Per previous this works...

void glFrustumf(float near, float far){
  float aspectRatio = .5;
  float DEG2RAD = 3.14159f / 180.0f;
  float fov = 90*DEG2RAD;
  float h = cosf(0.5f*fov)/sinf(0.5f*fov);
  float w = h * aspectRatio;
  float a =  - (near+far)/(near - far);
  float b = - ((2*far*near)/(far-near));

  float proj[16] = {
    w, 0, 0, 0,
    0, h, 0, 0,
    0, 0, a, 1,
    0, 0, b, 0
  };
  GLint projectionUniform = glGetUniformLocation(programObject, "Projection");
  glUniformMatrix4fv(projectionUniform, 1, 0, &proj[0]);
}
...
glFrustumf(0.1f, nf);

This now seems to work, I think Wolfgang's advice about the book is pretty solid. It helped a lot.

more info...

https://github.com/jrgleason/CrossGLESMobile

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged .