cocos2d opengl的一下知识总结一

cocos2d opengl的一下知识总结一,第1张

概述1:矩阵变换 case Projection::_3D: { float zeye = this->getZEye(); Mat4 matrixPerspective, matrixLookup; loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJ 1:矩阵变换
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;}

一些链接:
万向节死锁问题
四元数和旋转矩阵
四元数和旋转矩阵

3: 使用的shader

sprite竟然使用的是SHADER_name_position_TEXTURE_color_NO_MVP,没有mv矩阵的,只有投影矩阵CC_PMatrix。
在fillQuads已经对QuadCommand对应的节点进行了变换。
感觉很乱啊。(我的版本是3.4。)

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的一下知识总结一所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1080671.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-27
下一篇 2022-05-27

发表评论

登录后才能评论

评论列表(0条)

保存