ARTool初步涉足,从simpleLite.c里opengl的流程开始

刚接触ARTool,基于ARToolKit5-bin-5.3.2r1-Linux-x86_64.tar.gz,简单笔记一下,simpleLite.c作用是读入视频,找到对应贴图位置,然后贴一个六面体。这里主要分析了一下相关代码opengl的作用和流程。

这里在代码中笔记一下重要流程的comment。


主函数是Display()。根据解码后的一帧,和之前找到的需要贴图六面体的位置,进行贴图,并输出到screen。

//  gARTImage is one frame decoded.
//	// Grab a video frame.
//	if ((image = arVideoGetImage()) != NULL) {
//		gARTImage = image;	// Save the fetched image.
static void Display(void)
{
  	ARdouble p[16];
	ARdouble m[16];
	
	// Select correct buffer for this context. 
	glDrawBuffer(GL_BACK);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the buffers for new frame.
	
	// load gARTImage to GL_TEXTURE0, texture id contextSettings->texture
  	arglPixelBufferDataUpload(gArglSettings, gARTImage);
	arglDispImage(gArglSettings);
	// now frame is draw to opengl framebuffer.
	gARTImage = NULL; // Invalidate image data.
				
	// Projection transformation.
	// load the frustum matrix into p. The data is calculate in arDetectMarker() 
	arglCameraFrustumRH(&(gCparamLT->param), VIEW_DISTANCE_MIN, VIEW_DISTANCE_MAX, p);
	glMatrixMode(GL_PROJECTION);
#ifdef ARDOUBLE_IS_FLOAT
    	glLoadMatrixf(p);
#else
    	glLoadMatrixd(p);
#endif
	glMatrixMode(GL_MODELVIEW);
		
	glEnable(GL_DEPTH_TEST);

	// Viewing transformation.
	glLoadIdentity();
	// Lighting and geometry that moves with the camera should go here.
	// (I.e. must be specified before viewing transformations.)
	//none
	
	if (gPatt_found) {
	
		// Calculate the camera position relative to the marker.
		// Replace VIEW_SCALEFACTOR with 1.0 to make one drawing unit equal to 1.0 ARToolKit units (usually millimeters).
		arglCameraViewRH((const ARdouble (*)[4])gPatt_trans, m, VIEW_SCALEFACTOR);
		
		// glLoadMatrixf or glLoadMatrixd, move current coordinate system to m system(which is AR cube position)
#ifdef ARDOUBLE_IS_FLOAT
        	glLoadMatrixf(m);
#else
       	 	glLoadMatrixd(m);
#endif

		// All lighting and geometry to be drawn relative to the marker goes here.
		DrawCube();
	
	} // gPatt_found
	
	// Any 2D overlays go here.
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, (GLdouble)windowWidth, 0, (GLdouble)windowHeight, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glDisable(GL_LIGHTING);
    glDisable(GL_DEPTH_TEST);
...
    // swap buffer to display framebuffer data to screen. Refer to glutInitDisplayMode(GLUT_DOUBLE....
    glutSwapBuffers();
}

其中,将解码帧数据读到texture unit的函数是arglPixelBufferDataUpload()

int arglPixelBufferDataUpload(ARGL_CONTEXT_SETTINGS_REF contextSettings, ARUint8 *bufDataPtr)
{
...
		// enable GL_TEXTURE0, bind to texture id contextSettings->texture as a GL_TEXTURE_2D texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, contextSettings->texture);
    
    // set pixel transfer modes, GL_UNPACK_ALIGNMENT set to 4 or 1 depend on buffer size alignment
    glPixelTransferi(GL_UNPACK_ALIGNMENT, (((contextSettings->bufSizeX * contextSettings->pixSize) & 0x3) == 0 ? 4 : 1));
...
    if (arDebugMode == AR_DEBUG_DISABLE) {
        if (contextSettings->bufSizeIsTextureSize) {
        	  // load data bufDataPtr as a GL_TEXTURE_2D texture in GL_TEXTURE0, which texture id is contextSettings->texture
            glTexImage2D(GL_TEXTURE_2D, 0, contextSettings->pixIntFormat, contextSettings->textureSizeX, contextSettings->textureSizeY, 0, contextSettings->pixFormat, contextSettings->pixType, bufDataPtr);
        } else {
...        }
    } else {
...
    }
    contextSettings->textureDataReady = TRUE;
    return (TRUE);
}

然后,将读入的这帧数据draw到framebuffer中的函数是,arglDispImage()。做的工作相当于处理好映射的MVP矩阵,映射方式用glOrtho。最后调用arglDispImageStateful()进行画图。

void arglDispImage(ARGL_CONTEXT_SETTINGS_REF contextSettings)
{
...
    // Prepare an orthographic projection, set camera position for 2D drawing, and save GL state.
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    // load initial projection matrix
    glLoadIdentity();
    // if rotate 90 degree do:
    if (contextSettings->rotate90) glRotatef(90.0f, 0.0f, 0.0f, -1.0f);
    
    if (contextSettings->flipV) {
        bottom = (GLdouble)contextSettings->arParam.ysize;
        top = 0.0;
    } else {
        bottom = 0.0;
        top = (GLdouble)contextSettings->arParam.ysize;
    }
    if (contextSettings->flipH) {
        left = (GLdouble)contextSettings->arParam.xsize;
        right = 0.0;
    } else {
        left = 0.0;
        right = (GLdouble)contextSettings->arParam.xsize;
    }
    // set camara mode to ortho, capture size as (xsize, ysize) , near -1, far 1.
    glOrtho(left, right, bottom, top, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    // load initial model view matrix
    glLoadIdentity(); 
...
    arglDispImageStateful(contextSettings);
...   
    // Restore previous projection & camera position.
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
... 
}

真正画图的函数是arglDispImageStateful()。画的vertex和coords都在之前的初始化中处理好了,这里只需要绑定对应buffer就可以。可以选择直接按4个点画,或者拆分成多个三角画。

void arglDispImageStateful(ARGL_CONTEXT_SETTINGS_REF contextSettings)
{
...
		// activate GL_TEXTURE0. The decoded frame has already been loaded in this texture unit
    glActiveTexture(GL_TEXTURE0);
    
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    
    // bind to texture contextSettings->texture
    glBindTexture(GL_TEXTURE_2D, contextSettings->texture);
    glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &texEnvModeSave); // Save GL texture environment mode.
...
		// prepare to draw current texture
    glEnable(GL_TEXTURE_2D);
    
    // activate texture0
    // more: glActiveTexture and glClientActiveTexture: They control entirely different things. ActiveTexture sets the texture sampler stage that you're currently modifying -- operations like BindTexture, TexEnv, etc. ClientActiveTexture controls the texture coordinates you're sending, which may or may not be related to the textures. If you're using VertexAttribPointer, it has no effect. If you're using TexCoordPointer, it does. 
    glClientActiveTexture(GL_TEXTURE0);
    // bind to t2 coords buffer (output), which is initialed in arglSetupTextureGeometry(). All vertex and coords position is initialed in arglSetupTextureGeometry()
    glBindBuffer(GL_ARRAY_BUFFER, contextSettings->t2bo);
    glTexCoordPointer(2, GL_FLOAT, 0, NULL);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    
    // bind vertex buffer for v2 data (input)
    glBindBuffer(GL_ARRAY_BUFFER, contextSettings->v2bo);
    glVertexPointer(2, GL_FLOAT, 0, NULL);
    glEnableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    
    // draw. As a whole picture, or divided into several triangle
    if (contextSettings->disableDistortionCompensation) {
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    } else {
        for (i = 0; i < 20; i++) {
            glDrawArrays(GL_TRIANGLE_STRIP, i * 42, 42);
        }
    }
    
    // unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    
    // dont need texture 2D
    glDisable(GL_TEXTURE_2D);
    if (texEnvModeSave != GL_REPLACE) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texEnvModeSave); // Restore GL texture environment mode.
}

最后,将坐标系挪到对应需要贴AR的六面体的位置,然后调用drawCube()函数将内容写在framebuffer中

static void DrawCube(void)
{
    // Colour cube data.
    int i;
    float fSize = 40.0f;
    const GLfloat cube_vertices [8][3] = {
        /* +z */ {0.5f, 0.5f, 0.5f}, {0.5f, -0.5f, 0.5f}, {-0.5f, -0.5f, 0.5f}, {-0.5f, 0.5f, 0.5f},
        /* -z */ {0.5f, 0.5f, -0.5f}, {0.5f, -0.5f, -0.5f}, {-0.5f, -0.5f, -0.5f}, {-0.5f, 0.5f, -0.5f} };
    const GLubyte cube_vertex_colors [8][4] = {
        {255, 255, 255, 255}, {255, 255, 0, 255}, {0, 255, 0, 255}, {0, 255, 255, 255},
        {255, 0, 255, 255}, {255, 0, 0, 255}, {0, 0, 0, 255}, {0, 0, 255, 255} };
    const GLubyte cube_faces [6][4] = { /* ccw-winding */
        /* +z */ {3, 2, 1, 0}, /* -y */ {2, 3, 7, 6}, /* +y */ {0, 1, 5, 4},
        /* -x */ {3, 0, 4, 7}, /* +x */ {1, 2, 6, 5}, /* -z */ {4, 5, 6, 7} };
    
    glPushMatrix(); // Save world coordinate system.
    glRotatef(gDrawRotateAngle, 0.0f, 0.0f, 1.0f); // Rotate about z axis.
    // zoom ratio is fSize in xyz 
    glScalef(fSize, fSize, fSize);	
    // move current system
    glTranslatef(0.0f, 0.0f, 0.5f); // Place base of cube on marker surface. 
    glDisable(GL_LIGHTING);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);
    
    // set color pointer to cube_vertex_colors
    // here we don't need to set coords position, because we are using default value as input
    // if we try to print input cube, we should modify here, load a 2D texture and set coords.
    glColorPointer(4, GL_UNSIGNED_BYTE, 0, cube_vertex_colors);
    // set vertex to cube_vertices
    glVertexPointer(3, GL_FLOAT, 0, cube_vertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    
    // cube_faces refer to indices, which is draw order.
    for (i = 0; i < 6; i++) {
        glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_BYTE, &(cube_faces[i][0]));
    }
    glDisableClientState(GL_COLOR_ARRAY);
    glColor4ub(0, 0, 0, 255);
    for (i = 0; i < 6; i++) {
        glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, &(cube_faces[i][0]));
    }
    glPopMatrix();    // Restore world coordinate system.
}

一切都完成之后,调用glutSwapBuffers(),将framebuffer的内容显示在screen上。(因为初始化用的双frame buffer,glutInitDisplayMode(GLUT_DOUBLE)










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值