实现在Unity3D中渲染YUV420P文件,可以渲染一帧(即全景图片),也可以渲染多帧(即全景视频)。
Unity3D中创建场景
Sphere
首先在Sence中创建一个Sphere
注意sphere中Scale的Z一定要是负数,因为我们是在球的内部观看视频的。
Material
创建一个材质球,右键Assets—>Create—>Material,并将其挂在创建的Sphere上
Shader
创建一个Unilt Shader,右键Assets—>Create—>Shader—>Unlit Shader
在LOD 200下面加入cull off命令,以此可以在球的内部看到内容物:
将此着色器文件挂在刚刚创建好的材质球上:
Render Texture
创建Render Texture,右键Assets—>Create—>Render Texture
设置Size
将此渲染纹理挂在材质球上:
编写CS脚本进行渲染
创建脚本
创建C#脚本,右键Assets—>Create—>C# Script,将其挂在Sphere上
完整代码
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using System;
namespace YUV
{
public class yuvvideo : MonoBehaviour
{
public Renderer target;
int frameCount;
int frameNow = 0;
byte[] file;//最大值255
//public Renderer target;
private int w = 3840;
private int h = 1920;
// Plana 連續儲存,Packed 交錯儲存
// 使用 Plana YUV420 格式
void Start()
{
//一次读取所有比特
file = File.ReadAllBytes("D:/VideoPlayer/Assets/VideoSource/out3D_Rio.yuv");
frameCount = GetFrameCount(file, w, h); // 影像寬高
//输出总帧数
frameCount = 1;
print("Frame Count : " + frameCount);
}
void Update()
{
if (frameNow > frameCount - 1) return;
GetTexture(file,w, h) ; // 影像寬高
frameNow++;
print("Frame : " + (frameNow) + " (" + (int)(frameNow / (float)(frameCount) * 100) + "%)");
}
int GetFrameCount(byte[] file, int width, int height)
{
return file.Length / ((width * height) * 3 / 2);
}
//原始纹理t
Texture2D t = null;
private byte Y00, Y01, Y10, Y11;//Y分量
private float R00, G00, B00;
private float R01, G01, B01;
private float R10, G10, B10;
private float R11, G11, B11;
int i;
int mY;//颠倒y值
void GetTexture(byte[] file,int width, int height)
{
if (t != null) Destroy(t);
t = new Texture2D(width, height, TextureFormat.RGB24, false);
int Ysize = width * height;
int UorVsize = width * height / 4;
byte U = 0;
byte V = 0;
int k = 0;
//offset偏移量
int offset = frameNow * ((width * height) * 3 / 2);
for (int y = 0; y < height; y += 2)
{
for (int x = 0; x < width; x += 2)
{
U = file[offset + Ysize - 1 + k++]; //注意要减一
V = file[offset + Ysize - 1 + k + UorVsize]; //注意要减一
i = y * width + x;
mY = height - 1 - y;
Y00 = file[offset + i];
Y01 = file[offset + i + width];
Y10 = file[offset + i + 1];
Y11 = file[offset + i + width + 1];
R00 = (Y00 + 1.4075f * (V - 128)) / 255f;
G00 = (Y00 - 0.3455f * (U - 128) - 0.7169f * (V - 128)) / 255f;
B00 = (Y00 + 1.779f * (U - 128)) / 255f;
R01 = (Y01 + 1.4075f * (V - 128)) / 255f;
G01 = (Y01 - 0.3455f * (U - 128) - 0.7169f * (V - 128)) / 255f;
B01 = (Y01 + 1.779f * (U - 128)) / 255f;
R10 = (Y10 + 1.4075f * (V - 128)) / 255f;
G10 = (Y10 - 0.3455f * (U - 128) - 0.7169f * (V - 128)) / 255f;
B10 = (Y10 + 1.779f * (U - 128)) / 255f;
R11 = (Y11 + 1.4075f * (V - 128)) / 255f;
G11 = (Y11 - 0.3455f * (U - 128) - 0.7169f * (V - 128)) / 255f;
B11 = (Y11 + 1.779f * (U - 128)) / 255f;
t.SetPixel(x, mY, new Color(R00, G00, B00, 1));
t.SetPixel(x, mY - 1, new Color(R01, G01, B01, 1));
t.SetPixel(x + 1, mY, new Color(R10, G10, B10, 1));
t.SetPixel(x + 1, mY - 1, new Color(R11, G11, B11, 1));
}
}
t.Apply();
target.sharedMaterial.SetTexture("_MainTex", t);
}
}
}
实现效果
在场景中的Sphere上完成全景图片的渲染
参考链接
https://blog.csdn.net/weixin_38884324/article/details/80638027
https://blog.csdn.net/weixin_43778515/article/details/90268117