不知道有没有人遇到过一下情况:
- 兴高采烈的给sprite写个shader,打包出来各种纹理错乱
- 想通过sprite做一些uv相关的计算,总能发现总有纹理合图作怪
以上都是因为纹理合图,无论是静态合图还是动态合图都会出现。这严重打击给cocos写shader的信心。
好啦,解决方法来啦:给sprite保留一套原始uv,也就是第二套uv.
PS: 我完全不知道引擎组怎么想的,为什么不提供二套uv的支持
以下就是核心代码,创建一个ts文件放入项目中即可,只支持小程序以及h5游戏:
import { gfx, RenderData, Sprite, spriteAssembler } from "cc";
declare module "cc" {
interface Sprite {
enableUV2: boolean;
}
}
/**
* 在原有sprite的基础上,增加了一个uv1的属性,用于存储第二套uv
*/
const vfmtPosUv2Color = [
new gfx.Attribute(gfx.AttributeName.ATTR_POSITION, gfx.Format.RGB32F), // 3 floats
new gfx.Attribute(gfx.AttributeName.ATTR_TEX_COORD, gfx.Format.RG32F), // 2 floats
new gfx.Attribute(gfx.AttributeName.ATTR_COLOR, gfx.Format.RGBA32F), // 4 floats
new gfx.Attribute(gfx.AttributeName.ATTR_TEX_COORD1, gfx.Format.RG32F), // 2 floats
];
let simpleAssembler: any = spriteAssembler.getAssembler(new Sprite());
simpleAssembler.updateUVs = function(sprite: Sprite) {
if (!sprite.spriteFrame) return;
const renderData = sprite.renderData!;
const stride = renderData.floatStride;
const vData = renderData.chunk.vb;
const uv = sprite.spriteFrame.uv;
vData[3] = uv[0];
vData[4] = uv[1];
vData[stride+3] = uv[2];
vData[stride+4] = uv[3];
vData[stride*2+3] = uv[4];
vData[stride*2+4] = uv[5];
vData[stride*3+3] = uv[6];
vData[stride*3+4] = uv[7];
if(sprite.enableUV2) {
vData[9] = 0;
vData[10] = 1;
vData[stride+9] = 1;
vData[stride+10] = 1;
vData[stride*2+9] = 0;
vData[stride*2+10] = 0;
vData[stride*3+9] = 1;
vData[stride*3+10] = 0;
}
};
let requestRenderData = Sprite.prototype.requestRenderData;
Sprite.prototype.requestRenderData = function() {
if(this.enableUV2) {
const data = RenderData.add(vfmtPosUv2Color);
this._renderData = data;
return data;
}
return requestRenderData.call(this);
};
EnableSpriteUV2.ts 文件
import { Component, Sprite, spriteAssembler } from "cc";
import { _decorator } from "cc";
const { ccclass, property, requireComponent, executeInEditMode } = _decorator;
@ccclass('EnableSpriteUV2')
@requireComponent(Sprite)
@executeInEditMode
export class EnableSpriteUV2 extends Component {
private _sprite: Sprite;
get sprite() {
return this._sprite;
}
start() {
this._sprite = this.getComponent(Sprite);
this._sprite.enableUV2 = true;
let simpleAssembler: any = spriteAssembler.getAssembler(this._sprite);
if (this.sprite.renderData && this.sprite.renderData.data) {
this.sprite.destroyRenderData();
simpleAssembler.createData(this.sprite);
simpleAssembler.updateUVs(this.sprite);
}
}
}
然后给需要二套uv的sprite添加EnableSpriteUV2组件即可,这样就能开开心心的在sprite的自定义shader中使用第二套uv啦!
我们直接把uv1渲染出来,效果如下:

这样,比如做个边界判断如:
if(uv1.x < 0.1) {
return baseColor;
}
无论合图前后,表现都是一致的啦!!

