在2张贴图之间褪色转换的shader

本文介绍了一个Unity Shader实例,用于混合两种纹理。通过调整MixValue参数,可以实现两种纹理之间的平滑过渡。文章提供了完整的Shader代码,并探讨了如何通过代码动态调整MixValue。
Shader "VrorangeShaders/MixTexture" {
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
_Texture0 ("Texture0 (RGB)", 2D) = "white" {}
_Texture1 ("Texture1 (RGB)", 2D) = "white" {}
_MixValue ("MixValue (Range)",Range(0,1)) = 0.5
}
SubShader {
Cull Back
ZWrite On
ZTest LEqual
Tags {"Queue"="Geometry+0" "IgnoreProjector"="False" "RenderType"="Opaque" }
CGPROGRAM
#pragma surface surf Lambert

float4 _Color;
sampler2D _Texture0;
sampler2D _Texture1;
float _MixValue;

struct Input {
float2 uv_Texture0;
float2 uv_Texture1;
};

void surf (Input IN, inout SurfaceOutput o){
half4 c0=tex2D (_Texture0, IN.uv_Texture0);
half4 c1=tex2D (_Texture1, IN.uv_Texture1);
c0=c0*_MixValue;
c1=c1*(1-_MixValue);
o.Albedo=(c0+c1)*_Color;
}

ENDCG
}
FallBack "Diffuse"
}

效果图如下(就是改变我圈住的那个MinValue(Range)的这个值。用代码动态改变我不会,还望知道的指点下,谢谢了....)

 

<think>我们之前已经实现了基于模型坐标的单色渐变,现在用户的需求是使用两贴图(Texture)沿着模型坐标进行渐变混合。这意味着我们需要在模型的不同位置(比如沿着某个轴)将两贴图进行混合,混合因子由模型坐标决定。 实现思路: 1. 在属性中定义两贴图(_MainTex和_SecondTex)以及它们各自的颜色(如果需要可以调整颜色,也可以直接使用贴图颜色)。 2. 仍然使用一个轴(_Axis)来控制渐变方向,以及最小最大位置(_MinPos, _MaxPos)控制渐变范围。 3. 在片元着色器中,计算模型坐标在指定轴上的投影位置,并归一化到0-1的范围作为混合因子(lerpFactor)。 4. 使用lerpFactor对两贴图进行线性插值混合。 注意:我们需要对贴图进行采样,因此需要传递UV坐标。如果两贴图使用同一套UV,我们可以只传递一个UV;如果不同,则需要分别设置(这里我们假设使用同一套UV)。 修改后的Shader代码: ```hlsl Shader "Custom/ModelSpaceGradient_Textures" { Properties { _MainTex ("Texture A", 2D) = "white" {} _SecondTex ("Texture B", 2D) = "white" {} _Axis ("Gradient Axis", Vector) = (0,1,0,0) // 渐变方向轴 _MinPos ("Min Position", Float) = -1 // 渐变起点坐标 _MaxPos ("Max Position", Float) = 1 // 渐变终点坐标 // 可选:如果需要单独调整颜色,可以添加两个颜色属性 _ColorA ("Color A", Color) = (1,1,1,1) _ColorB ("Color B", Color) = (1,1,1,1) } SubShader { Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" } LOD 100 Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; // 第一套UV }; struct Varyings { float4 positionHCS : SV_POSITION; float3 positionOS : TEXCOORD0; // 模型空间坐标 float2 uv : TEXCOORD1; // UV坐标 }; CBUFFER_START(UnityPerMaterial) sampler2D _MainTex; sampler2D _SecondTex; float4 _MainTex_ST; // 为了支持UV的平铺和偏移 float4 _SecondTex_ST; // 如果两贴图使用不同的平铺偏移,需要分别设置 float3 _Axis; float _MinPos; float _MaxPos; half4 _ColorA; half4 _ColorB; CBUFFER_END Varyings vert (Attributes IN) { Varyings OUT; OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz); OUT.positionOS = IN.positionOS.xyz; // 应用UV变换(平铺和偏移) OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex); // 注意:如果两贴图的平铺偏移不同,那么我们需要传递两套UV,这里我们假设使用相同的变换 return OUT; } half4 frag (Varyings IN) : SV_Target { // 计算沿指定轴的投影位置 float posAlongAxis = dot(IN.positionOS, normalize(_Axis)); // 归一化坐标到0-1范围 float normalizedPos = saturate((posAlongAxis - _MinPos) / (_MaxPos - _MinPos)); // 采样两贴图 half4 texA = tex2D(_MainTex, IN.uv) * _ColorA; half4 texB = tex2D(_SecondTex, IN.uv) * _ColorB; // 使用归一化位置混合两贴图 half4 finalColor = lerp(texA, texB, normalizedPos); return finalColor; } ENDHLSL } } } ``` ### 说明 1. **贴图采样**:我们使用同一套UV(经过_MainTex的平铺偏移变换)来采样两贴图。如果希望两贴图使用不同的UV变换,可以复制UV变换代码,并为第二贴图使用_SecondTex_ST进行变换。 2. **颜色调整**:我们添加了_ColorA和_ColorB,用于分别调整两贴图颜色。如果不需要调整颜色,可以将这两个颜色设置为白色(1,1,1,1)。 3. **混合因子**:与之前的单色渐变相同,我们根据模型坐标在指定轴上的投影位置计算混合因子(normalizedPos),然后用它在片元着色器中对两贴图进行混合。 ### 使用示例 1. 创建一个材质,使用这个Shader2. 为_MainTex和_SecondTex分别赋予贴图。 3. 设置_Axis(例如(0,1,0)表示沿Y轴渐变)。 4. 设置_MinPos和_MaxPos(例如模型底部为0,顶部为2,则设置_MinPos=0, _MaxPos=2)。 5. 调整_ColorA和_ColorB(如果需要调整贴图的色调)。 ### 性能考虑 1. 这个Shader采样了两贴图,如果贴图尺寸较大,可能会增加带宽消耗。 2. 在移动平台上,可以考虑将两贴图合并到一贴图的不同通道(例如RGBA两个通道分别存储两贴图),然后通过一次采样获取两个颜色值,再混合。但这样会增加美术制作的复杂度。 ### 相关问题 1. 如何实现三贴图以上的渐变混合? 2. 如何根据模型的世界坐标(而不是模型坐标)进行渐变? 3. 如何实现非线性的渐变(比如使用曲线控制混合)?[^1] 4. 在Shader Graph中如何实现模型坐标渐变混合贴图?[^1] [^1]: Shader Graph提供了Time、Step、Remap等节点方便实现复杂效果。 </think># 双贴图沿模型坐标渐变的Shader实现 下面我将提供一个在URP中实现两贴图沿着模型坐标渐变的Shader解决方案,这种方法可以让两纹理在模型表面自然过渡,形成独特的视觉效果。 ## URP双贴图坐标渐变Shader ```hlsl Shader "Custom/DualTextureModelSpaceGradient" { Properties { _MainTex ("Texture A", 2D) = "white" {} _SecondTex ("Texture B", 2D) = "white" {} _Axis ("Gradient Axis", Vector) = (0,1,0,0) // 渐变方向轴 _MinPos ("Min Position", Float) = -1 // 渐变起点坐标 _MaxPos ("Max Position", Float) = 1 // 渐变终点坐标 _BlendThreshold ("Blend Threshold", Range(0,1)) = 0.5 // 混合阈值 _BlendStrength ("Blend Strength", Range(0,1)) = 0.5 // 混合强度 } SubShader { Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" } LOD 100 Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; // UV坐标用于采样贴图 }; struct Varyings { float4 positionHCS : SV_POSITION; float3 positionOS : TEXCOORD0; // 模型空间坐标 float2 uv : TEXCOORD1; // UV坐标 }; CBUFFER_START(UnityPerMaterial) sampler2D _MainTex; float4 _MainTex_ST; sampler2D _SecondTex; float4 _SecondTex_ST; float3 _Axis; float _MinPos; float _MaxPos; float _BlendThreshold; float _BlendStrength; CBUFFER_END Varyings vert (Attributes IN) { Varyings OUT; OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz); OUT.positionOS = IN.positionOS.xyz; OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex); // 应用纹理平铺和偏移[^1] return OUT; } half4 frag (Varyings IN) : SV_Target { // 计算沿指定轴的投影位置 float posAlongAxis = dot(IN.positionOS, normalize(_Axis)); // 归一化坐标到0-1范围 float normalizedPos = saturate((posAlongAxis - _MinPos) / (_MaxPos - _MinPos)); // 采样两贴图 half4 texA = tex2D(_MainTex, IN.uv); half4 texB = tex2D(_SecondTex, IN.uv); // 基于模型坐标的渐变混合 float blendFactor = smoothstep( _BlendThreshold - _BlendStrength, _BlendThreshold + _BlendStrength, normalizedPos); // 线性插值生成渐变纹理 half4 finalColor = lerp(texA, texB, blendFactor); return finalColor; } ENDHLSL } } } ``` ## 关键实现说明 1. **双纹理采样**: - 顶点着色器传递UV坐标 - 片元着色器使用`tex2D`函数分别采样两贴图 2. **渐变混合控制**: - 混合因子计算:$ \text{blendFactor} = \text{smoothstep}(t - s, t + s, p) $ - 其中:$ t $ = `_BlendThreshold`, $ s $ = `_BlendStrength`, $ p $ = `normalizedPos` 3. **平滑过渡**: - `smoothstep`函数创建平滑过渡效果 - 避免混合区域的硬边现象[^1] ## 使用示例 1. 材质参数设置: ```yaml _MainTex: 岩石纹理 _SecondTex: 草地纹理 _Axis: (0,1,0) // Y轴渐变 _MinPos: 0 // 模型底部开始 _MaxPos: 2 // 高度2米处结束 _BlendThreshold: 0.3 // 渐变开始位置 _BlendStrength: 0.2 // 渐变过渡范围 ``` 2. 效果:模型底部显示岩石纹理,中部平滑过渡到草地纹理 ## 性能优化建议 1. **纹理压缩**: - 使用ASTC或ETC2压缩格式减少内存占用 - 确保纹理尺寸合理(通常不超过2048×2048) 2. **混合优化**: ```hlsl // 使用step函数实现硬边过渡(性能更好) float blendFactor = step(_BlendThreshold, normalizedPos); ``` 3. **坐标计算优化**: ```hlsl // 预计算归一化参数 float _RangeRecip = 1.0 / (_MaxPos - _MinPos); // 然后使用 float normalizedPos = saturate((posAlongAxis - _MinPos) * _RangeRecip); ``` ## 替代实现方法 ### 使用Shader Graph实现 在Shader Graph中也可以通过以下节点实现类似效果: 1. **Position节点** - 获取模型位置 2. **Dot Product节点** - 计算沿指定轴的投影 3. **Remap节点** - 将位置值映射到0-1范围[^1] 4. **Lerp节点** - 混合两贴图 5. **Smoothstep节点** - 控制平滑过渡 ### 脚本控制渐变参数 可以使用C#脚本动态控制渐变参数: ```csharp using UnityEngine; public class GradientController : MonoBehaviour { public Material material; public Vector3 gradientAxis = Vector3.up; public float minPos = 0; public float maxPos = 2; void Update() { if(material != null) { material.SetVector("_Axis", gradientAxis); material.SetFloat("_MinPos", minPos); material.SetFloat("_MaxPos", maxPos); } } } ``` ## 应用场景 这种技术特别适合: - 地形中的海拔渐变(雪线、植被分布) - 角色装备的材质过渡 - 科幻场景中的能量扩散效果 - 季节变化的环境过渡 ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值