修改的代码:
import { _decorator, Component, RenderTexture, Sprite, Texture2D, ImageAsset, SpriteFrame, Vec2, gfx, director, log, math, v2 } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('GradientTransparency')
export class GradientTransparency extends Component {
public readPixels (texture:Texture2D, x = 0, y = 0, width?: number, height?: number) : Uint8Array | null {
log('width:', width, ' height:', height);
width = width || texture.width;
height = width || texture.height;
log('texture:', texture);
const gfxTexture = texture.getGFXTexture();
if (!gfxTexture) {
return null;
}
const bufferViews: ArrayBufferView[] = [];
const regions: gfx.BufferTextureCopy[] = [];
const region0 = new gfx.BufferTextureCopy();
region0.texOffset.x = x;
region0.texOffset.y = y;
region0.texExtent.width = width;
region0.texExtent.height = height;
regions.push(region0);
const buffer = new Uint8Array(width * height * 4);
bufferViews.push(buffer);
director.root?.device.copyTextureToBuffers(gfxTexture, bufferViews, regions)
return buffer;
}
public smoothstep(edge0: number, edge1: number, x: number): number {
// 将 x 限制在 [edge0, edge1] 范围内
//const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
const t = Math.min(Math.max((x - edge0) / (edge1 - edge0), 0.0), 1.0);
// 使用三次 Hermite 插值
return t * t * (3 - 2 * t);
}
/**
* 修改 Sprite 的透明度
* @param sprite 目标 Sprite
* @param points 给定的圆心点(UV 坐标,范围 [0, 1])
* @param radius1 第一个透明度分界点的半径(完全透明半径)
* @param radius2 第二个透明度分界点的半径(渐变透明半径)
*/
modifySpriteAlpha(sprite: Sprite, points: Vec2[], radius1: number, radius2: number) {
const spriteFrame = sprite.spriteFrame;
if (!spriteFrame) {
console.error("SpriteFrame 不存在!");
return;
}
const texture = spriteFrame.texture;
if (!texture) {
console.error("Texture 不存在!");
return;
}
// 创建 RenderTexture
const renderTexture = new RenderTexture();
renderTexture.reset({
width: spriteFrame.width,
height: spriteFrame.height,
});
// 获取像素数据
log('spriteFrame:', spriteFrame);
const pixels = this.readPixels(spriteFrame.texture as Texture2D, 0, 0, spriteFrame.width, spriteFrame.height);
log('pixels:', pixels);
const width = spriteFrame.width;
const height = spriteFrame.height;
// 最大不透明度
const maxAlpha = 200;
// 遍历每个像素
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const index = (y * width + x) * 4; // 每个像素的起始索引
let alpha = pixels[index + 3]; // 当前像素的 alpha 通道
// 将像素点转换为 UV 坐标
const uv = new Vec2(x / width, y / height);
// 计算与每个点的距离并修改透明度
points.forEach(point => {
const distance = uv.clone().subtract(point).multiply(v2(width, height)).length(); // 距离(按像素计算)
//let realPoint = v2(point.x * width, point.y * height);
//const distance = Vec2.distance(realPoint, v2(x, y));
if (distance < radius1) {
alpha = 0; // 完全透明
} else if (distance >= radius1 && distance < radius2) {
//alpha =
alpha = this.smoothstep(radius1, radius2, distance) * maxAlpha;
/*
const t = (distance - radius1) / (radius2 - radius1); // 计算线性插值
const calculatedAlpha = (1 - t) * maxAlpha; // 渐变透明
alpha = Math.min(alpha, calculatedAlpha); // 重叠透明度处理,叠加上限为 128
*/
} else {
alpha = Math.min(alpha, maxAlpha); // 超出范围,保持不透明度为 128
}
});
pixels[index + 3] = 255 - alpha; // 更新 alpha 通道
}
}
// 创建新的 ImageAsset
const newImageAsset = new ImageAsset();
newImageAsset.reset({
_data: pixels,
_compressed: false,
width: width,
height: height,
format: Texture2D.PixelFormat.RGBA8888,
});
// 创建新的 Texture2D
const newTexture = new Texture2D();
newTexture.image = newImageAsset;
// 创建新的 SpriteFrame
const newSpriteFrame = new SpriteFrame();
newSpriteFrame.texture = newTexture;
// 应用新的 SpriteFrame
sprite.spriteFrame = newSpriteFrame;
}
}
调用的代码:
import { _decorator, Component, Sprite, Vec2 } from "cc";
import { GradientTransparency } from "./fogImplement";
const { ccclass, property } = _decorator;
@ccclass('MainController')
export class MainController extends Component {
@property(Sprite)
targetSprite: Sprite = null; // 拖入目标 Sprite
onLoad() {
}
onClick(){
const gradientTransparency = this.getComponent(GradientTransparency);
if (gradientTransparency && this.targetSprite) {
// 设置两个 UV 坐标点
const points = [new Vec2(0.5, 0.5)]; //, new Vec2(0.7, 0.7)
const radius1 = 100; // 第一个分界点(完全透明)
const radius2 = 200; // 第二个分界点(渐变透明)
gradientTransparency.modifySpriteAlpha(this.targetSprite, points, radius1, radius2);
}
}
}