您的位置:首页 > 其它

关于在Box2dTest中开启调试打印

2014-05-03 21:42 363 查看
关于在Box2dTest中开启调试打印

    关于在Box2dTest中开启调试打印,实际就是使用OpenGL直接绘图方法绘制Box2d相关的信息,不过这个绘制是通过world->DrawDebugData()函数来完成的,我们无须多加干预,但是需要在其开始工作之前为其设置好工作环境。具体代码及注释如下:
//以下仅给出与打印相关的语句

//原示例程序没有包括该头文件及其对应的cpp,此两文件在Box2dTestBed项目中,
//是实现调试打印功能的关键代码,一定要包含,要么用相对路径,要么直接拷贝到本
//工程目录下,导入工程中就行了
#include "GLES-Render.h"

class Box2DTestLayer : public Layer
{
//调试打印实例的指针
GLESDebugDraw* _debugDraw;

//必须重载draw函数,注意尾巴后面那个override必须有
virtual void draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated) override;

protected:
//变换矩阵(不知道这么称呼专业否,文中再行解释)
kmMat4 _modelViewMV;
//自定义的draw方法实现
void onDraw();
CustomCommand _customCommand;
} ;

//看起来好像就这两个与调试打印功能相关,一个是着色器,一是自定义draw函数时使用
#include "renderer/CCRenderer.h"
#include "renderer/CCCustomCommand.h"

Box2DTestLayer::Box2DTestLayer()
: _spriteTexture(nullptr)
, world(nullptr)
{
//因为在该函数里面创建了调试打印对象实例,所以保留在此
this->initPhysics();
}

Box2DTestLayer::~Box2DTestLayer()
{
//构造函数里面创建,析构时删除
delete _debugDraw;
}

void Box2DTestLayer::initPhysics()
{
//创建调试打印对象,并且关联到物理世界
_debugDraw = new GLESDebugDraw( PTM_RATIO );
world->SetDebugDraw(_debugDraw);
//设置都需要打印哪些调试信息
uint32 flags = 0;
flags += b2Draw::e_shapeBit;
flags += b2Draw::e_jointBit;
flags += b2Draw::e_aabbBit;
flags += b2Draw::e_pairBit;
flags += b2Draw::e_centerOfMassBit;
_debugDraw->SetFlags(flags);
}

//似乎在Beta2版本中,重载draw是没有参数的,正式版中需要带参数了
void Box2DTestLayer::draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated)
{
//调用父类的绘图,保证纹理被正确绘制
Layer::draw(renderer, transform, transformUpdated);

//使能顶点绘制属性,没有深究OpenGL,不知道干什么的,尝试注释掉,也没有影响
GL::enableVertexAttribs( cocos2d::GL::VERTEX_ATTRIB_FLAG_POSITION );

//矩阵的压推栈操作,具体做什么的文中再说,反正记住成对出现就行了,
//至于这个kmMat4类型的modelViewMV和上面那个transform毛关系,就不知道了
//ND,也没个文档说说,就当时环境设置,按规矩来行了
kmGLPushMatrix();
kmGLGetMatrix(KM_GL_MODELVIEW, &_modelViewMV);//保留当前的矩阵,后面自定义绘画的时候有用

//使用着色器和CustomCommand定义自定义的绘制函数
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(Box2DTestLayer::onDraw, this);
renderer->addCommand(&_customCommand);

kmGLPopMatrix();
}

void Box2DTestLayer::onDraw()
{
//而且特别像MFC中选画笔的感觉,先保存旧的,然后换入所选的,用完后再还入旧的
kmMat4 oldMV;
kmGLGetMatrix(KM_GL_MODELVIEW, &oldMV);
kmGLLoadMatrix(&_modelViewMV);
////////////////////////////////////////////
//其实在这里还能做很多事情
world->DrawDebugData();
////////////////////////////////////////////
kmGLLoadMatrix(&oldMV);
}

    代码中的一些问题的解释:
    1、关于矩阵堆栈的问题

   
问了问度娘,其中有一段解释,总体而言就是这是OpenGL的工作模式决定的。

    1)OpenGL物体建模实际上是分两步走的。第一步,在世界坐标系的原点位置绘制出该物体;第二步,通过modelview变换矩阵对世界坐标系原点处的物体进行仿射变换,将该物体移动到世界坐标系的目标位置处。

    2)OpenGL中的modelview矩阵变换是一个马尔科夫过程:上一次的变换结果对本次变换有影响,上次modelview变换后物体在世界坐标系下的位置是本次modelview变换的起点。默认是本次变换和上次变换不独立。

    3)凡是使用glPushMatrix()和glPopMatrix()的程序一般可以判定是采用世界坐标系建模。既世界坐标系固定,modelview矩阵移动物体。

    4)将modelview变换放在glPushMatrix和glPopMatrix之间可以使本次变换和上次变换独立。

    以上就是glPushMatrix()和glPopMatrix()成对使用的原因。一般说来,矩阵堆栈常用于构造具有继承性的模型,即由一些简单目标构成的复杂模型。例如,一辆自行车就是由两个轮子、一个三角架及其它一些零部件构成的。它的继承性表现在当自行车往前走时,首先是前轮旋转,然后整个车身向前平移,接着是后轮旋转,然后整个车身向前平移,如此进行下去,这样自行车就往前走了。将上述模型的构造过程放在glPushMatrix和glPopMatrix之间,则本次汽车在世界坐标系中的位置不是基于上一次汽车的位置而给出的(以前一次的位置为参考),而是直接给出的以世界下的坐标(以世界坐标系的原点为参考)。整个过程是符合人的思维过程的,由于每次建模都是以单位阵为变换起点,故便于采用统一的实现方式进行处理。将本次需要执行的缩放、平移等操作放在glPushMatrix和glPopMatrix之间。glPushMatrix()和glPopMatrix()的配对使用可以消除上一次的变换对本次变换的影响。使本次变换是以世界坐标系的原点为参考点进行。

    矩阵堆栈对复杂模型运动过程中的多个变换操作之间的联系与独立十分有利。因为所有矩阵操作函数如glLoadMatrix()、glMultMatrix()、glLoadIdentity()等只处理当前矩阵或堆栈顶部矩阵,这样堆栈中下面的其它矩阵就不受影响。为了更好地理解这两个函数,我们可以形象地认为glPushMatrix()就是“记住自己在哪”,glPopMatrix()就是“返回自己原来所在地”。

    就这个来理解本例中的代码,大概就是以下这个意思:记住现在的位置,并且记住现在要做的那些变形,然后设置并调用自定义的绘画函数,在自定义函数中记住当前位置(猜测自定义函数的上下文环境和外面已经保存的这个不一样),并且使用记住的那些变形操作进行当前图形的绘制,完成后还原自定义函数的环境,自定义函数执行完成回到draw中,然后在draw中返回自己原来的位置。
    2、关于GL::enableVertexAttribs的问题

    实话实说,不知道是啥,反正不打算研究OpenGL。《捕鱼达人》代码大揭秘那本书上是这么说的:Cocos2dx中最大的变革是引入了OpenGL ES 2.0作为底层绘图,意味着渲染从过去的固定管线升级到了可编程管线,我们可以通过着色器定义每一个顶点或像素的着色方式。在渲染流水线上,存在两个对开发者可见的可编程着色器:

    顶点着色器(Vertex Shader):对每个顶点调用一次,完成顶点变换、法线变换……等操作,并最终确定渲染区域。在Cocos中,精灵和层都是矩形,他们的一次渲染会调用4次顶点着色器。

    段着色器(Fragment Shader):个人认为翻做碎片着色器更贴切些。这个着色器会在每个像素被渲染的时候调用,通常这个过程由显卡的图形处理单元并行化完成。

    这两个着色器不能单独使用,必须成对配合出现,因为顶点着色器会首先确定每一个
4000
显示到屏幕上的顶点的属性,然后这些顶点组成的区域被划分成一系列像素,由段着色器来完成剩下的工作。《捕鱼达人》就说到这里了,因为这是一门“高深的学问”,我也不打算多深入,不过度娘还是帮我们找到了以上这段话的英文原文,感兴趣的兄弟们可以瞟一眼。
    3、关于world->DrawDebugData上的那句注释:

    其实,如果不调用world的调试打印函数,以上的所有准备工作都等同于在Cocos2dx中使用OpenGL直接绘图的准备工作,不同的只在这里,如果不是调用world的调试打印函数,这里其实可以调用
glLineWidth
设置线宽,调用DrawPrimitives相关函数如drawLine等进行自定义绘图了。当然,有兄弟已经写了详细的方法,这里不献丑了。值得一提的是该文代码里有关矩阵堆栈的处理,似乎又与Box2dTest示例中的用法不同,貌似更漂亮一些。


void HelloWorld::draw(cocos2d::Renderer *renderer, const kmMat4 &transform, bool transformUpdated)
{
_customCommand.init(1);
_customCommand.func = CC_CALLBACK_0(HelloWorld::onDraw, this,transform,transformUpdated);
renderer->addCommand(&_customCommand);
}

void HelloWorld::onDraw(const kmMat4 &transform, bool transformUpdated)
{
kmGLPushMatrix();
kmGLLoadMatrix(&transform);

/*直线*/
CHECK_GL_ERROR_DEBUG();
DrawPrimitives::drawLine(VisibleRect::leftBottom(), VisibleRect::rightTop());

CHECK_GL_ERROR_DEBUG();

glLineWidth( 5.0f );
DrawPrimitives::setDrawColor4B(255,0,0,255);
DrawPrimitives::drawLine( Point(0, 0), Point(100, 100) );

// draw big point in the center
DrawPrimitives::setPointSize(64);
DrawPrimitives::setDrawColor4B(100, 0, 255, 128);
DrawPrimitives::drawPoint(VisibleRect::center());
CHECK_GL_ERROR_DEBUG();

// draw 4 small points
Point points[] = { Point(60,60), Point(70,70), Point(160,70), Point(170,60) };
DrawPrimitives::setPointSize(10);
DrawPrimitives::setDrawColor4B(0,10,255,255);
DrawPrimitives::drawPoints( points, 4);

CHECK_GL_ERROR_DEBUG();

// draw a green circle with 10 segments
glLineWidth(16);
DrawPrimitives::setDrawColor4B(0, 255, 0, 255);
DrawPrimitives::drawCircle( VisibleRect::center(), 100, 0, 10, false);

CHECK_GL_ERROR_DEBUG();

// draw a green circle with 50 segments with line to center
glLineWidth(2);
DrawPrimitives::setDrawColor4B(0, 255, 255, 255);
DrawPrimitives::drawCircle( VisibleRect::center(), 150, CC_DEGREES_TO_RADIANS(90), 50, false);

CHECK_GL_ERROR_DEBUG();

// draw a pink solid circle with 50 segments
glLineWidth(2);
DrawPrimitives::setDrawColor4B(255, 0, 255, 255);
DrawPrimitives::drawSolidCircle( VisibleRect::center() + Point(140,0), 40, CC_DEGREES_TO_RADIANS(90), 50, 1.0f, 1.0f);

CHECK_GL_ERROR_DEBUG();

// open yellow poly
DrawPrimitives::setDrawColor4B(255, 255, 0, 255);
glLineWidth(5);
Point vertices[] = { Point(10,10), Point(50,50), Point(100,50), Point(150,100), Point(200,150) };
DrawPrimitives::drawPoly( vertices, 5, false);

CHECK_GL_ERROR_DEBUG();

// filled poly
glLineWidth(1);
Point filledVertices[] = { Point(0,120), Point(50,120), Point(50,170), Point(25,200), Point(0,170) };
DrawPrimitives::drawSolidPoly(filledVertices, 5, Color4F(0.5f, 0.5f, 1, 1 ) );

// closed purble poly
DrawPrimitives::setDrawColor4B(255, 0, 255, 255);
glLineWidth(2);
Point vertices2[] = { Point(30,130), Point(30,230), Point(50,200) };
DrawPrimitives::drawPoly( vertices2, 3, true);

CHECK_GL_ERROR_DEBUG();

// draw quad bezier path
DrawPrimitives::drawQuadBezier(VisibleRect::leftTop(), VisibleRect::center(), VisibleRect::rightTop(), 50);

CHECK_GL_ERROR_DEBUG();

// draw cubic bezier path
DrawPrimitives::drawCubicBezier(VisibleRect::center(), Point(VisibleRect::center().x+30,VisibleRect::center().y+150), Point(VisibleRect::center().x+60,VisibleRect::center().y-300),Point(VisibleRect::center().x+90,VisibleRect::center().y+150),100);

CHECK_GL_ERROR_DEBUG();

//draw a solid polygon
Point vertices3[] = {Point(60,160), Point(70,190), Point(100,190), Point(90,160)};
DrawPrimitives::drawSolidPoly( vertices3, 4, Color4F(1,1,0,1) );

CHECK_GL_ERROR_DEBUG();

//end draw
kmGLPopMatrix();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: