实际上,那个时候,我已经看到动态合图里面有这些图片了,所以应该是正确的uv了
因为之前没有做过这类的处理,所以不知道你说的这些具体用到那些api,所以,请赐教[抱拳]
合图成功了 就用assember负责切图的
assember这个api没有找到
搜索这个 Assembler
好的,我晚点研究一下,谢谢
用顶点裁切。
自己做个组件,自己实现Assemble。参考mask组件的圆形裁切。组装顶点数据。
我查了些资料,感觉你这个传uv的方式做不了了。
因为cocos 里面给shader传参是uniform,这意味着你10个头像一次提交绘制时,这10个头像访问到的值都是相同的,也就是你出现的情况,只有最后一个正确绘制。你可以让这10个头像断批试试,应该10个就能正确绘制,但也就断批了。
第二个方法也许需要改引擎,原理其实也简单,你调出动态合图的情况来看,可以看到10个头像在一张大图里,假如这10个在大图里的头像都是早就切好的圆形呢,那就能按照普通情况合批了对吧。
这个就是要自己在下载上传到gpu之后切一下。
只有一个显示并裁剪 可以看看几何坐标是否都正确,别搞得都算的是同一个几何坐标了 都重叠在一起了
动态图集合图的时候,把微信头像搞成圆的
哈哈. 我倒觉得这样最好.
源头数据预先处理,就没后面什么事情了.
就如同cdn的资源链接后缀加上类似_round标签一样(cdn云端处理).
不过要考虑图片的处理数量是否会导致游戏卡顿.
可以详细说说怎么弄吗
又问下了 ChatGpt,也没验证,不过我觉得这种方式不如截图
user:
现在有一个 Uint8Array 的数据, 存储的是图片的像素数据,假设图片是正方形的, 现在想要将图片变成圆形,也就是圆形半径外的像素透明,直接修改 Uint8Array,代码怎么实现?
assistant:
要将一个正方形的图像转换为圆形,需要对每个像素进行计算,判断该像素是否在圆形内部。如果在圆形内部,则保留该像素的值,否则将该像素的值设置为透明。下面是一个可能的实现:
function squareToCircle(pixels, width, height, radius) {
const centerX = width / 2;
const centerY = height / 2;
const radiusSquared = radius * radius;
const bytesPerPixel = 4; // assuming RGBA format
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const offset = (y * width + x) * bytesPerPixel;
const dx = x - centerX;
const dy = y - centerY;
const distanceSquared = dx * dx + dy * dy;
// Check if the pixel is outside the circle
if (distanceSquared > radiusSquared) {
// Set the pixel to transparent
pixels[offset + 3] = 0;
}
}
}
}
这个函数接受一个 Uint8Array,宽度和高度,以及圆的半径。它假设每个像素使用 RGBA 格式,即每个像素由四个字节组成,依次是红、绿、蓝和透明度。该函数遍历所有像素,计算该像素到图像中心的距离,如果该距离大于圆半径,就将该像素的透明度设置为 0,即将其变为透明。
user:
假设,现在对象结构是这样的 SpriteFrame = {“texture”: { “image”: {“data”: []}}} 其中 data 是 Uint8Array, 重新编写代码
assistant:
好的,那么我们可以将之前的代码稍作修改,让其适用于新的对象结构:
function squareToCircle(spriteFrame, radius) {
const image = spriteFrame.texture.image;
const data = image.data;
const width = image.width;
const height = image.height;
const centerX = width / 2;
const centerY = height / 2;
const radiusSquared = radius * radius;
const bytesPerPixel = 4; // assuming RGBA format
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const offset = (y * width + x) * bytesPerPixel;
const dx = x - centerX;
const dy = y - centerY;
const distanceSquared = dx * dx + dy * dy;
// Check if the pixel is outside the circle
if (distanceSquared > radiusSquared) {
// Set the pixel to transparent
data[offset + 3] = 0;
}
}
}
}
这个函数接受一个 SpriteFrame
对象和圆的半径。它首先获取到图像数据 data
、宽度和高度,并计算出中心点和半径的平方。接下来,它遍历所有像素,计算该像素到图像中心的距离,如果该距离大于圆半径,就将该像素的透明度设置为 0,即将其变为透明。注意,这里直接修改了 data
数组,原始的 Uint8Array
对象也会被修改。
哈哈哈,可以可以,我抽空验证一下
假定你组装好了顶点的数据和三角形的数据结构如下
function getDefaultVerticesData(): IVerticesData {
return {
x: [],
y: [],
nu: [],
nv: [],
triangles: [],
}
}
然后你自己的assemble去提交渲染数据:
initData() {
this._renderData.createFlexData(0, 4, 6, this.getVfmt());
}
updateRenderData(maskSprite: MaskSprite) {
if (!maskSprite._vertsDirty) return;
let frame = maskSprite._spriteFrame;
let renderData = this._renderData;
if (!renderData || !frame) return;
let vertices = maskSprite.vertices;
if (!vertices) {
vertices = maskSprite.caculateVertices();
}
if (!vertices) return;
if (this.verticesCount != vertices.x.length) {
this.verticesCount = vertices.x.length;
this.indicesCount = vertices.triangles.length;
this._renderData.createFlexData(0, this.verticesCount, this.indicesCount, this.getVfmt());
}
this.updateIndices(vertices.triangles);
this.updateColor(maskSprite);
this.updateUVs(maskSprite);
this.updateVerts(maskSprite);
this.updateWorldVerts(maskSprite);
maskSprite._vertsDirty = false;
}
updateIndices(triangles: number[]) {
this._renderData.iDatas[0].set(triangles);
}
updateUVs(maskSprite: MaskSprite) {
let vertices = maskSprite.vertices,
u = vertices.nu,
v = vertices.nv;
let verts = this._renderData.vDatas[0];
for (let i = 0; i < u.length; i++) {
let dstOffset = i * RenderDataIndex.Count;
verts[dstOffset + RenderDataIndex.u] = u[i];
verts[dstOffset + RenderDataIndex.v] = v[i];
}
}
updateVerts(maskSprite: MaskSprite) {
let node = maskSprite.node,
contentWidth = Math.abs(node.width),
contentHeight = Math.abs(node.height),
appx = node.anchorX * contentWidth,
appy = node.anchorY * contentHeight;
let vertices = maskSprite.vertices,
x = vertices.x,
y = vertices.y;
let scaleX = node.scaleX,
scaleY = node.scaleY;
let local = this._local = [];
for (let i = 0, l = x.length; i < l; i++) {
local[i * 2] = (x[i] + node.width * node.anchorX - appx) * scaleX;
local[i * 2 + 1] = (- y[i] + node.height * (1 - node.anchorY) - appy) * scaleY;
}
this.updateWorldVerts(maskSprite);
}
updateWorldVerts(maskSprite: MaskSprite) {
let node = maskSprite.node;
let matrix = node._worldMatrix;
let matrixm = matrix.m;
let a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
tx = matrixm[12], ty = matrixm[13];
let local = this._local;
let world = this._renderData.vDatas[0];
let floatsPerVert = this.floatsPerVert;
for (let i = 0, l = this.verticesCount; i < l; i++) {
let lx = local[i * 2];
let ly = local[i * 2 + 1];
world[floatsPerVert * i] = lx * a + ly * c + tx;
world[floatsPerVert * i + 1] = lx * b + ly * d + ty;
}
}
我做了个东西,可以满足你的需求
我也碰到这个问题了,大佬最后怎么解决的?