I'm using Vuforia to place a 3D model on an image target. I have created a common C++ solution to work on both Android and iOS. It works on Android, but I can't get the 3D model to appear in iOS. It tracks the image target perfectly, but there's no sign of the 3D model. The 3D model I'm using can be found here.
This is how I'm doing:
This method is called by Vuforia every time the screen needs to be rendered:
- (void)renderFrameQCAR
{
[self setFramebuffer];
[[ObjectController getInstance] getObjectInstance]->renderFrame();
[self presentFramebuffer];
}
This is the setFramebuffer method (Objective-C++):
- (void)setFramebuffer
{
if (context) {
[EAGLContext setCurrentContext:context];
if (!defaultFramebuffer) {
[self performSelectorOnMainThread:#selector(createFramebuffer) withObject:self waitUntilDone:YES];
}
#ifdef USE_OPENGL1
glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
#else
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
#endif
}
}
This is the renderFrame method (C++):
void IDRObject::renderFrame()
{
// Clear color and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Get the state from QCAR and mark the beginning of a rendering section
QCAR::State state = QCAR::Renderer::getInstance().begin();
// Explicitly render the Video Background
QCAR::Renderer::getInstance().drawVideoBackground();
#ifdef DEVICE_OPENGL_1
// Set GL11 flags:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
#endif
glEnable(GL_DEPTH_TEST);
// We must detect if background reflection is active and adjust the culling direction.
// If the reflection is active, this means the post matrix has been reflected as well,
// therefore standard counter clockwise face culling will result in "inside out" models.
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
if(QCAR::Renderer::getInstance().getVideoBackgroundConfig().mReflection == QCAR::VIDEO_BACKGROUND_REFLECTION_ON)
glFrontFace(GL_CW); //Front camera
else
glFrontFace(GL_CCW); //Back camera
SampleUtils::checkGlError("gl start setup stuff");
// Did we find any trackables this frame?
for(int tIdx = 0; tIdx < state.getNumTrackableResults(); tIdx++)
{
// Get the trackable:
const QCAR::TrackableResult* result = state.getTrackableResult(tIdx);
const QCAR::Trackable& trackable = result->getTrackable();
QCAR::Matrix44F modelViewMatrix = QCAR::Tool::convertPose2GLMatrix(result->getPose());
// Choose the texture based on the target name:
int textureIndex;
if (strcmp(trackable.getName(), "chips") == 0)
{
textureIndex = 0;
}
else if (strcmp(trackable.getName(), "stones") == 0)
{
textureIndex = 1;
}
else
{
textureIndex = 2;
}
const Texture* const thisTexture = textures[textureIndex];
#ifdef DEVICE_OPENGL_1
// Load projection matrix:
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(projectionMatrix.data);
// Load model view matrix:
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(modelViewMatrix.data);
glTranslatef(0.f, 0.f, kObjectScale);
glScalef(kObjectScale, kObjectScale, kObjectScale);
// Draw object:
glBindTexture(GL_TEXTURE_2D, thisTexture->mTextureID);
glTexCoordPointer(2, GL_FLOAT, 0, (const GLvoid*) &teapotTexCoords[0]);
glVertexPointer(3, GL_FLOAT, 0, (const GLvoid*) &teapotVertices[0]);
glNormalPointer(GL_FLOAT, 0, (const GLvoid*) &teapotNormals[0]);
glDrawElements(GL_TRIANGLES, NUM_TEAPOT_OBJECT_INDEX, GL_UNSIGNED_SHORT,
(const GLvoid*) &teapotIndices[0]);
#else
QCAR::Matrix44F modelViewProjection;
SampleUtils::translatePoseMatrix(0.0f, 0.0f, kObjectScale, &modelViewMatrix.data[0]);
SampleUtils::scalePoseMatrix(kObjectScale, kObjectScale, kObjectScale, &modelViewMatrix.data[0]);
SampleUtils::multiplyMatrix(&projectionMatrix.data[0], &modelViewMatrix.data[0], &modelViewProjection.data[0]);
glUseProgram(shaderProgramID);
glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) &teapotVertices[0]);
glVertexAttribPointer(normalHandle, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) &teapotNormals[0]);
glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) &teapotTexCoords[0]);
glEnableVertexAttribArray(vertexHandle);
glEnableVertexAttribArray(normalHandle);
glEnableVertexAttribArray(textureCoordHandle);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, thisTexture->mTextureID);
glUniformMatrix4fv(mvpMatrixHandle, 1, GL_FALSE, (GLfloat*)&modelViewProjection.data[0] );
glUniform1i(texSampler2DHandle, 0 /*GL_TEXTURE0*/);
glDrawElements(GL_TRIANGLES, NUM_TEAPOT_OBJECT_INDEX, GL_UNSIGNED_SHORT, (const GLvoid*) &teapotIndices[0]);
LOG("Tracking awesome targets.\n");
SampleUtils::checkGlError("ImageTargets renderFrame\n");
#endif
}
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
#ifdef DEVICE_OPENGL_1
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
#else
glDisableVertexAttribArray(vertexHandle);
glDisableVertexAttribArray(normalHandle);
glDisableVertexAttribArray(textureCoordHandle);
#endif
QCAR::Renderer::getInstance().end();
}
And the last presentFrameBuffer (Objective-C++):
- (BOOL)presentFramebuffer
{
BOOL success = FALSE;
if (context) {
[EAGLContext setCurrentContext:context];
#ifdef USE_OPENGL1
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
#else
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
#endif
success = [context presentRenderbuffer:GL_RENDERBUFFER];
}
return success;
}
It turned out that the projectionMatrix never was set.
I was missing the following calls:
// Cache the projection matrix:
const QCAR::CameraCalibration& cameraCalibration = QCAR::CameraDevice::getInstance().getCameraCalibration();
projectionMatrix = QCAR::Tool::getProjectionGL(cameraCalibration, 2.0f, 2500.0f);
They are originally placed in the startCameramethod in the ImageTarget sample from Vuforia.
Related
I'm brand new to OpenGL and am having some difficulty rendering multiple objects.
I have a vector each of which has its own VertexBuffer. Then, in the while loop I draw each shape on its own.
It's all well and good when I have many of the same objects (multiple cubes etc.) however, when I add a triangle mesh everything gets all out of whack.
I can have many cubes
I can have a single triangle mesh:
But, when I try to have a cube and then a triangle mesh I get:
I'm totally at a loss for what's going on. The code for my loop is provided below.
while (!glfwWindowShouldClose(window))
{
// Get the size of the window
int width, height;
glfwGetWindowSize(window, &width, &height);
float aspect_ratio = 1 * float(height)/float(width); // corresponds to the necessary width scaling
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
// Clear the framebuffer
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Enable depth test
glEnable(GL_DEPTH_TEST);
glUniform3f(program.uniform("triangleColor"), 1.0f, 1.0f, 1.0f);
glUniformMatrix4fv(program.uniform("proj"), 1, GL_FALSE, projection.data());
glUniformMatrix4fv(program.uniform("view"), 1, GL_FALSE, view.data());
int tally = 0;
for (int i = 0; i < surfaces.size(); i++) {
Surface *s = surfaces[i];
Vector3f color = s->getColor();
int tempIndex = triangleIndex;
Matrix4f model = s->getModel();
// Convert screen position to world coordinates
double xworld = ((xpos/double(width))*2)-1;
double yworld = (((height-1-ypos)/double(height))*2)-1; // NOTE: y axis is flipped in glfw
if (isPressed && mode == "translate") {
if(tempIndex == i) {
Vector4f center = s->getCenter() + model.col(3);
Vector4f displacement = Vector4f(xworld, yworld, 0, 1) - center;
Matrix4f translation = translateMatrix(displacement(0), displacement(1), displacement(2));
model = translation * s->getModel();
s->setModel(model);
}
}
glUniform3f(program.uniform("triangleColor"), color(0), color(1), color(2));
glUniformMatrix4fv(program.uniform("model"), 1, GL_FALSE, model.data());
glDrawArrays(GL_TRIANGLES, 0, s->getVertices().size());
}
And I initialize each VBO when making the object as
VertexBufferObject VBO;
VBO.init();
VBO.update(Vertices);
program.bindVertexAttribArray("position", VBO);
Surface* s = new Surface(VBO, Vertices, percentScale, 0, transformedCenter, SmoothNormals, FlatNormals, color);
s->setModel(model);
surfaces.push_back(s);
And where Program::bindVertexAttribArray is defined as
GLint Program::bindVertexAttribArray(
const std::string &name, VertexBufferObject& VBO) const
{
GLint id = attrib(name);
if (id < 0)
return id;
if (VBO.id == 0)
{
glDisableVertexAttribArray(id);
return id;
}
VBO.bind();
glEnableVertexAttribArray(id);
glVertexAttribPointer(id, VBO.rows, GL_FLOAT, GL_FALSE, 0, 0);
check_gl_error();
return id;
}
You're not binding any buffers before the draw call. You're probably simply drawing whatever buffer you last bound when you initialised them. You'll need something like this at the end of your loop before glDrawArrays:
...
program.bindVertexAttribArray("position", VBO); // where VBO is the buffer of surface s
glUniform3f(program.uniform("triangleColor"), color(0), color(1), color(2));
glUniformMatrix4fv(program.uniform("model"), 1, GL_FALSE, model.data());
glDrawArrays(GL_TRIANGLES, 0, s->getVertices().size());
while I am running the drawPlane with:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
everything is fine. The image is rendered and also my triangles.
However, while changing to
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
the texture is not updated anymore only my triangles...
How can I fix it?
void drawCursorHit() {
float cx = (hit_coord.x / (float)wWnd) * 2 - 1;
float cy = ((hit_coord.y / (float)hWnd) * 2 - 1)*-1.f;
float lx = 0.02f;
float ly = lx * 16. / 9.;
glLineWidth(1.5);
glColor3f(0.25f, 0.55f, 0.85f);
glBegin(GL_LINES);
glVertex3f(cx - lx, cy, 0.0);
glVertex3f(cx + lx, cy, 0.0);
glVertex3f(cx, cy - ly, 0.0);
glVertex3f(cx, cy + ly, 0.0);
glEnd();
}
void drawPlane() {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f(0.25f, 0.55f, 0.85f);
glBegin(GL_TRIANGLES);
for (int i = 0; i < continuous_plane.triangles.size(); i++)
{
sl::float3 vertices_1 = continuous_plane.vertices.at(continuous_plane.triangles.at(i).x);
sl::float3 vertices_2 = continuous_plane.vertices.at(continuous_plane.triangles.at(i).y);
sl::float3 vertices_3 = continuous_plane.vertices.at(continuous_plane.triangles.at(i).z);
int pixel_x_1 = static_cast<int>(camera_cx + (vertices_1.x * camera_fx) / vertices_1.z);
int pixel_y_1 = static_cast<int>(camera_cy + (vertices_1.y * camera_fy) / vertices_1.z);
int pixel_x_2 = static_cast<int>(camera_cx + (vertices_2.x * camera_fx) / vertices_2.z);
int pixel_y_2 = static_cast<int>(camera_cy + (vertices_2.y * camera_fy) / vertices_2.z);
int pixel_x_3 = static_cast<int>(camera_cx + (vertices_3.x * camera_fx) / vertices_3.z);
int pixel_y_3 = static_cast<int>(camera_cy + (vertices_3.y * camera_fy) / vertices_3.z);
float x_gl_1 = (pixel_x_1 / (float)wWnd) * 2 - 1;
float y_gl_1 = ((pixel_y_1 / (float)hWnd) * 2 - 1)*-1.f;
float x_gl_2 = (pixel_x_2 / (float)wWnd) * 2 - 1;
float y_gl_2 = ((pixel_y_2 / (float)hWnd) * 2 - 1)*-1.f;
float x_gl_3 = (pixel_x_3 / (float)wWnd) * 2 - 1;
float y_gl_3 = ((pixel_y_3 / (float)hWnd) * 2 - 1)*-1.f;
glVertex3f(x_gl_1, y_gl_1, 0.0);
glVertex3f(x_gl_2, y_gl_2, 0.0);
glVertex3f(x_gl_3, y_gl_3, 0.0);
}
glEnd();
}
/**
OpenGL draw function
Render Image and wireframe mesh into a texture using the FrameBuffer
**/
void drawGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glViewport(0, 0, wWnd, hWnd);
// Render image and wireframe mesh into a texture using frame buffer
// Bind the frame buffer and specify the viewport (full screen)
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Render the ZED view (Left) in the framebuffer
glUseProgram(shader_image->getProgramId());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, imageTex);
glUniform1i(texID, 0);
//invert y axis and color for this image (since its reverted from cuda array)
glUniform1i(glGetUniformLocation(shader_image->getProgramId(), "revert"), 1);
glUniform1i(glGetUniformLocation(shader_image->getProgramId(), "rgbflip"), 1);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, quad_vb);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glUseProgram(0);
// Unbind the framebuffer since the texture is now updated
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Render the texture to the screen
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glUseProgram(shader_image->getProgramId());
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glUniform1i(texID, 0);
glUniform1i(glGetUniformLocation(shader_image->getProgramId(), "revert"), 0);
glUniform1i(glGetUniformLocation(shader_image->getProgramId(), "rgbflip"), 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, quad_vb);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glUseProgram(0);
glDisable(GL_TEXTURE_2D);
if (user_hit_the_screen > 0)
{
drawPlane();
drawCursorHit();
}
// Swap buffers
glutSwapBuffers();
}
You have to set glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); before the 1st glDrawArrays in the function drawGL:
void drawGL() {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
.....
glDrawArrays(GL_TRIANGLES, 0, 6);
....
if (user_hit_the_screen > 0)
{
drawPlane();
drawCursorHit();
}
glutSwapBuffers();
}
To understand the issue, you have to know that OpenGL is a state machine. Every state which is set, is kept, until it is changed again.
Further, the main loop function drawGL is executed continuously.
Note, when glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) is set in drawPlane, then the polygon rasterization mode is changes to GL_LINE.
All the states which are active when the function is left are still active at the begin, when the function is executed the next time. This means that, in the next frame, the rasterization mode is GL_LINE at the beginning.
That is what you didn't expect and is not what you want. You have to ensure that all states are proper set at the begin of the function.
I want to draw a cube and a sphere and apply a different texture to each.
I use blender to create the scene and then export to an obj file which then includes the vertices, normals, uvs and faces for both objects as well as the textures.
I have created a routine which loads all the data from the obj file. This all works as I can load the objects and display them etc but with only one texture. As I say I have gone through pages and pages of code and posts and 99% only deal with 1 texture to 1 object and those that deal with multiple textures only deal with one object or are in a very old version of openGL.
The one thing I haven't tried is uniform sample2D arrays in the fragment shader but I haven't found an explanation on that so haven't tried it.
My code that I have below:
ObjLoader *obj = new ObjLoader();
string _filepath = "objects\\" + _filename;
//bool res = obj->loadObjWithStaticColor(_filepath.c_str(), _vertices, _normals, vertex_colors, _colors, 1.0);
bool res = obj->loadObjWithTextures(_filepath.c_str(), _objects, _textures);
program = InitShader("shaders\\vshader.glsl", "shaders\\fshader.glsl");
glUseProgram(program);
GLuint vao_world_objects;
glGenVertexArrays(1, &vao_world_objects);
glBindVertexArray(vao_world_objects);
//GLuint vbo_world_objects;
//glGenBuffers(1, &vbo_world_objects);
//glBindBuffer(GL_ARRAY_BUFFER, vbo_world_objects);
NumVertices = _objects[_objects.size() - 1]._stop + 1;
for (size_t i = 0; i < _objects.size(); i++)
{
_vertices.insert(_vertices.end(), _objects[i]._vertices.begin(), _objects[i]._vertices.end());
_normals.insert(_normals.end(), _objects[i]._normals.begin(), _objects[i]._normals.end());
_uvs.insert(_uvs.end(), _objects[i]._uvs.begin(), _objects[i]._uvs.end());
}
GLuint _vSize = _vertices.size() * sizeof(point4);
GLuint _nSize = _normals.size() * sizeof(point4);
GLuint _uSize = _uvs.size() * sizeof(point2);
GLuint _totalSize = _vSize + _uSize; // normals + vertices + uvs
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, _vSize, &_vertices[0], GL_STATIC_DRAW);
GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, _uSize, &_uvs[0], GL_STATIC_DRAW);
TextureID = glGetUniformLocation(program, "myTextureSampler");
TextureObjects = new GLuint[_textures.size()];
glGenTextures(_textures.size(), TextureObjects);
for (size_t i = 0; i < _textures.size(); i++)
{
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, TextureObjects[i]);
// Give the image to OpenGL
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _textures[i].width, _textures[i].height, 0, GL_BGR, GL_UNSIGNED_BYTE, _textures[i]._tex_data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
for (size_t i = 0; i < _objects.size(); i++)
{
if (i == 0)
{
glActiveTexture(GL_TEXTURE0);
}
else
{
glActiveTexture(GL_TEXTURE1);
}
glBindTexture(GL_TEXTURE_2D, TextureObjects[i]);
GLuint _v_size = _objects[i]._vertices.size() * sizeof(point4);
GLuint _u_size = _objects[i]._uvs.size() * sizeof(point2);
GLuint vPosition = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(vPosition);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
if (i == 0)
{
glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
}
else
{
glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(_v_size));
}
GLuint vUV = glGetAttribLocation(program, "vUV");
glEnableVertexAttribArray(vUV);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
if (i == 0)
{
glVertexAttribPointer(vUV, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
}
else
{
glVertexAttribPointer(vUV, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(_u_size));
}
if (i == 0)
{
glUniform1i(TextureID, 0);
}
else
{
glUniform1i(TextureID, 1);
}
}
_scale = Scale(zoom, zoom, zoom);
_projection = Perspective(45.0, 4.0 / 3.0, 0.1, 100.0);
_view = LookAt(point4(Camera.x, Camera.y, Camera.z, 0), point4(0, 0, 0, 0), point4(0, 1, 0, 0));
_model = mat4(1.0); // identity matrix
_mvp = _projection * _view * _model;
MVP = glGetUniformLocation(program, "MVP");
theta = glGetUniformLocation(program, "theta");
Zoom = glGetUniformLocation(program, "Zoom");
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE);
glClearColor(1.0, 1.0, 1.0, 1.0);
I understand that I have to switch between the active textures when drawing an object but I can't figure out how.
UPDATE
#immibis Ok I tried to do that yesterday but it didn't work but it was late and I was highly frustrated. SO just to get my thinking correct here, do I have to create a buffer every time (glGenBuffer) and then fill it, activate texture and then glDrawArrays or do I just create the buffer and then fill it every time with the different vetices and uvs for each object, set the offsets and then call glDrawArray for each object?
When I tried this originally I didn't know where the
glGetAttribLocation / glEnableVertexAttribArray /glBindBuffer
should go. So if I understand correctly every time I do a transformation like rotating around the x axis then buffers have to be filled etc so the code needs to go in the display function. Is that correct?
SOLVED
Ok so thanx to immibus' comments, it got me looking in a different direction. I was staring the whole time into how the data was pumped into the arrays that I never even looked at glDrawArrays. I was searching the web again and I came across a piece of code in a tutorial and the person explained glDrawArrays and I saw that you can tell it what to draw.
So then this became easy, as I originally thought it was supposed to be. I changed my code back to pumping everything in the buffers and since I have a start and stop property on my objects returned from my loader it was real easy to tell glDrawArrays what to do.
Thank you.
I was drawing a square with coordinates (-.5, -.5), (-.5, .5), (.5, .5), (.5, -.5) and I noticed that it appeared squashed in my 800 x 600 window (which seems entirely logical).
I was trying to fix it so that the square appeared square, not rectangular. My approach was to call glOrtho() with values of left = -ar, right = ar, bottom = -1, top = 1 where ar was my aspect ratio (800/600). What I found was that any call I made to glOrtho() had no effect, including the one I was already making (I could remove it and nothing would change).
My understanding of glOrtho() is that it maps the corners of the OpenGL context to the values supplied, and stretches everything between those points to fit. Is that incorrect, or am I doing something that's preventing my call to glOrtho() from taking effect?
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import java.nio.FloatBuffer;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
public class GLOrthoTestDriver {
public static void main(String[] args) {
try {
Display.setDisplayMode(new DisplayMode(800, 600));
Display.setTitle("glOrtho Test");
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
Display.destroy();
System.exit(1);
}
// Initialization code for OpenGL
glMatrixMode(GL_PROJECTION);
glOrtho(-1, 1, -1, 1, -1, 1);
glLoadIdentity();
// Scene setup
int vertexBufferHandle;
int colorBufferHandle;
FloatBuffer vertexData = BufferUtils.createFloatBuffer(8);
vertexData.put(new float[]
{
-.5f, -.5f,
-.5f, .5f,
.5f, .5f,
.5f, -.5f
}
);
vertexData.flip();
FloatBuffer colorData = BufferUtils.createFloatBuffer(12);
colorData.put(new float[]
{
1, 1, 1,
1, 1, 1,
1, 1, 1,
1, 1, 1
}
);
colorData.flip();
vertexBufferHandle = glGenBuffers();
colorBufferHandle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle);
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, colorBufferHandle);
glBufferData(GL_ARRAY_BUFFER, colorData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
while (!Display.isCloseRequested()) {
glClear(GL_COLOR_BUFFER_BIT);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle);
glVertexPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, colorBufferHandle);
glColorPointer(3, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
Display.update();
Display.sync(60);
}
glDeleteBuffers(vertexBufferHandle);
glDeleteBuffers(colorBufferHandle);
Display.destroy();
}
}
Ah - your problem is that you're calling glLoadIdentity after calling glOrtho. glLoadIdentity replaces the matrix in the current mode (GL_PROJECTION) with the identity matrix, thus wiping out any previous call to glOrtho.
Try calling glLoadIdentity before glOrtho.
I have successfully created a VAO which produces a triangle which can then be rotated with the mouse (with help from shaders).
My problem comes when I try to draw something else using the standard 'glBegin()' and 'glEnd()' functions. It draws successfully, but now, when I try to rotate the triangle the new drawing also rotates.
I know the problem is somehow fixed using the glUseProgram() function, but I'm not entirely sure why or where it should be added.
Here is my code (I've added it all but the main area of focus should be the display() and init() functions:
#include <GL/glew/glew.h>
#include <GL/freeglut.h>
#include <CoreStructures\CoreStructures.h>
#include <iostream>
#include "texture_loader.h"
#include "shader_setup.h"
using namespace std;
using namespace CoreStructures;
float theta = 0.0f;
bool mDown = false;
int mouse_x, mouse_y;
GLuint myShaderProgram;
GLuint locT; // location of "T" uniform variable in myShaderProgram
GLuint locR; // location of "R" uniform variable in myShaderProgram
GLuint sunPosVBO, sunColourVBO, sunIndicesVBO, sunVAO;
// Packed vertex arrays for the star object
// 1) Position Array - Store vertices as (x,y) pairs
static GLfloat sunVertices [] = {
-0.1f, 0.7f,
0.1f, 0.7f,
0.0f, 0.55f
};
// 2) Colour Array - Store RGB values as unsigned bytes
static GLubyte sunColors [] = {
255, 0, 0, 255,
255, 255, 0, 255,
0, 255, 0, 255
};
// 4) Index Array - Store indices to star vertices - this determines the order the vertices are to be processed
static GLubyte sunVertexIndices [] = {0, 1, 2};
void setupSunVAO(void) {
glGenVertexArrays(1, &sunVAO);
glBindVertexArray(sunVAO);
// copy star vertex position data to VBO
glGenBuffers(1, &sunPosVBO);
glBindBuffer(GL_ARRAY_BUFFER, sunPosVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(sunVertices), sunVertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0);
// copy star vertex colour data to VBO
glGenBuffers(1, &sunColourVBO);
glBindBuffer(GL_ARRAY_BUFFER, sunColourVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(sunColors), sunColors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (const GLvoid*)0);
// enable position, colour buffer inputs
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
// setup star vertex index array
glGenBuffers(1, &sunIndicesVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sunIndicesVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(sunVertexIndices), sunVertexIndices, GL_STATIC_DRAW);
glBindVertexArray(0);
}
void report_version(void) {
int majorVersion, minorVersion;
glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
cout << "OpenGL version " << majorVersion << "." << minorVersion << "\n\n";
}
void init(void) {
// initialise glew library
GLenum err = glewInit();
// ensure glew was initialised successfully before proceeding
if (err==GLEW_OK)
cout << "GLEW initialised okay\n";
else
cout << "GLEW could not be initialised\n";
report_version();
glClearColor(0.0, 0.0, 0.0, 0.0);
//
// setup "sun" VBO and VAO object
//
setupSunVAO();
//
// load shader program
//
myShaderProgram = setupShaders(string("Resources\\Shaders\\basic_vertex_shader.txt"), string("Resources\\Shaders\\basic_fragment_shader.txt"));
// get the index / location of the uniform variables "T" and "R" in shader program "myShaderProgram"
locT = glGetUniformLocation(myShaderProgram, "T");
locR = glGetUniformLocation(myShaderProgram, "R");
// "plug-in" shader into GPU pipeline
glUseProgram(myShaderProgram); // we're in the driving seat!!!!! Our shaders now intercept and process our vertices as part of the GPU rendering pipeline (as shown in the lecture notes)
}
// Example rendering functions - draw objects in local, or modelling coordinates
void drawSun(void) {
glBindVertexArray(sunVAO);
glDrawElements(GL_TRIANGLE_STRIP, 3, GL_UNSIGNED_BYTE, (GLvoid*)0);
}
void drawShape()
{
glColor3f(0.0f, 0.6f, 0.2f);
glBegin(GL_POLYGON);
glVertex2f(-1.0f, -1.0f); // Left
glVertex2f(-1.0f, -0.1f);
glVertex2f(-0.9f, -0.05f);
glVertex2f(-0.55f, -0.045f);
glVertex2f(-0.49f, -0.06f);
glVertex2f(-0.4f, -0.055f);
glVertex2f(-0.2f, -0.052f);
glVertex2f(0.0f, -0.02f); // Middle
glVertex2f(0.3f, -0.085f);
glVertex2f(0.5f, -0.08f);
glVertex2f(0.8f, -0.088f);
glVertex2f(1.0f, -0.1f);
glVertex2f(1.0f, -1.0f); // Right
glEnd();
}
//
//
void drawScene()
{
drawSun();
drawShape();
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Setup translation matrix and store in T. Pass this over the the shader with the function glUniformMatrix4fv
GUMatrix4 T = GUMatrix4::translationMatrix(0.01f, 0.01f, 0.0f);
glUniformMatrix4fv(locT, 1, GL_FALSE, (GLfloat*)&T);
// Setup rotation matrix and store in R. Pass this over the the shader with the function glUniformMatrix4fv
GUMatrix4 R = GUMatrix4::rotationMatrix(0.0f, 0.0f, theta);
glUniformMatrix4fv(locR, 1, GL_FALSE, (GLfloat*)&R);
// Draw the scene (the above transformations will be applied to each vertex in the vertex shader)
drawScene();
glutSwapBuffers();
}
void mouseButtonDown(int button_id, int state, int x, int y) {
if (button_id==GLUT_LEFT_BUTTON) {
if (state==GLUT_DOWN) {
mouse_x = x;
mouse_y = y;
mDown = true;
} else if (state == GLUT_UP) {
mDown = false;
}
}
}
void mouseMove(int x, int y) {
if (mDown) {
int dx = x - mouse_x;
int dy = y - mouse_y;
float delta_theta = (float)dy * (3.142f * 0.01f);
theta += delta_theta;
mouse_x = x;
mouse_y = y;
glutPostRedisplay();
}
}
void keyDown(unsigned char key, int x, int y) {
if (key=='r') {
theta = 0.0f;
glutPostRedisplay();
}
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
initCOM();
glutInitContextVersion(3, 3);
glutInitContextProfile (GLUT_COMPATIBILITY_PROFILE);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(800, 800);
glutInitWindowPosition(0, 0);
glutCreateWindow("Combining Transforms");
glutDisplayFunc(display);
glutKeyboardFunc(keyDown);
glutMouseFunc(mouseButtonDown);
glutMotionFunc(mouseMove);
init();
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
glutMainLoop();
shutdownCOM();
return 0;
}
EDIT
I have an array of x,y vertices and am trying to draw them alongside the above code. For some reason this seems to take vertex data from the sunVAO.
Is there some kind of cache that needs to be cleared? I've searched google and I can't seem to find anyone else who has conflicting VAO and vertex arrays.
(Also, I have checked my code and the vertex data supplied in the array of vertices is correct, they're just not displayed correctly.)
Code:
static GLfloat bottomMarkerVertices[] = {
-0.045f, -0.75f,
0.045f, -0.75f,
-0.07f, -1.0f,
0.07f, -1.0f
};
glVertexPointer(2, GL_FLOAT, 0, bottomMarkerVertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
note: vertex arrays have been enabled.
Assuming you're defining your coordinates in normalized device space (suggested by the apparent absence of a projection matrix), the rendering loop needs to look a little like this:
void drawScene()
{
//update shader parameters for the sun shader if necessary
drawSun();
glUseProgram(0);
// at this point, the PROJECTION and MODELVIEW matrices are both the identity
// so the shape is expected to be in NDCs and is not to be transformed
// at all
drawShape();
glUseProgram(progForSun);
}
Note that I don't advise to mix legacy and modern OpenGL like that. The results of vertex processing triggered by drawShape() are only defined because you're using a compatibility profile context.
The two elements of your scene move together because they are both using the same transformation matrices, specificed by these lines:
// Setup translation matrix and store in T. Pass this over the the shader with the function glUniformMatrix4fv
GUMatrix4 T = GUMatrix4::translationMatrix(0.01f, 0.01f, 0.0f);
glUniformMatrix4fv(locT, 1, GL_FALSE, (GLfloat*)&T);
// Setup rotation matrix and store in R. Pass this over the the shader with the function glUniformMatrix4fv
GUMatrix4 R = GUMatrix4::rotationMatrix(0.0f, 0.0f, theta);
glUniformMatrix4fv(locR, 1, GL_FALSE, (GLfloat*)&R);
If you want drawShape() not to move with the mouse, you need to reset locR with a fixed theta value before you call it.
drawSun();
GUMatrix4 R = GUMatrix4::rotationMatrix(0.0f, 0.0f, 0.0f);
glUniformMatrix4fv(locR, 1, GL_FALSE, (GLfloat*)&R);
drawShape();