自学内容网 自学内容网

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;
        }

        // 创建 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);
        }
    }
}


原文地址:https://blog.csdn.net/wutaozhao/article/details/145032696

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!