2D骨骼动画(2D Skeleton Animation)
皮肤与皮肤占位符
1、新建皮肤1(skin1)、皮肤2(skin2),并选择skin1
2、在骨骼下新建皮肤占位符(placeholder)
选中skin1,并在placeholder下放置图片gum。再选中skin2,并在placeholder下放置图片goggles。
3、两套皮肤制作完成,现在可以通过切换skin1和skin2来显示不同的皮肤了。
libgdx 运行库
[官网] libGDX
[GitHub] libgdx
libgdx wiki
使用 gdx-setup.jar 创建 libgdx Android Studio 工程
java -jar gdx-setup.jar
[百度网盘] gdx-setup.jar 提取码 pmx8
3D Graphics (3D图形)
● 3D animations and skinning (3D动画与蒙皮)
● 3D Particle Effects (3D粒子特效)
● 3D Picking (3D拾取)
● Decals (贴花,一种贴图技术)
● Importing Blender models in LibGDX (导入Blender模型)
● Material and environment (材质与环境)
● ModelBatch (模型批处理,一种GPU优化技术)
● ModelBuilder,MeshBuilder and MeshPartBuilder (模型构建器,网格构建器与网格部分构建器)
● ModelCache (模型缓存)
● Models (模型)
● Quick start (快速启动)
● Virtual Reality (VR) (虚拟现实)
.fbx 转 .g3db or .g3dj 工具
fbx-conv (命令行版本)
https://github.com/libgdx/fbx-conv
下载 fbx-conv.exe
libgdx-fbxconv-gui (Java GUI 版本),运行环境需要Java 7
https://github.com/ASneakyFox/libgdx-fbxconv-gui
自己编译生成fbx-conv.exe
1、 安装 Autodesk FBX Software Developer Kit (FBX SDK 2019.0)
通过fbx-conv工程中的generate_vs2015.bat生成Visual Studio工程时需要用到FBX SDK,需要配置环境变量FBX_SDK_ROOT={FBX SDK 安装目录}
2、 将 fbx-conv visual studio 2015 工程升级到 visual studio 2019
1) 项目右键->属性->平台工具集-选择Visual Studio 2019(v142)
2) 项目->重定目标解决方案
3) 生成->重新生成 fbx-conv
fbx-conv命令行:
-? -显示帮助信息
-o <type> -设置输出文件类型 <type>:FBX, G3DJ(json) or G3DB(二进制)
-f -纹理贴图垂直翻转
-p -顶点颜色值转成一个float
-m <size> -网格可能包含的顶点或索引的最大数量(默认值:32k)
-b <size> -未分离可包含的最大骨骼数量(默认值:12)
-w <size> -每个顶点的最大骨骼权重(默认值:4)
-v -详细信息:打印其他进度信息
示例
fbx-conv-win32.exe -f -v myModel.fbx convertedModel.g3db
示例代码:替换附件
//(1) 找插槽 Slot slot = skeleton.findSlot("插槽名") //(2) 获取附件 Attachment attachment = slot.getAttachment(); //(3) 创建并加载纹理 Texture texture = new Texture(Gdx.files.internal("纹理地址")); //设置纹理参数 texture.setFilter(Texture.TextureFilter.MipMap, Texture.TextureFilter.MipMap); texture.setWrap(Texture.TextureWrap.ClampToEdge, Texture.TextureWrap.ClampToEdge); //(4) 创建纹理区域对象 TextureAtlas.AtlasRegion region = new TextureAtlas.AtlasRegion(new TextureRegion(texture)); //(5) 替换附件 //区域附件 if (attachment instanceof RegionAttachment) { RegionAttachment regionAttachment = (RegionAttachment) attachment; regionAttachment.setRegion(region); regionAttachment.updateOffset(); } //网格附件 else if (attachment instanceof MeshAttachment) { MeshAttachment meshAttachment = (MeshAttachment) attachment; meshAttachment.setRegion(region); meshAttachment.updateUVs(); } //(6) 移除附件(卸装) slot.setAttachment(null);
WebGL 运行库
(1) 用VS Code打开Spine-ts工程
(2) 在VS Code的终端运行
npm install
npm run dev
(3) 然后就可以按F5运行demo了。VS Code会启动一个本地Web服务器。
(4) 执行发布命令 npm build,会在工程下生成dist目录,将dist丢到Web服务器上即可访问。
注意:使用 npm 命令需要安装node.js,并配置环境变量。
需要在html页面中嵌入必要的js文件
<script src="../dist/iife/spine-webgl.js"></script>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>;
示例代码:获取webgl对象
//(1) 获取画布 var canvas = document.getElementById("canvas"); canvas.width = window.innerWidth; canvas.height = window.innerHeight; //(2) 获取webgl var config = { alpha: false }; var gl = canvas.getContext("webgl", config) || canvas.getContext("experimental-webgl", config); if (!gl) { alert('WebGL is unavailable.'); }
示例代码:加载骨骼和图集
//骨骼文件名 var skeletonName = "2dnansheng.skel"; //图集文件名 var atlasName = "2dnansheng.atlas"; //创建资源管理器 var assetManager = new spine.AssetManager(gl, "assets/"); //加载二进制骨骼文件 assetManager.loadBinary(skeletonName); //加载图集 assetManager.loadTextureAtlas(atlasName); //执行加载 requestAnimationFrame(load); //加载函数 function load() { if (assetManager.isLoadingComplete()) { //获取图集 var atlas = assetManager.require(atlasName); //创建图集附件加载器 var atlasLoader = new spine.AtlasAttachmentLoader(atlas); //创建骨骼加载器 var skeletonLoader = new spine.SkeletonBinary(atlasLoader); skeletonLoader.scale = 1; //读取骨骼数据 var skeletonData = skeletonLoader.readSkeletonData(assetManager.require(skeletonName)); //创建骨骼 var skeleton = new spine.Skeleton(skeletonData); } else { //继续调用load(),直到所有资源加载完成 requestAnimationFrame(load); } }
示例代码:替换附件
//加载换装图片assets/xxx.png assetManager.loadTexture("xxx.png"); //执行加载 requestAnimationFrame(load); //加载函数 function load() { if (assetManager.isLoadingComplete()) { //获取插槽 var slot = skeleton.findSlot("插槽名"); //获取插槽下面的当前附件 var attachment = slot.getAttachment(); //提取图片 var texture = assetManager.require("xxx.png"); //获取Image对象 var image = texture.getImage(); //创建GLTexture var glTexture = new spine.GLTexture(gl, image); //设置纹理滤波 glTexture.setFilters(spine.TextureFilter.MipMap, spine.TextureFilter.MipMap); //设置纹理环绕模式 glTexture.setWraps(spine.TextureWrap.ClampToEdge, spine.TextureWrap.ClampToEdge); //判断附件类型 if (attachment instanceof spine.RegionAttachment) { //创建纹理区域 var textureRegion = new spine.TextureRegion(); textureRegion.renderObject = glTexture;//绑定要渲染的纹理 //替换附件 attachment.setRegion(textureRegion); //更新位置 attachment.updateOffset(); } else if (attachment instanceof spine.MeshAttachment) { //替换附件 //attachment.setRegion(textureRegion);//没这个函数 var image = glTexture.getImage(); var page = new spine.TextureAtlasPage(); page.name = glTexture.name; page.minFilter = spine.TextureFilter.MipMap; page.magFilter = spine.TextureFilter.MipMap; page.uWrap = spine.TextureWrap.ClampToEdge; page.vWrap = spine.TextureWrap.ClampToEdge; page.width = image.width; page.height = image.height; page.setTexture(glTexture); var region = new spine.TextureAtlasRegion(); region.page = page; region.width = image.width; region.height = image.height; region.originalWidth = image.width; region.originalHeight = image.height; region.u = region.v = 0; region.u2 = region.v2 = 1; region.renderObject = glTexture; //替换附件 attachment.region = region; //更新UV attachment.updateUVs(); } } else { //继续调用load(),直到所有资源加载完成 requestAnimationFrame(load); } }
Unity 运行库
[Spine菜单]->[导出...] *.skel.bytes、*.atlas.txt、*.png
Unity Runtime 需要加载的文件:skeleton-name.json或skeleton-name.skel.bytes、skeleton-name.atlas.txt、skeleton-name.png。
正确的Texture打包器导出和Texture & Material导入设置:
1. Premultiplied Alpha
Texture 打包器启用 Premultiply alpha
Unity Texture 设置中启用 sRGB (Color Texture) 且禁用 Alpha Is Transparency
Unity Material 参数中禁用 Straight Alpha Texture
2. Straight Alpha
Texture 打包器禁用 Premultiply alpha , 启用 Bleed
Unity Texture 设置启用 sRGB (Color Texture) 且启用 Alpha Is Transparency
Unity Material 参数中启用 Straight Alpha Texture
using UnityEngine; using Spine; /// <summary> /// Spine辅助工具类 /// </summary> public sealed class SpineHelper { /// <summary> /// 使用外部图片替换插槽下的附件图片 /// </summary> /// <param name="skeleton">骨骼对象</param> /// <param name="slotName">插槽名称</param> /// <param name="texture2D">外部图片</param> public static void ReplaceSkin(Skeleton skeleton, string slotName, string attachmentName, Texture2D texture2D) { if (skeleton == null || texture2D == null) return; Slot slot = skeleton.FindSlot(slotName); if (slot == null) return; //当插槽下的所有附件处于隐藏状态时,slot.Attachment为null //如果想要获取到隐藏状态的附件,可以使用skeleton.GetAttachment()方法 Attachment attachment = skeleton.GetAttachment(slotName, attachmentName); if (attachment == null) return; Material material = new Material(Shader.Find("Spine/Skeleton")); material.mainTexture = texture2D; AtlasPage page = new AtlasPage(); page.rendererObject = material; page.name = texture2D.name; page.minFilter = TextureFilter.MipMap; page.magFilter = TextureFilter.MipMap; page.uWrap = TextureWrap.ClampToEdge; page.vWrap = TextureWrap.ClampToEdge; page.width = texture2D.width; page.height = texture2D.height; AtlasRegion region = new AtlasRegion(); region.page = page; region.width = texture2D.width; region.height = texture2D.height; region.originalWidth = texture2D.width; region.originalHeight = texture2D.height; region.u = region.v = 0; region.u2 = region.v2 = 1; region.rotate = false; if (attachment is RegionAttachment) { RegionAttachment regionAttachment = attachment as RegionAttachment; regionAttachment.RendererObject = region; regionAttachment.SetUVs(0f, 1f, 1f, 0f, 0); regionAttachment.UpdateOffset(); } else if (attachment is MeshAttachment) { MeshAttachment meshAttachment = attachment as MeshAttachment; meshAttachment.RendererObject = region; meshAttachment.RegionU = 0f; meshAttachment.RegionV = 1f; meshAttachment.RegionU2 = 1f; meshAttachment.RegionV2 = 0f; meshAttachment.UpdateUVs(); } } }