What is The Correct View Matrix For The HUD Camera?
-
04-07-2021 - |
Question
I'm using OpenSceneGraph in Android with GLES2.
I have two cameras: one for the scene and the other for the HUD. The scene camera is the main camera in my osgViewer. My trouble is with the HUD's camera. I am trying to add an OSG geometry to the 2D scene (HUD camera) but can't seem to get it to show up.
I'm using custom shaders to manipulate the geometry's position. To my understanding the projection matrix is correct but I think the problem may be with the view matrix since I'm using two cameras. I've tried setting the HUD's view to be the scene's initial view but to no avail. Please correct me if I am wrong in this.
// New camera for the HUD
hud_camera = new osg::Camera;
// Set the camera's view properties
hud_camera->setProjectionMatrix(
osg::Matrix::ortho2D(0, 1280, 0, 696));
hud_camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
hud_camera->setViewMatrix(osg::Matrix::identity());
hud_camera->setViewport(0, 0, 1280, 696);
// Clear the depth buffer
hud_camera->setClearMask(GL_DEPTH_BUFFER_BIT);
// Draw the subgraph after the main camera view and don't allow this camera
// to grab evente focurs from the main camera
hud_camera->setRenderOrder(osg::Camera::POST_RENDER);
hud_camera->setAllowEventFocus(false);
osg::Geode * geode;
osg::Geometry * geom;
osg::Vec3Array * vertices;
osg::Program * program;
// Create the geode and geometry to hold the crosshair image
geode = new osg::Geode;
geom = new osg::Geometry;
geode->addDrawable(geom);
hud_camera->addChild(geode);
// Set the vertices
vertices = new osg::Vec3Array;
vertices->push_back(osg::Vec3(0.0, 0.0, 0.0));
vertices->push_back(osg::Vec3(1.0, 0.0, 0.0));
vertices->push_back(osg::Vec3(1.0, 0.0, 1.0));
vertices->push_back(osg::Vec3(0.0, 0.0, 1.0));
geom->setVertexArray(vertices);
// set colors
osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back(osg::Vec4(1.0, 0.0, 0.0, 1.0));
colors->push_back(osg::Vec4(0.0, 1.0, 0.0, 1.0));
colors->push_back(osg::Vec4(0.0, 0.0, 1.0, 1.0));
colors->push_back(osg::Vec4(1.0, 0.0, 1.0, 1.0));
geom->setVertexAttribArray(7, colors);
geom->setVertexAttribBinding(7, osg::Geometry::BIND_PER_VERTEX);
// Set primitive set
geom->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
geom->setUseVertexBufferObjects(true);
// Vertex Shader
char vertSource[] =
"attribute vec4 osg_Vertex;\n"
"attribute vec4 a_col;"
"uniform mat4 osg_ModelViewProjectionMatrix;\n"
"uniform mat4 proj_matrix;\n"
"uniform mat4 view_matrix;\n"
"varying vec4 v_col;"
"void main(void)\n"
"{\n"
"gl_Position = view_matrix * proj_matrix * osg_Vertex;\n"
"v_col = a_col;\n"
"}\n";
// Fragment shader
char fragSource[] =
"precision mediump float;\n"
"varying vec4 v_col;"
"void main(void)\n"
"{\n"
"gl_FragColor = v_col;\n"
"}\n";
// Set the shaders
program = new osg::Program;
program->setName("Crosshair Shader");
program->addShader(new osg::Shader(osg::Shader::VERTEX, vertSource));
program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragSource));
program->addBindAttribLocation("a_col", 7);
osg::StateSet* state = geode->getOrCreateStateSet();
state->addUniform(
new osg::Uniform("proj_matrix", hud_camera->getProjectionMatrix()));
state->addUniform(
new osg::Uniform("view_matrix", hud_camera->getViewMatrix());
// Add the program shaders
geode->getOrCreateStateSet()->setAttributeAndModes(
program, osg::StateAttribute::ON );
// Needs no lighting or any depth for a 2D image
geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
state->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
Afterwards I attach the hud_camera as a child to the scene data. Also the scene camera is doing nothing special other than looking at a particular point in the scene.
I do know for a fact that the geometry is being created. By using this in the vertex shader:
gl_Position = osg_ModelViewProjectionMatrx * osg_Vertex
I can see it off to the left in the scene.
Solution
First of all, you shouldn't be performing view * proj * vertex
, it should be proj * view * vertex
.
For a hud I think don't really need to have a view matrix at all. My understanding is that you just want to draw a flat quad on the screen?
If your projection matrix maps (0,0) to (1280,696), then you can just draw objects in this coordinate system (a quad from (0,0) to (640,696) will cover the left half of the screen, etc).
Or if you want to draw things in the space from (0,0) to (1,1) then just override the projection matrix to map this space. It doesn't make much sense to me to involve a view matrix for something as simple as a HUD.