试想一下,有十个简单的“立方体”都是一样的场景。
他们每个人都有相同的材料“M1”,它具有简单的标准着色器,和一个简单的PNG作为纹理。
如果你去的材料,并调整平铺,
您可以方便的翻转纹理周围不同的外观。
请注意,这当然会改变立方体的所有十个的一次。
是否有可能修改标准着色器,这样,简单地说,
(所以:一个立方体将显示平铺-1,1,一个立方体将显示平铺-1,-1等等......每个立方体不同,虽然都使用相同的材料,只有一种材料存在。)
注意,
(1)它是完全微不足道的生成几个不同版本的材料,每个具有不同的平铺,并随机地选择那些对于每一个立方体的一个。这不是要走的路
(2)注意,如果你改变的材料,这当然使多个副本。你不能有材料成千上万。
解决的办法是具有(一个)着色器,其知道该变化(比如,随机地)偏移,着色器内 - 对每个对象它正在。 (即,在每一个具体的目的的基础上)
这就是我想咨询一下这里。
我注意到,你真的想什么,但着色器来做到这一点。你不能单独着色器做到这一点。这个问题是不能够产生着色器的随机数。这个问题是能够做一次。我还没有找到一种方法,这样做,不认为你可以。
这是应该使用C#侧的代码加以解决的问题。
(1)它是完全微不足道的生成几个不同版本的材料,每个具有不同的平铺,并随机地选择那些对于每一个立方体的一个。这不是要走的路
(2)注意,如果你改变的材料,这当然使多个副本。你不能有材料成千上万。
不是一个问题 - 所有。这是MaterialPropertyBlock
的用途。它允许你修改shader属性,而不产生材料的新实例。
“在要绘制具有相同材料的多个对象,但略有不同的性质的情况下使用它。”
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);
}
随着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);
}
如果这是在比赛中完成一次,它并没有真正意义的脚本附加到每个游戏对象。只要重视它吨至一个空的游戏物体只,找到标签的所有对象,然后运行每一个代码。
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);
}
}
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由于这里的随机性是从世界空间物体的位置来。配料也将打破随机性。
如果你想翻转使用的α= 0的那些对象,并为他人的α= 1。
在着色器的顶点数据写是这样的:
半倒装= 1 -2 * vertex.a;
因此,翻转将是-1或1。
从评论:
但是,请注意每次访问.mesh
,在统一时间,你是一个全新的网格:
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
}
}
}
我将在此为答案,就可以尝试一下,看看它是否适合你。 (如果没有,也许别人会发现这个解决方案有帮助)。平铺可以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)]));
}
}