使用参考资源
CocosCreator v3.6.2
cocomat 腾讯开源公共组件框架
Cocos Creator 3D特制 Video MeshRender 播放器(Cocos商店购买)
TcPlayer 腾讯开源 Web 播放器
视频流 hls 库
正文
场景漫游引发的思考
元宇宙,虚拟世界。OK,不同的人有不同的理解!在一个阳光明媚的上午,我偶然浏览到了一个炫酷的场景漫游视频,引发了我在 cocos 上实现的思考:
-
在 cocos 里实现场景漫游需要什么?
-
在 cocos 里能漫游预览什么?
-
社区里大家都实现过什么,有哪些没实现的?
-
在游戏里玩游戏,或者在游戏里刷视频是不是很好玩?
基础的漫游解决方案
3D 的场景漫游,首先最核心的就是摄像机运动,主角移动。逛逛商城,发现摇杆组件大家都封装过,有解决方案了。
摄像机位置移动,我想到了动画编辑器,或者是其他工具导出的一系列 Vec3 坐标点,让摄像机沿着移动,照着切线方向。也有解决方案了。
模型、粒子、模型动画,这些静态展示的,美工建模师都可以输出。
对了,有些场景需要 3D 文本,还有 2D 的 Spine 动画以 3D 的形式做展示,尝试解决了下这个。
cocos 的模型是直接放的,摄像机是动画编辑器编辑好路径与速度与旋转,进行播放的;文字与 spine 是单独一个分组摄像机渲染到一个 renderTexture
上,然后赋给材质,用 3D 物体平面渲染的 Plane。
如下图,一个摄像机分组为 show2
,然后仅渲染该分组,渲染后的纹理赋值给材质,材质挂到 plane 上:
核心代码:
start() {
this.renderTexture = new RenderTexture();
this.renderTexture.initialize({ width: 720, height: 720 });
this.show2Camera.targetTexture = this.renderTexture;
this.show2Material.setProperty('mainTexture', this.renderTexture);
}
OK,文本和 spine 搞定了,相信大家也发现了上面演示 gif 最后的视频渲染,视频渲染是最有意思的。
视频渲染尝试
我先简单说说关于视频渲染到 webgl 里的原理:
在 Web 平台,我们知道 video 标签赋予一个 src 后便可以播放视频,那么想个办法把 video 标签的播放内容采集,形成纹理传进去呗!在 webgl 里渲染图片,我们会这样:
const gl = canvas.getContext('webgl');
const image = new Image();
image.src = "./kuokuo.png";
// 图片加载完渲染到 webgl
image.onload = function () {
// ... 省略顶点配置,shader书写
gl.activeTexture(gl.TEXTURE0);
// 创建纹理对象
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// 核心
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
// ... 省略配置 texture
// 绘制
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
};
大家可以看到,texImage2D
的最后一个参数就是原生的 image 对象,实际上就是绑定纹理数据进去。视频也是同理,texImage2D 这个方法最后一个参数可以直接传入 video 标签。那就 OK 了,只剩下最后一步,如何在 cocos 中实现?
在 CocosCreator v2.x 版本中,因为是 js 引擎代码,底层暴露不多,需要重写类。具体实现可以直接看 cocomat 封装的 CCMVideo 组件,其核心代码:
https://github.com/cocos/cocomat/blob/main/coco-mat/lib/CCMVideo/CCMVideo.ts
this.impl = document.createElement('video');
this.impl.crossOrigin = 'anonymous';
this.impl.autoplay = false;
this.impl.loop = false;
this.impl.muted = false;
// ....
this.update = dt => {
if (this.isInPlaybackState()) {
gl.bindTexture(gl.TEXTURE_2D, this.textures[0]._glID);
// 核心
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.impl);
// @ts-ignore
cc.renderer.device._restoreTexture(0);
}
};
大家可自行查看。
关于 CocosCreator v3.x 版本中,引擎用 ts 重写了,底层也暴露了不少能力,就咱们谈的这个视频渲染,可以取 cc 下的 gfx 模块:
import { gfx } from 'cc';
// 就是上述的 gl
gfx.deviceManager.gfxDevice;
gfx.Device;
// 官方封装方法
gfx.Device.createTexture(...args);
gfx.Device.copyTexImagesToTexture(...args);
研究了好一阵终于搞出来,代码写的很乱,想整理下发官方商城,但发现有一个大佬已经写好了。针不戳!现在你的代码是我的了!
链接:https://store.cocos.com/app/detail/3726
原本研究就到此结束了,休息一下,搂着老婆看会电视!但是看着看着,我心想:在元宇宙里看电视该是多么炫酷的一件事呀!!!湖南卫视!整!
直播渲染尝试
先研究下网上已经有的直播拉流解决方案:m3u8,rtsp,rtmp,flv,mp4 等等,那大厂都用啥呢?去 B 站直播间逛下:
就决定是你了皮卡丘(m3u8),百度一波 m3u8 直播拉流的实现,发现了腾讯的 TcPlayer + hls 的实现方式,原生的 html 实验很简单,引入两个 SDK 然后 new 一个 TcPlayer 传入直播拉流地址就可以:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>直播测试</title>
<script src="TcPlayer-2.3.3.js" charset="utf-8"></script>
<script src="hls.min.js" charset="utf-8"></script>
</head>
<body>
<div id="kuokuo_test_video" style="width:100%; height:auto;"></div>
<script>
window.kuokuoPlayer = new TcPlayer('kuokuo_test_video', {
m3u8: "http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8",
autoplay: true,
width: '500', //视频分辨率宽度
height: '500' //视频分辨率高度
});
</script>
</body>
</html>
引入到 Cocos 里:
然后魔改了一波 Video MeshRender 播放器的代码,原理就是把我新建的一个用来播放湖南卫视直播的 video 标签,替换掉渲染的那个 video 标签,采集内容的原理都是一样的。
最终实现的效果:
舒服,可以在游戏里看电视直播了!
更多文章与分享
个人网站:www.kuokuo666.com
2022!Day Day Up!