creator中实现使用spine的atlas进行换肤

这是一个有点奇葩的项目需求,大概率没有人会这么玩。

需求背景

在spine中有一个插槽隐藏了,也就是下边的copy

导出的spine纹理中是携带这个copy纹理的

项目需求

希望动态的将copy纹理替换原图对应的插槽纹理

这样也有好处,因为替换纹理都在一张图里面,drawcall不会发生变化

但是copy纹理发生了旋转,所以需要对SpriteFrame的顶点uv数据处理下

换图后发现图的纹理旋转异常,图被旋转了180°

因为frame如果是旋转的,究其原因,还是因为旋转的定义不一样导致的

解决办法

我首先想到的是修改SpriteFrame的顶点,仔细看了相关的引擎源码,发现重新计算SpriteFrame的顶点没有用,因为spine的region在计算时,使用的是SpriteFrame.rect进行计算的

我想要复用之前的逻辑,使用SpriteFrame替换纹理,所以首先要解决的问题就是怎么拿到SpriteFrame的信息,js engine比较好解决,c++的解析atlas的逻辑导出给jsb就有点麻烦,想来想去,决定将解析atlas的逻辑参考spine,重新使用js实现下。

  • spine解析atlas的逻辑
js 复制代码
 var TextureAtlas = (function () {
    function TextureAtlas(atlasText, textureLoader) {
        this.pages = new Array();
        this.regions = new Array();
        this.load(atlasText, textureLoader);
    }
    TextureAtlas.prototype.load = function (atlasText, textureLoader) {
        if (textureLoader == null)
            throw new Error("textureLoader cannot be null.");
        var reader = new TextureAtlasReader(atlasText);
        var tuple = new Array(4);
        var page = null;
        while (true) {
            var line = reader.readLine();
            if (line == null)
                break;
            line = line.trim();
            if (line.length == 0)
                page = null;
            else if (!page) {
                page = new TextureAtlasPage();
                page.name = line;
                if (reader.readTuple(tuple) == 2) {
                    page.width = parseInt(tuple[0]);
                    page.height = parseInt(tuple[1]);
                    reader.readTuple(tuple);
                }
                reader.readTuple(tuple);
                page.minFilter = spine.Texture.filterFromString(tuple[0]);
                page.magFilter = spine.Texture.filterFromString(tuple[1]);
                var direction = reader.readValue();
                page.uWrap = spine.TextureWrap.ClampToEdge;
                page.vWrap = spine.TextureWrap.ClampToEdge;
                if (direction == "x")
                    page.uWrap = spine.TextureWrap.Repeat;
                else if (direction == "y")
                    page.vWrap = spine.TextureWrap.Repeat;
                else if (direction == "xy")
                    page.uWrap = page.vWrap = spine.TextureWrap.Repeat;
                page.texture = textureLoader(line);
                page.texture.setFilters(page.minFilter, page.magFilter);
                page.texture.setWraps(page.uWrap, page.vWrap);
                page.width = page.texture.getImage().width;
                page.height = page.texture.getImage().height;
                this.pages.push(page);
            }
            else {
                var region = new TextureAtlasRegion();
                region.name = line;
                region.page = page;
                var rotateValue = reader.readValue();
                if (rotateValue.toLocaleLowerCase() == "true") {
                    region.degrees = 90;
                }
                else if (rotateValue.toLocaleLowerCase() == "false") {
                    region.degrees = 0;
                }
                else {
                    region.degrees = parseFloat(rotateValue);
                }
                region.rotate = region.degrees == 90;
                reader.readTuple(tuple);
                var x = parseInt(tuple[0]);
                var y = parseInt(tuple[1]);
                reader.readTuple(tuple);
                var width = parseInt(tuple[0]);
                var height = parseInt(tuple[1]);
                region.u = x / page.width;
                region.v = y / page.height;
                if (region.rotate) {
                    region.u2 = (x + height) / page.width;
                    region.v2 = (y + width) / page.height;
                }
                else {
                    region.u2 = (x + width) / page.width;
                    region.v2 = (y + height) / page.height;
                }
                region.x = x;
                region.y = y;
                region.width = Math.abs(width);
                region.height = Math.abs(height);
                if (reader.readTuple(tuple) == 4) {
                    if (reader.readTuple(tuple) == 4) {
                        reader.readTuple(tuple);
                    }
                }
                region.originalWidth = parseInt(tuple[0]);
                region.originalHeight = parseInt(tuple[1]);
                reader.readTuple(tuple);
                region.offsetX = parseInt(tuple[0]);
                region.offsetY = parseInt(tuple[1]);
                region.index = parseInt(reader.readValue());
                region.texture = page.texture;
                this.regions.push(region);
            }
        }
    };
    TextureAtlas.prototype.findRegion = function (name) {
        for (var i = 0; i < this.regions.length; i++) {
            if (this.regions[i].name == name) {
                return this.regions[i];
            }
        }
        return null;
    };
    TextureAtlas.prototype.dispose = function () {
        for (var i = 0; i < this.pages.length; i++) {
            this.pages[i].texture.dispose();
        }
    };
    return TextureAtlas;
}());

问题:c++使用spine图集换肤,顶点超过了1,导致渲染异常

异常情况如下:

MeshAttachment在处理degress的时候,c++和js的实现逻辑不一样

主要就是在设置宽高时的逻辑有出入,可以看到上图中textureWidth的计算方式不一样,但是结果应该是一样的,我这里出现了不一样,是因为c++的regionHeight导致的问题,排查了很久,感觉处理degress的逻辑应该没问题,问题出在换肤的SpriteFramerect.width/rect.height上。

因为使用的spine图集中的frame,发生逆时针旋转90度,所以这里我主动传递了degress=90来矫正(我感觉这样处理可能会不合理,但是目前我也没找到合适的解决办法),此时我应该同步将宽高互换的。

目前是凭直觉这样解决了,没发现问题,具体逻辑还需要后续深究,这块有点绕。

结果

相关推荐
不说别的就是很菜9 分钟前
【前端面试】CSS篇
前端·css·面试
by__csdn31 分钟前
nvm安装部分node版本后没有npm的问题(14及以下版本)
前端·npm·node.js
by__csdn36 分钟前
Node与Npm国内最新镜像配置(淘宝镜像/清华大学镜像)
前端·npm·node.js
脸大是真的好~1 小时前
黑马JAVAWeb -Vue工程化-API风格 - 组合式API
前端·javascript·vue.js
我命由我123451 小时前
CesiumJS 案例 P35:添加图片图层(添加图片数据)
开发语言·前端·javascript·css·html·html5·js
你挚爱的强哥1 小时前
【sgMobileUploadTypeSelect】自定义组件:从底部弹出选择上传图片文件的方式【1、上传本地文件,2、拍摄上传】
前端·javascript·vue.js
Mike_jia1 小时前
Checkmate:自建监控新标杆!开源替代Zabbix的轻量级方案实战
前端
fury_1231 小时前
tsfile.raw提示
java·前端·javascript
喝拿铁写前端1 小时前
从面条代码到抽象能力:一个小表单场景里的前端成长四阶段
前端·设计模式·架构
LXA08092 小时前
Vue 3中使用JSX
前端·javascript·vue.js