开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
一个三角形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是如何产生的呢?