PolygonSprite的特性就是可以动态改变绘制Sprite的顶点数量,顶点数量越多意味着Sprite的三角化程度越细,绘制的空白像素也将越少,可以提高绘制效率,但顶点数量的增加会增加内存消耗。
当一张纹理的像素宽高比较大,空白区域或者接近透明的区域比较多,那么可以使用PolygonSprite。
一、使用示例
二、PolygonInfo:网格数据
// 保存了绘制一个图形需要的所有数据// 1、顶点数据:3D网格,最简单的情况就是一个三角形// 2、着色器// 3、混合// 4、纹理// 5、材质// 不过在这里,主要是处理顶点数据的变化,其他数据不做改变。// 比如三角形数量增加,顶点数量增加(内存消耗增加),绘制的图形不变,结果是绘制的空白像素将减少,提升绘制效率。// 这是以空间换时间。// 当图片文件像素宽高较大,空白较多,那么使用PolygonSprite的效果将比较明显。class CC_DLL PolygonInfo{public:PolygonInfo(); // 空数据PolygonInfo(const PolygonInfo& other); // 复制网格数据PolygonInfo& operator= (const PolygonInfo &other); // 复制网格数据~PolygonInfo();// 设置为一个矩形的顶点数据,注意这些顶点数据是从外部传入,因为在这为weak referencevoid setQuad(V3F_C4B_T2F_Quad *quad);// 设置为numberOfQuads个矩形的顶点数据,其他同上。void setQuads(V3F_C4B_T2F_Quad *quads, int numberOfQuads);// 设置为一个三角形的顶点数据,其他同上。void setTriangles(const TrianglesCommand::Triangles& triangles);unsigned int getVertCount() const; // 顶点数量unsigned int getTrianglesCount() const; // 三角形数量float getArea() const; // 获得总面积(三角形总面积)const Rect& getRect() const; // 如果是一个矩形,比如用来计算使用多边形之后,像素面积变化了多少void setRect(const Rect& rect); // 又外部来设置const std::string& getFilename() const; //void setFilename(const std::string& filename ); //protected:bool _isVertsOwner; // 顶点数据是不是在这里管理Rect _rect; // 一般是设置为如果是普通Sprite时的矩形框std::string _filename;TrianglesCommand::Triangles triangles; // 保存的顶点数据private:void releaseVertsAndIndices(); // 如果是_isVertsOwner,则要我们自己及时清楚顶点数据及其索引。};
三、AutoPolygon:生成网格数据
// 是一个工具类,用于动态生成一个图像的2D(三角形)网格数据。// 输出的就是上面的PolygonInfo。class CC_DLL AutoPolygon{public:// filename: 必须是一个32bit PNG格式。AutoPolygon(const std::string &filename);// 获得image中的rect区域中alpha > threshold的像素// 沿着rect的outline顺时针遍历寻找。std::vector<Vec2> trace(const cocos2d::Rect& rect, float threshold = 0.0f);/*** reduce the amount of points so its faster for GPU to process and draw* based on Ramer-Douglas-Peucker algorithm* @param points a vector of Vec2 points as input* @param rect a texture rect for specify an area of the image to avoid over reduction* @param epsilon the perpendicular distance where points smaller than this value will be discarded* @return a vector of Vec2 of the remaining points in clockwise order* @code* auto ap = AutoPolygon();* std::vector<Vec2> reduced = ap.reduce(inputPoints, rect);//default epsilon is 2* @endcode*///std::vector<Vec2> reduce(const std::vector<Vec2>& points, const Rect& rect, float epsilon = 2.0f);/*** expand the points along their edge, useful after you reduce the points that cuts intothe sprite* using ClipperLib* @param points a vector of Vec2 points as input* @param rect a texture rect for specify an area of the image, the expanded points will be clamped in this rect, ultimately resulting in a quad if the expansion is too great* @param epsilon the distance which the edges will expand* @return a vector of Vec2 as the result of the expansion* @code* auto ap = AutoPolygon();* std::vector<Vec2> expanded = ap.expand(inputPoints, rect, 2.0);* @endcode*/std::vector<Vec2> expand(const std::vector<Vec2>& points, const Rect& rect, float epsilon);/*** Triangulate the input points into triangles for rendering* using poly2tri* @warning points must be closed loop, cannot have 2 points sharing the same position and cannot intersect itself* @param points a vector of vec2 points as input* @return a Triangles object with points and indices* @code* auto ap = AutoPolygon();* TrianglesCommand::Triangles myPolygons = ap.triangulate(myPoints);* @endcode*/TrianglesCommand::Triangles triangulate(const std::vector<Vec2>& points);/*** calculate the UV coordinates for each points based on a texture rect* @warning This method requires the AutoPolygon object to know the texture file dimension* @param rect a texture rect to specify where to map the UV* @param verts a pointer to the verts array, served both as input and output verts* @param count the count for the verts array* @code* auto ap = AutoPolygon("grossini.png");* TrianglesCommand::Triangles myPolygons = ap.triangulate(myPoints);* ap.calculateUV(rect, myPolygons.verts, 20);* @endcode*/void calculateUV(const Rect& rect, V3F_C4B_T2F* verts, ssize_t count);/*** packing trace, reduce, expand, triangulate and calculate uv in one function* @param rect texture rect, use Rect::ZERO for the size of the texture, default is Rect::ZERO* @param epsilon the value used to reduce and expand, default to 2.0* @param threshold the value where bigger than the threshold will be counted as opaque, used in trace* @return a PolygonInfo, to use with sprite* @code* auto ap = AutoPolygon("grossini.png");* PolygonInfo myInfo = ap.generateTriangles();//use all default values* auto sp1 = Sprite::create(myInfo);* polygonInfo myInfo2 = ap.generateTriangles(Rect::ZERO, 5.0, 0.1);//ap can be reused to generate another set of PolygonInfo with different settings* auto sp2 = Sprite::create(myInfo2);* @endcode*/PolygonInfo generateTriangles(const Rect& rect = Rect::ZERO, float epsilon = 2.0f, float threshold = 0.05f);// 等价于下面:// AutoPolygon ap(filename);// ap.generateTriangles(rect, epsilon, threshold);// 一般用于只需创建一次的情况,因为每次都要通过filename创建image,所以一般采用以下方法:// AutoPolygon ap(filename); // 创建一次// ap.generateTriangles(rect, epsilon, threshold); // 多次生成网格数据// ap.generateTriangles(rect, epsilon, threshold); // 多次生成网格数据static PolygonInfo generatePolygon(const std::string& filename,const Rect& rect = Rect::ZERO,float epsilon = 2.0f,float threshold = 0.05f);}
