I'm trying to get an object to always face the camera. I looked up a way to do this, but the problem is when I put this part into the view matrix nothing is affected by the model matrix. How can I get it to translate it using the model matrix? code:
GLuint transformLocation=glGetUniformLocation(textureShaders,"transform");
glm::mat4 transform;
glm::mat4 model;
glm::vec3 playerPosition=user.getPosition();
model=glm::translate(model,glm::vec3(xpos,0.0f,zpos));
glm::mat4 view;
view=glm::lookAt(cam.getPositionVector(),cam.getPositionVector()+cam.getFrontVector(),cam.getUpVector());
glm::mat4 rotationMatrix=glm::transpose(glm::lookAt(glm::vec3(xpos,0.0f,zpos),playerPosition,glm::vec3(0.0f,1.0f,0.0f)));
view*=rotationMatrix;
glm::mat4 projection;
projection=glm::perspective(45.0f,(float)900/(float)600,0.1f,100.0f);
transform=projection*view*model;
Your "rotation" matrix doesn't really make sense:
rotationMatrix=glm::transpose(glm::lookAt(glm::vec3(xpos,0.0f,zpos),playerPosition,glm::vec3(0.0f,1.0f,0.0f)));
This will not result in a rotation matrix (except when both xpos and zpos happen to be zero). lookAt will create a transform matrix which can be decomposed to r * t(-pos) (for whatever pos you call it with). Building the transpose of this matrix will result in the translation column beeing transposed to the fourth row, which completely will screw the final w coordinate.
I'm using spherically billboarded sprites along with 3D objects. Because the quad leans backwards to match the camera angle, it intersects with 3D objects immediately behind it. It is more noticeable when the camera angle is very large.The following link provides a very clear visual.
http://answers.unity3d.com/questions/582680/billboard-issue-in-front-of-3d-object.html
Is there an efficient way to resolve this?
The best solution I could come up with was to use cylindrical billboarding for depth calculations and spherical for the quad's actual position. This allows you to use spherical billboarding while ensuring the quad's depth remains constant.
For reference here are the billboarding ModelView Matrixes. [x]: implies the value is left as is.
Cylindrical mvMatrix Spherical mvMatrix
[1][x][0][x] [1][0][0][x]
[0][x][0][x] [0][1][0][x]
[0][x][1][x] [0][0][1][x]
[x][x][x][x] [x][x][x][x]
First modify the ModelViewMatrix for cylindrical billboarding and generate a depth vertex as such:
depthV = projectionMatrix * (mvm * vertex);
Next set the second column values for spherical billboarding and create the quad as usual:
mvm[1][0] = 0; mvm[1][2] = 0; mvm[1][1] = 1;
gl_Position = projectionMatrix * (mvm * vertex);
Finally send depthV to the fragment shader and use it for the depth calculation.
float ndcDepth = depthV.z / depthV.w;
gl_FragDepth = ((gl_DepthRange.diff * ndcDepth ) + gl_DepthRange.near + gl_DepthRange.far) / 2.0;
Scaling should be done before applying the ModelView Matrixes.
I'm creating basic OpenGL scene and I have problem with manipulating with my object. Each has different transformation matrix, there's also modelview/translation/scaling matrix for whole scene.
How do I bind this data tomy object before executing calculations from vertex shader? I've read about gl(Push|Pop)Matrix(), but these functions are deprecated from what I understood.
A bit of my code. Position from vertex shader:
gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
And C++ function to display objects:
// Clear etc...
mat4 lookAt = glm::lookAt();
glLoadMatrixf(&lookAt[0][0]);
mat4 combined = lookAt * (mat4) sceneTranslation * (mat4) sceneScale;
glLoadMatrixf(&combined[0][0]);
mat4 objectTransform(1.0);
// Transformations...
// No idea if it works, but objects are affected by camera position but not individually scaled, moved etc.
GLuint gl_ModelViewMatrix = glGetUniformLocation(shaderprogram, "gl_ModelViewMatrix");
glUniformMatrix4fv(gl_ModelViewMatrix, 1, GL_FALSE, &objectTransform[0][0]);
// For example
glutSolidCube(1.0);
glutSwapBuffers();
Well, you dont have to use glLoadMatrix and other built in matrix functions, because it could be even more difficult than handling your own matrixes.
A simple camera example without controlling it, its a static camera:
glm::mat4x4 view_matrix = glm::lookAt(
cameraPosition,
cameraPosition+directionVector, //or the focus point the camera is pointing to
upVector);
It returns a 4x4 matrix, this is the view matrix.
glm::mat4x4 projection_matrix =
glm::perspective(60.0f, float(screenWidth)/float(screenHeight), 1.0f, 1000.0f);
this is the projection matrix
so now you have the view and projection matrixes, and you can send it to the shader:
gShader->bindShader();
gShader->sendUniform4x4("view_matrix",glm::value_ptr(view_matrix));
gShader->sendUniform4x4("projection_matrix",glm::value_ptr(projection_matrix));
the bindshader is the simple glUseProgram(shaderprog);
the uniform program is
void sendUniform4x4(const string& name, const float* matrix, bool transpose=false)
{
GLuint location = getUniformLocation(name);
glUniformMatrix4fv(location, 1, transpose, matrix);
}
Your model matrix is individual for each of your objects:
glm::mat4x4 model_matrix= glm::mat4(1); //this is the identity matrix, so its static
model_matrix= glm::rotate(model_matrix,
rotationdegree,
vec3(axis)); //same as opengl function.
This created a model matrix, and you can send it to your shader too
gShader->bindShader();
gShader->sendUniform4x4("model_matrix",glm::value_ptr(model_matrix));
the glm::value_ptr(...) creates a 2 dimensional array of your matrix.
in your shader code don't use the glModelViewMatrix and gl_ProjectionMatrix,
matrixes are sent via uniforms.
uniform mat4 projection_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;
void main(){
gl_Position = projection_matrix*view_matrix*model_matrix*gl_Vertex;
//i wrote gl_Vertex because of the glutSolidTeapot.
}
I've never used this build in mesh function so i dont know how it works, supposing it is sending the vertexes to the shader with immediate mode use gl_Vertex.
If you create your own meshes use VBO vertexattribpointer and drawarrays/elements.
Don't forget to bind the shader before sending uniforms.
So with a complete example:
glm::mat4x4 view_matrix = glm::lookAt(2,4,2,-1,-1,-1,0,1,0);
glm::mat4x4 projection_matrix =
glm::perspective(60.0f, float(screenWidth)/float(screenHeight), 1.0f, 10.0f);
glm::mat4x4 model_matrix= glm::mat4(1); //this remains unchanged
glm::mat4x4 teapot_model_matrix= glm::rotate(model_matrix, //this is the teapots model matrix, apply transformations to this
45,
glm::vec3(1,1,1));
teapot_model_matrix = glm::scale(teapot_model_matrix,vec3(2,2,2);
gShader->bindShader();
gShader->sendUniform4x4("model_matrix",glm::value_ptr(model_matrix));
gShader->sendUniform4x4("view_matrix",glm::value_ptr(view_matrix));
gShader->sendUniform4x4("projection_matrix",glm::value_ptr(projection_matrix));
glutSolidCube(0.0); //i don't know what the (0.0) stands for :/
glutSwapBuffers();
///////////////////////////////////
in your shader:
uniform mat4 projection_matrix; //these are the matrixes you've sent
uniform mat4 view_matrix;
uniform mat4 model_matrix;
void main(){
gl_Position = projection_matrix*view_matrix*model_matrix*vec4(gl_Vertex.xyz,1);
}
Now you should have a camera positioned at 2,4,2, focusing at -1,-1,-1, and the up vector is pointing up:)
A teapot is rotated by 45 degrees around the (1,1,1) vector, and scaled by 2 in every direction.
After changing the model matrix, send it to the shader, so if you have more objects to render
send it after each if you want to have different transformations applied to each mesh.
A pseudocode for this looks like:
camera.lookat(camerapostion,focuspoint,updirection); //sets the view
camera.project(fov,aspect ratio,near plane, far plane) //and projection matrix
camera.sendviewmatrixtoshader;
camera.sendprojectionmatrixtoshader;
obj1.rotate(45 degrees, 1,1,1); //these functions should transform the model matrix of the object. Make sure each one has its own.
obj1.sendmodelmatrixtoshader;
obj2.scale(2,1,1);
obj2.sendmodelmatrixtoshader;
If it doesn't work try it with a vertexBuffer, and a simple triangle or cube created by yourself.
You should use a math library, I recommend GLM. It has its matrix functions just like in OpenGL, and uses column major matrixes so you can calculate your owns, and apply them for objects.
First, you should have a matrix class for your scene, which calculates your view matrix, and projection matrix. (glm::lookAt, and glm::project). They work the same as in openGL. You can send them as uniforms to the vertex shader.
For the obejcts, you calculate your own marixes, and send them as the model matrix to the shader(s).
In the shader or on cpu you calculate the mv matrix:
vp = proj*view.
You send your individual model matrixes to the shader and calculate the final position:
gl_Position = vp*m*vec4(vertex.xyz,1);
MODEL MATRIX
with glm, you can easily calculate, transform you matrixes. You create a simple identity matrix:
glm::mat4x4(1) //identity
you can translate, rotate, scale it.
glm::scale
glm::rotate
glm::translate
They work like in immediate mode in opengl.
after you have your matrix send it via the uniform.
MORE MODEL MATRIX
shader->senduniform("proj", camera.projectionmatrix);
shader->senduniform("view", camera.viewmatrix);
glm::mat4 model(1);
obj1.modelmatrix = glm::translate(model,vec3(1,2,1));
shader->senduniform("model", obj1.modelmatrix);
objectloader.render(obj1);
obj2.modelmatrix = glm::rotate(model,obj2.degrees,vec3(obj2.rotationaxis));
shader->senduniform("model", obj2.modelmatrix);
objectloader.render(obj2);
This is just one way to do this. You can write a class for push/pop matrix calculations, automate the method above like this:
obj1.rotate(degrees,vec3(axis)); //this calculates the obj1.modelmatrix for example rotating the identity matrix.
obj1.translate(vec3(x,y,z))//more transform
obj1.render();
//continue with object 2
VIEW MATRIX
the view matrix almost the same as model matrix. Use this to control the global "model matrix", the camera. This transforms your screen globally, and you can have model matrixes for your objects individually.
In my camera class I calculate this with the glm::lookAt(the same as opengl) then send it via uniform to all shaders I use.
Then when I render something I can manipulate its model matrix, rotating or scaling it, but the view matrix is global.
If you want a static object, you don't have to use model matrix on it, you can calculate the position with only:
gl_Position = projmatrix*viewmatrix*staticobjectvertex;
GLOBAL MODEL MATRIX
You can have a global model matrix too.
Use it like
renderer.globmodel.rotate(axis,degree);
renderer.globmodel.scale(x,y,z);
Send it as uniform too, and apply it after the objects' model matrix.
(I've used it to render ocean reflections to texture.)
To sum up:
create a global view(camera) matrix
create a model matrix for each of your sceens, meshes or objects
transform the objects' matrixes individually
send the projection, model and view matrixes via uniforms to the shader
calculate the final position: proj*camera*model*vertex
move your objects, and move your camera
I'm not saying there aren't any better way to do this, but this works for me well.
PS: if you'd like some camera class tuts I have a pretty good one;).
I want to view a flat fullscreen texture as it is spherical, by transforming it in a postprocess shader.
I figure I have to apply a projectionmatrix to the texture coordinate in the shader.
I found this website: http://www.songho.ca/opengl/gl_projectionmatrix.html which learns me a lot about the inners of the projectionmatrix.
But how do I apply it? I thought I would have to multiply the third row of the projection matrix to the texture coordinate with a calculated z value added to make it spherical. My efforts don't show any result though.
EDIT: I see the same issue here: http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/2008-April/009765.html
I think after you multiply text coords by projection matrix you have to make a perspective division and move from 3D to 2D (since the texture is 2D). This is the same as with shadow mapping.
// in fragment shader:
vec4 proj = uniformModelViewProjMatrix * tex_coords;
proj.xyz /= proj.w;
proj.xyz += vec3(1.0);
proj.xyz *= 0.5;
vec4 col = texture2D(sampler, proj.xy);
or look at http://www.ozone3d.net/tutorials/glsl_texturing_p08.php (for texture2DProj)
I am making a game in OpenGL where I have a few objects within the world space. I want to make a function where I can take in an object's location (3D) and transform it to the screen's location (2D) and return it.
I know the the 3D location of the object, projection matrix and view matrix in the following varibles:
Matrix projectionMatrix;
Matrix viewMatrix;
Vector3 point3D;
To do this transform, you must first take your model-space positions and transform them to clip-space. This is done with matrix multiplies. I will use GLSL-style code to make it obvious what I'm doing:
vec4 clipSpacePos = projectionMatrix * (viewMatrix * vec4(point3D, 1.0));
Notice how I convert your 3D vector into a 4D vector before the multiplication. This is necessary because the matrices are 4x4, and you cannot multiply a 4x4 matrix with a 3D vector. You need a fourth component.
The next step is to transform this position from clip-space to normalized device coordinate space (NDC space). NDC space is on the range [-1, 1] in all three axes. This is done by dividing the first three coordinates by the fourth:
vec3 ndcSpacePos = clipSpacePos.xyz / clipSpacePos.w;
Obviously, if clipSpacePos.w is zero, you have a problem, so you should check that beforehand. If it is zero, then that means that the object is in the plane of projection; it's view-space depth is zero. And such vertices are automatically clipped by OpenGL.
The next step is to transform from this [-1, 1] space to window-relative coordinates. This requires the use of the values you passed to glViewport. The first two parameters are the offset from the bottom-left of the window (vec2 viewOffset), and the second two parameters are the width/height of the viewport area (vec2 viewSize). Given these, the window-space position is:
vec2 windowSpacePos = ((ndcSpacePos.xy + 1.0) / 2.0) * viewSize + viewOffset;
And that's as far as you go. Remember: OpenGL's window-space is relative to the bottom-left of the window, not the top-left.