case Projection::_3D: { float zeye = this->getZEye(); Mat4 matrixPerspective,matrixLookup; loadIDentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);#if CC_TARGET_PLATFORM == CC_PLATFORM_WP8 //if needed,we need to add a rotation for Landscape orIEntations on windows Phone 8 since it is always in Portrait Mode GLVIEw* vIEw = getopenGLVIEw(); if(getopenGLVIEw() != nullptr) { multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION,getopenGLVIEw()->getorIEntationMatrix()); } #endif // issue #1334 Mat4::createPerspective(60,(GLfloat)size.wIDth/size.height,10,zeye+size.height/2,&matrixPerspective); multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION,matrixPerspective); Vec3 eye(size.wIDth/2,size.height/2,zeye),center(size.wIDth/2,0.0f),up(0.0f,1.0f,0.0f); Mat4::createLookAt(eye,center,up,&matrixLookup); multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION,matrixLookup); loadIDentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); break; }
好奇的是为什么视图矩阵放在投影矩阵栈中的呢?网上我也看到过别人的吐槽,但是cocos为什么这么做肯定是有它的原因的。仔细一想其实这样是很正常的,一个顶点坐标要经过MVP变换,但是cocos只会传入模型变换(相对根节点的各种变换,但是投影和视图变换对所有节点都是一样的), 虽然模型和视图矩阵总是放在一起的,但其实也没必要这么死板,M*(V*p) = (M*V)*P,反正都一样。既然视图变换不会改变,为何不把视图和投影放在一起呢。如果真的要纠结这个问题,那我们就试着改一下吧,将视图变换移到loadIDentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
把
MATRIX_STACK_PROJECTION换成MATRIX_STACK_MODELVIEW,其实也是一样的。
10和zeye+size.height/2分别代表了近截面和远截面。如果一个顶点的z 坐标是9或者 zeye+size.height/2 +1 ,将都显示不出来。
2:节点的变换const Mat4& Node::getNodetoParenttransform() const{ if (_transformDirty) { // Translate values float x = _position.x; float y = _position.y; float z = _positionZ; if (_ignoreAnchorPointForposition) { x += _anchorPointInPoints.x; y += _anchorPointInPoints.y; } bool needsSkewMatrix = ( _skewX || _skewY ); Vec2 anchorPoint(_anchorPointInPoints.x * _scaleX,_anchorPointInPoints.y * _scaleY); // caculate real position if (! needsSkewMatrix && !_anchorPointInPoints.equals(Vec2::ZERO)) { x += -anchorPoint.x; y += -anchorPoint.y; } // Build transform Matrix = translation * rotation * scale Mat4 translation; //move to anchor point first,then rotate Mat4::createTranslation(x + anchorPoint.x,y + anchorPoint.y,z,&translation); //需要绕锚点旋转,先移动到锚点 Mat4::createRotation(_rotationQuat,&_transform); if (_rotationZ_X != _rotationZ_Y) //表示这部分还没懂 { // Rotation values // Change rotation code to handle X and Y // If we skew with the exact same value for both x and y then we're simply just rotating float radiansX = -CC_degrees_TO_radians(_rotationZ_X); float radiansY = -CC_degrees_TO_radians(_rotationZ_Y); float cx = cosf(radiansX); float sx = sinf(radiansX); float cy = cosf(radiansY); float sy = sinf(radiansY); float m0 = _transform.m[0],m1 = _transform.m[1],m4 = _transform.m[4],m5 = _transform.m[5],m8 = _transform.m[8],m9 = _transform.m[9]; _transform.m[0] = cy * m0 - sx * m1,_transform.m[4] = cy * m4 - sx * m5,_transform.m[8] = cy * m8 - sx * m9; _transform.m[1] = sy * m0 + cx * m1,_transform.m[5] = sy * m4 + cx * m5,_transform.m[9] = sy * m8 + cx * m9; } _transform = translation * _transform; //旋转矩阵 //move by (-anchorPoint.x,-anchorPoint.y,0) after rotation _transform.translate(-anchorPoint.x,0); //之前移到了锚点,现在移回。 if (_scaleX != 1.f) { _transform.m[0] *= _scaleX,_transform.m[1] *= _scaleX,_transform.m[2] *= _scaleX; } if (_scaleY != 1.f) { _transform.m[4] *= _scaleY,_transform.m[5] *= _scaleY,_transform.m[6] *= _scaleY; } if (_scaleZ != 1.f) { _transform.m[8] *= _scaleZ,_transform.m[9] *= _scaleZ,_transform.m[10] *= _scaleZ; } //以上为translation * rotation * scale //其中rotation采用四元数来做的,具体请看其他blog。_rotationQuat如何生成,旋转矩阵如何从四元数来的。 // FIXME:: Try to inline skew // If skew is needed,apply skew and then anchor point if (needsSkewMatrix) { float skewMatArray[16] = { 1,(float)tanf(CC_degrees_TO_radians(_skewY)),0,(float)tanf(CC_degrees_TO_radians(_skewX)),1,1 }; Mat4 skewMatrix(skewMatArray); _transform = _transform * skewMatrix; //也还没懂 // adjust anchor point if (!_anchorPointInPoints.equals(Vec2::ZERO)) //这部分也还没懂 { // FIXME:: Argh,Mat4 needs a "translate" method. // FIXME:: Although this is faster than multiplying a vec4 * mat4 _transform.m[12] += _transform.m[0] * -_anchorPointInPoints.x + _transform.m[4] * -_anchorPointInPoints.y; _transform.m[13] += _transform.m[1] * -_anchorPointInPoints.x + _transform.m[5] * -_anchorPointInPoints.y; } } if (_useAdditionaltransform) { _transform = _transform * _additionaltransform; } _transformDirty = false; } return _transform;}
一些链接:
万向节死锁问题
四元数和旋转矩阵
四元数和旋转矩阵
sprite竟然使用的是SHADER_name_position_TEXTURE_color_NO_MVP,没有mv矩阵的,只有投影矩阵CC_PMatrix。
在fillQuads已经对QuadCommand对应的节点进行了变换。
感觉很乱啊。(我的版本是3.4。)
请参考:
相关内容
可以用来实现场景截图。参考cocos2d的RenderTexture。
5: 模板测试,Alpha测试和遮罩cocos2d的遮罩ClipPingNode采用模板测试和Alpha测试。
设置翻转属性可以决定是显示模板内的背景还是模板外的背景。
先将不翻转的情况吧,此时显示模板内的背景区域。
如果做到这点呢?
1:先覆盖模板缓冲,设置为0;此时如果要在一个点绘制一个像素,肯定不能成功。
glStencilMask(mask_layer);
glStencilFunc(GL_NEVER,mask_layer,mask_layer);
glStencilOp(!_inverted ? GL_ZERO : GL_REPLACE,GL_KEEP,GL_KEEP);
2:然后绘制模板
glStencilFunc(GL_NEVER,mask_layer);glStencilOp(!_inverted ? GL_REPLACE : GL_ZERO,GL_KEEP);_stencil->visit(renderer,_modelVIEwtransform,flags);
此时在模板区域内的值都为mask_layer(glStencilMask),其他部分的值还是0。模板并没有绘制出来,它只是为了填充模板缓冲中的一部分模板值。
3:绘制背景
glStencilFunc(GL_EQUAL,_mask_layer_le,_mask_layer_le);glStencilOp(GL_KEEP,GL_KEEP);this->draw(renderer,flags);
GL_EQUAL表示只有模板值和_mask_layer_le相等,才通过验证,但是目前模板缓冲中的所有值要么是0,要么是mask_layer。(这里我也是又点疑问的,为什么是_mask_layer_le,知道它是为了多层嵌套,但是还是理解不了它要做的效果。如果没有多层嵌套_mask_layer_le = mask_layer。估计先不管那么多吧。我们就考虑单层的情况吧!),只有模板区域内的模板值和参考值相等,所以只有模板区域内的像素能画出来。
现在拿一张背景图和一张部分透明的模板图做成遮罩,那部分透明的区域,我也不像显示背景的部分,该怎么做呢?此时加入Alpha测试,Alpha测试在模板测试之前,所以设置模板样图中透明部分不参加模板测试就好了,Alpha测试过滤掉模板样图的透明部分。
做法如下:
// enable Alpha testingglEnable(GL_Alpha_TEST);// pixel will be drawn only if greater than an Alpha thresholdglAlphaFunc(GL_GREATER,_AlphaThreshold);
此时只有Alpha值大于_AlphaThreshold的模板区域才会去进行模板测试。
渲染完模板样图之后,要恢复Alpha测试之前的状态。
if (_AlphaThreshold < 1.0) //恢复以前的Alpha测试的状态{ glAlphaFunc(_currentAlphaTestFunc,_currentAlphaTestRef); if (!_currentAlphaTestEnabled) { gldisable(GL_Alpha_TEST); }}6:绘图
(1):cocos2d drawNode绘制点:
这个比较简单,代码很好懂,我实现了一遍,碰到的几个问题:
glDrawArrays(GL_POINTS,_bufferCountGLPoint);//正确 glDrawArrays(GL_POINT,_bufferCountGLPoint);//错误
我不小心写成了下面这种,导致不能正确显示出来。那如何断点到这里的呢,我们可以获取opengl错误glGetError,cocos2d里面也封装了获取opengl错误的函数:CHECK_GL_ERROR_DEBUG,直接拿来调试就好了。
它们有什么区别呢:GL_POINTS是绘制模式是图元,GL_POINT多用来表示多边形的绘制填充模式(轮廓点式多边形、轮廓线式多边形或全填充式多边形)。
(2):还有个疑问,那就是glBufferData中的GL_STREAM_DRAW,为什么绘制点的时候是GL_STREAM_DRAW模式呢?
网上这样描述几种的区别:GL_STATIC_DRAW,GL_STREAM_DRAW,GL_DYNAMIC_DRAW用于给OpenGL系统提醒:预期数据是一直不变、数据每帧变一次或几帧变一次、数据每帧变两三次以上,方便硬件内部优化吧。
(3):吐槽一下:
GL::bindVAO(_vaoGLPoint);glGenBuffers(1,&_vboGLPoint);glBindBuffer(GL_ARRAY_BUFFER,_vboGLPoint);glBufferData(GL_ARRAY_BUFFER,sizeof(V2F_C4B_T2F)*_bufferCapacityGLPoint,_bufferGLPoint,GL_STREAM_DRAW);
DrawNode初始化vao,vbo就向显卡传递了所有初始化的数据(这些根据就没用)
glBindBuffer(GL_ARRAY_BUFFER,GL_STREAM_DRAW);
这里又传递了所有数据。真的有这个必要嘛!!!
我的修改:
glBufferData(GL_ARRAY_BUFFER,GL_STREAM_DRAW);
换成:
glBufferData(GL_ARRAY_BUFFER,nullptr,GL_STREAM_DRAW);
######分割线@H_40_419@ glBufferData(GL_ARRAY_BUFFER,GL_STREAM_DRAW);
换成
glBufferData(GL_ARRAY_BUFFER,_bufferGLpointCount*sizeof(V2F_C4F_T2F),_bufferPoints,GL_STREAM_DRAW);
也是同样的效果,如果不对,望大神指正。
(4):如何制定点的大小:(cocos2d的点是方形的)
V2F_C4F_T2F point = { position,color,Tex2F(pointSize,0) };
一时不解,改了这个Tex2F(pointSize,0),换成Tex2F(pointSize,pointSize),Tex2F(0,0)如何呢,发现后两个都没反应,默认大小还是1。于是查看了shader,才发现问题所在:
@H_502_447@gl_position = CC_MVPMatrix * a_position;@H_502_447@gl_PointSize = a_texCoord.x;@H_502_447@v_fragmentcolor = a_color;
(7):颜色有问题
通过drawNode画点或者画线。颜色都感觉有问题,我传进去color4F(255.0,255.0)红色,显示出来的却是淡蓝色,于是查看了下shader,下面是line的着色器:
v_color = vec4(a_color.rgb * a_color.a,a_color.a);
将v_color 硬设置成(1.0,0.0,1.0)是ok的,所以问题就出在我们的程序到顶点着色器。
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_color,4,GL_UNSIGNED_BYTE,GL_TRUE,sizeof(V2F_C4B_T2F),(GLvoID *)offsetof(V2F_C4B_T2F,colors));
这是设置line的vao和vbo时候对颜色的设置。感觉不对啊,为什么是GL_UNSIGNED_BYTE,改成GL_float就对了。
7:数据传递方式:方式一:
glBufferData(GL_ARRAY_BUFFER,sizeof(_quadVerts[0]) * _numberQuads * 4,nullptr,GL_DYNAMIC_DRAW);voID *buf = glMapBuffer(GL_ARRAY_BUFFER,GL_WRITE_ONLY);memcpy(buf,_quadVerts,sizeof(_quadVerts[0])* _numberQuads * 4);glunmapBuffer(GL_ARRAY_BUFFER);
这是一段往vbo中填充数据的代码。
方式二:
glBufferData(GL_ARRAY_BUFFER,sizeof(_quadVerts[0]) * _numberQuads * 4,GL_DYNAMIC_DRAW);
一样的效果。
函数解释:
GLvoID *glMapBuffer(GLenum target,gluenum access):返回一个指向缓冲区对象的指针,可以在这个缓冲区对象中写入新值及更新之后,再调用GLboolean glunMapBuffer(GLenum target)表示已经完成了对数据的更新,取消对这个缓冲区的映射。如果只需要更新所需范围内的数据值,也可调用GLvoID *glMapBuffwerRange(GLenum target,Glintptr offset,GLsizeiptr length,GLbitfIEld access)
voID glBufferData(GLenum target,GLsizeiptr size,const GLvoID * data,GLenum usage );
功能是分配size个存储单位的OpenGL服务器内存,用于存储顶点数据或索引。以前有与当前缓冲区对象相关联的数据将删除。
glBufferData()首先在OpenGL拂去其中分配内存以存储数据。如果成功分配,data!=NulL,size个单位就会从客户机内存复制到这个对象中。如果data=NulL,为数据保留适当的空间,但不会初始化。
详细请看:opengl缓冲对象
具体采用哪种现在也还没个具体方案。cocos2d两种都有,render中采用glMapBuffer,很多其他地方用glBufferData。
第一部分就暂时这样吧!!!
总结以上是内存溢出为你收集整理的cocos2d opengl的一下知识总结一全部内容,希望文章能够帮你解决cocos2d opengl的一下知识总结一所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)