【问题标题】:Making a Fisheye Skybox Shader in Unity在 Unity 中制作鱼眼天空盒着色器
【发布时间】:2020-03-24 09:29:48
【问题描述】:

Unity 有一个内置的 Skybox 着色器,它可以采用立方体贴图纹理或像这样的 equirectangular 纹理

加载它并关注the instructions 以将其用作天空盒作品

我想扩展它来处理这样的鱼眼图像

着色器的代码可从built in shaders 获得,测试版(乍一看似乎相同)可从here 获得

查看着色器代码,在顶点着色器中计算 3D 方向并传递给片段着色器。然后片段着色器应该采用该 3D 方向并生成纹理坐标。

这是 equirectangular 图像的代码

inline float2 ToRadialCoords(float3 coords)
{
  float3 normalizedCoords = normalize(coords);
  float latitude = acos(normalizedCoords.y);
  float longitude = atan2(normalizedCoords.z, normalizedCoords.x);
  float2 sphereCoords = float2(longitude, latitude) * float2(0.5/UNITY_PI, 1.0/UNITY_PI);
  return float2(0.5,1.0) - sphereCoords;
}

这是我尝试将其更改为鱼眼图像的代码

inline float2 ToFisheyeCoords(float3 coords)
  float3 normalizedCoords = normalize(coords);

  float r = 2.0 * atan2(length(normalizedCoords.xy), abs(normalizedCoords.z)) / UNITY_PI;
  float theta = atan2(normalizedCoords.y, normalizedCoords.x * sign(normalizedCoords.z));
  float2 uv = float2(cos(theta), sin(theta)) * r * 0.5 + 0.5;
  return frac(uv * float2(-1, 1));
}

但它不起作用。

我觉得我忽略了一些明显的东西。

整个项目是here。要在鱼眼示例和 equirectangular 示例之间切换,您需要打开 Window->Rendering->Light Settings,然后将 SkyboxMaterialEquirectangular 拖到 Lighting 窗口中的 Skybox Material 插槽中。

【问题讨论】:

    标签: unity3d shader fragment-shader


    【解决方案1】:

    我玩了一下这个,我想我会发布它。唯一要添加到您的答案中的是,在 360 度情况下,选择要对图像的哪一半进行采样。

    inline float2 ToFisheyeCoords(float3 coords)
    {
        float3 n = normalize(coords);        
    
        // u = r cos(phi) + 0.5
        // v = r sin(phi) + 0.5
        //where
        // r = atan2(sqrt(x * x + y * y), p.z) / pi
        // phi = atan2(y, x)
    
        float r = atan2(length(n.xy), abs(n.z)) / UNITY_PI;
        float phi = atan2(n.y, n.x * sign(n.z));
        float2 uv = float2(cos(phi), sin(phi)) * r + .5;
    
        uv.x *= .5;   
        //Choose image half to sample depending on sign of normal.z            
        uv.x += .25*(1 - sign(n.z));
    
        return uv;
    }
    

    单个(未拆分)图像的更通用解决方案似乎是:

    inline float2 ToFisheyeCoords(float3 coords)
    {
        float3 n = normalize(coords);
        //float FOV = UNITY_PI; // 180 degrees
        float FOV = UNITY_PI*2; // 360 degrees
        float r = atan2(length(n.xy), n.z) / FOV;
        float phi = atan2(n.y, n.x);
        float2 uv = float2(cos(phi), sin(phi)) * r + .5;
        return saturate(uv);
    }
    

    【讨论】:

    • 这也不对。显然有 360degree fisheye 这样的东西(假设两个 180 鱼眼并排)。我猜有更多选择(T_T)
    【解决方案2】:

    多花点功夫,这似乎行得通

    inline float2 ToFisheyeCoords(float3 coords)
    {
      float3 normalizedCoords = normalize(coords);
    
      float r = 2.0 * atan2(length(normalizedCoords.xy), abs(normalizedCoords.z)) / UNITY_PI;
      float theta = atan2(normalizedCoords.y, normalizedCoords.x);
      float2 uv = float2(cos(theta), sin(theta)) * r * 0.5 + 0.5;
      return float2(uv.x * 0.5, uv.y);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多