我正在使用Vuforia将 3D 模型放置在图像目标上。我创建了一个通用的 C++ 解决方案,可以在 Android 和 iOS 上工作。它适用于 Android,但我无法让 3D 模型出现在 iOS 中。它完美地跟踪图像目标,但没有 3D 模型的迹象。我使用的 3D 模型可以在这里找到。
这就是我正在做的事情:
每次需要渲染屏幕时,Vuforia 都会调用此方法:
- (void)renderFrameQCAR
{
[self setFramebuffer];
[[ObjectController getInstance] getObjectInstance]->renderFrame();
[self presentFramebuffer];
}
这是setFramebuffer
方法(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
}
}
这是renderFrame
方法(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();
}
最后一个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;
}