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

Fat*_*tie 11 shader unity-game-engine

想象一下,十个简单的"立方体"的场景都是一样的.

它们各自具有相同的材料"M1",其具有简单的标准着色器,并且具有简单的PNG作为纹理.

如果你去材料,并调整平铺,

在此输入图像描述

在此输入图像描述

您可以方便地翻转纹理以获得不同的外观.

请注意,这当然会同时更改所有十个立方体.

是否可以修改标准着色器,简单地说,

  • 在每个使用该材料的对象上

  • 着色器随机更改平铺(例如,偏移)

  • 再一次,我的意思是"每个对象" ; 在该示例中,十个中的每一个将随机地不同.

(所以:一个立方体会显示平铺-1,1,一个立方体会显示平铺-1,-1等等......每个立方体都不同,尽管所有立方体都使用相同的材料,只存在一种材料.)

注意,

(1)生成一些不同版本的材料是完全无关紧要的,每个版本都有不同的平铺,并为每个立方体随机选择其中一个.这不是要走的路

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

解决方案是让(一个)着色器知道在着色器内部的每个对象上改变(例如,随机地)偏移量. (即基于每个特定对象)

这就是我在这里问的问题.

Pro*_*mer 8

我注意到你真的很想用除了着色器之外的任何东西.单独使用着色器无法执行此操作.问题是无法在着色器中生成随机数.问题是能够做到一次.我没有找到办法这样做,也不认为你可以.

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

(1)生成一些不同版本的材料是完全无关紧要的,每个版本都有不同的平铺,并为每个立方体随机选择其中一个.这不是要走的路

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

根本不是问题.这是MaterialPropertyBlock用于.它允许您修改着色器属性,而无需创建该材质的新实例.

"在想要使用相同材质绘制多个对象但属性略有不同的情况下使用它." 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);
}
Run Code Online (Sandbox Code Playgroud)

有了MaterialPropertyBlock,这个问题就解决了.不进行材料复制.既然你关心性能,你也应该使用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);
}
Run Code Online (Sandbox Code Playgroud)

如果在游戏中完成一次,那么将脚本附加到每个GameObject并没有多大意义.只需将它附加到一个空的GameObject,按标签查找所有对象,然后在每个对象上运行代码.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


gam*_*erm 5

伪随机翻转

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
    }
}
}
Run Code Online (Sandbox Code Playgroud)

虽然你最好不要移动这些物体:D因为这里的随机性来自世界空间中物体的位置.批处理也会打破随机性.