Cocos2dx-x tiledmap缝隙问题分析以及解决方案

简介: Cocos2dx-x tiledmap缝隙问题分析以及解决方案

一个三角形3个顶点,一个8个三角形,4个四边形

  • 如果瓦片在同一张纹理上不会出现裂缝问题
    网络异常,图片无法展示
    |
    网络异常,图片无法展示
    |

  • 如果瓦片在不同的纹理上就会会出现裂缝问题
    网络异常,图片无法展示
    |
    网络异常,图片无法展示
    |

tiled.tml文件内容,tmx格式

<?xml version="1.0" encoding="UTF-8"?>
<map version="1.5" tiledversion="1.6.0" orientation="orthogonal" renderorder="right-down" width="2" height="1" tilewidth="32" tileheight="32" infinite="0" mapScale="1" nextlayerid="2" nextobjectid="1">
 <tileset firstgid="1" name="2" tilewidth="32" tileheight="32" tilecount="1" columns="1">
  <image source="2.png" width="32" height="32"/>
 </tileset>
 <tileset firstgid="2" name="1" tilewidth="32" tileheight="32" tilecount="1" columns="1">
  <image source="1.png" width="32" height="32"/>
 </tileset>
 <layer id="1" name="图块层 1" width="2" height="1">
  <data encoding="csv">2,1</data>
 </layer>
</map>
复制代码
  • CCFastTMXTiledMap.cpp
bool TMXTiledMap::initWithTMXFile(const std::string& tmxFile)
{
    TMXMapInfo *mapInfo = TMXMapInfo::create(tmxFile);
    buildWithMapInfo(mapInfo);
    return true;
}
复制代码
  • CCTMXXMLParser.cpp
bool TMXMapInfo::initWithTMXFile(const std::string& tmxFile)
{
    return parseXMLFile(_TMXFileName); // xml解析,使用的SAX解析流
}
void TMXMapInfo::startElement(void* /*ctx*/, const char *name, const char **atts)
{    
    TMXMapInfo *tmxMapInfo = this;
    std::string elementName = name;
    ValueMap attributeDict;
    if (atts && atts[0])
    {
        // 属性是一个一维数组,所以要+2
        for (int i = 0; atts[i]; i += 2)
        {
            std::string key = atts[i];
            std::string value = atts[i+1];
            attributeDict.emplace(key, Value(value));
        }
    }
}
TMXTilesetInfo
tmxMapInfo->getTilesets().pushBack(tileset);
TMXLayerInfo
tmxMapInfo->getLayers().pushBack(layer);
在endElement的时候会设置每一层的tiles
layer->_tiles
void TMXLayer::setupTiles(){
    int length = _TileSetGroup.size();
    for(int i=0; i<length; ++i){
        _TileSetGroup[i]._set->_imageSize = _TileSetGroup[i]._texture->getContentSizeInPixels();
        // 设置图集纹理参数
        _TileSetGroup[i]._texture->setAliasTexParameters();
    }
}
复制代码

TMX下边会有TMXLayer这个节点

网络异常,图片无法展示
|

void TMXLayer::updateTotalQuads(const Rect& culledRect)
渲染命令
 std::vector<PrimitiveCommand> _renderCommands;
复制代码

在线框模式下,很明显看到提交的顶点是分离的

网络异常,图片无法展示
|

  • CCPrimitive.cpp
void Primitive::draw(){
        if(_verts){
            _verts->use();
        }
}
复制代码
  • CCVertexIndexData.cpp
void VertexData::use()
{
    uint32_t flags(0);
    for(auto& element : _vertexStreams)
    {
        flags = flags | (1 << element.second._stream._semantic);
    }
    GL::enableVertexAttribs(flags);
    int lastVBO = -1;
    for(auto& element : _vertexStreams)
    {
        //glEnableVertexAttribArray((GLint)element.second._stream._semantic);
        auto vertexStreamAttrib = element.second._stream;
        auto vertexBuffer = element.second._buffer;
        // don't call glBindBuffer() if not needed. Expensive operation.
        int vbo = vertexBuffer->getVBO();
        if (vbo != lastVBO) {
            // 顶点的数据来源,vertexBuffer的vbo
            glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->getVBO());
            lastVBO = vbo;
        }
        glVertexAttribPointer(GLint(vertexStreamAttrib._semantic),
                              vertexStreamAttrib._size,
                              vertexStreamAttrib._type,
                              vertexStreamAttrib._normalize,
                              vertexBuffer->getSizePerVertex(),
                              (GLvoid*)((long)vertexStreamAttrib._offset));
    }
}
复制代码
  • 更新顶点的逻辑
void TMXLayer::updateVertexBuffer()
{
    GL::bindVAO(0);
    if(nullptr == _vData)
    {
        _vertexBuffer = VertexBuffer::create(sizeof(V3F_C4B_T2F), (int)_totalQuads.size() * 4);
        _vData = VertexData::create();
        _vData->setStream(_vertexBuffer, VertexStreamAttribute(0, GLProgram::VERTEX_ATTRIB_POSITION, GL_FLOAT, 3));
        _vData->setStream(_vertexBuffer, VertexStreamAttribute(offsetof(V3F_C4B_T2F, colors), GLProgram::VERTEX_ATTRIB_COLOR, GL_UNSIGNED_BYTE, 4, true));
        _vData->setStream(_vertexBuffer, VertexStreamAttribute(offsetof(V3F_C4B_T2F, texCoords), GLProgram::VERTEX_ATTRIB_TEX_COORD, GL_FLOAT, 2));
        CC_SAFE_RETAIN(_vData);
        CC_SAFE_RETAIN(_vertexBuffer);
    }
    if(_vertexBuffer)
    {
        // 顶点信息来源:_totalQuads,顶点坐标没有问题
        _vertexBuffer->updateVertices((void*)&_totalQuads[0], (int)_totalQuads.size() * 4, 0);
    }
}
复制代码

使用的shader: SHADER_NAME_POSITION_TEXTURE_COLOR

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
    gl_Position = CC_MVPMatrix * a_position;
    v_fragmentColor = a_color;
    v_texCoord = a_texCoord;
}
复制代码
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
    gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
}
复制代码

CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL

struct CC_DLL V3F_C4B_T2F
{
    /// vertices (3F)
    Vec3     vertices;            // 12 bytes
    /// colors (4B)
    Color4B      colors;              // 4 bytes
    // tex coords (2F)
    Tex2F        texCoords;           // 8 bytes
};
复制代码

测试使用sprite拼接,是没有缝隙的

最终焦点聚集到了纹理参数上

网络异常,图片无法展示
|

GL_TEXTURE_MIN_FILTER

缩小

  • GL_NEAREST: OpenGL会选择中心点最接近纹理坐标的那个像素
  • GL_LINEAR
  • GL_NEAREST_MIPMAP_NEAREST
  • GL_LINEAR_MIPMAP_NEAREST
  • GL_NEAREST_MIPMAP_LINEAR:默认值
  • GL_LINEAR_MIPMAP_LINEAR

GL_TEXTURE_MAG_FILTER

放大

  • GL_NEAREST
  • GL_LINEAR:默认值

发现调整为LINER也没有解决缝隙的问题

cocos creator 2.4.8没有这个问题

const auto& matrixP = _director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);

Mat4 matrixMVP = matrixP * matrixMV;

确认是MPV矩阵的问题

gl_Position = CC_MVPMatrix * a_position;

当我尝试将顶点的范围控制在[-1, 1]时,将CC_MVPMatrix矩阵移除计算过程,发现线框模式下,就没有再出现缝隙了

网络异常,图片无法展示
|

至此,可以确定就是MVP矩阵出现了问题。

观察有bug和没有bug的矩阵value

平移会影响12,13

网络异常,图片无法展示
|
缩放会影响0,10,11

网络异常,图片无法展示
|

再次追击问题

发现MVP矩阵都是相同的,再次验证矩阵是没有问题的

网络异常,图片无法展示
|
仔细观察顶点,出现缝隙时,两个四边形顶点的z是不一样,很可能问题就出现在这里,因为顶点着色器里面:

gl_Position = CC_MVPMatrix * a_position;

很可能z的不同,在经过矩阵计算后,导致x、y也发生了变化,之前的焦点一直聚集在x、y上,导致忽略了这个问题。

那么z是如何产生的呢?



目录
相关文章
|
3月前
|
网络协议 NoSQL Anolis
开局一张图,debug全靠瞪|内核问题定位与静态分析实战
本文描述了一个在AnolisOS 8.8操作系统上遇到的内核崩溃问题的调试过程。
|
6月前
|
存储 缓存 NoSQL
不扒瞎,这个程序让我从150s优化到了5s
在优化一个业务开发组的生产问题时,发现销售管理系统查询数据延迟高达2-3分钟。问题根源在于,程序在for循环中频繁读取Redis大KEY数据,导致性能下降。解决方案是采用本地缓存HutoolCache,将耗时降至毫秒级别。此外,还对RedisTemplate配置进行了研究,Jackson2JsonRedisSerializer在序列化时包括了所有字段,即使字段值为null,增加了数据体积。通过对ObjectMapper的调整,仅序列化非空字段,可以显著提升redis读取性能。本文同时还提醒我们在使用Redis时要注意大对象缓存,强调了正确使用和配置缓存以及避免大对象存储的重要性。
71 5
|
算法 图形学
Unity——导航系统补充说明
Unity——导航系统补充说明
|
前端开发 容器
重识Flutter — 探索Slivers的奇妙世界(综合实例)
本文将通过一个炫酷的综合案例来帮助你理解Slivers,和我一起继续探索Sliver的世界,利用其强大的特性和灵活的组合方式,创建出更加有趣和具有交互性的滚动界面吧!
|
Python
最后一课:体育竞技问题分析
最后一课:体育竞技问题分析
131 0
最后一课:体育竞技问题分析
|
前端开发 JavaScript 小程序
印象最深的一个bug——使用uinapp做混合开发静态图片在安卓端不显示
这几天一直在做混合开发,使用的是uni-app开发的,一套代码,多端使用,适用于各个平台。听起来很完美,使用过程不可多说,不知道是因为我们的需求变态还是我们团队两端技术水平太差。总之,开发联调过程十分痛苦,加上uniapp的调试十分困难,一度让我们两端互怼。这其中我印象最深的一个bug就是在对接联调总出现的
1665176 33
印象最深的一个bug——使用uinapp做混合开发静态图片在安卓端不显示
|
Web App开发 移动开发 前端开发
技术分享 | Bug定位方法
技术分享 | Bug定位方法
|
定位技术 vr&ar 图形学
【Unity3D 灵巧小知识点】 ☀️ | Unity中几个简单又常见的报错异常
Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。 包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。 Unity 平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。 也可以简单把 Unity 理解为一个游戏引擎,可以用来专业制作游戏!
【Unity3D 灵巧小知识点】 ☀️ | Unity中几个简单又常见的报错异常
|
人工智能 程序员
AlphaGo程序出BUG了——第四局观感
AlphaGo程序出BUG了——第四局观感
110 0
|
设计模式 缓存 JavaScript
90%的人会遇到性能问题,如何用1行代码快速定位?
今天,齐光将会基于之前列举的众多指标,给出一些常见的调优分析思路,即:如何在众多异常性能指标中,找出最核心的那一个,进而定位性能瓶颈点,最后进行性能调优。整篇文章会按照代码、CPU、内存、网络、磁盘等方向进行组织,针对对某一各优化点,会有系统的「套路」总结,便于思路的迁移实践。
2325 0