Set projection mode in OpenGL 3? - opengl

In old OpenGL versions spatial projection (where objects become smaller with growing distance) could be enabled via a call to
glMatrixMode(GL_PROJECTION);
(at least as far as I remember this was the call to enable this mode).
In OpenGL 3 - when this slow stack-mode is no longer used - this function does not work any more.
So how can I have the same spatial effect here? What is the intended way for this?

You've completely misunderstood what glMatrixMode actually did. The old, legacy OpenGL fixed function pipeline kept a set of matrices around, which were all used indiscriminately when drawing stuff. The two most important matrices were:
the modelview matrix, which is used to describe the transformation from model local space into view space. View space is still kind of abstract, but it can be understood as the world transformed into the coordinate space of the "camera". Illumination calculations happened in that space.
the projection matrix, which is used to describe the transformation from view space into clip space. Clip space is an intermediary stage right before reaching device coordinates (there are few important details involved in this, but those are not important right now), which mostly involves applying the homogenous divide i.e. scaling the clip coordinate vector by the reciprocal of its w-component.
The fixed transformation pipeline always was
position_view := Modelview · position
do illumination calculations with position_view
position_clip := Projection · position_view
position_pre_ndc := position_clip · 1/position_clip.w
In legacy OpenGL the modelview and projection matrix are always there. glMatrixMode is a selector, which of the existing matrices are subject to the operations done by the matrix manipulation functions. One of these functions is glFrustum which generates and multiplies a perspective matrix, i.e. a matrix which will create a perspective effect through the homogenous divide.
So how can I have the same spatial effect here? What is the intended way for this?
You generate a perspective matrix of the desired properties, and use it to transform the vertex attribute you designate as model local position into clip space and submit that into the gl_Position output of the vertex shader. The usual way to do this is by passing in a modelview and a projection matrix as uniforms.
The most bare bones GLSL vertex shader doing that would be
#version 330
uniform mat4 modelview;
uniform mat4 projection;
in vec4 pos;
void main(){
gl_Position = projection * modelview * pos;
}
As for generating the projection matrix: All the popular computer graphics math libraries got you covered and have functions for that.

Related

How to translate the projected object in screen in opengl

I've rendered an 3d object and its 2d projection in the image is correct. However now I want to shift the 2d projected object by some pixels. How do I achieve that?
Note that simply translating the 3d object doesn't work because under perspective projection the 2d projected object could change. My goal is to just shift the 2d object in the image without changing its shape and size.
If you're using the programmable pipeline, you can apply the translation after you applied the projection transformation.
The only thing you have to be careful about is that the transformed coordinates after applying the projection matrix have a w coordinate that will be used for the perspective division. To make the additional translation amount constant in screen space, you'll have to multiply it by w. The key fragments of the vertex shader would look like this:
in vec4 Position;
uniform mat4 ModelViewProjMat;
uniform vec2 TranslationOffset;
void main() {
gl_Position = ModelViewProjMat * Position;
gl_Position.xy += TranslationOffset * gl_Position.w;
}
After the perspective division by w, this will result in a fixed offset.
Another possibility that works with both the programmable and fixed pipeline is that you shift the viewport. Say if the window size is vpWidth times vpHeight, and the offset you want to apply is (xOffset, yOffset), you can set the viewport to:
glViewport(xOffset, yOffset, vpWidth + xOffset, vpHeight + yOffset);
One caveat here is that the geometry will still be clipped by the same view volume, but only be shifted by the viewport transform after clipping was applied. If the geometry would fit completely inside the original viewport, this will work fine. But if the geometry would have been clipped originally, it will still be clipped with the same planes, even though it might actually be inside the window after the shift is applied.
As an addition to Reto Koradi's answer: You don't need shaders and you don't need to modify the viewport you use (which has the clipping issues mentioned in the answer). You can simply modifiy the projection matrix by pre-multiplying some translation (which in effect will be applied last, after the projective transformation):
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranstlate(x,y,z); // <- this one was added
glFrustum(...) or gluPerspective(...) or whatever you use
glFrustum and gluPerspective will multiply the current matrix with the projective transfrom matrix they build, that is why one typically loads identity first. However, it doesn't necessarily have to be identity, and this case is one of the rare cases where one should load something else.
Since you want to shift in pixels, but that transformation is applied in clip space, you need some unit conversions. Since the clip space is just the homogenous representation of the normalized device space, where the frustum is [-1,1] in all 3 dimensions (so the viewport is 2x2 units big in that space), you can use the following:
glTranslate(x * 2.0f/viewport_width, y * 2.0f/viewport_height, 0.0f);
to shift the output by (x,y) pixels.
Note that while I wrote this for fixed-function GL, the math will of course work with shaders as well, and you can simply modify the projection matrix used by the shader in the same way.

Normal mapping, how to transform vectors

In the vertex shader we usually create TBN matrix:
vec3 n = normalize(gl_NormalMatrix * gl_Normal);
vec3 t = normalize(gl_NormalMatrix * Tangent.xyz);
vec3 b = normalize(gl_NormalMatrix * Bitangent.xyz);
mat3 tbn = mat3(t, b, n);
This matrix transform vertices from Tangent space into Eye/Camera space.
Now for normal mapping (done in forward rendering) we have two options:
inverse tbn matrix and transform light_vector and view_direction and send those vectors to the fragment shader. After that those vectors are in Tangent space.
that way in the fragment shader we only need to read normal from a normal map. Since such normals are in Tangent space (by "definition") they match with out transformed light_vector and view_direction.
this way we do light calculations in Tangent space.
pass the tbn matrix into fragment shader and then transform each normal read from a normal map by that. That way we transform such normal into View space.
this way we do light calculations in Eye/Camera space
Option 1 seems to be faster: we have most transformations in the vertex shader, only one read from normal map.
Option 2 requires to transform each normal from normal map by the TBN matrix. But it seems a bit simpler.
Questions:
Which option is better?
Is there any performance loss? (maybe texture read will "cover" costs of doing the matrix transformation)
Which option is more often used?
I'll tell you this much right now - depending on your application, option 1 may not even be possible.
In a deferred shading graphics engine, you have to compute the light vector in your fragment shader, which rules out option 1. You cannot keep the TBN matrix around when it comes time to do lighting in deferred shading either, so you would transform your normals into world-space or view-space (this is not favored very often anymore) ahead of time when you build your normal G-Buffer (the calculation of the TBN matrix can be done in the vertex shader and passed to the fragment shader as a flat mat3). Then you sample the normal map using the basis and write it in world space.
I can tell you from experience that the big name graphics engines (e.g. Unreal Engine 4, CryEngine 3, etc.) actually do lighting in world-space now. They also employ deferred shading, so for these engines neither option you proposed above is used at all :)
By the way, you are wasting space in your vertex buffer if you are actually storing the normal, binormal and tangent vectors. They are basis vectors for an orthonormal vector space, so they are all at right angles. Because of this, you can compute the third vector given any two by taking the cross product. Furthermore, since they are at right angles and should already be normalized you do not need to normalize the result of the cross product (recall that |a x b| = |a| * |b| * sin(a,b)). Thus, this should suffice in your vertex shader:
// Normal and tangent should be orthogonal, so the cross-product
// is also normalized - no need to re-normalize.
vec3 binormal = cross (normal, tangent);
TBN = mat3 (tangent, binormal, normal);
This will get you on your way to world-space normals (which tend to be more efficient for a lot of popular post-processing effects these days). You probably will have to re-normalize the matrix if you intend to alter it to produce view-space normals.

How to move from model space to orthographic view in OpenGL 3.0+?

I've recently completed some examples in OpenGL which resulted in me drawing some triangles in the space -1 >= x <= 1, -1 >= y <= 1. What do I need to do to move to an orthographic view? What transforms do I need to perform? I'm assuming the resulting transform will be set into the vertex shader as a uniform variable, then applied to any incoming vertices.
Is it wise to use pixels as the scale of the view (i.e. 1024x768) or to use logical units (pixels x1000 for example)?
What do I need to do to move to an orthographic view? What transforms do I need to perform?
You must apply a orthographic projection. Note that the identity transform you used so far is already orthographic.
It's a good idea to decompose the transformation process into projection and modelview transformations. Each is described by a 4×4 matrix, which, you a right, are passed as uniforms to the vertex shader.
The typical vertex shader layout looks like
#version 120 /* or something later */
attribute vec4 position;
uniform mat4 proj;
uniform mat4 mv;
varying vec4 vert_pos; // for later versions of GLSL replace 'varying' with 'out'
void main()
{
// order matters, matrix multiplication is not
vert_pos = proj * mv * position; commutative */
}
The projection matrix itself must be supplied by you. You can either look at older fixed function OpenGL specifications to see how they're implemented. Or you use some ready to use graphics math library, like →GLM or (self advertisement) →linmath.h
Update due to comment
The modelview transform is used to set the point of view and the placement of geometry drawn into the scene. In general the modelview usually differs for each model drawn. Modelview itself can be decomposed into model and view. The view is what some people set using some sort of "lookAt" function. And model is the geometry placement part.
The projection is kind of the "lens" of OpenGL and what's responsible for the "ortho" or "perspective" or whatever look.
Like stated above the specific projection to be used is user defined, but usually follows the typical transformation matrices like found in older OpenGL specifications or in graphics math libraries. Just look at some older specification of OpenGL (say OpenGL-1.5 or so) for the definition of ortho and frustum matrices (they can be found for the fixed functions glOrtho and glFrustum).

In glsl, what is the formula used to compute gl_fragCoord from gl_position?

Please correct me if I'm wrong.
When using vertex and pixel shaders, we usually provide the code to compute the output gl_position of the vertex shader.
Then, we find ouselves with the input gl_FragCoord in the pixel shader.
What are the name of the operations performed by OpenGL to compute gl_FragCoord from gl_position ? Is it correct that those are "projection" and "clip coordinates transform" ?
Then, what exactly are the transformations performs during those operations ?
In other terms, what is the mathematical relation between gl_FragCoord and gl_position, that I could use to replace the openGL function ?
Thank you very much for any contribution.
gl_Position is in post-projection homogeneous coordinates.
It's worth noting that gl_Position is the (4d) position of a vertex, while gl_FragCoord is the (2d) position of a fragment.
The operations that happen in between are
primitive assembly (to generate a triangle from 3 vertices, e.g.)
clipping (i.e. cut the triangle in multiple triangles that are all on inside the view, if it does not initially fit)
viewport application
rasterization (take those triangles and generate covered fragments from them)
So, while you can find the formula to transform the arbitrary point that is represented from the vertex position in the 2d space that is the viewport, it's not in and of itself that useful, as the generated fragments do not align directly to the vertex position. the formula to get the 2d coordinate of the vertex is
2d_coord_vertex = viewport.xy + viewport.wh * (1 + gl_Position.xy / gl_Position.w)/2
Again, this is not gl_FragCoord. Check the details on rasterization in the GL specification if you want more in-depth knowledge.
I'm not sure exactly what you mean by "replace the openGL function", but rasterizing is non-trivial, and way beyond the scope of an SO answer.

How to transform back-facing vertices in GLSL when creating a shadow volume

I'm writing a game using OpenGL and I am trying to implement shadow volumes.
I want to construct the shadow volume of a model on the GPU via a vertex shader. To that end, I represent the model with a VBO where:
Vertices are duplicated such that each triangle has its own unique three vertices
Each vertex has the normal of its triangle
For reasons I'm not going to get into, I was actually doing the above two points anyway, so I'm not too worried about the vertex duplication
Degenerate triangles are added to form quads inside the edges between each pair of "regular" triangles
Using this model format, inside the vertex shader I am able to find vertices that are part of triangles that face away from the light and move them back to form the shadow volume.
What I have left to figure out is what transformation exactly I should apply to the back-facing vertices.
I am able to detect when a vertex is facing away from the light, but I am unsure what transformation I should apply to it. This is what my vertex shader looks like so far:
uniform vec3 lightDir; // Parallel light.
// On the CPU this is represented in world
// space. After setting the camera with
// gluLookAt, the light vector is multiplied by
// the inverse of the modelview matrix to get
// it into eye space (I think that's what I'm
// working in :P ) before getting passed to
// this shader.
void main()
{
vec3 eyeNormal = normalize(gl_NormalMatrix * gl_Normal);
vec3 realLightDir = normalize(lightDir);
float dotprod = dot(eyeNormal, realLightDir);
if (dotprod <= 0.0)
{
// Facing away from the light
// Need to translate the vertex along the light vector to
// stretch the model into a shadow volume
//---------------------------------//
// This is where I'm getting stuck //
//---------------------------------//
// All I know is that I'll probably turn realLightDir into a
// vec4
gl_Position = ???;
}
else
{
gl_Position = ftransform();
}
}
I've tried simply setting gl_position to ftransform() - (vec4(realLightDir, 1.0) * someConstant), but this caused some kind of depth-testing bugs (some faces seemed to be visible behind others when I rendered the volume with colour) and someConstant didn't seem to affect how far the back-faces are extended.
Update - Jan. 22
Just wanted to clear up questions about what space I'm probably in. I must say that keeping track of what space I'm in is the greatest source of my shader headaches.
When rendering the scene, I first set up the camera using gluLookAt. The camera may be fixed or it may move around; it should not matter. I then use translation functions like glTranslated to position my model(s).
In the program (i.e. on the CPU) I represent the light vector in world space (three floats). I've found during development that to get this light vector in the right space of my shader I had to multiply it by the inverse of the modelview matrix after setting the camera and before positioning the models. So, my program code is like this:
Position camera (gluLookAt)
Take light vector, which is in world space, and multiply it by the inverse of the current modelview matrix and pass it to the shader
Transformations to position models
Drawing of models
Does this make anything clearer?
the ftransform result is in clip-space. So this is not the space you want to apply realLightDir in. I'm not sure which space your light is in (your comment confuses me), but what is sure is that you want to add vectors that are in the same space.
On the CPU this is represented in world
space. After setting the camera with
gluLookAt, the light vector is multiplied by
the inverse of the modelview matrix to get
it into eye space (I think that's what I'm
working in :P ) before getting passed to
this shader.
multiplying a vector by the inverse of the mv matrix brings the vector from view space to model space. so you're saying your light-vector (in world space), is applied a transform that does view->model. It makes little sense to me.
We have 4 spaces:
model space: the space where your gl_Vertex is defined in.
world space: a space that GL does not care about in general, that represents an arbitrary space to locate the models in. It's usually what the 3d engine works in (it maps to our general understanding of world coordinates).
view space: a space that corresponds to the referencial of the viewer. 0,0,0 is where the viewer is, looking down Z. Obtained by multiplying gl_Vertex by the modelview
clip space: the magic space that the matrix projection brings us in. result of ftransform is in this space (so is gl_ModelViewProjectionMatrix * gl_Vertex )
Can you clarify exactly which space your light direction is in ?
What you need to do, however, is make the light vector addition in either model, world or view space: Bring all the bits of your operation in the same space. E.g. for model space, just compute the light direction in model space on CPU, and do a:
vec3 vertexTemp = gl_Vertex + lightDirInModelSpace * someConst
then you can bring that new vertex position in clip space with
gl_Position = gl_ModelViewProjectionMatrix * vertexTemp
Last bit, don't try to apply vector additions in clip-space. It won't generally do what you think it should do, as at that point you are necessarily dealing with homogeneous coordinates with non-uniform w.