creator3.0 camera怎么截图

原理还是一样的,只是不再需要手动调用 camera 的 render 了,所有开启的 Camera 组件都会被渲染。参考 RenderTexture 文档

https://docs.cocos.com/creator/3.0/manual/zh/asset/render-texture.html?h=rendertexture

在 Test cases 3d 中也有相关的用例可以参考

感觉大佬没get到我的点啊,所以只能下一帧 将 targetTexture = null?这样就会闪一下的。

哦,这段是没注意,闪一下指的是第一帧有内容,第二帧没内容?

1赞

对的,因为不知道什么时候才能将targetTexture的渲染到新的texture上面,所以,只能下一帧再将targetTexture = null 这样会导致原有的camera会有一帧没有渲染到屏幕上面,所以会闪一下。

let texture = new RenderTexture();
texture.reset(view.getVisibleSize());
this.camera.targetTexture = texture;
let newSpFrame = new SpriteFrame();
newSpFrame.texture = texture;
this.targetSprite.getComponent(UITransform).contentSize = view.getVisibleSize();
this.targetSprite.spriteFrame = newSpFrame;
this.scheduleOnce(()=>{
    this.camera.targetTexture = null;
}, 0);

大概就是这样的

2.4.x 完全可以

    this.camera.targetTexture = texture;
    this.camera.render();
    this.camera.targetTexture = null;

这一帧就搞定,然后没有闪的感觉。

1赞

Camera的TargetTexture不为空相机的内容就会输出到RenderTexture,而不会渲染到屏幕上了,当然会有一帧闪烁。你可以截图的时候临时创建一个新相机专门用于渲染截图

首先,截图显示的Sprite是用一个新相机(ps:相机2)来渲染的; 然后,如果你是指把原有的相机(相机1)克隆为一个新相机(ps: 相机3),这样能解决不闪烁的问题,但是如果原有相机不只是一个,是多个,我需要把多个相机的targetTexture赋给新的texture, 这样,我需要把所有的原相机都克隆一下,而且,这样都是重复渲染了两层。感觉这样的解决方案,不是很好。

Camera 的渲染是在渲染阶段完成的,所以我理解你遇到的问题是第一帧没内容,因为 Camera 渲染没完成。所以到第二帧才有内容。跟 targetTexture 设置为空应该没有关联,还是我理解错了?

如果是我说的情况,我建议提前一帧添加这个 Camera 做预渲染(比如在前一个场景预先渲染内容)。或者可以把场景截图发出来,标注一下 RT 的内容是什么,我们结合场景分析下有没有别的办法

demo我补充的上面了已经,大佬可以down下来看看,原本有camera.render()的情况下,完全可以在一帧里面完成,targetTexture就可以设置为null,这样在视觉上是不会产生差异的。目前3.0中的解决方案,我再demo里面都有列举,感觉都做不到之前那么完美

我看到你的问题是什么了,帮你调整了一个版本,你看看

test3_0.zip (2.5 MB)

如果要用 RT 来拍摄一部分场景并呈现的核心思路应该是这样的:

  1. 在场景中添加一个 CaptureCamera,此摄像机的 visibility 要包含所有需要被捕捉的内容,这个 demo 中设置为 UI_2D(包含两个 sprite 和一个按钮)
  2. 在 Assets 中创建一个 RenderTexture 资源,将 CaptureCamera 的 targetTexture 设置为这个 RenderTexture
  3. 添加一个 RTSprite 来作为 RT 的载体,将它的 layer 设置为不被 CaptureCamera 拍摄但是被主相机拍摄的 layer,在这个 demo 中我设置为 test
  4. 设置主相机的可见性,这个场景中同时设置了 UI_2D 和 test,这样在它可以同时拍到两个普通 sprite 和RTSprite
  5. 按下按钮后,设置 RTSprite 的 spriteFrame 让它显示之前 UI_2D layer 下的内容。此时 RTSprite 会覆盖住两个普通 sprite(注意,理论上此时主相机不需要拍摄 UI_2D layer,我没改,但是你们后续开发中很可能需要动态调整可见性,以及做好 layer 的规划)

主相机:

CaptureCamera

你之前 demo 中的误区是用主 camera 来拍摄内容到 render texture 上。实际上 Camera 可见性和节点的 layer 的调整是很灵活的,可以自由控制每个 camera 应该看到什么。要拍摄作为 RT 的 camera 应该一直挂着 RT,不需要被渲染到主屏,他的渲染目标永远都是 RT。主相机也不应该临时挂载 RT,他应该始终被渲染到主屏上,所以也就不会出现闪烁现象。

1赞

其实 2.x 就是这样的流程。但是我觉得官方是不是可以集成一下这几个步骤。
其实开发人员要的功能很简单:

  1. 将指定节点内容渲染到一个 spriteFrame 上去,并能够导出图片。
  2. 这个功能完成后可以制作截图,也可以制作一个灵活的小地图。

但是官方的这个解决步骤,十分复杂,以及对新手不友好。关键问题还在于,即使根据教程走,中间步骤也容易出错。有些问题还需要看源码,hack,才能搞懂。比如:自定义 camera 默认的 z 轴是 0,导致第一帧渲染,一移动,就黑屏的问题。

希望官方能封装其中的复杂而重复的部分。

确实,灵活性和易用性的平衡还得再找找,目前是灵活度为优先,确保不阻碍开发者

如果没了render() ,那是不是没有离屏相机的概念了。

如果我有一个渲染400帧动画的需求,是不是要等引擎走400帧才能渲染好。

离屏相机当然有,Camera 设置 targetTexture 就是一个离屏相机。是否离屏和渲染的机制没有关联。相机值决定渲染什么内容到什么目标上,而渲染过程是渲染器管理的,渲染器目前没有开放独立的渲染入口,是以渲染帧来驱动渲染的。在 TS 环境下渲染帧和逻辑帧还是同步的,但是在 3.1 中,我们即将拆分渲染线程和引擎主循环线程。

官方是否会考虑出个类似Unity MonoBehaviour.OnRenderImage的回调方法?不仅方便截图,更方便做后处理

拆!现在的离屏还是要跟着游戏逻辑帧来,不科学。

大佬,有没有办法拿到当前屏幕渲染的纹理?

按照你的思路,测试了在多个摄像机的情况下,采用多个对应的captureCamera,然后其targetTexture用同一个renderTexture。发现,renderTexture被摄像机顺序渲染,但也会顺序清除再覆盖上一次的结果(并不是保留依次渲染的纹理),所以导致多个摄像机场景下截图,完全没有了解决方案。

注意相机的 clearFlag 只有第一个应该 clear color 或者 skybox,其他的都应该是 only depth 或者 none,否则如果标记清除 color 那么你看到的也是正确行为

TestCamera.zip (1.4 MB)
这是测试demo,这里再发一下,为了给其他开发者也可以看到,除了主相机,其他全部设置成为DONT_CLEAR和DEPTH_ONLY都无效

求官方大大,尽快能回复一下,谢谢