Forum

GL matrix story (stupid but true)

Discuss programming topics for the various GPL'd game engine sources.

Moderator: InsideQC Admins

GL matrix story (stupid but true)

Postby Baker » Mon Apr 16, 2018 3:47 pm

I am writing code to force portrait display mode by rotating the frustum/ortho/viewport.

Results in a 90 turn just by inserting ...

glRotatef (90, 0, 0, 1); // Add me!
glFrustum (-xmax, +xmax, -ymax, -ymax, glnear, glfar);

Stupidly, OpenGL fails to do this! Possibly due to a division by zero I am guessing where perhaps -xmax and xmax are used somewhere in the matrix calculation in a way they add together to be zero.

Hilarously ... instead I use mh's glmatrix frustum calculation which performs the calculation in a way that avoids division by 0 in common situations --- then do glLoadMatrixf (m) to load that matrix.

Then I live in "Not my problem!" city!
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3661
Joined: Tue Mar 14, 2006 5:15 am

Re: GL matrix story (stupid but true)

Postby Spike » Mon Apr 16, 2018 8:32 pm

well, (-ymax)-(-ymax) == 0, so yeah, what do you expect?
I really hope that was a typo in your post and not your code. :P

glFrustum internally does a glMultMatrix, so make sure your prior matrix is sane. Also that you've got GL_MATRIX_MODE set properly. too much state sucks. but yeah, glLoadMatrix is the most sane way to do most of this anyway. The matrix generated by the function is well defined and well documented so implementing your own should be fairly easy, and more efficient on account of using glLoadMatrix instead of the implicit glMultMatrix of glFrustum.
Spike
 
Posts: 2878
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: GL matrix story (stupid but true)

Postby Baker » Tue Apr 17, 2018 1:36 am

Spike wrote:well, (-ymax)-(-ymax) == 0, so yeah, what do you expect?
I really hope that was a typo in your post and not your code. :P

Twas a typo. That'd be a very small vertical frustum otherwise :biggrin:
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3661
Joined: Tue Mar 14, 2006 5:15 am

Re: GL matrix story (stupid but true)

Postby mh » Wed Apr 18, 2018 4:40 am

Yeah, the great thing about OpenGL is that you can look at the spec, read how things are implemented, then construct your own variant if you need to.

It should be possible (and easy!) to write a GL_RotatedFrustum that does the same in a single operation, not that it would be a performance improvement (unless for some reason you're calling glFrustum thousands or more times per frame).

None of these calls do anything special or magic or voodoo. They just construct an ordinary 4x4 matrix, do a multiplication and load the result to the GPU. There's nothing mysterious going on in their internals.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
User avatar
mh
 
Posts: 2287
Joined: Sat Jan 12, 2008 1:38 am

Re: GL matrix story (stupid but true)

Postby toneddu2000 » Thu Apr 19, 2018 5:39 pm

Since we're talking about GL matricies, could please tell me, you, engine gurus, if it's possible to create an ortographic matrix to pass to FTE shadowmap code to make it project dynamic parallel shadows? Because I tried and I tried but so far I only created weird static plane shadows! :biggrin:

Note that I created same matrix also in GLSL and pass it to the shadow map fragment shader part

PS:sorry to have sneaked into your post with a question, Baker, but the opportunity was too greedy!! :biggrin:
toneddu2000
 
Posts: 1301
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: GL matrix story (stupid but true)

Postby Spike » Thu Apr 19, 2018 9:53 pm

toneddu2000, you're actually looking for two projection matricies.
the one used to render the shadowmap needs to transform from camera space to clip space.
the one used to read the shadowmap needs to transform again from camera space, but this time to the texture coords (with depth).

clip space in opengl ranges from -1 on the left, bottom, and nearest part of the screen, to 1 on the right, top, and furthest part of the screen.
on the other hand, texture coords range from 0 to 1, as does the 'red' component of the shadowmap texture (aka the depth).
sampling from a 2d shadow sampler can be done with a 3d texcoord - the 3rd coord being a reference value to compare the texture against. This gives slightly smoother results. the alternative is to treat it as a regular texture and do the compare yourself, which may be needed with gles2, but mneh.

so the first matrix is a standard ortho matrix, while the second one can be generated from the first by multiplying it against a bias matrix, but if you care about precision you'd get more precise results by calculating it directly.
and don't forget the divide-by-w thing, though I don't recall it actually being needed with ortho matricies.
Spike
 
Posts: 2878
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: GL matrix story (stupid but true)

Postby toneddu2000 » Fri Apr 20, 2018 10:23 am

thanks a lot Spike, I'll reply in the original thread, to avoid spoling Baker's thread
toneddu2000
 
Posts: 1301
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: GL matrix story (stupid but true)

Postby Baker » Fri Apr 20, 2018 2:46 pm

Doesn't bother me in the slightest, just fyi. Was just sharing a short experience.

Your post about shadowmapping was interesting. Carry on ... should you wish ...
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3661
Joined: Tue Mar 14, 2006 5:15 am

Re: GL matrix story (stupid but true)

Postby toneddu2000 » Sat Apr 21, 2018 2:20 pm

Lol, thanks Baker. Anyway, I couldn't get it work. Spike advices were very clear but probably my opengl skills are too low to create a working orthographic projection in FTE for project parallel shadows.

I adapted this GLSL shader that mimic parallel light and I used this site as reference for bias matrix and for learning how shadows are applied in fragment shader

This is the modification in Sh_GenShadowMap() in gl_shadow.c. I simply delete all the code regarding omni/spot and replaced with this. Just temp code.
Code: Select all
float left = -1;
float bottom = -1;
float znear = -1;
float right = 1;
float top = 1;
float zfar = 1;
Matrix4x4_CM_Orthographic(r_refdef.m_projection_std,left,right,bottom,top,znear,zfar);
memcpy(r_refdef.m_projection_view, r_refdef.m_projection_std, sizeof(r_refdef.m_projection_view));


In CSQC_UpdateView I created a simple light
Code: Select all
ltest = dynamiclight_add(cam.origin,cvar("render_light_radius"),[cvar("render_light_intensity"),cvar("render_light_intensity"),cvar("render_light_intensity")],0,"",0);


This is the GLSL shader created by Hugh Kennedy (MIT license)
Code: Select all
!!permu FOG
!!samps diffuse
!!cvarf render_sun_ground
!!cvarf render_sun_x
!!cvarf render_sun_y
!!cvarf render_sun_z
!!cvarf render_sun_back_x
!!cvarf render_sun_back_y
!!cvarf render_sun_back_z
!!cvarf render_sun_intensity
#include "sys/defs.h"
#include "sys/pcf.h"
#include "sys/fog.h"
#define shdwIntensity 0.1
varying vec2 tc;
varying vec3 eyevector,normalvector,lightvector;
varying vec4 modelvector,viewvector,vtexprojcoord,shadowCoord ;
uniform float cvar_render_sun_x,cvar_render_sun_y,cvar_render_sun_z,cvar_render_sun_ground;
uniform float cvar_render_sun_back_x,cvar_render_sun_back_y,cvar_render_sun_back_z,cvar_render_sun_intensity;
//Copyright (c) 2014 Hugh Kennedy - MIT License - https://github.com/hughsk/glsl-directional-light
//adapted to FTE engine by Antonio "toneddu2000" Latronico - antoniolatronico.com
#ifdef VERTEX_SHADER
void main (void)
{
   vec3 eyeminusvertex = e_eyepos - v_position.xyz;
   normalvector = -v_normal.xyz;
   eyevector.x = dot(eyeminusvertex, v_svector.xyz);
   eyevector.y = dot(eyeminusvertex, v_tvector.xyz);
   eyevector.z = dot(eyeminusvertex, v_normal.xyz);
   lightvector = l_lightposition - v_position.xyz;
   const float right = 1.0;
    const float bottom = -1.0;
    const float left = -1.0;
    const float top = 1.0;
    const float far = 1.0;
    const float near = -1.0;
   mat4 shdwmat = mat4(
        vec4(2.0 / (right - left), 0, 0, -(right + left) / (right - left)),
        vec4(0, 2.0 / (top - bottom), 0, -(top + bottom) / (top - bottom)),
      vec4(0, 0, -2.0 / (far - near), -(far + near) / (far - near)),
      vec4(0, 0, 0, 1)
    );
   mat4 biasmat = mat4(
        vec4(0.5, 0.0, 0.0, 0.0),
        vec4( 0.0, 0.5, 0.0, 0.0),
      vec4( 0.0, 0.0, 0.5, 0.0),
      vec4(0.5, 0.5, 0.5, 1.0)
    );
   mat4 depthMVP = m_projection * m_view * m_model;
   mat4 depthBiasMVP = biasmat*depthMVP;
   vtexprojcoord = (shdwmat*biasmat*vec4(1.0,1.0,1.0, 1.0));
   shadowCoord = depthBiasMVP * vec4(v_position.xyz, 1.0);
   gl_Position = ftetransform();
}
#endif
#ifdef FRAGMENT_SHADER
vec3 directional_light(vec3 normal,vec3 light,vec3 surface,vec3 lightDirection,mat4 modelMatrix,mat4 viewMatrix,vec3 viewPosition,float shininess,float specularity)
{
   vec3 direction = normalize((vec4(lightDirection, 1.0)).xyz);
   vec3 halfDirection = normalize(direction + viewPosition);
   vec3 tNormal = normalize((modelMatrix * vec4(normal, 1.0)).xyz);
   float diffuse = max(dot(tNormal, direction), 0.0);
   float halfDot = max(dot(tNormal, halfDirection), 0.0);
   float specular = max(pow(halfDot, shininess), 0.0);
   return max(light * (diffuse * surface + diffuse * specular * specularity), vec3(0.0));
}

vec3 directional_light(vec3 normal,vec3 light,vec3 surface,vec3 lightDirection,mat4 modelMatrix,mat4 viewMatrix,vec3 viewPosition)
{
   vec3 direction = normalize((modelMatrix * vec4(lightDirection, 1.0)).xyz);
   float diffuse = max(dot(normal, direction),shdwIntensity);
   return max(light * diffuse * surface,vec3(0.0));
}

void main (void)
{
   vec3 sky = vec3(0.510,0.247,0.000);
   vec3 gnd = vec3(0.002,0.486,0.912);
   vec3 direction1 = normalize(vec3(cvar_render_sun_x,cvar_render_sun_y, cvar_render_sun_z));
   vec3 direction2 = normalize(vec3(cvar_render_sun_back_x, cvar_render_sun_back_y, cvar_render_sun_back_z));
   vec3 surface = vec3(1.0,1.0,1.0);
   vec3 color = vec3(0.3,0.3,0.3);
   //realtime shadows
   float visibility = 1.0;
   if ( ShadowmapFilter(s_shadowmap, shadowCoord)  <  shadowCoord.z){
      visibility = 0.2;
   }
   #ifdef GREENBRIGHT
      color = vec3(0.059,0.750,0.000);
   #endif
   #ifdef GREENDARK
      color = vec3(0.000,0.510,0.003);
   #endif
   #ifdef GREENYELLOW
      color = vec3(0.484,0.840,0.032);
   #endif
   #ifdef BROWNBRIGHT
      color = vec3(0.795,0.391,0.027);
   #endif
   #ifdef BROWNDARK
      color = vec3(0.545,0.267,0.001);
   #endif
   #ifdef GREYBRIGHT
      color = vec3(0.645,0.655,0.622);
   #endif
   #ifdef GREYDARK
      color = vec3(0.507,0.515,0.489);
   #endif
   #ifdef GREYVERYDARK
      color = vec3(0.369,0.375,0.356);
   #endif
   #ifdef RED
      color = vec3(0.990,0.188,0.000);
   #endif
   #ifdef YELLOW
      color = vec3(0.990,0.700,0.016);
   #endif   
   vec3 composite = mix(surface,color,max(dot(normalvector, direction1),shdwIntensity));
   color *= vec3(cvar_render_sun_intensity);
   #ifdef SHDW
   color = color + (visibility * l_lightcolour );
   #endif
   vec3 lightsun = vec3(1.000,0.878,0.000);//light sun (usually bright sun)
   vec3 lightambient = vec3(0.081,0.593,0.685);//light gi (usually dark blue)
   mat4 matrixModel = m_projection;
   mat4 matrixView = m_invviewprojection;
   vec3 lighting =
   directional_light(normalvector, lightsun, color, direction1, matrixModel, matrixView, eyevector)
   + directional_light(normalvector, lightambient, color, direction2, matrixModel, matrixView, eyevector);
   gl_FragColor = fog4(vec4(lighting,1.0));
   gl_FragDepth = gl_FragCoord.z;
}
#endif


And this is the material with the BEMODE for rtlights. Note that diffusemap it's useless, since GLSL colors meshes by itself,it's there only to avoid FTE complaining about missing pass
Code: Select all
parallelshdw
{
   //first set textures
   diffusemap textures/env/green.tga
   //second bemode for realtime lights
   bemode rtlight
   {
      program ton_lightparallel#SHDW
   }
}

This will make a nice diffuse parallel light with a counter ambient light, which it's cool.Look how round light is.
Image

And this is the shader with the #SHDW flag... practically nothing useful! :)
Image
As you can see, shadow is just a square sitting in the middle of scene. It's like it was placed at specific coordinates

Weird thing is that, even with FTE release without my modification, rendering is the same as above
toneddu2000
 
Posts: 1301
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: GL matrix story (stupid but true)

Postby Spike » Sat Apr 21, 2018 3:33 pm

for a start, you're not even using the ortho matrix in your glsl, at least not in any way that would prevent it from being optimised out.

your light is in one place and its projecting onto some meshes. the vertex coords get multiplied by the model matrix which gives you the vertexes world coord. at this point things diverge - you have both a camera (with its view + perspective-projection matrix), and a light (which has its own orientation/view matrix, and its own ortho-projection matrix).
gl_Position needs the screen/camera position in clip space.
however, your shadowCoord needs the shadow coord in texture space upon your projected texture. this has absolutely nothing to do with the camera's view or projection matrix - the only normal matrix that matters for this varying is the model matrix.

what I'd recommend you try is to first just get your texture projection working.
ditch the shadow map for now, and just project a regular coloured 2d image onto a black wall for now.
that way you'll know when your s+t texture coords are correct, that there's no weird affine issues, etc, in a way that is completely separate from the shadowmap generation.
divide and conquer. you won't know when the p coord is correct until you reinstate the actual shadowmap, but at least you'll know that you're actually reading the right part of the shadowmap. the actual depth values themselves are probably the last thing you should tackle (ignoring stuff like pcf/smoothing/etc).
Spike
 
Posts: 2878
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: GL matrix story (stupid but true)

Postby toneddu2000 » Sat Apr 21, 2018 11:02 pm

Spike wrote:what I'd recommend you try is to first just get your texture projection working.
ditch the shadow map for now, and just project a regular coloured 2d image onto a black wall for now.

Something like that?
Image

I projected this texture
on this scene.
Image
I used same matrix trasformations for both gl_Position and projected texture coords.
It's important to mention that, in FTE, if you want to assign to gl_Position, something that is not ftetranform(), you have to use z margin to "extrude" it a little, otherwise zfighting will ruin the rendering
Here's the code
Code: Select all
#include "sys/defs.h"
varying vec4 projectedCoords;
#ifdef VERTEX_SHADER
void main (void)
{
   projectedCoords = m_projection * m_view * m_model* vec4(v_position.xyz, 1.0);
   //projection in clip space
   gl_Position = m_projection * m_view * m_model* vec4(v_position.xyz, 1.0);
   //z-fighting fix copied from here: https://stackoverflow.com/questions/24142068/z-fighting-solutions-in-depth-test-in-opengl-how-do-they-work
   float Z = 1.0;
   float far = 2000.0;   
   gl_Position.z = 2.0*log(gl_Position.w*Z + 1.0)/log(far*Z + 1.0) - 1.0;
   gl_Position.z *= gl_Position.w;
}
#endif
#ifdef FRAGMENT_SHADER
uniform sampler2D s_t0;
void main (void)
{
   vec4 projectimg = texture2DProj(s_t0,normalize(projectedCoords));
   gl_FragColor = projectimg;
}
#endif

Of course, now, inclination of texture is tied to camera inclination.
Was that what you meant? Now what? :biggrin:
Should I use, instead of camera inclination, an arbitrary matrix for rotation?
This is fun :biggrin:
toneddu2000
 
Posts: 1301
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: GL matrix story (stupid but true)

Postby Spike » Sun Apr 22, 2018 12:33 am

no, you want to project the texture, not sample it from screen space. If you'd wanted that then there are easier ways to do it. Ones that do not require you creating a z-fighting minefield. Try re-reading the second block of text in my previous post.
Spike
 
Posts: 2878
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: GL matrix story (stupid but true)

Postby toneddu2000 » Sun Apr 22, 2018 8:35 am

ok, this is what I did so far. I premise that I use this page as reference(for those interested, go to "9.3 Projective Texturing" chapter).

I don't sample anymore from screen space but I use model matrix multiplied by the light projection matrix (engine-builtin l_cubematrix matrix)

vertex shader(same for both "versions").
Code: Select all
void main (void)
{
   texCoordProj = m_model* l_cubematrix * vec4(v_position.xyz, 1.0);
   gl_Position = ftetransform();
}


fragment shader
Code: Select all
uniform sampler2D s_t0;
void main (void)
{
   vec2 uv = normalize(gl_FragCoord.xy/gl_FragCoord.w)/2.0;
   vec4 tex = texture2D(s_t0,uv);
   vec4 projectimg,texCoordProjNorm;
   texCoordProjNorm = normalize(texCoordProj);   
   projectimg = texture2DProj(s_t0,texCoordProjNorm);
   gl_FragColor = projectimg;
}


And I ended up with this.
Image
As you can see, texture is projected but scale is very low. I put in the top-right corner a zoomed view of texture.
This one was the texture2DProj version. Now the other one.

The next one uses .st swizzle of texCoordProjNorm and texture2D instead using the full vec4 coord and texture2DProj,
Code: Select all
uniform sampler2D s_t0;
void main (void)
{
   vec2 uv = normalize(gl_FragCoord.xy/gl_FragCoord.w)/2.0;
   vec4 tex = texture2D(s_t0,uv);
   vec4 projectimg,texCoordProjNorm;
   texCoordProjNorm = normalize(texCoordProj);   
   projectimg = texture2D(s_t0,texCoordProjNorm.st);
   gl_FragColor = projectimg;
}

so probably it's not what I should do, but, weirdly, final image is exactly what I wanted to achieve!
Image
Now texture orientation is not tied anymore to camera inclination and it seems that texture "covers" entire scene with same texture coordinates. But I used texture2D, and not texture2DProj

adding to vertex shader a bias matrix and multiplying it to model matrix and l_cubematrix, makes image less "warped"
Code: Select all
mat4 biasmat = mat4(
        vec4(0.5, 0.0, 0.0, 0.0),
        vec4( 0.0, 0.5, 0.0, 0.0),
      vec4( 0.0, 0.0, 0.5, 0.0),
      vec4(0.5, 0.5, 0.5, 1.0)
    );
   texCoordProj = m_model* l_cubematrix * biasmat* vec4(v_position.xyz, 1.0);

Image

So, did I do things correctly? Is it right to use texture2D, instead of texture2DProj? Or was the texture2DProj approach the correct one(but I missed some steps)? Or none of them? :biggrin:


Then, I used another approach from this page, which it uses projection matrix multiplied by model matrix
Code: Select all
!!ver 130
#include "sys/defs.h"
varying vec4 texCoordProj;
#ifdef VERTEX_SHADER
void main (void)
{
   mat4 biasmat = mat4(
        vec4(0.5, 0.0, 0.0, 0.0),
        vec4( 0.0, 0.5, 0.0, 0.0),
      vec4( 0.0, 0.0, 0.5, 0.0),
      vec4(0.5, 0.5, 0.5, 1.0)
    );
   texCoordProj = m_projection* m_model* biasmat* vec4(v_position.xyz, 1.0);
   gl_Position = ftetransform();
}
#endif
#ifdef FRAGMENT_SHADER
uniform sampler2D s_t0;
void main (void)
{
   vec2 uv = normalize(gl_FragCoord.xy/gl_FragCoord.w)/2.0;
   vec4 tex = texture2D(s_t0,uv);
   vec4 projectimg,texCoordProjNorm;
   texCoordProjNorm = normalize(texCoordProj);   
   projectimg = texture2DProj(s_t0,texCoordProj);
   gl_FragColor = projectimg;
}
#endif

And the image is this
Image
Personally, this seems a weird projection and texture is stretched above spheres. It seems more like that every object preserves its own texture coords. But this approach uses texture2DProj
toneddu2000
 
Posts: 1301
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: GL matrix story (stupid but true)

Postby toneddu2000 » Sat Apr 28, 2018 3:19 pm

Today I tried a different approach. Instead of using engine builtin matricies, I asked myself: how would it be if I use arbitrary rotation matrix for texture plane projection?
So I learned here how openGL uses matricies for transformation and I created a rotation on X axys matrix
Code: Select all
    mat4 rot_mat_x_axis = mat4(
        vec4(1.0, 0, 0, 0),
        vec4(0,cos(cvar_glsl_project_angle),-sin(cvar_glsl_project_angle),0),
      vec4(0, sin(cvar_glsl_project_angle),cos(cvar_glsl_project_angle),0),
      vec4(0, 0, 0, 1)
    );

which I used as inclination for plane projection.
This is the glsl file
Code: Select all
!!ver 430
!!cvarf glsl_project_angle
#include "sys/defs.h"
varying vec4 ProjTexCoord;
varying vec2 uv;
uniform float cvar_glsl_project_angle;
#ifdef VERTEX_SHADER
void main (void)
{
   mat4 rot_mat_x_axis = mat4(
        vec4(1.0, 0, 0, 0),
        vec4(0,cos(cvar_glsl_project_angle),-sin(cvar_glsl_project_angle),0),
      vec4(0, sin(cvar_glsl_project_angle),cos(cvar_glsl_project_angle),0),
      vec4(0, 0, 0, 1)
    );
   vec4 pos4 = vec4(v_position.xyz, 1.0);
    ProjTexCoord = (m_projection*rot_mat_x_axis*pos4);
   uv.xy = v_texcoord;
   gl_Position = ftetransform();
}
#endif
#ifdef FRAGMENT_SHADER
uniform sampler2D s_t0,s_t1;
void main (void)
{
   vec4 texProj = vec4(0.0);
   vec4 texDiff = texture2D(s_t0,uv.xy);
   vec4 finalColor;
    if( ProjTexCoord.z < cvar_glsl_project_angle ){
       texProj = textureProj( s_t1, ProjTexCoord );
       finalColor = texProj;
   }
   else{
      finalColor = texDiff;
   }
    gl_FragColor = finalColor;
}
#endif

This is the rendering
Image
you can use cvar_glsl_project_angle to change angle of orientation of the projected plane. As you can see, both spheres have same inclination of projection, cubes seems that have their own. Plus, rotating objects like the cube in the screenshot, rotate the projection with them, so it's again in object coordinates, not world coords. But, really, I cannot understand how to convert it.
toneddu2000
 
Posts: 1301
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy


Return to Engine Programming

Who is online

Users browsing this forum: No registered users and 2 guests