Finding world position of element in screen space - c++

I'm attempting to find the world position of an object that exists in screen space. For example in the below screenshot the pistol and hands are rendered without being translated into world space (using only projectionMatrix * modelMatrix), while the other objects in the scene exist in world space (translated via projectionMatrix * viewMatrix * modelMatrix):
I have added a "muzzle" bone to the end of the armature for this pistol, and I am attempting to convert the translation of the muzzle bone into world space so that I can cast a ray starting at this position.
I have this kind of working, but something isn't quite right. For example, note the closest green sphere in the above screenshot. That is the position which I come up with in world space for my muzzle bone. What I am expecting is below:
To obtain this position I am multiplying the position of the muzzle bone by the inverse of the projection and view matrixes of the world camera as follows:
glm::mat4 invMat = glm::inverse(worldStage.getCamera().value().getProjectionMatrix() *
worldStage.getCamera().value().getViewMatrix());
glm::vec4 tmp = this->weapons[this->currentWeapon].actor->getTransform().getMatrix() *
glm::vec4(this->weapons[this->currentWeapon].muzzleBone->translation, 1.0f);
glm::vec4 muzzleWorldTranslation = invMat * tmp;
muzzleWorldTranslation /= muzzleWorldTranslation.w;
It feels like I'm pretty close and there's just something that I'm missing or messed up slightly. If anyone is able to point out what that might be, I would be very grateful!

If you render an object with standard model M, view V and P matrices, you get the P*V*M as the overall transformation. If you draw a model without the view transform, you're placing the object directly in view space. However, conceptually, that will be the same as first placing your object in world space (by applying a modified model matrix M'), and rendering that with the full P*V*M' pipline.
Since V transforms from world to view space, inverse(V) will transform from view space to world space, and therefore M' = inverse(V) * M will get you P*V*M' = P*V*inverse(V)*M = P*M, and M' is exactly the transformation you are looking for. Note that the projection matrix has nothing to do with that at all, and you are not unprojecting any positions back from screen space as the question title suggests.

Related

Translate objects relative to the camera view

I'm trying to translate objects via matrices in OpenGL and I know how to rotate/translate/scale objects in model coordinates.
However, I want to make a callback to translate objects relative to the camera view (so, the z-axis always looks at the camera):
I'm operating with objects using the MVP matrix. Does somebody know how to translate objects on the screen coordinates, not world ones?
So you have this sequence of matrices: project * view * model * <vertices>.
Going right-to-left:
model converts the model from model space to world space.
view converts it from world space to camera space.
project converts it from camera space to clip space.
You have your offset in camera space, and want to convert it to model space, so you need to apply:
view.inverse() to transform from camera space to world space.
model.inverse() to transform from world space to model space.
Those are too ordered right-to-left, so:
modelspace_offset = model.inverse() * view.inverse() * cameraspace_offset

When I use glm::rotate to perform rotation, why the origin that rotate around changes after translation?

I am developing a robot hand simulation program in which I can load and draw a robot hand model(the model built in 3DS MAX) and perform some actions according to the inputs, for an example, joint angles.
the hand model contains many different parts, each part have it's own model matrix and VBO storing vertex coordinates, normals and uvs.
I want to perform rotation using glm::rotate() on a joint around a certain axis(not coordinate axis), so I was going to translate it to the world origin, and perform rotation, and finally move back.
The problem here is that when I perform rotation after translation, the world origin it rotates around seems changed as well, it looks like the world origin have been translated in the same way.
also, I don't really know whether glm::rotate rotates around world origin? it's confusing that why it changes, I have tested rotating directly not to translate before rotation, and it actually rotates around world origin,but when I perform translation before rotation, it changes.
More details:
I also think the problem are most likely in the coordinate system. I used a Robothand class to represent the robot hand object, and those "parts" are objects of Model class, there are parent-child relationships among models, so every transformation performed in one specific model will have the same effect on their children model.
Vertex shader
void main(){
mat4 MVP = P * V * M;
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
Position_worldspace = (M * vec4(vertexPosition_modelspace,1)).xyz;
vec3 vertexPosition_cameraspace = (V * M * vec4(vertexPosition_modelspace,1)).xyz;
EyeDirection_cameraspace = vec3(0,0,0) - vertexPosition_cameraspace;
vec3 LightPosition_cameraspace = (V * vec4(LightPosition_worldspace,1)).xyz;
LightDirection_cameraspace = LightPosition_cameraspace + EyeDirection_cameraspace;
Normal_cameraspace = ( V * M * vec4(vertexNormal_modelspace,0)).xyz;
UV = vertexUV;
Color = vertexColor;
}
I have to explain that the robot hand model is built in 3ds max, and exported as .obj file.In 3DS MAX, all the models share the same world origin, which means the their origin of model coordinate systems are in the same position. There are not any problems if I rotate any model without translation, it will rotate around world coordinate axis, but the real problem is, if I translate first, the world origin will be translated in the same way, it looks like rotating in a new coordinate system.

Why do you use camera space instead of model space for normals?

I am learning OpenGL graphics, and am getting into shadows. The tutorials that I am reading are telling me to transform my normals and light vector to camera space. Why is this? Why can't you just keep the coords in model space?
A follow up question to this is how to handle model transformations. I am unable to find a definitive answer. I currently have this code:
vec3 normCamSpace = normalize(mat3(V) * normal);"
vec3 dirToLight = (V*vec4(lightPos, 0.0)).xyz;"
float cosTheta = clamp(dot(normCamSpace, dirToLight),0,1);"
V is the view matrix, or the camera matrix. I am unsure how to move or edit the light when the model changes in position, rotation, and scale.
The main reason is, that usually your light positions will not be given in model space, but world space. However for illumination to work efficiently all calculations must happen in a common space. In your usual transformation chain, model local coordinates are transformed by the modelview matrix directly into view space
p_view = MV · p_local
Since you normally have only one modelview matrix it would be cumbersome to separate this steap into something like
p_world = M · p_local
p_view = V · p_world
For that you required MV to be separated.
Since the projection transformation traditionally happens as a separate step, view space is the natural "common lower ground" on which illumination calculation to base on. It just involves transforming transforming your light positions from world to view space, and since light positions are not very complex, this is done on the CPU and the pretransformed light positions given as shader.
Note that nothing is stopping you from performing illumination calculations in world space, or model local space. It just takes transforming the light positions correctly.
I am learning OpenGL graphics, and am getting into shadows. The tutorials that I am reading are telling me to transform my normals and light vector to camera space. Why is this? Why can't you just keep the coords in model space?
Actually if you're the one writing the shader, you can use whatever coordinate space you want. IMO calculating lighting in world space feels more "natural", but that's matter of taste.
However, there are two small details:
You cannot "naturally" calculate lighting in object space, if your object is a skinned mesh (character model animated by bones). Such model will require world space or view space. If your object can be only translated and rotated (affine transforms only), then lighting can be easily calculated in model/object space. I think some game engines actualy worked this way.
If you use camera space, you can drop one subtraction when calculating specular highlights. Blinn/phong specular models require vector to(or from) eye to calculate specular factor. In camera space vector from eye to point is equal to point position. This is a very small optimization and it probably isn't worth the effort.

Sight vector in OpenGL

The problem I have is that I cant get "line of sight" vector in OpenGL. I've done some research and found that it should be Z vector after transformations, but it doesn't want to work. I've got this code to retrive velocity of the block( i want it to move foward from "camera"), but all the time it moves irrelevant to camera, but all the time same way compared to rendered world:
GLfloat matrix[16];
glGetFloatv (GL_MODELVIEW_MATRIX, matrix);
GLfloat d = sqrt( matrix[8]*matrix[8] + matrix[9]*matrix[9] + matrix[10]*matrix[10]);
xmov = matrix[8]/d;
ymov = matrix[9]/d;
zmov = matrix[10]/d;
What I've done wrong?
Okay, now after you clarified what you really want to do, I'm pretty sure this is the correct answer:
You are probably used to something called ModelView matrix. Didn't it seem strange for you that it's essentially combined of two parts? Well, it was for me, and after I thought about it for a while, it made sense. The final vertex position is calculated like this:
gl_Position = ProjectionMat * ModelViewMat * VertexPos;
You see, there's no difference for OpenGL whether you move "camera" from origin by [x,y,z] or move objects by [-x,-y,-z] - you'll get the same results. It is however useful to distinguish a "camera" position as something that can be different from the origin.
gl_Position = ProjectionMat * ViewMat * ModelMat * VertexPos;
I think the most natural way to do it is, as I said, split the calculations into two matrices : Model and View. Every object on the scene now has to change the Model matrix, and camera position is set by changing View matrix. Makes sense?
I'll give you an example. If your camera is in [5,0,0] (which corresponds to Translate(-5,0,0)), and your object in [-5,0,0], it will land 10 units from the camera. Now, when you move your camera further away from origin (increasing the first translation distance), distance between "camera" and the object grows.
The object translation is the Model, the camera translation is the View.
So it's not hard to come to conclusion, that if you want to ignore camera position, just strip the View part from the equation; every object will now be drawn without taking camera position into account, thus relative only to your viewport.
gl_Position = ProjectionMat * ModelMat * VertexPos;
Our hypothetical model will now land 5 units along the X axis from the viewport regardless of what you're currently "looking at", and that's, I think, pretty much what you wanted to achieve.
Anyway, you could probably use a nice tutorial about it

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.