Unty中通过镜像优化HDRI全景图体积

Posted hont

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unty中通过镜像优化HDRI全景图体积相关的知识,希望对你有一定的参考价值。

全景图即HDRI贴图,可以代替6面cubemap,传统3D软件运用比较广。一般反射探针,天空盒等都会用到。

但是体积过大是个问题,特别是移动端会对包体大小进行控制,虽说可以通过球面贴图替换掉部分环境类贴图,但适用范围依然有限。

这里通过镜像的方式来做贴图大小的优化,可以将贴图优化到一半大小,缺点是会产生接缝。

 

原图如下(网络收集):

技术分享图片

 

最终效果:

技术分享图片

技术分享图片

 

github上有一些Equirectangular map的转换函数,类似球面坐标,直接拿来主义了。

参考:

https://github.com/tolotratlt/UnityPhotosphericView

https://github.com/Mapiarz/CubemapToEquirectangular

 

经过测试是可以x,y轴镜像的。首先需要裁剪原始HDRI图片。直接用Texture2D的Resize裁一下即可。

Material mat = new Material(Shader.Find("Hidden/ConvShader"));
var rt = RenderTexture.GetTemporary(new RenderTextureDescriptor(tex.width, tex.height, RenderTextureFormat.ARGB32));
Graphics.Blit(tex, rt, mat);

var instanceTex = Instantiate(tex);

instanceTex.Resize(instanceTex.width, instanceTex.height / 2);
instanceTex.ReadPixels(new Rect(0, 0, instanceTex.width, instanceTex.height), 0, 0);
instanceTex.Apply();
...

 

需要注意的是转换全景图的两个函数,参考了github上的内容,顺带把常量改成了内置的UNITY_PI。

float3 UvToDir(float2 uv)
{
    uv *= float2(UNITY_TWO_PI, UNITY_PI);

    float theta = uv.y;
    float phi = uv.x;
    float3 dir = float3(0, 0, 0);

    dir.x = sin(phi) * sin(theta) * -1;
    dir.y = cos(theta) * -1;
    dir.z = cos(phi) * sin(theta) * -1;

    return dir;
}

float2 DirToUV(float3 a_coords)
{
    float3 a_coords_n = normalize(a_coords);

    float lon = atan2(a_coords_n.z, a_coords_n.x);
    float lat = acos(a_coords_n.y);
    float2 sphereCoords = float2(lon, lat) * (1.0 / UNITY_PI);
    return float2(1 - (sphereCoords.x * 0.5 - 0.5), 1 - sphereCoords.y); //must flip x
}

 

 

转换之后就是在显示部分做修改,传入一个方向向量输出全景图的UV,在内部做一个镜像图片修复

需要注意输出的x并非0-1区间,而是0-2,估计由于全景图宽高2:1造成的,这里简单修复了下。

y轴接缝比较明显,手动调节了一下误差。设置好贴图的压缩关闭mipmap等,接缝会缓解不少。

float2 DirToUV(float3 a_coords)
{
    float3 a_coords_n = normalize(a_coords);

    float lon = atan2(a_coords_n.z, a_coords_n.x);
    float lat = acos(a_coords_n.y);
    float2 sphereCoords = float2(lon, lat) * (1.0 / UNITY_PI);
    float2 uv = float2(1 - (sphereCoords.x * 0.5 - 0.5), 1 - sphereCoords.y);

    //----------------------------
    uv.x -= 1;

    if (uv.x > 0.5)
        uv.x = 0.5 - (uv.x - 0.5);

    uv.x *= 2;
    //----------------------------Mirror X.

    //----------------------------
    uv.y *= 1.999;

    if (uv.y < 1)
        uv.y *= -0.97;
    else
        uv.y *= 1.03;
    //----------------------------Mirror Y.

    return uv;
}

 

 

基本上就是这样,另外很多情况下需要Cubemap转HDRI全景图,可以直接参考维基百科上的Cubemaping映射函数:

https://en.wikipedia.org/wiki/Cube_mapping

 

以上是关于Unty中通过镜像优化HDRI全景图体积的主要内容,如果未能解决你的问题,请参考以下文章

看360全景技术如何让我们的生活变得更加便利

vscode中通过快捷键`vh`将vue初始化代码结构自动输出

vscode中通过快捷键`vh`将vue初始化代码结构自动输出

Docker镜像构建的优化总结

云原生全景图详解系列:带你了解云原生技术图谱

项目优化