我在B站(我有一个小喷壶)持续更新Shader特效视频,所有代码免费,欢迎关注
这是视频演示
炼丹房·第19炉】截图功能:截屏+抠道具透明背景,代码免费拿
说下思路是看的这个
截图!长按保存分享!Cocos Creator
创建截图相机 一个rendertexture 截图相机渲染到这个rendertexture 然后创建一个sprite显示这个rendertexture
节点截图是获取节点坐标 width height
获取像素保存图片记得翻转y轴 否则图片是倒立的
// 方法3:使用更高效的像素操作(使用 TypedArray 视图)saveWithEfficientFlip(ctx:CanvasRenderingContext2D,pixels:Uint8Array,width:number,height:number){constimageData=ctx.createImageData(width,height);constoutput=imageData.data;// 使用 set 方法逐行复制,效率更高for(let y=0;y<height;y++){constsrcY=height-1-y;constsrcOffset=srcY*width*4;constdstOffset=y*width*4;// 复制整行output.set(pixels.subarray(srcOffset,srcOffset+width*4),dstOffset);}ctx.putImageData(imageData,0,0);this.downloadCanvas(ctx.canvas);}这是截屏
import{_decorator,Camera,Component,Node,RenderTexture,Sprite,SpriteFrame}from'cc';const{ccclass,property}=_decorator;@ccclass('oo')export class oo extends Component{@property(RenderTexture)renderTex:RenderTexture=null;@property(Camera)captureCamera:Camera=null!;// 专用的截图相机(必须为正交相机)start(){// 延迟读取,确保渲染完成this.scheduleOnce(()=>{//this.captureAndSave();},0.5);}captureAndSave(){// 关键修改:使用世界坐标设置相机位置constwidth=this.renderTex.width;constheight=this.renderTex.height;constpixels=newUint8Array(width*height*4);// 读取像素this.renderTex.readPixels(0,0,width,height,pixels);console.log('Pixel data length:',pixels.length);// 转换为图片并下载this.savePixelsAsImage(pixels,width,height);}savePixelsAsImage(pixels:Uint8Array,width:number,height:number){constcanvas=document.createElement('canvas');canvas.width=width;canvas.height=height;constctx=canvas.getContext('2d');if(!ctx){console.error('Failed to get canvas context');return;}// 方法1:使用 Canvas 变换同时翻转 X 和 Ythis.saveWithEfficientFlip(ctx,pixels,width,height);// 或者使用方法2:手动翻转像素数据(更可靠)// this.saveWithManualFlip(ctx, pixels, width, height);}// 方法1:使用 Canvas 变换saveWithTransform(ctx:CanvasRenderingContext2D,pixels:Uint8Array,width:number,height:number){// 创建原始图像数据constimageData=ctx.createImageData(width,height);imageData.data.set(pixels);// 同时翻转 X 和 Y 轴ctx.save();ctx.scale(-1,-1);// 同时翻转 X 和 Yctx.translate(-width,-height);// 将图像移回可视区域ctx.putImageData(imageData,0,0);ctx.restore();this.downloadCanvas(ctx.canvas);}// 方法2:手动翻转像素数据(最可靠)saveWithManualFlip(ctx:CanvasRenderingContext2D,pixels:Uint8Array,width:number,height:number){constimageData=ctx.createImageData(width,height);constoutput=imageData.data;constrowSize=width*4;// 创建行的视图,避免复制for(let y=0;y<height;y++){constsrcRow=height-1-y;output.set(pixels.subarray(srcRow*rowSize,(srcRow+1)*rowSize),y*rowSize);}ctx.putImageData(imageData,0,0);this.downloadCanvas(ctx.canvas);}// 方法3:使用更高效的像素操作(使用 TypedArray 视图)saveWithEfficientFlip(ctx:CanvasRenderingContext2D,pixels:Uint8Array,width:number,height:number){constimageData=ctx.createImageData(width,height);constoutput=imageData.data;// 使用 set 方法逐行复制,效率更高for(let y=0;y<height;y++){constsrcY=height-1-y;constsrcOffset=srcY*width*4;constdstOffset=y*width*4;// 复制整行output.set(pixels.subarray(srcOffset,srcOffset+width*4),dstOffset);}ctx.putImageData(imageData,0,0);this.downloadCanvas(ctx.canvas);}// 下载 Canvas 内容downloadCanvas(canvas:HTMLCanvasElement){// 生成 DataURLconstdataUrl=canvas.toDataURL('image/png');// 下载constlink=document.createElement('a');link.href=dataUrl;link.download='render_texture_capture.png';document.body.appendChild(link);link.click();document.body.removeChild(link);}update(deltaTime:number){}}这是节点截图
import{_decorator,Camera,Color,Component,director,Node,Rect,rect,RenderTexture,UITransform,Vec2,Vec3,view}from'cc';const{ccclass,property}=_decorator;@ccclass('o')export class o extends Component{@property(Camera)captureCamera:Camera=null!;// 专用的截图相机(必须为正交相机)@property(Node)targetNode:Node=null!;// 要截图的节点@property(RenderTexture)renderTex:RenderTexture=null!;// 渲染纹理@property({tooltip:'留白边距,1.0表示不留白,1.1表示留10%'})margin:number=1.1;// 留白边距// 是否自动设置相机的 cullingMask(如果已经在编辑器中手动设置好,可以关闭)@property({tooltip:'是否自动设置相机的可见层(如果已在编辑器中设置好,可关闭)'})autoSetVisibility:boolean=true;capture(){if(!this.targetNode){console.error('targetNode 未设置');return;}if(!this.captureCamera){console.error('captureCamera 未设置');return;}if(!this.renderTex){console.error('renderTex 未设置');return;}constbounds=this.getWorldBounds(this.targetNode);if(!bounds){console.error('无法获取节点包围盒,请确保节点或子节点包含 UITransform 组件');return;}constcenterX=(bounds.min.x+bounds.max.x)/2;constcenterY=(bounds.min.y+bounds.max.y)/2;constnodeWidth=bounds.max.x-bounds.min.x;constnodeHeight=bounds.max.y-bounds.min.y;// 关键修改:使用世界坐标设置相机位置this.captureCamera.node.setWorldPosition(centerX,centerY,1000);// 设置透明背景this.captureCamera.clearFlags=Camera.ClearFlag.SOLID_COLOR;this.captureCamera.clearColor=newColor(0,0,0,0);// 可选:自动设置可见层(如果已在编辑器中设置好,可注释掉或关闭开关)//if (this.autoSetVisibility) {//this.captureCamera.visibility = 1 << this.targetNode.layer;//}// 计算 orthoHeight(保持不变)consttexW=this.renderTex.width;consttexH=this.renderTex.height;consttexAspect=texW/texH;constnodeAspect=nodeWidth/nodeHeight;let orthoHeight=nodeHeight/2;if(nodeAspect>texAspect){orthoHeight=(nodeWidth/texAspect)/2;}orthoHeight*=this.margin;this.captureCamera.orthoHeight=orthoHeight;// 7. 延迟一帧读取像素(确保 GPU 渲染完成)this.scheduleOnce(()=>{constpixels=newUint8Array(texW*texH*4);this.renderTex.readPixels(0,0,texW,texH,pixels);this.saveImage(pixels,texW,texH);},0.1);}/** * 递归获取节点及其所有子节点的世界包围盒(轴对齐,忽略旋转) * 返回 { min: Vec3, max: Vec3 } 或 null(如果没有 UITransform) */privategetWorldBounds(node:Node):{min:Vec3;max:Vec3}|null{constmin=newVec3(Infinity,Infinity,Infinity);constmax=newVec3(-Infinity,-Infinity,-Infinity);let hasValid=false;consttraverse=(n:Node)=>{constui=n.getComponent(UITransform);if(ui){constpos=n.worldPosition;consthalfW=ui.width/2;consthalfH=ui.height/2;constleft=pos.x-halfW;constright=pos.x+halfW;constbottom=pos.y-halfH;consttop=pos.y+halfH;if(left<min.x)min.x=left;if(right>max.x)max.x=right;if(bottom<min.y)min.y=bottom;if(top>max.y)max.y=top;// 2D 游戏通常忽略 Z,但为了完整性也记录if(pos.z<min.z)min.z=pos.z;if(pos.z>max.z)max.z=pos.z;hasValid=true;}for(let child of n.children){traverse(child);}};traverse(node);returnhasValid ?{min,max}:null;}/** * 将像素数据保存为 PNG 图片(处理 Y 轴翻转) */privatesaveImage(pixels:Uint8Array,width:number,height:number){constcanvas=document.createElement('canvas');canvas.width=width;canvas.height=height;constctx=canvas.getContext('2d');if(!ctx){console.error('无法创建 canvas 上下文');return;}constimageData=ctx.createImageData(width,height);constrowSize=width*4;// 翻转 Y 轴:因为 readPixels 原点在左下角,Canvas 原点在左上角for(let y=0;y<height;y++){constsrcRow=height-1-y;constsrcStart=srcRow*rowSize;constsrcEnd=srcStart+rowSize;imageData.data.set(pixels.subarray(srcStart,srcEnd),y*rowSize);}ctx.putImageData(imageData,0,0);// 下载图片constdataUrl=canvas.toDataURL('image/png');constlink=document.createElement('a');link.href=dataUrl;link.download=`capture_${Date.now()}.png`;document.body.appendChild(link);link.click();document.body.removeChild(link);}}