当前位置: 首页 > news >正文

那个网站做h5不要钱网站建设公司百家号

那个网站做h5不要钱,网站建设公司百家号,域名解析后多久打开网站,网站后台管理开发atlas数据的处理 作用 图集#xff0c;描述了spine使用的图片信息。 结构 page 页块 页块包含了页图像名称, 以及加载和渲染图像的相关信息。 page1.pngsize: 640, 480format: RGBA8888filter: Linear, Linearrepeat: nonepma: truename: 首行为该页中的图像名称. 图片位…atlas数据的处理 作用 图集描述了spine使用的图片信息。 结构 page 页块 页块包含了页图像名称, 以及加载和渲染图像的相关信息。 page1.pngsize: 640, 480format: RGBA8888filter: Linear, Linearrepeat: nonepma: truename: 首行为该页中的图像名称. 图片位置由atlas加载器来查找, 通常是再atlas文件的同目录下size: 页中图像的宽度和高度. 在加载图像之前告知atlas加载器是非常有必要的, 例如, 可以提前为其分配缓冲区. 若省略则默认为0,0.format: atlas加载器在内存中存储图像时应使用的格式. Atlas加载器可忽略该属性, 其可用值为: Alpha、Intensity、LuminanceAlpha、RGB565、RGBA4444、RGB888或RGBA8888. 若省略则默认为RGBA8888.filter: Texture过滤器的缩略和放大方式. Atlas加载器可忽略该属性. 其可用值为: Nearest, Linear, MipMap, MipMapNearestNearest, MipMapLinearNearest, MipMapNearestLinear, 或MipMapLinearLinear. 若省略则默认为Nearest.repeat: Texture包裹设置. Atlas加载器可忽略该属性. 其可用值为: x, y, xy, 或 none. 若省略则默认为none.pma: 若值为true则表示图像使用了premultiplied alpha. 若省略则默认为false. 过滤方式 OpenGL 纹理 参考https://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/06%20Textures/ Nearest对应GL的GL_NEAREST邻近过滤。是OpenGL默认的纹理过滤方式。会选择中心点最接近纹理坐标的那个像素 加号代表纹理坐标。左上角那个纹理像素的中心距离纹理坐标最近所以它会被选择为样本颜色 Linear对应GL的GL_LINEAR线性过滤。会基于纹理坐标附近的纹理像素计算出一个插值近似出这些纹理像素之间的颜色 一个纹理像素的中心距离纹理坐标越近那么这个纹理像素的颜色对最终的样本颜色的贡献越大 具体区别如下图 GL_NEAREST产生了颗粒状的图案我们能够清晰看到组成纹理的像素而GL_LINEAR能够产生更平滑的图案很难看出单个的纹理像素。GL_LINEAR可以产生更真实的输出。 以下是多级渐远纹理 问题假设我们有一个包含着上千物体的大房间每个物体上都有纹理。有些物体会很远但其纹理会拥有与近处物体同样高的分辨率。由于远处的物体可能只产生很少的片段OpenGL从高分辨率纹理中为这些片段获取正确的颜色值就很困难因为它需要对一个跨过纹理很大部分的片段只拾取一个纹理颜色。在小物体上这会产生不真实的感觉更不用说对它们使用高分辨率纹理浪费内存的问题了 解决OpenGL使用一种叫做多级渐远纹理(Mipmap)的概念来解决这个问题它简单来说就是一系列的纹理图像后一个纹理图像是前一个的二分之一。多级渐远纹理背后的理念很简单距观察者的距离超过一定的阈值OpenGL会使用不同的多级渐远纹理即最适合物体的距离的那个。由于距离远解析度不高也不会被用户注意到。 MipMapNearestNearest对应GL的GL_NEAREST_MIPMAP_NEAREST。使用最邻近的多级渐远纹理来匹配像素大小并使用邻近插值进行纹理采样。MipMapLinearNearest对应GL的GL_LINEAR_MIPMAP_NEAREST。使用最邻近的多级渐远纹理级别并使用线性插值进行采样MipMapNearestLinear对应GL的GL_NEAREST_MIPMAP_LINEAR。在两个最匹配像素大小的多级渐远纹理之间进行线性插值使用邻近插值进行采样MipMapLinearLinear对应GL的GL_LINEAR_MIPMAP_LINEAR。在两个邻近的多级渐远纹理之间使用线性插值并使用线性插值进行采样 premultiplied alpha 参考https://segmentfault.com/a/1190000002990030 Alpha通道的工作原理: 最常见的像素表示格式是RGBA8888即 (r, g, b, a)每个通道8位0-255。例如红色60%透明度就是 (255, 0, 0, 153)为了表示方便alpha通道一般记成正规化后的0-1的浮点数也就是 (255, 0, 0, 0.6) Premultiplied Alpha 则是把RGB通道乘以透明度也就是 (r * a, g * a, b * a, a)50%透明红色就变成了(153, 0, 0, 0.6)。 透明通道在渲染的时候通过 Alpha Blending 产生作用如果一个透明度为 a s a_s as​的颜色 C s C_s Cs​渲染到颜色 C d C_d Cd​上混合后的颜色如下 C o α s C s ( 1 − α s ) C d C_o \alpha_{s} C_s (1 - \alpha_{s})C_d Co​αs​Cs​(1−αs​)Cd​ 以60%透明的红色渲染到白色背景为例 C o ( 255 , 0 , 0 ) ⋅ 0.6 ( 255 , 255 , 255 ) ⋅ ( 1 − 0.6 ) ( 255 , 102 , 102 ) C_o (255,0,0) \cdot 0.6 (255,255,255) \cdot (1 - 0.6) (255,102,102) Co​(255,0,0)⋅0.6(255,255,255)⋅(1−0.6)(255,102,102) 如果按照Premultiplied Alpha存储那么实际上的 α s C s \alpha_{s}C_s αs​Cs​已经计算过了一次。 Premultiplied Alpha 之后混合的时候可以少一次乘法这可以提高一些效率但这并不是最主要的原因。 最主要的原因是 没有 Premultiplied Alpha 的纹理无法进行 Texture Filtering除非使用最近邻插值。 我们使用的PNG图片纹理一般是不会 Premultiplied Alpha 的。游戏引擎在载入PNG纹理后回手动处理然后再glTexImage2D传给GPU 比如 Cocos2D-x 中的 CCImage::premultipliedAlpha void Image::premultipliedAlpha() {unsigned int* fourBytes (unsigned int*)_data;for (int i 0; i lt; _width * _height; i) {unsigned char* p _data i * 4;fourBytes[i] CC_RGB_PREMULTIPLY_ALPHA(p[0], p[1], p[2], p[3]);} _hasPremultipliedAlpha true; }而GPU专用的纹理格式比如 PVR、ETC 一般在生成纹理都是默认 Premultiplied Alpha 的这些格式一般是GPU硬解码引擎用CPU处理会很慢。 总之 glTexImage2D 传给 GPU 的纹理数据最好都是 Multiplied Alpha 的要么在生成纹理时由纹理工具 Pre-multiplied要么载入纹理后由游戏引擎或UI框架 Post-multiplied。 区域块 Region 区域块包含了页图像中的区域位置以及该区域的其他信息 bg-dialogindex: -1rotate: falsebounds: 519, 223, 17, 38offsets: 2, 2, 21, 42split: 10, 10, 29, 10pad: -1, -1, 28, 10L1/L1_01rotate: truexy: 1855, 118size: 73, 78orig: 211, 216offset: 69, 69index: -1name: 首行为区域名称, 用于在atlas中定位一个区域. 多个区域若索引(index)各不相同, 则它们可以同名.index: 索引可以打包许多同名图像, 只要每个图像索引不同即可. 通常情况下, 索引是区域的帧号, 这些区域在逐帧动画中会依序绘制. 若省略则默认为-1.bounds: 该图像在页图像中的像素位置x和y, 以及打包后图像尺寸, 即该图像在页图像中的像素尺寸. 若省略则默认为0,0,0,0.有些会以xy、size的方式记录。offsets: 在打包前, 要从图像的左侧和底部边缘去除的空白像素值, 以及原始图像尺寸(此图像在打包前的像素尺寸). 如果进行了去除操作, 则打包后的图像尺寸可能会小于原始图像. 若省略则左侧和底部像素偏移默认为0,0, 原始图像尺寸等于打包后的图像尺寸.rotate: 若为true, 则表示该区域被逆时针旋转90度后存储在页图像中; 若为false则表示没有旋转. 属性值也可直接填入旋转角度(范围是0至360度). 若省略则默认为0.split: 对图像进行九宫格分割, 属性值是从原图边缘算起的像素值. 分割所定义的3x3的网格, 可以在缩放图像时不用拉伸图像的所有部分. 若省略则默认为null.pad: 九宫格分割后四周的填充厚度, 属性值是从原图边缘算起的像素值. 填充可以把置于九宫格中的内容以不同的方式嵌入到分片中. 若省略则默认为null. 数据结构 以下都以cocos2dx源码作为说明。 由上面可以知道一个atlas文件由两个部分组成Page和Region。 那么对于一个Atlas结构 struct spAtlas {spAtlasPage* pages;spAtlasRegion* regions;void* rendererObject; };其中spAtlasPage如下 struct spAtlasPage {const spAtlas* atlas;const char* name;spAtlasFormat format;spAtlasFilter minFilter, magFilter;spAtlasWrap uWrap, vWrap;void* rendererObject;int width, height;spAtlasPage* next; };其中spAtlasFormat对应的就是数据中的format,其结构为 typedef enum {SP_ATLAS_UNKNOWN_FORMAT,SP_ATLAS_ALPHA,SP_ATLAS_INTENSITY,SP_ATLAS_LUMINANCE_ALPHA,SP_ATLAS_RGB565,SP_ATLAS_RGBA4444,SP_ATLAS_RGB888,SP_ATLAS_RGBA8888 } spAtlasFormat;spAtlasFilter对应filter typedef enum {SP_ATLAS_UNKNOWN_FILTER,SP_ATLAS_NEAREST,SP_ATLAS_LINEAR,SP_ATLAS_MIPMAP,SP_ATLAS_MIPMAP_NEAREST_NEAREST,SP_ATLAS_MIPMAP_LINEAR_NEAREST,SP_ATLAS_MIPMAP_NEAREST_LINEAR,SP_ATLAS_MIPMAP_LINEAR_LINEAR } spAtlasFilter;spAtlasWrap对应split。 typedef enum {SP_ATLAS_MIRROREDREPEAT,SP_ATLAS_CLAMPTOEDGE,SP_ATLAS_REPEAT } spAtlasWrap;最后的 spAtlasPage* next; 表示结构是用一个链表的方式存储。 在看看区域块Region的数据结构。 struct spAtlasRegion {const char* name;int x, y, width, height;float u, v, u2, v2;int offsetX, offsetY;int originalWidth, originalHeight;int index;int/*bool*/rotate;int/*bool*/flip;int* splits;int* pads;spAtlasPage* page;spAtlasRegion* next; };读取 读取函数为spAtlas_createFromFile 大概实现如下 spAtlas* spAtlas_createFromFile(const char* path, void* rendererObject) {int dirLength;char *dir;int length;const char* data;spAtlas* atlas 0;/* Get directory from atlas path. */const char* lastForwardSlash strrchr(path, /);const char* lastBackwardSlash strrchr(path, \\);const char* lastSlash lastForwardSlash lastBackwardSlash ? lastForwardSlash : lastBackwardSlash;if (lastSlash path) lastSlash; /* Never drop starting slash. */dirLength (int)(lastSlash ? lastSlash - path : 0);dir MALLOC(char, dirLength 1);memcpy(dir, path, dirLength);dir[dirLength] \0;//上面在处理路径这里才是读取atlas文件。data _spUtil_readFile(path, length);//将文件流转换成spAtlas结构的对象。if (data) atlas spAtlas_create(data, length, dir, rendererObject);FREE(data);FREE(dir);return atlas; }//读取文件返回文件二进制数据和长度 char* _spUtil_readFile (const char* path, int* length) {Data data FileUtils::getInstance()-getDataFromFile(FileUtils::getInstance()-fullPathForFilename(path));if (data.isNull()) return 0;// avoid buffer overflow (int is shorter than ssize_t in certain platforms) #if COCOS2D_VERSION 0x00031200ssize_t tmpLen;char *ret (char*)data.takeBuffer(tmpLen);*length static_castint(tmpLen);return ret; #else*length static_castint(data.getSize());char* bytes MALLOC(char, *length);memcpy(bytes, data.getBytes(), *length);return bytes; #endif }函数spAtlas_create 很长大概作用就是对读出来的文件流进行解析解析的格式按照 spAtlasPage和spAtlasRegion结构体来。返回spAtlas对象。 对于spAtlas上的rendererObject传入都是0对于spAtlasPage上rendererObject是保存page中的name属性对应的图片的纹理。具体创建是 void _spAtlasPage_createTexture (spAtlasPage* self, const char* path) {Texture2D* texture Director::getInstance()-getTextureCache()-addImage(path);CCASSERT(texture ! nullptr, Invalid image);texture-retain();Texture2D::TexParams textureParams {filter(self-minFilter), filter(self-magFilter), wrap(self-uWrap), wrap(self-vWrap)};texture-setTexParameters(textureParams);self-rendererObject texture;self-width texture-getPixelsWide();self-height texture-getPixelsHigh(); }目的是缓存纹理提升速度。 使用 spAtlas被创建出来之后会调用Cocos2dAttachmentLoader_create方法将spAtlas对象转换成spAttachmentLoader对象。 根据Spine官方文档中指出 创建SkeletonJson或SkeletonBinary实例需要指定一个AttachmentLoader它包含返回新附件实例的方法。AttachmentLoader提供了一个加载时自定义附件的方式如设置附件的图集区域以便稍后渲染。这个很常用所以Spine运行时自带有一个功能完全相同的AtlasAttachmentLoader Cocos2dAttachmentLoader* Cocos2dAttachmentLoader_create (spAtlas* atlas) {Cocos2dAttachmentLoader* self NEW(Cocos2dAttachmentLoader);_spAttachmentLoader_init(SUPER(self), _Cocos2dAttachmentLoader_dispose, _Cocos2dAttachmentLoader_createAttachment,_Cocos2dAttachmentLoader_configureAttachment, _Cocos2dAttachmentLoader_disposeAttachment);self-atlasAttachmentLoader spAtlasAttachmentLoader_create(atlas);return self; }spAtlasAttachmentLoader* spAtlasAttachmentLoader_create (spAtlas* atlas) {spAtlasAttachmentLoader* self NEW(spAtlasAttachmentLoader);_spAttachmentLoader_init(SUPER(self), _spAttachmentLoader_deinit, _spAtlasAttachmentLoader_createAttachment, 0, 0);self-atlas atlas;return self; } 对于 spAtlasAttachmentLoader其中包含了spAtlas不过添加了spAttachmentLoader的对象。 typedef struct spAtlasAttachmentLoader {spAttachmentLoader super;spAtlas* atlas; } spAtlasAttachmentLoader;typedef struct spAttachmentLoader {const char* error1;const char* error2;const void* const vtable; #ifdef __cplusplusspAttachmentLoader () :error1(0),error2(0),vtable(0) {} #endif } spAttachmentLoader;spAtlasAttachmentLoader_create创建了spAtlasAttachmentLoader对象直接保存spAtlas对象关键是 _spAttachmentLoader_init 函数会去创建spAttachmentLoader 对象该实现有值得学习的思路。 void _spAttachmentLoader_init (spAttachmentLoader* self,void (*dispose) (spAttachmentLoader* self),spAttachment* (*createAttachment) (spAttachmentLoader* self, spSkin* skin, spAttachmentType type, const char* name,const char* path),void (*configureAttachment) (spAttachmentLoader* self, spAttachment*),void (*disposeAttachment) (spAttachmentLoader* self, spAttachment*) ) {CONST_CAST(_spAttachmentLoaderVtable*, self-vtable) NEW(_spAttachmentLoaderVtable);VTABLE(spAttachmentLoader, self)-dispose dispose;VTABLE(spAttachmentLoader, self)-createAttachment createAttachment;VTABLE(spAttachmentLoader, self)-configureAttachment configureAttachment;VTABLE(spAttachmentLoader, self)-disposeAttachment disposeAttachment; }他会去构建dispose、createAttachment、configureAttachment、disposeAttachment到结构体中这样可以直接通过结构体去调用该方法每个结构体创建的时候可以传入不同的函数。 简单来说spAtlasAttachmentLoader就是把spAtlas对象和其他需要用的方法以附件的方式加载到结构体中。 最后Cocos2dAttachmentLoader会配合JSON或者Binary文件来创建Spine。 cocos2dx-lua的改进 从源码上来看对于Altals文件会IO从二进制最后再解析从spAtlas对象。 创建也可以直接用spAtlas对象创建这里减少对文件的IO。 对于lua的导出这里并没有实现的方法估计是对spAtlas结构体的导出没有实现。 这里思路可以建立一个缓存机制创建一次Spine将其所有保存下来下一次创建的时候先检查缓存中是否有如果有的话那么就读缓存。 JSON和Binary JSON SkeletonJson其好处是可读缺点是文件较大解析慢。 Binary SkeletonBinary不可读但是加载速度快文件小。 JSON数据 参考https://zh.esotericsoftware.com/spine-json-format Skeleton skeleton: {hash: 5WtEfO08B0TzTg2mDqj4IHYpUZ4,spine: 3.8.24,x: -17.2,y: -13.3,width: 470.86,height: 731.44,images: ./images/,audio: ./audio/ },hash: 所有skeleton数据的哈希值. 工具软件用它来检测Skeleton数据自上次加载后是否有变化.version: 导出数据的Spine版本. 工具软件用它将Skeleton数据限制于某个特定的Spine版本.x: skeleton附件AABB(axis-aligned bounding box)包围盒左下角点的X坐标, 与Spine中的setup pose相同.y: skeleton附件AABB包围盒左下角点的Y坐标, 与Spine中的setup pose相同.width: skeleton附件AABB包围盒宽度, 与Spine中的setup pose相同. 虽然skeleton的AABB盒取决于其pose, 但也可作为skeleton的大体尺寸.height: skeleton附件AABB包围盒高度, 与Spine中的setup pose相同.fps: Dopesheet(摄影表)的帧率, 单位为帧数/秒, 与Spine中相同. 若省略则默认为30. 非必要数据.images: 图像文件路径, 与Spine中相同. 非必要数据.audio: 音频文件路径, 与Spine中相同. 非必要数据. 骨骼(Bones) 导出文件的bones部分存储了setup pose状态的骨骼数据. bones: [{ name: root },{ name: torso, parent: root, length: 85.82, x: -6.42, y: 1.97, rotation: 94.95 },... ],骨骼是有序的, 父骨骼总是排在子骨骼之前. name: 骨骼名称, 该名称在skeleton上唯一.length: 骨骼长度. 运行时通常不使用骨骼长度属性, 除非需要为骨骼绘制调试线. 若省略则默认为0.transform: 该属性决定子骨骼以何种方式继承父骨骼的变换: normal, onlyTranslation, noRotationOrReflection, noScale或noScaleOrReflection. 若省略则默认为normal.skin: 若为true, 则只有当活动皮肤包含该骨骼时该骨骼才算活动. 若省略则默认为false.x: setup pose时骨骼相对于父对象位置的X值. 若省略则默认为0.y: setup pose时骨骼相对于父对象位置的Y值. 若省略则默认为0.rotation: setup pose时骨骼相对于父对象的旋转角度. 若省略则默认为0.scaleX: setup pose时骨骼X方向的缩放比例. 若省略则默认为1.scaleY: setup pose时骨骼Y方向的缩放比例. 若省略则默认为1.shearX: setup pose时骨骼X方向的斜切角度. 若省略则默认为0.shearY: setup pose时骨骼Y方向的斜切角度. 若省略则默认为0.color: 骨骼的颜色, 与Spine中相同. 若省略则默认为0x989898FF RGBA. 非必要数据. 槽位(Slots) 槽位部分描述了绘制顺序和可分配附件的可用槽位. slots: [{ name: left shoulder, bone: left shoulder, attachment: left-shoulder },{ name: left arm, bone: left arm, attachment: left-arm },... ],如果没有槽位, slots部分可被省略. 槽位是按照setup pose的绘制顺序排序的. 索引较高的槽位中的图像被绘制在索引较低的槽位的图像之上. name: 槽位名称. 该名称在skeleton上唯一.bone: 该槽位所在骨骼的名称.color: setup pose时槽位的颜色. 它是一个长度为8的字符串, 包含4个按RGBA顺序排列的两位十六进制数字. 若省略alpha, 则alpha默认为 “FF”. 若省略该属性则默认为 “FFFFFFF”.dark: 设置setup pose时槽位用于双色tinting的dark color. 这是一个6个字符的字符串, 包含3个按RGB顺序排列的两位十六进制数字. 当不使用双色tinting时则省略.attachment: setup pose时槽位中附件的名称. 若省略则默认setup pose没有附件.blend: 在绘制槽位中可见附件时要使用的blend类别: normal, additive, multiply, 或screen. 约束(Constraints) IK约束 IK约束用于设置骨骼旋转可使骨骼末梢接触或指向目标骨骼。这有多种用途但最常见的是通过移动手或脚来控制四肢。 ik: [{name: left leg,order: 2,bones: [ left thigh, left shin ],target: left ankle,mix: 0.5,bendPositive: false,compress: true,},... ],如果没有IK约束, ik部分可被省略. name: 约束名称. 该名称在skeleton上唯一.order: 约束生效(applied)的顺序序数.skin: 若为true, 则只有当活动皮肤包含该约束时该约束才生效. 若省略则默认为false.bones: 一个包含1到2个骨骼名称的列表, 这些骨骼的旋转将被IK约束限制.target: 目标(target)骨骼的名称.mix: 一个介于0到1区间的值, 表示约束对骨骼的影响, 其中0表示只有FK, 1表示只有IK, 而中间值表示混合了FK和IK. 若省略则默认为1.*softness: 对于双骨骼IK, 表示目标骨骼到旋转减缓前骨骼的最大活动范围的距离. 若省略则默认为0.bendPositive: 若为true, 则骨骼的弯曲方向为正的旋转方向. 若省略则默认为false.compress: 若为true且只有一个骨骼被约束, 则当目标太近时会缩放骨骼以保持连接. 若省略则默认为false.stretch: 若为true且如果目标超出了范围, 将缩放父骨骼以保持连接. 若约束了多个骨骼且父骨骼的局部缩放比例非均匀(nonuniform), 则不应用拉伸(stretch). 若省略则默认为false.uniform: 若为true且只约束了一个骨骼, 而且使用了压缩或拉伸, 则该骨骼将在X和Y方向上缩放. 若省略则默认为false. Transform约束 变换约束可将骨骼的世界旋转、平移、缩放和/或剪切(其变换)复制到一个或多个其他骨骼 变换约束对高级装配有许多巧妙的用途。最简单的方法是移动一个骨骼然后让其他骨骼也移动。它可用于模拟有不同父对象的骨骼例如摘下帽子、装备武器或抛出物体。可以通过仅约束变换的子集(例如仅限制缩放或剪切)来创建有趣的效果。可以将一个骨骼自动放置在其他两个骨骼之间距离的任意百分比等等。 transform: [{ name: weapon to hip, order: 1, bone: weapon, target: hip },... ],如果没有变换约束, transform部分可被省略. name: 约束名称. 该名称在skeleton上唯一.order: 约束生效(applied)的顺序序数.skin: 若为true, 则只有当活动皮肤包含该约束时该约束才生效. 若省略则默认为false.bones: 将被约束控制transform的骨骼.target: 目标(target)骨骼的名称.rotation: 相对于目标骨骼的旋转角度偏移量. 若省略则默认为0.x: 相对于目标骨骼的X方向距离偏移量. 若省略则默认为0.y: 相对于目标骨骼的Y方向距离偏移量. 若省略则默认为0.scaleX: 相对于目标骨骼的X方向缩放偏移量. 若省略则默认为0.scaleY: 相对于目标骨骼的Y方向缩放偏移量. 若省略则默认为0.shearY: 相对于目标骨骼的Y方向斜切角度偏移量. 若省略则默认为0.rotateMix: 一个介于0到1区间的值, 表示约束对骨骼的影响, 其中0表示无影响, 1表示只有约束, 而中间值表示正常pose和约束的混合. 若省略则默认为1.translateMix: 参见 rotateMix.scaleMix: 参见 rotateMix.shearMix: 参见 rotateMix.local: 如果需要影响目标的局部transform则设置为True, 反之则影响全局transform. 若省略则默认为false.relative: 如果目标的transform为相对的则设置为True, 反之则其transform为绝对的. 若省略则默认为false. Path约束 路径约束使用路径调整骨骼变换。骨骼可以沿路径平移并将其旋转调整为指向路径。 路径约束可以替换平移关键帧从而可以通过使用路径更轻松地定义移动。许多其他用途包括将多个骨骼约束到一条路径然后通过操纵路径来控制骨骼而非单独调整每个骨骼。例如骨骼可以沿路径均匀分布也可以放大使它们看起来像是沿着路径生长。 path: [{name: constraintName,order: 0,bones: [ boneName1, boneName2 ],target: slotName,positionMode: fixed,spacingMode: length,rotateMode: tangent,rotation: 45,position: 204,spacing: 10,rotateMix: 0,translateMix: 1},... ],如果没有路径约束, path部分可被省略. name: 约束名称. 该名称在skeleton上唯一.order: 约束生效(applied)的顺序序数.skin: 若为true, 则只有当活动皮肤包含该约束时该约束才生效. 若省略则默认为false.bones: 将被约束控制旋转或平移的骨骼.target: 目标(target)骨骼的名称.positionMode: 指定计算路径位置的方式: 定值(fixed)或百分比(percent). 若省略则默认为percent.spacingMode: 指定骨骼间间距的计算方式: 长度(length), 定值(fixed)或百分比(percent). 若省略则默认为length.rotateMode: 决定骨骼旋转的计算方式: 切线(tangent)、链式或链式缩放. 若省略则默认为tangent.rotation: 相对于路径的旋转偏移量. 若省略则默认为0.position: 路径位置. 若省略则默认为0.spacing: 骨骼间间距. 若省略则默认为0.rotateMix: 一个介于0到1区间的值, 表示约束对骨骼的影响, 其中0表示无影响, 1表示只有约束, 而中间值表示正常pose和约束的混合. 若省略则默认为1.translateMix: 参见 rotateMix. Skins(皮肤) skins: [{name: skinName,attachments: {slotName: {attachmentName: { x: -4.83, y: 10.62, width: 63, height: 47 },...},...}},{name: skinName,attachments: {slotName: {attachmentName: { name: actualAttachmentName, x: 53.94, y: -5.75, rotation: -86.9, width: 121, height: 132 },...},...}},... ],如果没有皮肤或附件, skins部分可被省略. 每个皮肤本质上是一个映射(map), 键名是槽位和附件名称的复合键名, 其键值为一个附件. 虽然键中使用的附件名称对每个皮肤都相同, 但附件的实际附件名可能会有所不同. 当一个skeleton需要找到一个槽位中的一个附件时, 它首先会检查其皮肤. 如果没有找到, skeleton就会检查其默认皮肤. 默认皮肤包含没有被其他皮肤包含的附件, Spine可以混合使用皮肤和非皮肤附件. 默认皮肤总是带有default这个字样. 其他皮肤可能包含骨骼和/或约束: skins: [{name: skinName,bones: [ bone1, bone2 ],ik: [ ik1, ik2 ],transform: [ transform1, transform2 ],path: [ path1, path2 ],attachments: {...}},... }附件(Attachments) 每个附件的属性根据附件类型的不同而不同. 事件(Events) 事件部分描述了在动画过程中可以触发的命名事件及其setup pose值. events [name: { int: 1, float: 2, string: three },name: { int: 1, float: 2, string: three, audio: hit.wav, volume: 0.9, balance: -0.25 },... ],动画(Animations) 一个动画包含一个时间轴列表. 每条时间轴均存储了一个关键帧列表, 这些时间轴描述了骨骼或槽位的值如何随时间变化. animations: {name: {bones: { ... },slots: { ... },ik: { ... },deform: { ... },events: { ... },draworder: { ... },},... }骨骼时间轴 动画的bones部分描述了控制骨骼的时间轴. { bones: {boneName: {timelineType: [{ time: 0, angle: -26.55 },{ time: 0.1333, angle: -8.78 },...],...},... },每个关键帧的属性依时间轴的类型不同而变化. 槽位时间轴 动画的slots部分描述了操作槽位时间轴. slots: {slotName: {timelineType: [{ time: 0.2333, name: eyes closed },{ time: 0.6333, name: eyes open },...],...},... }每个关键帧的属性依时间轴的类型不同而变化. IK约束时间轴 动画的ik部分描述了IK约束时间轴. ik: {constraintName: [{ time: 0.5333, mix: 0.616, bendPositive: true },...],... },Path约束时间轴 动画的path部分描述了路径约束时间轴. path: {constraintName: position: [{ time: 1.81, position: 0.7 },...],spacing: [{ time: 2.92, spacing: 0.05 },...],mix: [{ time: 3.03, rotateMix: 0.5, translateMix: 0.75 },...],... },Deform时间轴 动画的deform部分描述了用于操作每个网格附件的顶点(网格变形)的时间轴. deform: {skinName: {slotName: {meshName: [{time: 0,curve: [ 0.25, 0, 0.75, 1 ]},{time: 1.5,offset: 12,vertices: [ -0.75588, -3.68987, -1.01898, -2.97404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1.01898, -2.97404, -0.75588, -3.68987, 0, 0, -0.75588, -3.68987, -0.75588, -3.68987,-1.01898, -2.97404, -1.01898, -2.97404, -1.01898, -2.97404, -0.75588, -3.68987 ],curve: [ 0.25, 0, 0.75, 1 ]},...],...},...},... }外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Event时间轴 动画的events部分描述了一个用于触发事件的时间轴. events: [{ time: 0.2, name: event1, int: 1, float: 2, string: three },{ time: 0.6, name: event2, int: 4, float: 5, string: six },... }绘制顺序(Draw order)时间轴 动画的draworder部分描述了一个用于改变绘制顺序的时间轴, 它是一个skeleton上需绘制附件的槽位列表. draworder: [{time: 0.2,offsets: [{ slot: slotName, offset: 1 },{ slot: slotName, offset: -2 },...]},... }二进制数据 参考https://zh.esotericsoftware.com/spine-binary-format#%E6%A0%BC%E5%BC%8F 读取Json typedef struct spSkeletonJson {float scale;spAttachmentLoader* attachmentLoader;const char* const error; } spSkeletonJson; spSkeletonJson本质上就是spAttachmentLoader的组合加上一个缩放属性。 spSkeletonData* spSkeletonJson_readSkeletonDataFile (spSkeletonJson* self, const char* path) {int length;spSkeletonData* skeletonData;const char* json _spUtil_readFile(path, length);if (length 0 || !json) {_spSkeletonJson_setError(self, 0, Unable to read skeleton file: , path);return 0;}skeletonData spSkeletonJson_readSkeletonData(self, json);FREE(json);return skeletonData; }函数spSkeletonJson_readSkeletonData将json文件序列化spSkeletonData对象即二进制对象。 typedef struct spSkeletonData {const char* version;const char* hash;float width, height;int bonesCount;spBoneData** bones;int slotsCount;spSlotData** slots;int skinsCount;spSkin** skins;spSkin* defaultSkin;int eventsCount;spEventData** events;int animationsCount;spAnimation** animations;int ikConstraintsCount;spIkConstraintData** ikConstraints;int transformConstraintsCount;spTransformConstraintData** transformConstraints;int pathConstraintsCount;spPathConstraintData** pathConstraints; } spSkeletonData;spBoneData骨骼的信息 typedef enum {SP_TRANSFORMMODE_NORMAL,SP_TRANSFORMMODE_ONLYTRANSLATION,SP_TRANSFORMMODE_NOROTATIONORREFLECTION,SP_TRANSFORMMODE_NOSCALE,SP_TRANSFORMMODE_NOSCALEORREFLECTION } spTransformMode;typedef struct spBoneData spBoneData; struct spBoneData {const int index;const char* const name;spBoneData* const parent;float length;float x, y, rotation, scaleX, scaleY, shearX, shearY;spTransformMode transformMode;#ifdef __cplusplusspBoneData() :index(0),name(0),parent(0),length(0),x(0), y(0),rotation(0),scaleX(0), scaleY(0),shearX(0), shearY(0),transformMode(SP_TRANSFORMMODE_NORMAL) {} #endif };spSlotData插槽信息 typedef enum {SP_BLEND_MODE_NORMAL, SP_BLEND_MODE_ADDITIVE, SP_BLEND_MODE_MULTIPLY, SP_BLEND_MODE_SCREEN } spBlendMode;typedef struct spSlotData {const int index;const char* const name;const spBoneData* const boneData;const char* attachmentName;spColor color;spColor* darkColor;spBlendMode blendMode;#ifdef __cplusplusspSlotData() :index(0),name(0),boneData(0),attachmentName(0),color(),darkColor(0),blendMode(SP_BLEND_MODE_NORMAL) {} #endif } spSlotData;spSkin皮肤 typedef struct spSkin {const char* const name;#ifdef __cplusplusspSkin() :name(0) {} #endif } spSkin;spEventData事件数据 typedef struct spEventData {const char* const name;int intValue;float floatValue;const char* stringValue;#ifdef __cplusplusspEventData() :name(0),intValue(0),floatValue(0),stringValue(0) {} #endif } spEventData;spAnimation时间线数据 typedef struct spAnimation {const char* const name;float duration;int timelinesCount;spTimeline** timelines;#ifdef __cplusplusspAnimation() :name(0),duration(0),timelinesCount(0),timelines(0) {} #endif } spAnimation;spIkConstraintData IK约束数据 typedef struct spIkConstraintData {const char* const name;int order;int bonesCount;spBoneData** bones;spBoneData* target;int bendDirection;float mix;#ifdef __cplusplusspIkConstraintData() :name(0),bonesCount(0),bones(0),target(0),bendDirection(0),mix(0) {} #endif } spIkConstraintData; spTransformConstraintDataTransform约束数据 typedef struct spTransformConstraintData {const char* const name;int order;int bonesCount;spBoneData** const bones;spBoneData* target;float rotateMix, translateMix, scaleMix, shearMix;float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;int /*boolean*/ relative;int /*boolean*/ local;#ifdef __cplusplusspTransformConstraintData() :name(0),bonesCount(0),bones(0),target(0),rotateMix(0),translateMix(0),scaleMix(0),shearMix(0),offsetRotation(0),offsetX(0),offsetY(0),offsetScaleX(0),offsetScaleY(0),offsetShearY(0),relative(0),local(0) {} #endif } spTransformConstraintData;spPathConstraintData path路径约束 typedef struct spPathConstraintData {const char* const name;int order;int bonesCount;spBoneData** const bones;spSlotData* target;spPositionMode positionMode;spSpacingMode spacingMode;spRotateMode rotateMode;float offsetRotation;float position, spacing, rotateMix, translateMix;#ifdef __cplusplusspPathConstraintData() :name(0),bonesCount(0),bones(0),target(0),positionMode(SP_POSITION_MODE_FIXED),spacingMode(SP_SPACING_MODE_LENGTH),rotateMode(SP_ROTATE_MODE_TANGENT),offsetRotation(0),position(0),spacing(0),rotateMix(0),translateMix(0) {} #endif } spPathConstraintData;总的说来就是读取json按照数据结构解析成spSkeletonData对象。 读取二进制 void SkeletonRenderer::initWithBinaryFile (const std::string skeletonDataFile, spAtlas* atlas, float scale) {_atlas atlas;_attachmentLoader SUPER(Cocos2dAttachmentLoader_create(_atlas));spSkeletonBinary* binary spSkeletonBinary_createWithLoader(_attachmentLoader);binary-scale scale;spSkeletonData* skeletonData spSkeletonBinary_readSkeletonDataFile(binary, skeletonDataFile.c_str());CCASSERT(skeletonData, binary-error ? binary-error : Error reading skeleton data file.);spSkeletonBinary_dispose(binary);setSkeletonData(skeletonData, true);initialize(); }同样解析成spSkeletonData数据的在spSkeletonBinary_readSkeletonDataFile spSkeletonData* spSkeletonBinary_readSkeletonDataFile (spSkeletonBinary* self, const char* path) {int length;spSkeletonData* skeletonData;const char* binary _spUtil_readFile(path, length);if (length 0 || !binary) {_spSkeletonBinary_setError(self, Unable to read skeleton file: , path);return 0;}skeletonData spSkeletonBinary_readSkeletonData(self, (unsigned char*)binary, length);FREE(binary);return skeletonData; }spSkeletonBinary_readSkeletonData函数按照二进制的数据结构读取然后解析成spSkeletonData二进制的数据结构在 https://zh.esotericsoftware.com/spine-binary-format#%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%AF%BC%E5%87%BA%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F spSkeletonData数据结构和上面json的是一样的。 实例化数据对象 先看看官方给出的流程图 可以发现解析完数据之后就是instance Data即实例化数据。 void SkeletonRenderer::setSkeletonData (spSkeletonData *skeletonData, bool ownsSkeletonData) {_skeleton spSkeleton_create(skeletonData);_ownsSkeletonData ownsSkeletonData; }拿骨骼举例数据解析为spBoneData那么实例化数据对象就是spBone。 怎么理解呢 Setup Pose Data也就是解析Json或者Binary对数据只是做了一次预处理它并不会完全的去将所有数据处理成后面渲染的时候能用的数据。 两者有一定的区别 数据是无状态的可在任意数量的骨架实例间共用数据中的属性代表装配姿势通常不会改动实例对象中的相同属性表示播放动画时该实例的当前姿势。每个实例对象保有一个其数据参考用于将实例对象重置回装配姿势。 可以理解成数据是原始数据一般不会涉及到对其进行转换修改等。实例数据对象就是将数据处理成后续渲染的时候需要用的数据里面会有一些状态记录坐标转换等方法。 这样做的一好处就是备份原始数据方便状态还原。 实例中有两个比较关键的方法updateWorldTransform和setToSetUpPose。 updateWorldTransform为更新世界变换本质是触发骨骼位置的计算由于骨骼位置可能发生旋转偏移其对应的子骨骼也会受到影响因此需要更新世界变换重新计算所有骨骼的最新坐标位置。 setToSetUpPose为更新实例到当前初始状态一般才初始化时或重置人物状态时调用会将人物形象骨骼装扮等切换为初始最初的状态。 Animation处理 实例对象生存之后会调用Animation的处理 动画模块是被单独抽离出来的目的是为了方便维护和更新实例的状态信息。 由动画state实例去触发skeleton实例的更新接下来skeleton实例调用updateWorldTransform更新世界变化之后重新上屏渲染。 void SkeletonAnimation::initialize () {super::initialize();_ownsAnimationStateData true;_state spAnimationState_create(spAnimationStateData_create(_skeleton-data));_state-rendererObject this;_state-listener animationCallback; }在cocos2dx中类为SkeletonAnimation继承于SkeletonRenderer 该函数会生存两个对象 spAnimationStateData存储AnimationState动画更改时要应用的混合交叉淡入淡出持续时间。spAnimationState 随着时间调用动画动画入队等待播放允许多个动画叠加。分多个track存储动画、区分不同动画的timeline针对event事件的处理逻辑等。
http://www.dnsts.com.cn/news/157355.html

相关文章:

  • 做彩票网站模板免费下载官方百度
  • 网站怎么记录搜索引擎的关键词网站开发和软件开发区别
  • wordpress多站点好吗question2answer wordpress 整合
  • 网站制作培训中心学产品设计好找工作吗
  • 做软装平台网站网站建设的财务计划书
  • 网站网页翻页设计博星卓越营销网站设计
  • 网站备案怎么这么麻烦wordpress手机pc分开模板
  • 规划建立一个网站 项目如何创建网站小程序
  • 私自使用他人图片做网站宣传无法登录wordpress
  • 寻找集团网站建设查老板查企业
  • 湘潭网站设计济宁任城区建设局网站
  • 做一个网上商城网站建设费用多少深度科技有限公司
  • 网站收费标准建设基础化学网站的经验
  • 佛山网站建设团队市场营销策划案怎么写
  • 个人网站建设方案书 范文网站建设的技术支持
  • 移动网站优化排名上海市建设工程安全生产协会网站
  • 成都犀牛网站建设广东江门最新消息今天
  • 模板下载网站源码天津优化网络公司的建议
  • 京华建设科技有限公司网站山东微商网站建设
  • 网站设计机构文档wordpress 发布到公网
  • 宁波网站建设信息php 个人网站 源码
  • 昆明网站优化建设网站设计公司网页设计
  • 销售网站排名瓷砖 中企动力 网站建设
  • 深圳做律师网站公司WordPress文章生成不是HTML
  • 徐州营销网站建设上海网站设计哪家好
  • 上海的招聘网站有哪些做网站需要固定ip么
  • 做内容的网站2022年装修效果图大全
  • 骨骼型的网站网站后台是怎么更新
  • 六安网站建设推荐百度关键词排名推广话术
  • 快手seo关键词优化云南放心seo整站优化