我是3D代码和编写着色器的新手,所以我可能在这里做一些愚蠢的事情。我正在研究一个简单的Minecraft副本,只是为了学习Unity,我认为最简单的对地面进行纹理处理的方法是使用带有草+尘土纹理的纹理地图集,并使用着色器选择要获取地图集的哪一部分取决于表面法线的纹理。即,对于一个指向上方的立方体表面,将使用草纹理,对于所有其他面孔,将使用污垢纹理。纹理看起来像这样:
在我的着色器中,如果执行以下操作,我将按预期得到每个面上的污垢纹理:
float y = (IN.uv_MainTex.y / 2.0f);
float2 uv = {IN.uv_MainTex.x, y};
fixed4 c = tex2D (_MainTex, uv) * _Color;
o.Albedo = c.rgb;
[如果我使用相同的代码,但始终向y添加0.5f以获得上半部分,即float y = (IN.uv_MainTex.y / 2.0f) + 0.5f;
,则可以按预期获得到处的草纹理:
但是当我尝试基于法线设置y时,即float y = (IN.uv_MainTex.y / 2.0f) + floor(IN.worldNormal.y) * 0.5f;
,我得到了一个奇怪的结果,其中顶面主要是草皮,但部分污垢纹理以对角线显示:
IN.worldNormal
是否正确使用了法线,还是需要将其转换为其他空间?还是我如何使用floor()
的问题?任何建议表示赞赏。
完整的着色器代码:
Shader "Custom/GroundShader"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
float3 worldNormal;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
void surf (Input IN, inout SurfaceOutputStandard o)
{
float y = (IN.uv_MainTex.y / 2.0f) + floor(IN.worldNormal.y) * 0.5f;
float2 uv = {IN.uv_MainTex.x, y};
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, uv) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
在Unity论坛上复制从Namey5获得的答案:
这似乎是一个精度问题(可能来自顶点法线插值)。可能有更聪明的方法可以做到这一点,但是简单的修复方法,您可以仅对正常值添加一点偏差,即;
float y = (IN.uv_MainTex.y / 2.0f) + floor (IN.worldNormal.y + 0.01) * 0.5f;
我将其略微修改为float y = (IN.uv_MainTex.y / 2.0f) + floor (IN.worldNormal.y * 1.1f) * 0.5f;
,这可确保底面也显示出污垢纹理,因为法线将降低到-2而不是-1。
编辑:看起来更好的方法只是使用Mesh.uv
属性而不是使用自定义着色器设置网格的UV。