Cocos Creator 3.8 修改纹理像素值
修改的代码:
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;}// 创建 RenderTextureconst 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 通道}}// 创建新的 ImageAssetconst newImageAsset = new ImageAsset();newImageAsset.reset({_data: pixels,_compressed: false,width: width,height: height,format: Texture2D.PixelFormat.RGBA8888,});// 创建新的 Texture2Dconst newTexture = new Texture2D();newTexture.image = newImageAsset;// 创建新的 SpriteFrameconst newSpriteFrame = new SpriteFrame();newSpriteFrame.texture = newTexture;// 应用新的 SpriteFramesprite.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; // 拖入目标 SpriteonLoad() {}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);}}
}