开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
很久之前,我在cocos2dx的基础上,实现了一个多纹理合批的功能。
在后续项目使用中,也发现了一些没有注意到的细节问题,导致了一些很隐晦的bug
问题:渲染错误
因为我是将纹理ID存储在顶点的z中,所以直接排查顶点数据就发现了问题。
void Renderer::fillVerticesAndIndices(const TrianglesCommand* cmd)
{
// fill vertex, and convert them to world coordinates
const Mat4& modelView = cmd->getModelView();
for(ssize_t i=0; i < cmd->getVertexCount(); ++i)
{
Vec3* point = &(_verts[i + _filledVertex].vertices);
modelView.transformPoint(point);
}
}
因为提交的顶点数据是在CPU进行了矩阵转换,直接观察经过矩阵转换后的顶点数据,发现Z发生了变化
看来还不能在sprite顶点组装阶段将Z写入到顶点信息中,因为经过矩阵计算,z会变化,解决办法只需要在transformPoint之后再次写入z就行了,很暴力但是很见效。
目前也没想到有啥更好的方案,因为cocos2dx 不支持自定义vertices数据的解析,因为底层解析顶点数据的结构是定死的(V3F_C4B_T2F)
如果MVP矩阵计算放在GPU,估计这个问题会更加隐晦,其实最初我就是从shader开始排查的。
gl_Position = MVP * a_position
问题:读取位置 0xCDCDCDCD 时发生访问冲突
直接表现为:
0x0F6F395E (vcruntime140d.dll)处(位于 client_tank5.exe 中)引发的异常: 0xC0000005:
网上大部分都是说野指针的问题,但是我不知道为什么会产生野指针。
通过IsBadReadPtr判断野指针
#include <iostream>
#include <windows.h>
int main(int, char**) {
int* p = new int;
delete p;
p = nullptr;
if (IsBadReadPtr(p, sizeof(int)) == TRUE)
{
std::cout << "bad ptr";
return 1;
}
std::cout << *p;
}
我尝试着这么做,去排查野指针的问题,但是我这个野指针直接跳过了判断,看来还得找为啥会产生野指针。
多重纹理置灰shader导致的bug
最终排查TrianglesCommand,发现它是在getVertices()的时候返回的顶点指针是野指针,排查思路就从这里切入:
struct Triangles
{
/**Vertex data pointer.*/
V3F_C4B_T2F* verts;
/**Index data pointer.*/
unsigned short* indices;
/**The number of vertices.*/
int vertCount;
/**The number of indices.*/
int indexCount;
};
classs TrianglesCommand{
Triangles _triangles;
}
问题就出在这里,TrianglesCommand的_triangles是个结构体,不是指针,而Triangles并没有对结构体就行初始化,所以直接使用
this->_triangles->verts;
返回的当然是野指针,坑就在这里。
因为cocos默认的渲染会重新赋值_triangles的,所以不存在这个问题,很明显我没有更新_triangles。
为什么没有更新?
因为node当前的program不能转换为多纹理program不能转换,why?
因为node进行了置灰操作,更新了program!
问题终于找到了,怎么解决嘞?
当发现program无法正常转换时,就使用原来的program逻辑进行初始化triangleCommand。
总结
一定要对值进行初始化,非常重要!