为了账号安全,请及时绑定邮箱和手机立即绑定

如何在 Unity 中创建一个可以显示由许多小图像组成的纹理的着色器

如何在 Unity 中创建一个可以显示由许多小图像组成的纹理的着色器

C#
HUX布斯 2023-12-17 17:01:32
所以我想做的是从 SQL 表加载卫星图像并将它们包裹在一个球体周围以创建一个地球仪。我知道我已经加载了所覆盖的图像,我只是不确定如何使我的着色器以正确的方向显示图像。我访问了 Unity 论坛并从 Unity 文档中查看了此代码。使用链接的着色器代码和我在论坛上收到的帮助,这是我最终得到的代码:Properties    {        _MainTexArray("Tex", 2DArray) = "" {}        _SliceRange("Slices", Range(0,32)) = 6        _UVScale("UVScale", Float) = 1        _COLUMNS("Columns", Range(0, 5)) = 1        _ROWS("Rows", Range(0, 5)) = 1        _CELLS("Cells", Range(0, 32)) = 16    }        SubShader        {            Pass            {                CGPROGRAM                #pragma vertex vert                #pragma fragment frag                // texture arrays are not available everywhere,                // only compile shader on platforms where they are                #pragma require 2darray                #include "UnityCG.cginc"                struct v2f                {                    float3 uv : TEXCOORD0;                    float4 vertex : SV_POSITION;                };                float _SliceRange;                float _UVScale;                v2f vert(float4 vertex : POSITION)                {                    v2f o;                    o.vertex = UnityObjectToClipPos(vertex);                    o.uv.xy = (vertex.xy + 0.5) * _UVScale;                    o.uv.z = (vertex.z + 0.5) * _SliceRange;                    return o;                }                float _COLUMNS; //Columns and rows only go between 0 and 1                float _ROWS;                float _CELLS;                UNITY_DECLARE_TEX2DARRAY(_MainTexArray);                        half4 frag(v2f i) : SV_Target                {                    float3 uv = float3(i.uv.x * _CELLS, i.uv.y * _CELLS, 0);                    uv.z = floor(i.uv.x / _COLUMNS) * floor(i.uv.y / _ROWS);                    return UNITY_SAMPLE_TEX2DARRAY(_MainTexArray, uv / _CELLS);                 }                ENDCG            }        }
查看完整描述

1 回答

?
慕妹3242003

TA贡献1824条经验 获得超6个赞

如果您可以对照片数组进行索引,以便有效地获得地球的等距柱状投影,则可以尝试使用着色器代码的修改形式Farfarer Unity论坛复制并稍作修改如下:

Shader "Custom/Equirectangular" {

    Properties{

        _MainTexArray("Tex", 2DArray) = "" {}

        _COLUMNS("Columns", Int) = 2

        _ROWS("Rows", Int) = 2

    }


        SubShader{

            Pass {

                Tags {"LightMode" = "Always"}


                CGPROGRAM

                    #pragma vertex vert

                    #pragma fragment frag

                    #pragma require 2darray


                    #include "UnityCG.cginc"


                    struct appdata {

                       float4 vertex : POSITION;

                       float3 normal : NORMAL;

                    };


                    struct v2f

                    {

                        float4    pos : SV_POSITION;

                        float3    normal : TEXCOORD0;

                    };


                    v2f vert(appdata v)

                    {

                        v2f o;

                        o.pos = UnityObjectToClipPos(v.vertex);

                        o.normal = v.normal;

                        return o;

                    }


                    UNITY_DECLARE_TEX2DARRAY(_MainTexArray);


                    int _ROWS;

                    int _COLUMNS;


                    #define PI 3.141592653589793


                    inline float2 RadialCoords(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 / PI);

                        return float2(sphereCoords.x * 0.5 + 0.5, 1 - sphereCoords.y);

                    }


                    float4 frag(v2f IN) : COLOR

                    {

                        float2 equiUV = RadialCoords(IN.normal);


                        float2 texIndex;

                        float2 uvInTex = modf(equiUV * float2(_COLUMNS,_ROWS), texIndex);


                        int flatTexIndex = texIndex.x * _ROWS + texIndex.y;


                        return UNITY_SAMPLE_TEX2DARRAY(_MainTexArray,

                                float3(uvInTex, flatTexIndex));

                    }

                ENDCG

            }

        }

    FallBack "VertexLit"

}

您还需要使用


texArr = new Texture2DArray(256, 256, textures.Length, TextureFormat.RGBA32, false, true);

代替


texArr = new Texture2DArray(256, 256, textures.Length, TextureFormat.RGBA32, true, false); 

如果我将此脚本附加到球体上,它对我有用:


Material myMat;

public List<Texture2D> texes;


IEnumerator Start()

{

    yield return null;

    myMat = GetComponent<Renderer>().material;


    Texture2DArray texArr = new Texture2DArray(256, 256, 9, 

            TextureFormat.RGBA32, false, true);

    texArr.filterMode = FilterMode.Bilinear;

    texArr.wrapMode = TextureWrapMode.Clamp;


    for (int i = 0 ; i < texes.Count ; i++)

    {

        texArr.SetPixels(texes[i].GetPixels(), i, 0);

    }


    texArr.Apply();


    myMat.SetTexture("_MainTexArray", texArr);

}

并在texes中按顺序添加这些纹理:

https://img1.sycdn.imooc.com/657eb92b0001bb2702871094.jpg

https://img1.sycdn.imooc.com/657eb93d00010f2e02861085.jpg

https://img1.sycdn.imooc.com/657eb946000152d102870273.jpg

并将行和列设置为 3,它会产生不错的结果:

https://img1.sycdn.imooc.com/657eb95f0001600b23451289.jpg

如果启用双线性过滤,纹理边界处仍然存在一些伪影。但这些文物必须放大得很近才能看到。由于双线性过滤缺乏相邻像素,它们大多显示为混合不当或丢失像素:

https://img1.sycdn.imooc.com/657eb97000012c0e23401291.jpg

当然,这个示例没有正确平铺,因此沿着一条经线有明显的接缝:

https://img1.sycdn.imooc.com/657eb9800001e48923421287.jpg

由于此设置需要来自球体的法线,因此这只适用于法线接近球体的物体。因此,例如,它无法在平面上正确渲染。



查看完整回答
反对 回复 2023-12-17
  • 1 回答
  • 0 关注
  • 138 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信