三渲二 Cocos Creator

分享把3D动画输出成序列帧图片的一种方法,希望对大家有所帮助,代码工程将整理到 Cocos 论坛。

实现效果

10cf0db0ea440b75e67619b83a3d289c.gif

fb76c1030a547996e24c703c485097a4.png

f4341fa716a364db44087452acb9ccec.png

配置环境

  • Cocos Creator 3.6.2 编辑器

  • Chrome 浏览器

实现

原理

  • 相机渲染成一张纹理

  • 读取纹理数据传给 Canvas 绘制

  • Canvas 生成纹理数据传给 HTML <a> 标签

affb03d63b6b4496f42501d7f471349a.jpeg

步骤

  • 将动画的模型放入场景中

  • 调整相机视角,修改相机参数
    07fd39756cedf1b0d401f987c1bdb72d.png

  • 引入脚本组件,填充参数
    149ec36cb69593241c5ee5994d632aff.png

讲解视频

https://www.bilibili.com/video/BV1g8411u7Pp

工程代码

ScreenCapture.ts

面向网络编程,拼凑起来的代码,在此感谢各路神仙

import {
    _decorator, Component, log, Camera
    , math, view, RenderTexture, Animation
} from 'cc';
const { ccclass, property } = _decorator;

@ccclass('ScreenCapture')
export class ScreenCapture extends Component {
    @property(Camera)
    camera: Camera = null!

    @property(Animation)
    animation: Animation = null!

    @property
    count = 3

    start() {
        log('欢迎关注微信公众号【白玉无冰】 https://mp.weixin.qq.com/s/4WwCjWBtZNnONh8hZ7JVDA')
        const defaultState = this.animation.getState(this.animation.defaultClip!.name)
        let count = this.count;
        if (count < 2) count = 2;
        defaultState.stop();
        const stepTime = defaultState.duration / count;
        const doAfterCap = () => {
            count--;
            if (count > 0) {
                defaultState.update(stepTime);
                this.doCapture(doAfterCap)
            }
        }
        defaultState.update(0);
        this.doCapture(doAfterCap);
    }

    private doCapture(doAfterCap = () => {

    }) {
        let vSize = new math.Size
        vSize.width = view.getVisibleSize().width
        vSize.height = view.getVisibleSize().height
        let texture = new RenderTexture();
        texture.reset(vSize);
        this.camera.targetTexture = texture;
        this.scheduleOnce(() => {
            this.saveCapture(texture)
            this.camera.targetTexture = null;
            doAfterCap()
        }, 0)
    }

    private index = 0
    private timestamp = Date.now()
    private saveCapture(rt: RenderTexture) {
        let data: string = this.getImgBase(rt)
        this.saveAs(`${this.timestamp}_${++this.index}`, data)
    }

    private getImgBase(texture: RenderTexture) {
        const rtW = Math.floor(texture.width);
        const rtH = Math.floor(texture.height);
        const texPixels = new Uint8Array(rtW * rtH * 4);
        let data = texture.readPixels(0, 0, rtW, rtH, texPixels)!

        let canvas = document.createElement('canvas')
        let ctx = canvas.getContext('2d')!

        canvas.width = texture.width
        canvas.height = texture.height

        let width = texture.width
        let height = texture.height

        let rowBytes = width * 4
        for (let row = 0; row < height; row++) {
            let srow = height - 1 - row
            let imgData = ctx.createImageData(width, 1)
            let start = srow * width * 4
            for (let i = 0; i < rowBytes; i++) {
                imgData.data[i] = data[start + i]
            }
            ctx.putImageData(imgData, 0, row)
        }
        let dataUrl = canvas.toDataURL('image/png')
        console.log(dataUrl)
        return dataUrl
    }

    private saveAs(fileName: string, data: any | string) {
        var element = document.createElement('a');
        if (typeof data === "string") {
            element.setAttribute('href', data);
        }
        else {
            element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(data));
        }

        element.setAttribute('download', fileName);
        element.style.display = 'none';
        document.body.appendChild(element);
        element.click();
        document.body.removeChild(element);
    }
}

示例工程

capture-ccc3.6.2.zip (488.2 KB)

https://forum.cocos.org/uploads/short-url/9Q24VrBnMKyybOaKQM8SwRYtZkw.zip

文末阅读原文可下载

参考资料

  • https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement

  • https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement

  • https://developer.mozilla.org/en-US/docs/web/api/htmlelement/click

更多精彩

零代码实现面片效果(UV滚动,帧动画)  Cocos Creator

如何快速升级 Cocos Shader 版本,以简易水shader为例

游戏开发资料合集,2022年版

【3D游戏基础】蒙皮骨骼动画与骨架

让编辑器显示场景内的相机视角

aa7fdb8881d94651e6d2e7bd22c1d14b.jpeg

点击“阅读原文”下载完整工程

“点赞“ ”在看” 鼓励一下790e212df163ef28519acfe1e6d70c52.png

Cocos Creator模拟砸金蛋3d旋转效果 | 附代码egg.zip // Learn TypeScript: // - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/typescript.html // - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/typescript.html // Learn Attribute: // - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/reference/attributes.html // - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/reference/attributes.html // Learn life-cycle callbacks: // - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/life-cycle-callbacks.html // - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/life-cycle-callbacks.html const {ccclass, property} = cc._decorator; @ccclass export default class Game extends cc.Component { @property Count: number = 5; @property(cc.Prefab) prefab: cc.Prefab = null; @property(cc.Node) nodeParent: cc.Node = null; private mEggs: cc.Node[] = []; // LIFE-CYCLE CALLBACKS: // onLoad () {} start () { } // update (dt) {} onClick(event, data){ switch(data){ case &#39;add&#39;:{ this.addEggs(); break; } case &#39;move&#39;:{ this.moveEggs(); break; } case &#39;stop&#39;:{ this.stopMoveEggs(); break; } } } addEggs(){ if(this.Count <= 0){ return; } this.mEggs = []; const N = 360 / this.Count; for(let i = 0; i < this.Count; i++){ let egg = cc.instantiate(this.prefab); let js = egg.getComponent(&#39;Egg&#39;); js.setRadian(i * N * Math.PI / 180); js.updatePos(); egg.parent = this.nodeParent; this.mEggs.push(egg); } } moveEggs(){ for(let i = 0; i < this.mEggs.length; i++){ this.mEggs[i].getComponent(&#39;Egg&#39;).setMove(true); } } stopMoveEggs(){ for(let i = 0; i < this.mEggs.length; i++){ this.mEggs[i].getComponent(&#39;Egg&#39;).setMove(false); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值