代码之家  ›  专栏  ›  技术社区  ›  Fattie

统一,修改标准着色器以随机翻转纹理?

  •  10
  • Fattie  · 技术社区  · 7 年前

    它们都有相同的材质“M1”,它有简单的标准着色器,还有一个简单的PNG作为纹理。

    如果你去材料,调整瓷砖,

    enter image description here

    enter image description here

    你可以方便地翻转不同的外观纹理。

    请注意,这当然会改变 全部十个 一次完成所有的立方体。

    是否可以修改标准着色器,以便,

    • 在每个使用材质的对象上

    • 着色器随机更改平铺(以及偏移)

    • 再说一次,我是说 “每对象”基础 ;在示例中 十个人中的任何一个都是随机不同的。

    (所以:一个立方体显示平铺-1,1,一个立方体显示平铺-1,-1,依此类推。。。每个立方体都不同,尽管都使用 相同的 材质,仅存在一种材质。)

    (2) 请注意,如果更改一个材质,它当然会生成多个副本。你不能有成千上万的材料。

    解决的办法是有(一个)明暗器,它知道在明暗器内部改变(比如,随机地)偏移量-在它处理的每个对象上。

    这就是我要问的。

    4 回复  |  直到 7 年前
        1
  •  8
  •   Fattie    7 年前

    . 我还没找到办法,你也不行。

    这是一个应该用C端代码来解决的问题。

    (1) 生成几个不同版本的 材质,每个具有不同的平铺,并随机选择其中一个

    一点问题都没有。这是什么 MaterialPropertyBlock

    如果要使用相同的材质绘制多个对象,但属性略有不同,请使用它

    下面的代码将导致创建许多材质实例:

    void Start()
    {
        MeshRenderer meshRenderer = gameObject.GetComponent<MeshRenderer>();
        int tileX = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
        int tileY = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
        Vector2 tile = new Vector2(tileX, tileY);
        meshRenderer.material.SetTextureScale("_MainTex", tile);
    }
    

    材料属性块 ,这个问题就解决了。未制作材料副本。既然你关心性能,你也应该使用 Shader.PropertyToID :

    void Start()
    {
        int propertyID = Shader.PropertyToID("_MainTex_ST");
        meshRenderer = gameObject.GetComponent<MeshRenderer>();
        int tileX = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
        int tileY = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
        Vector2 tile = new Vector2(tileX, tileY);
    
        MaterialPropertyBlock matPropBlock = new MaterialPropertyBlock();
        //Get the current MaterialPropertyBlock settings
        meshRenderer.GetPropertyBlock(matPropBlock);
        //Assign the new tile value
        matPropBlock.SetVector(propertyID, tile);
        //matPropBlock.SetVector(Shader.PropertyToID("_MainTex_ST"), tile);
        //Apply the modified MaterialPropertyBlock back to the renderer
        meshRenderer.SetPropertyBlock(matPropBlock);
    }
    

    如果在游戏中只执行一次,那么将脚本附加到每个游戏对象就没有意义了。只需将它附加到一个空的游戏对象上,按标签找到所有对象,然后在每个对象上运行代码。

    void Start()
    {
        GameObject[] objs = GameObject.FindGameObjectsWithTag("YourObjTag");
        int propertyID = Shader.PropertyToID("_MainTex_ST");
        for (int i = 0; i < objs.Length; i++)
        {
            MeshRenderer meshRenderer = objs[i].GetComponent<MeshRenderer>();
            int tileX = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
            int tileY = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
            Vector2 tile = new Vector2(tileX, tileY);
    
            MaterialPropertyBlock matPropBlock = new MaterialPropertyBlock();
            //Get the current MaterialPropertyBlock settings
            meshRenderer.GetPropertyBlock(matPropBlock);
            //Assign the new tile value
            matPropBlock.SetVector(propertyID, tile);
            //Apply the modified MaterialPropertyBlock back to the renderer
            meshRenderer.SetPropertyBlock(matPropBlock);
        }
    }
    
        2
  •  5
  •   game development germ    7 年前

    Pseudorandomly flipped

    Shader "RandomFlip"
    {
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "DisableBatching"="True" }
        LOD 100
    
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
    
            #include "UnityCG.cginc"
    
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
    
            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };
    
            sampler2D _MainTex;
            float4 _MainTex_ST;
    
            v2f vert (appdata v)
            {
                // position of pivot in world space
                float3 pivotWorldPos = float3( unity_ObjectToWorld[0].w, unity_ObjectToWorld[1].w, unity_ObjectToWorld[2].w );
    
                // randomness achieved by feeding trigonometry function with large numbers
                float flipHorizontally = sin( ( pivotWorldPos.x + pivotWorldPos.y + pivotWorldPos.z ) * 1000 ) > 0;
                float flipVertically = cos( ( pivotWorldPos.x + pivotWorldPos.y + pivotWorldPos.z ) * 1000 ) > 0;
    
                // randomly flipping uvs 
                float2 uv = lerp( v.uv, float2( 1.0 - v.uv.x, v.uv.y ), flipVertically );
                uv = lerp( uv, float2( uv.x, 1.0 - uv.y ), flipHorizontally ); 
    
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
    
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
    }
    

    尽管你最好不要移动这些物体:D,因为这里的随机性来自于物体在世界空间中的位置。批处理也将打破随机性。

        3
  •  4
  •   Fattie    7 年前

    如果要翻转,请对这些对象使用alpha=0,对其他对象使用alpha=1。

    半翻转=1-2*顶点a;

    所以翻转应该是-1或1。

    enter image description here

    但是请注意,每次访问 .mesh ,在Unity中,您正在创建一个全新的网格:

    public class TestFlipUV : MonoBehaviour
        {
            private void Awake()
            {
    
                Mesh mesh = GetComponent<MeshFilter>().mesh;
                // NOTE. IN UNITY, ACCESSING .mesh CREATES
                // A NEW INSTANCE OF THAT MESH EVERY TIME
    
                Vector2[] uv2 = mesh.uv;
    
                float rnd = Random.RandomRange(0.0f, 1.0f);
                if (rnd > 0.5f)
                {
                    for (int i = 0; i < uv2.Length; i++)
                    {
                        uv2[i].x *= -1;    
                    }
                }
    
                rnd = Random.RandomRange(0.0f, 1.0f);
                if (rnd > 0.5f)
                {
                    for (int i = 0; i < uv2.Length; i++)
                    {
                        uv2[i].y *= -1;    
                    }
                }
                mesh.uv2 = uv2;
            }
        }
    

    ... 然后。。。

    Shader "Unlit/FlipUV"
    {
        Properties
        {
            _MainTex ("Texture", 2D) = "white" {}
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            LOD 100
    
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
    
                #include "UnityCG.cginc"
    
                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                    float2 uv2 : TEXCOORD1;
                };
    
                struct v2f
                {
                    float2 uv : TEXCOORD0;
                    float4 vertex : SV_POSITION;
                };
    
                sampler2D _MainTex;
                float4 _MainTex_ST;
                float4 _MainTex_TexelSize;
    
                v2f vert (appdata v)
                {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.uv = v.uv;
                    o.uv *= v.uv2;
                    return o;
                }
    
                fixed4 frag (v2f i) : SV_Target
                {
                    fixed4 col = tex2D(_MainTex, i.uv);
                    return col;
                }
                ENDCG
            }
        }
    }
    
        4
  •  0
  •   obywan    7 年前

    SetTextureScale

    为每个立方体附加。

    public class MatTilingChange : MonoBehaviour {
        MeshRenderer mr;
        int[] vals = new int[] { -1, 1 };
    
        private void Awake()
        {
            mr = GetComponent<MeshRenderer>();
        }
    
        void Start () {
            mr.material.SetTextureScale("_MainTex", new Vector2(vals[Random.Range(0, 2)], 
    vals[Random.Range(0, 2)]));
        }
    }