Related
I am trying to develop a POC which helps to visualize a 3D object on camera feed. The kind 3D object I have, easily gets rendered using this project. And I am referring Camera Ripple code by Apple for showing camera feed. Both of these are separate objects in the same context. Each of these uses its own shader program. I am confused how to switch from one program to another.
My glkview:drawInRect: method looks like this
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(_program);
if (_ripple)
{
glDrawElements(GL_TRIANGLE_STRIP, [_ripple getIndexCount], GL_UNSIGNED_SHORT, 0);
}
glUseProgram(_program1);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set View Matrices
[self updateViewMatrices];
glUniformMatrix4fv(_uniforms.uProjectionMatrix, 1, 0, _projectionMatrix1.m);
glUniformMatrix4fv(_uniforms.uModelViewMatrix, 1, 0, _modelViewMatrix1.m);
glUniformMatrix3fv(_uniforms.uNormalMatrix, 1, 0, _normalMatrix1.m);
// Attach Texture
glUniform1i(_uniforms.uTexture, 0);
// Set View Mode
glUniform1i(_uniforms.uMode, self.viewMode.selectedSegmentIndex);
// Enable Attributes
glEnableVertexAttribArray(_attributes.aVertex);
glEnableVertexAttribArray(_attributes.aNormal);
glEnableVertexAttribArray(_attributes.aTexture);
// Load OBJ Data
glVertexAttribPointer(_attributes.aVertex, 3, GL_FLOAT, GL_FALSE, 0, cubeOBJVerts);
glVertexAttribPointer(_attributes.aNormal, 3, GL_FLOAT, GL_FALSE, 0, cubeOBJNormals);
glVertexAttribPointer(_attributes.aTexture, 2, GL_FLOAT, GL_FALSE, 0, cubeOBJTexCoords);
// Load MTL Data
for(int i=0; i<cubeMTLNumMaterials; i++)
{
glUniform3f(_uniforms.uAmbient, cubeMTLAmbient[i][0], cubeMTLAmbient[i][1], cubeMTLAmbient[i][2]);
glUniform3f(_uniforms.uDiffuse, cubeMTLDiffuse[i][0], cubeMTLDiffuse[i][1], cubeMTLDiffuse[i][2]);
glUniform3f(_uniforms.uSpecular, cubeMTLSpecular[i][0], cubeMTLSpecular[i][1], cubeMTLSpecular[i][2]);
glUniform1f(_uniforms.uExponent, cubeMTLExponent[i]);
// Draw scene by material group
glDrawArrays(GL_TRIANGLES, cubeMTLFirst[i], cubeMTLCount[i]);
}
// Disable Attributes
glDisableVertexAttribArray(_attributes.aVertex);
glDisableVertexAttribArray(_attributes.aNormal);
glDisableVertexAttribArray(_attributes.aTexture);
}
this cause a crash by throwing this error gpus_ReturnGuiltyForHardwareRestart
I found solution to my problem is reseting everything between the use of both programs. Now my glkview:drawInRect: looks like below,
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(_program);
if (_ripple)
{
glDrawElements(GL_TRIANGLE_STRIP, [_ripple getIndexCount], GL_UNSIGNED_SHORT, 0);
[self resetProgrameOne];
}
glUseProgram(_program1);
glClear(GL_DEPTH_BUFFER_BIT);
// Set View Matrices
[self updateViewMatrices];
glUniformMatrix4fv(_uniforms.uProjectionMatrix, 1, 0, _projectionMatrix1.m);
glUniformMatrix4fv(_uniforms.uModelViewMatrix, 1, 0, _modelViewMatrix1.m);
glUniformMatrix3fv(_uniforms.uNormalMatrix, 1, 0, _normalMatrix1.m);
// Attach Texture
glUniform1i(_uniforms.uTexture, 0);
// Set View Mode
glUniform1i(_uniforms.uMode, 1);
// Enable Attributes
glEnableVertexAttribArray(_attributes.aVertex);
glEnableVertexAttribArray(_attributes.aNormal);
glEnableVertexAttribArray(_attributes.aTexture);
// Load OBJ Data
glVertexAttribPointer(_attributes.aVertex, 3, GL_FLOAT, GL_FALSE, 0, table1OBJVerts);
glVertexAttribPointer(_attributes.aNormal, 3, GL_FLOAT, GL_FALSE, 0, table1OBJNormals);
glVertexAttribPointer(_attributes.aTexture, 2, GL_FLOAT, GL_FALSE, 0, table1OBJTexCoords);
// Load MTL Data
for(int i=0; i<table1MTLNumMaterials; i++)
{
glUniform3f(_uniforms.uAmbient, table1MTLAmbient[i][0], table1MTLAmbient[i][1], table1MTLAmbient[i][2]);
glUniform3f(_uniforms.uDiffuse, table1MTLDiffuse[i][0], table1MTLDiffuse[i][1], table1MTLDiffuse[i][2]);
glUniform3f(_uniforms.uSpecular, table1MTLSpecular[i][0], table1MTLSpecular[i][1], table1MTLSpecular[i][2]);
glUniform1f(_uniforms.uExponent, table1MTLExponent[i]);
// Draw scene by material group
glDrawArrays(GL_TRIANGLES, table1MTLFirst[i], table1MTLCount[i]);
}
// Disable Attributes
glDisableVertexAttribArray(_attributes.aVertex);
glDisableVertexAttribArray(_attributes.aNormal);
glDisableVertexAttribArray(_attributes.aTexture);
}
and resetProgrameOne method resets all the buffers and necessary things by deleting buffers and disabling glDisableVertexAttribArrays.
I am rendering my scene as the code below
struct vertex
{
float x, y, z, nx, ny, nz;
};
bool CShell::UpdateScene()
{
glEnable(GL_DEPTH_TEST);
glClearColor(0.3f, 0.3f, 0.4f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set the OpenGL projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
const float near = 0.1f;
const float far = 1000.0f;
float top = near * tanf(fieldOfView * SIMD_PI / 180.0f);
float bottom = -top;
float left = bottom * aspectRatio;
float right = top * aspectRatio;
glFrustumf(left, right, bottom, top, near, far);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
bool CShell::RenderScene()
{
glEnable(GL_DEPTH_TEST);
glBindBuffer(GL_ARRAY_BUFFER, vertsVBO);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, elementSize, 0);
glNormalPointer(GL_FLOAT, elementSize, (const GLvoid*) normalOffset);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesVBO);
glEnable(GL_LIGHTING);
lightPosition[0] = (-gravity.x()+0.0)*lightHeight;
lightPosition[1] = (-gravity.y()+0.0)*lightHeight;
lightPosition[2] = (-gravity.z()+0.5)*lightHeight;
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
float worldMat[16];
/// draw donuts
for (int i=0;i<numDonuts;i++)
{
sBoxBodies[i]->getCenterOfMassTransform().getOpenGLMatrix(worldMat);
glPushMatrix();
glMultMatrixf(worldMat);
glVertexPointer(3, GL_FLOAT, elementSize, (const GLvoid*)(char*)sizeof(vertex));
glNormalPointer(GL_FLOAT, elementSize, (const GLvoid*)(char*)(sizeof(vertex)+normalOffset));
glDrawElements(GL_TRIANGLES, numberOfIndices, GL_UNSIGNED_SHORT, (const GLvoid*)(char*)sizeof(GLushort));
glPopMatrix();
}
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisable(GL_LIGHTING);
return true;
}
My project uses Oolong Engine
These are two screenshots, iPodTouch 4G (iOS 6.0)
and iPodTouch 2G (iOS 4.2.1)
What could be causing those strange artitacts that appears on the later screenshot?
It apears as if the triangles on the back are overlapping those of the front
It occurs some times thought, as the artifats are jerky, it's like if there is "z-fighting", but triangles on the back have z values below of those for triangles on the front
Here is an image of the vertices and normals z arrangement
The blue arrows are normals shared by the surrounding faces, and the triangle with red lines is a representation of what could be causing those artifacts
it's like if there is "z-fighting", but triangles on the back have z values below of those for triangles on the front
It doesn't matter so much that one has z-value less than the other, you get z-fighting when your objects are too close together and you don't have enough z resolution.
The problem here I guess is that you set your projection range too large, from 0.1 to 1000. The greater magnitude the difference between these numbers, the less z-resolution you will get.
I recommend to try near/far of 0.1/100, or 1.0/1000, as long as that works with your application. It should help your z-fighting issue.
I'm using GLKit in an OpenGL project. Everything is based on GLKView and GLKBaseEffect (no custom shaders). In my project I have several views that have GLKViews for showing 3D objects, and occasionally several of those view can be "open" at once (i.e. are in the modal view stack).
While until now everything was working great, in a new view I was creating I needed to have a rectangle with texture to simulate a measuring tape for the 3D world of my app. For some unknown reason, in that view only, the texture isn't loaded right into the opengl context: the texture is loaded right by GLKTextureLoader, but when drawing the rectangle is black, and looking at the OpenGL frame in debug, I can see that an empty texture is loaded (there's a reference to a texture, but it's all zeroed out or null).
The shape I'm drawing is defined by: (it was originally a triangle strip, but I switched for triangles to make sure it's not the issue)
static const GLfloat initTape[] = {
-TAPE_WIDTH / 2.0f, 0, 0,
TAPE_WIDTH / 2.0f, 0, 0,
-TAPE_WIDTH / 2.0f, TAPE_INIT_LENGTH, 0,
TAPE_WIDTH / 2.0f, 0, 0,
TAPE_WIDTH / 2.0f, TAPE_INIT_LENGTH, 0,
-TAPE_WIDTH / 2.0f, TAPE_INIT_LENGTH, 0,
};
static const GLfloat initTapeTex[] = {
0, 0,
1, 0,
0, 1.0,
1, 0,
1, 1,
0, 1,
};
I set the effect variable as:
effect.transform.modelviewMatrix = modelview;
effect.light0.enabled = GL_FALSE;
// Projection setup
GLfloat ratio = self.view.bounds.size.width/self.view.bounds.size.height;
GLKMatrix4 projection = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(self.fov), ratio, 0.1f, 1000.0f);
effect.transform.projectionMatrix = projection;
// Set the color of the wireframe.
if (tapeTex == nil) {
NSError* error;
tapeTex = [GLKTextureLoader textureWithContentsOfFile:[[[NSBundle mainBundle] URLForResource:#"ruler_texture" withExtension:#"png"] path] options:nil error:&error];
}
effect.texture2d0.enabled = GL_TRUE;
effect.texture2d0.target = GLKTextureTarget2D;
effect.texture2d0.envMode = GLKTextureEnvModeReplace;
effect.texture2d0.name = tapeTex.name;
And the rendering loop is:
[effect prepareToDraw];
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribPosition, COORDS, GL_FLOAT, GL_FALSE, 0, tapeVerts);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 0, tapeTexCoord);
glDrawArrays(GL_TRIANGLES, 0, TAPE_VERTS);
glDisableVertexAttribArray(GLKVertexAttribPosition);
glDisableVertexAttribArray(GLKVertexAttribTexCoord0);
I've also tested the texture itself in another view with other objects and it works fine, so it's not the texture file fault.
Any help would be greatly appreciated, as I'm stuck on this issue for over 3 days.
Update: Also, there are no glErrors during the rendering loop.
After many many days I've finally found my mistake - When using multiple openGL contexts, it's important to create a GLKTextureLoader using a shareGroup, or else the textures aren't necessarily loaded to the right context.
Instead of using the class method textureWithContentOf, every context needs it's own GLKTextureLoader that is initialized with context.sharegroup, and use only that texture loader for that view. (actually the textures can be saved between different contexts, but I didn't needed that feature of sharegroups).
Easy tutorial http://games.ianterrell.com/how-to-texturize-objects-with-glkit/
I think it will help you.
I've been bashing my head on the wall this afternoon persuading my openGLES2.0 code to perform correctly when I move from using VBO to VAO / VBO. Basically I'm working my way through Apple's "expert" advice on openGLES and moving to using Vertex Array Objects was top of the list ...
I've reviewed the similar question and response here but that didn't seem to help me, other than re-assure me that other people run into similar problems :(
My scenario is that I have approximately 500 rectangular textures moving around the screen. The code all works fine without VAO, but when I define USE_VAO (my constant) it's crashing on the first draw elements call. I'm obviously not understanding VAO properly ... but I can't see the error of my ways!
The setupBeforeRender method is called as the last part of my setup before entering the render loop.
-(void) setupBeforeRender {
glClearColor(0.6, 0.6, 0.6, 1);
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
glEnable(GL_DEPTH_TEST);
glUniform1i(_textureUniform, 0);
glActiveTexture(GL_TEXTURE0);
glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_colorSlot);
glEnableVertexAttribArray(_texCoordSlot);
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
}
And here's the render method
- (void)render:(CADisplayLink*)displayLink {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Model view matrix and projection code removed for clarity
GLsizei stride = sizeof(Vertex);
const GLvoid* colourOffset = (GLvoid *) sizeof(float[3]);
const GLvoid* textureOffset = (GLvoid *) sizeof(float[7]);
for (my objectToDraw in objectToDrawArray)
{
if (objectToDraw.vertexBufferObject == 0)
{
#ifdef USE_VAO
glGenVertexArraysOES(1,&_vao);
glBindVertexArrayOES(_vao);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, stride, 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, stride, colourOffset);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE,stride, textureOffset);
objectToDraw.vertexBufferObject = [objectToDraw createAndBindVBO];
objectToDraw.vertexArrayObject = _vao;
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArrayOES(0);
#else
objectToDraw.vertexBufferObject = [objectToDraw createAndBindVBO];
#endif
}
// Texture binding removed for clarity
#ifdef USE_VAO
// This code crashes with EXC_BAD_ACCESS on the glDrawElements
glBindVertexArrayOES(objectToDraw.vertexArrayObject);
glDrawElements(GL_TRIANGLES, sizeof(Indices) / sizeof(Indices[0]), GL_UNSIGNED_SHORT,0);
glBindVertexArrayOES(0);
#else
// This path works fine. So turning VAO off works :(
glBindBuffer(GL_ARRAY_BUFFER, storyTile.vertexBufferObject);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, stride, 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, stride, colourOffset);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, stride, textureOffset);
glDrawElements(GL_TRIANGLES, sizeof(Indices) / sizeof(Indices[0]), GL_UNSIGNED_SHORT,0);
#endif
} // End for each object
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
Finally, my create and bind VBO method looks like this;
-(GLuint) createAndBindVBO {
const float* rgba = CGColorGetComponents([self.colour CGColor]);
Vertex Vertices[] = {
{{0, 1, 0}, {1, 0, 1, 1}, {0,1}},
{{0, 0, 0}, {1, 0, 1, 1}, {0,0}},
{{1, 1, 0}, {1, 0, 1, 1}, {1,1}},
{{1, 0, 0}, {1, 0, 1, 1}, {1,0}}
};
// Code removed for clarity - sets up geometry and colours
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
return vertexBuffer;
}
I've tried various permutations of this and have sprinkled the code with glGetError() to see if that helps point to where the problem arises. Alas I get no errors, other than the BAD_ACCESS crash on the drawElements call.
EDIT: As suggested, this unfortunately also doesn't work
objectToDraw.vertexBufferObject = [objectToDraw createVBO];
glGenVertexArraysOES(1,&_vao);
glBindVertexArrayOES(_vao);
glBindBuffer(GL_ARRAY_BUFFER, objectToDraw.vertexBufferObject);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, stride, 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, stride, colourOffset);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE,stride, textureOffset);
objectToDraw.vertexArrayObject = _vao;
glBindVertexArrayOES(0);
I must be doing something dumb with the vertex array object ... but can someone figure out what the problem is?
The vertex array enabled flags are part of the VAO state, so you need to enable the vertex attribute arrays using glEnableVertexAttribArray while the VAO is bound.
From: http://www.khronos.org/registry/gles/extensions/OES/OES_vertex_array_object.txt
The resulting
vertex array object is a new state vector, comprising all the state values (listed in Table 6.2, except ARRAY_BUFFER_BINDING):
VERTEX_ATTRIB_ARRAY_ENABLED
VERTEX_ATTRIB_ARRAY_SIZE,
VERTEX_ATTRIB_ARRAY_STRIDE,
VERTEX_ATTRIB_ARRAY_TYPE,
VERTEX_ATTRIB_ARRAY_NORMALIZED,
VERTEX_ATTRIB_ARRAY_POINTER,
ELEMENT_ARRAY_BUFFER_BINDING,
VERTEX_ATTRIB_ARRAY_BUFFER_BINDING.
You should call glVertexAttribPointer after glBindBuffer function call.
I had a similar problem, didn't know what was causing it.
Eventually it turned out that i have to put in a const int number of vertices in glDrawArrays.
sizeof() was not doing it right.
I am trying to follow a tutorial on Dynamic Textures in iOS by Ray Wenderlich
http://www.raywenderlich.com/3857/how-to-create-dynamic-textures-with-ccrendertexture
but using Cocos2D 2.0 and OpenGL ES 2.0 instead of 1.1. The tutorial begins by drawing a coloured square to the screen with a shadow gradient applied to it, but I cannot get the gradient to render to the coloured square. This part of the tutorial is where OpenGL ES code is sent to the CCRenderTexture, so I figure I must be setting up my OpenGL ES 2.0 code wrong (I have very little experience with OpenGL / OpenGL ES). The OpenGL ES 1.1 code is
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
float gradientAlpha = 0.7;
CGPoint vertices[4];
ccColor4F colors[4];
int nVertices = 0;
vertices[nVertices] = CGPointMake(0, 0);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0 };
vertices[nVertices] = CGPointMake(textureSize, 0);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0};
vertices[nVertices] = CGPointMake(0, textureSize);
colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};
vertices[nVertices] = CGPointMake(textureSize, textureSize);
colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};
glVertexPointer(2, GL_FLOAT, 0, vertices);
glColorPointer(4, GL_FLOAT, 0, colors);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)nVertices);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
which goes between the CCRenderTexture begin and end methods (full code can be found at the above link). My Cocos2D 2.0 / OpenGL ES 2.0 attempt is
float gradientAlpha = 0.7;
CGPoint vertices[4];
ccColor4F colors[4];
int nVertices = 0;
vertices[nVertices] = CGPointMake(0, 0);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0 };
vertices[nVertices] = CGPointMake(textureSize, 0);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0};
vertices[nVertices] = CGPointMake(0, textureSize);
colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};
vertices[nVertices] = CGPointMake(textureSize, textureSize);
colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};
// Setup OpenGl ES shader programs
CCGLProgram *positionColourProgram = [[CCShaderCache sharedShaderCache] programForKey:kCCShader_PositionColor];
[rt setShaderProgram:positionColourProgram];
ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position | kCCVertexAttribFlag_Color);
glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_FLOAT, GL_FALSE, 0, colors);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)nVertices);
where rt is the CCRenderTexture object. There are no errors in the console but the image on the screen is a solid colour square with no gradient. Do I need to use an OpenGL blending function perhaps? Any help would be much appreciated. Thanks in advance.
I have figured out the changes needed to make it \work and I posted my comment in the tutorial's forum http://www.raywenderlich.com/forums//viewtopic.php?f=20&t=512&start=40
Hope it is not too late for you.
To save you time from looking through the forum to find my posting, here it is what I posted there:
I have posted my fix at:
http://www.wfu.edu/~ylwong/download/cocos2d-2.0-texture/
The HelloWorldLayer.mm is the final file incorporated all the changes so you do not have to type them in. The pdf file marks up the changes in case you want to see what the changes are.
Basically, in addition to replacing the statements that are not supported in OpenGLES 2.0, I have to add code to set up the shaders for vertex and fragment. Also, instead of using the range 0 to textureSize in the vertex arrays, I have to use the range -1 to 1, which means that in setting up the vertex arrays, the texture width is now 2, 0 becomes -1, and textureSize becomes 1.
To set up the shaders for that tutorial, we can use the ones that come with Cocos2d or write custom but simple shaders. I have included both methods to choose from.
Hope this helps!