Shader 边缘发光、变灰、高亮着色器

//转自omuying

变灰:

Shader "Custom/GreyShader" 
{
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Lambert

		sampler2D _MainTex;

		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			c = float4(Luminance(c)); //设置灰度值
			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}
		ENDCG
	} 
	FallBack "Diffuse"
}
LightShader.shader(外发光效果):

Shader "Custom/LightShader" 
{
	Properties {
		_RimColor ("Rim Color", Color) = (1,1,1,0.5)
		_InnerColor ("Inner Color", Color) = (1,1,1,0.5)
		_InnerColorPower ("Inner Color Power", Range(0.0,1.0)) = 0.5
		_RimPower ("Rim Power", Range(0.0,5.0)) = 2.5
		_AlphaPower ("Alpha Rim Power", Range(0.0,8.0)) = 4.0
		_AllPower ("All Power", Range(0.0, 10.0)) = 1.0
	}
	SubShader {
		Tags { "Queue" = "Transparent" }

		CGPROGRAM
		#pragma surface surf Lambert alpha
		struct Input {
		float3 viewDir;
		INTERNAL_DATA
		};
		float4 _RimColor;
		float _RimPower;
		float _AlphaPower;
		float _AlphaMin;
		float _InnerColorPower;
		float _AllPower;
		float4 _InnerColor;
		void surf (Input IN, inout SurfaceOutput o) {
		half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
		o.Emission = _RimColor.rgb * pow (rim, _RimPower)*_AllPower+(_InnerColor.rgb*2*_InnerColorPower);
		o.Alpha = (pow (rim, _AlphaPower))*_AllPower;
		}
		ENDCG
	}
	Fallback "VertexLit"
} 

核心代码是half rim = 1.0 - saturate(dot (normalize(IN.viewDir),o.Normal));

//saturate:returns 0 if x is less than 0; returns 1 if x is greater than 1; returns x otherwise 

//saturate for float scalars could be implemented like this 

//float saturate(float x){

//return max(0,min(1,x));

//}

//视线方向与法向量夹角为90度时,正好用来模拟侧光的强度

    o.Emission=_RimColor.rgb*pow(rim,_RimPower);

//将rim值用一个pow函数进行放大,强化边缘发亮的效果



LightShader1.shader(外发光效果):

Shader "Custom/LightShader1" 
{
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _Color ("Main Color", Color) = (1,1,1,1)
        _RimColor ("Rim Color", Color) = (1, 1, 1, 1)
        _RimWidth ("Rim Width", Float) = 0.7
    }
    SubShader {
        Pass {
       		Lighting Off
            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "UnityCG.cginc"

                struct appdata 
                {
                    float4 vertex : POSITION;
                    float3 normal : NORMAL;
                    float2 texcoord : TEXCOORD0;
                };

                struct v2f 
                {
                    float4 pos : SV_POSITION;
                    float2 uv : TEXCOORD0;
                    fixed3 color : COLOR;
                };

                uniform float4 _MainTex_ST;
                uniform fixed4 _RimColor;
                float _RimWidth;

                v2f vert (appdata_base v) {
                    v2f o;
                    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

                    float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));
                    float dotProduct = 1 - dot(v.normal, viewDir);
                   
                    o.color = smoothstep(1 - _RimWidth, 1.0, dotProduct);
                    o.color *= _RimColor;

                    o.uv = v.texcoord.xy;
                    return o;
                }

                uniform sampler2D _MainTex;
                uniform fixed4 _Color;

                fixed4 frag(v2f i) : COLOR {
                    fixed4 texcol = tex2D(_MainTex, i.uv);
                    texcol *= _Color;
                    texcol.rgb += i.color;
                    return texcol;
                }
            ENDCG
        }
    }
}
OutlineShader.shader(边缘发光效果):

Shader "Custom/OutlineShader" 
{
	Properties {
		_Color ("Main Color", Color) = (1,1,1,1)
		_OutlineColor ("Outline Color", Color) = (1,1,1,1)
		_Outline ("Outline width", Range (0.0, 0.03)) = .005
		_MainTex ("Base (RGB)", 2D) = "white" { }
	}
 
CGINCLUDE
#include "UnityCG.cginc"
 
struct appdata {
	float4 vertex : POSITION;
	float3 normal : NORMAL;
};
 
struct v2f {
	float4 pos : POSITION;
	float4 color : COLOR;
};
 
uniform float _Outline;
uniform float4 _OutlineColor;
 
v2f vert(appdata v) {
	// just make a copy of incoming vertex data but scaled according to normal direction
	v2f o;
	o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
 
	float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
	float2 offset = TransformViewToProjection(norm.xy);
 
	o.pos.xy += offset * o.pos.z * _Outline;
	o.color = _OutlineColor;
	return o;
}
ENDCG
 
	SubShader {
		Tags { "Queue" = "Transparent" }
 
		// note that a vertex shader is specified here but its using the one above
		Pass {
			Name "OUTLINE"
			Tags { "LightMode" = "Always" }
			Cull Off
			ZWrite Off
			ZTest Always
			ColorMask RGB // alpha not used
 
			// you can choose what kind of blending mode you want for the outline
			Blend SrcAlpha OneMinusSrcAlpha // Normal
			//Blend One One // Additive
			//Blend One OneMinusDstColor // Soft Additive
			//Blend DstColor Zero // Multiplicative
			//Blend DstColor SrcColor // 2x Multiplicative
 
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
 
half4 frag(v2f i) :COLOR {
	return i.color;
}
ENDCG
		}
 
		Pass {
			Name "BASE"
			ZWrite On
			ZTest LEqual
			Blend SrcAlpha OneMinusSrcAlpha
			Material {
				Diffuse [_Color]
				Ambient [_Color]
			}
			Lighting On
			SetTexture [_MainTex] {
				ConstantColor [_Color]
				Combine texture * constant
			}
			SetTexture [_MainTex] {
				Combine previous * primary DOUBLE
			}
		}
	}
 
	SubShader {
		Tags { "Queue" = "Transparent" }
 
		Pass {
			Name "OUTLINE"
			Tags { "LightMode" = "Always" }
			Cull Front
			ZWrite Off
			ZTest Always
			ColorMask RGB
 
			// you can choose what kind of blending mode you want for the outline
			Blend SrcAlpha OneMinusSrcAlpha // Normal
			//Blend One One // Additive
			//Blend One OneMinusDstColor // Soft Additive
			//Blend DstColor Zero // Multiplicative
			//Blend DstColor SrcColor // 2x Multiplicative
 
			CGPROGRAM
			#pragma vertex vert
			#pragma exclude_renderers gles xbox360 ps3
			ENDCG
			SetTexture [_MainTex] { combine primary }
		}
 
		Pass {
			Name "BASE"
			ZWrite On
			ZTest LEqual
			Blend SrcAlpha OneMinusSrcAlpha
			Material {
				Diffuse [_Color]
				Ambient [_Color]
			}
			Lighting On
			SetTexture [_MainTex] {
				ConstantColor [_Color]
				Combine texture * constant
			}
			SetTexture [_MainTex] {
				Combine previous * primary DOUBLE
			}
		}
	}
 
	Fallback "Diffuse"
}
OutlineShader1.shader(边缘发光效果):

Shader "Custom/OutlineShader1" {
	Properties {
		_Color ("Main Color", Color) = (1,1,1,1)
		_OutlineColor ("Outline Color", Color) = (1,1,1,1)
		_Outline ("Outline width", Range (0.0, 0.03)) = .005
		_MainTex ("Base (RGB)", 2D) = "white" { }
		_BumpMap ("Bumpmap", 2D) = "bump" {}
	}
 
CGINCLUDE
#include "UnityCG.cginc"
 
struct appdata {
	float4 vertex : POSITION;
	float3 normal : NORMAL;
};
 
struct v2f {
	float4 pos : POSITION;
	float4 color : COLOR;
};
 
uniform float _Outline;
uniform float4 _OutlineColor;
 
v2f vert(appdata v) {
	// just make a copy of incoming vertex data but scaled according to normal direction
	v2f o;
	o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
 
	float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
	float2 offset = TransformViewToProjection(norm.xy);
 
	o.pos.xy += offset * o.pos.z * _Outline;
	o.color = _OutlineColor;
	return o;
}
ENDCG
 
	SubShader {
		Tags { "Queue" = "Transparent" }
 
		// note that a vertex shader is specified here but its using the one above
		Pass {
			Name "OUTLINE"
			Tags { "LightMode" = "Always" }
			Cull Off
			ZWrite Off
			ZTest Always
 
			// you can choose what kind of blending mode you want for the outline
			Blend SrcAlpha OneMinusSrcAlpha // Normal
			//Blend One One // Additive
			//Blend One OneMinusDstColor // Soft Additive
			//Blend DstColor Zero // Multiplicative
			//Blend DstColor SrcColor // 2x Multiplicative
 
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
 
half4 frag(v2f i) : COLOR {
	return i.color;
}
ENDCG
		}
 
 
CGPROGRAM
#pragma surface surf Lambert
struct Input {
	float2 uv_MainTex;
	float2 uv_BumpMap;
};
sampler2D _MainTex;
sampler2D _BumpMap;
uniform float3 _Color;
void surf(Input IN, inout SurfaceOutput o) {
	o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * _Color;
	o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
ENDCG
 
	}
 
	SubShader {
		Tags { "Queue" = "Transparent" }
 
		Pass {
			Name "OUTLINE"
			Tags { "LightMode" = "Always" }
			Cull Front
			ZWrite Off
			ZTest Always
			Offset 15,15
 
			// you can choose what kind of blending mode you want for the outline
			Blend SrcAlpha OneMinusSrcAlpha // Normal
			//Blend One One // Additive
			//Blend One OneMinusDstColor // Soft Additive
			//Blend DstColor Zero // Multiplicative
			//Blend DstColor SrcColor // 2x Multiplicative
 
			CGPROGRAM
			#pragma vertex vert
			#pragma exclude_renderers gles xbox360 ps3
			ENDCG
			SetTexture [_MainTex] { combine primary }
		}
 
CGPROGRAM
#pragma surface surf Lambert
struct Input {
	float2 uv_MainTex;
	float2 uv_BumpMap;
};
sampler2D _MainTex;
sampler2D _BumpMap;
uniform float3 _Color;
void surf(Input IN, inout SurfaceOutput o) {
	o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * _Color;
	o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
ENDCG
 
	}
 
	Fallback "Outlined/Silhouetted Diffuse"
}
OutlineShader2.shader(边缘发光效果):

Shader "Custom/OutlineShader2" {
	Properties {
		_OutlineColor ("Outline Color", Color) = (1,1,1,1)
		_Outline ("Outline width", Range (0.0, 0.03)) = .005
	}
 
CGINCLUDE
#include "UnityCG.cginc"
 
struct appdata {
	float4 vertex : POSITION;
	float3 normal : NORMAL;
};
 
struct v2f {
	float4 pos : POSITION;
	float4 color : COLOR;
};
 
uniform float _Outline;
uniform float4 _OutlineColor;
 
v2f vert(appdata v) {
	// just make a copy of incoming vertex data but scaled according to normal direction
	v2f o;
	o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
 
	float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
	float2 offset = TransformViewToProjection(norm.xy);
 
	o.pos.xy += offset * o.pos.z * _Outline;
	o.color = _OutlineColor;
	return o;
}
ENDCG
 
	SubShader {
		Tags { "Queue" = "Transparent" }
 
		Pass {
			Name "BASE"
			Cull Back
			Blend Zero One
 
			// uncomment this to hide inner details:
			//Offset -8, -8
 
			SetTexture [_OutlineColor] {
				ConstantColor (0,0,0,0)
				Combine constant
			}
		}
 
		// note that a vertex shader is specified here but its using the one above
		Pass {
			Name "OUTLINE"
			Tags { "LightMode" = "Always" }
			Cull Front
 
			// you can choose what kind of blending mode you want for the outline
			//Blend SrcAlpha OneMinusSrcAlpha // Normal
			//Blend One One // Additive
			Blend One OneMinusDstColor // Soft Additive
			//Blend DstColor Zero // Multiplicative
			//Blend DstColor SrcColor // 2x Multiplicative
 
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
 
half4 frag(v2f i) :COLOR {
	return i.color;
}
ENDCG
		}
 
 
	}
 
	Fallback "Diffuse"
}
然后我把这些着色器封装了一下,取名 MaterialController.cs,主要代码如下:然后我把这些着色器封装了一下,取名 MaterialController.cs,主要代码如下:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class MaterialController
{
	private static string GRAY_SHADER_PATH = "Custom/GreyShader";
	private static string GRAY_MATERIAL_NAME = "GreyMaterial";

	private static string LIGHT_SHADER_PATH_1 = "Custom/LightShader";
	private static string LIGHT_SHADER_PATH_2 = "Custom/LightShader1";
	private static string LIGHT_MATERIAL_NAME = "LightMaterial";
	
	private static string OUTLINE_SHADER_PATH_1 = "Custom/OutlineShader";
	private static string OUTLINE_SHADER_PATH_2 = "Custom/OutlineShader1";
	private static string OUTLINE_SHADER_PATH_3 = "Custom/OutlineShader2";
	private static string OUTLINE_MATERIAL_NAME = "OutlineMaterial";

	/// <summary>
	/// 设置灰度材质
	/// </summary>
	/// <param name="renderer">Renderer.</param>
	/// <param name="hashtable">Hashtable.</param>
	public static void SetGrayMaterial(Renderer renderer, Hashtable shaderParams = null)
	{
		if (renderer == null) return;

		SetMaterial (renderer, Shader.Find (GRAY_SHADER_PATH), GRAY_MATERIAL_NAME, shaderParams);
	}

	/// <summary>
	/// 取消设置灰度材质
	/// </summary>
	/// <returns><c>true</c> if cancel set gray material the specified renderer; otherwise, <c>false</c>.</returns>
	/// <param name="renderer">Renderer.</param>
	public static void CancelSetGrayMaterial(Renderer renderer)
	{
		if (renderer == null) return;

		CancelSetMaterial (renderer, GRAY_MATERIAL_NAME);
	}

	/// <summary>
	/// 设置发光材质
	/// </summary>
	/// <param name="renderer">Renderer.</param>
	/// <param name="materialIndex">Material index.</param>
	/// <param name="shaderParams">Shader parameters.</param>
	public static void SetLightMaterial(Renderer renderer, int materialIndex = 1, Hashtable shaderParams = null)
	{
		if (renderer == null) return;

		string shaderName = LIGHT_SHADER_PATH_1;
		if (materialIndex == 2) shaderName = LIGHT_SHADER_PATH_2;
		
		SetMaterial (renderer, Shader.Find (shaderName), LIGHT_MATERIAL_NAME, shaderParams);
	}
	
	/// <summary>
	/// 取消设置发光材质
	/// </summary>
	/// <returns><c>true</c> if cancel set gray material the specified renderer; otherwise, <c>false</c>.</returns>
	/// <param name="renderer">Renderer.</param>
	public static void CancelSetLightMaterial(Renderer renderer)
	{
		if (renderer == null) return;
		
		CancelSetMaterial (renderer, LIGHT_MATERIAL_NAME);
	}
	
	/// <summary>
	/// 设置边缘发光材质
	/// </summary>
	/// <param name="renderer">Renderer.</param>
	/// <param name="materialIndex">Material index.</param>
	/// <param name="shaderParams">Shader parameters.</param>
	public static void SetOutlineMaterial(Renderer renderer, int materialIndex = 1, Hashtable shaderParams = null)
	{
		if (renderer == null) return;

		string shaderName = OUTLINE_SHADER_PATH_1;
		if (materialIndex == 2) shaderName = OUTLINE_SHADER_PATH_2;
		if (materialIndex == 3) shaderName = OUTLINE_SHADER_PATH_3;

		SetMaterial (renderer, Shader.Find (shaderName), OUTLINE_MATERIAL_NAME, shaderParams);
	}
	
	/// <summary>
	/// 取消设置边缘发光材质
	/// </summary>
	/// <returns><c>true</c> if cancel set gray material the specified renderer; otherwise, <c>false</c>.</returns>
	/// <param name="renderer">Renderer.</param>
	public static void CancelSetOutlineMaterial(Renderer renderer)
	{
		if (renderer == null) return;
		
		CancelSetMaterial (renderer, OUTLINE_MATERIAL_NAME);
	}

	/// <summary>
	/// 添加材质
	/// </summary>
	/// <param name="renderer">Renderer.</param>
	/// <param name="shader">Shader.</param>
	/// <param name="materialName">Material name.</param>
	/// <param name="shaderParams">Shader parameters.</param>
	public static void SetMaterial(Renderer renderer, Shader shader, string materialName, Hashtable shaderParams)
	{
		if (renderer == null || shader == null || string.IsNullOrEmpty(materialName)) return;

		if (GetMaterial (renderer, materialName) == null) 
		{
			Material[] sharedMaterials = renderer.sharedMaterials;
			int materialLength = sharedMaterials.Length;
			
			Material[] materialList = new Material[materialLength * 2];
			for (int index = 0; index < materialLength; index ++) 
			{
				materialList[index] = sharedMaterials[index];
				Material material = new Material(shader);
				material.name = materialName;

				if(material.HasProperty("_MainTex"))
				{
					if(shaderParams != null && shaderParams.ContainsKey("_MainTex"))
					{
						material.SetTexture("_MainTex", (Texture)shaderParams["_MainTex"]);
					}else{
						if(sharedMaterials[index].HasProperty("_MainTex"))
						{
							Texture mainTexture = sharedMaterials[index].GetTexture("_MainTex");
							if(mainTexture != null) material.SetTexture("_MainTex", mainTexture);
						}
					}
				}
				
				if(material.HasProperty("_BumpMap"))
				{
					if(shaderParams != null && shaderParams.ContainsKey("_BumpMap"))
					{
						material.SetTexture("_BumpMap", (Texture)shaderParams["_BumpMap"]);
					}else{
						if(sharedMaterials[index].HasProperty("_BumpMap"))
						{
							Texture bumpMap = sharedMaterials[index].GetTexture("_BumpMap");
							if(bumpMap != null) material.SetTexture("_BumpMap", bumpMap);
						}
					}
				}

				if(shaderParams != null)
				{
					foreach (DictionaryEntry dictionaryEntry in shaderParams)
					{
						if(material.HasProperty(dictionaryEntry.Key.ToString()))
						{
							if(dictionaryEntry.Value.GetType() == typeof(float))
							{
								material.SetFloat(dictionaryEntry.Key.ToString(), (float)dictionaryEntry.Value);
							}
							else if(dictionaryEntry.Value.GetType() == typeof(Color))
							{
								material.SetColor(dictionaryEntry.Key.ToString(), (Color)dictionaryEntry.Value);
							}
						}
					}
				}

				materialList[index + materialLength] = material;
			}
			renderer.sharedMaterials = materialList;
		}
	}

	/// <summary>
	/// 移除材质
	/// </summary>
	/// <returns><c>true</c> if cancel set material the specified renderer materialName; otherwise, <c>false</c>.</returns>
	/// <param name="renderer">Renderer.</param>
	/// <param name="materialName">Material name.</param>
	public static void CancelSetMaterial(Renderer renderer, string materialName)
	{
		if (renderer == null || string.IsNullOrEmpty(materialName)) return;
		
		if (GetMaterial (renderer, materialName)) 
		{
			IList<Material> sharedMaterials = new List<Material>();
			foreach(Material material in renderer.sharedMaterials)
			{
				if(material.name != materialName)
				{
					sharedMaterials.Add(material);
				}
			}
			int materialLength = sharedMaterials.Count;

			Material[] materialList = new Material[materialLength];
			for(int index = 0; index < materialLength; index ++)
			{
				materialList[index] = sharedMaterials[index];
			}
			renderer.sharedMaterials = materialList;
		}
	}


	/// <summary>
	/// 获取材质
	/// </summary>
	/// <returns>The material.</returns>
	/// <param name="renderer">Renderer.</param>
	/// <param name="grayMaterialName">Gray material name.</param>
	private static Material GetMaterial(Renderer renderer, string materialName)
	{
		Material[] materialList = renderer.sharedMaterials;
		if (materialList == null || materialList.Length == 0) return null;

		foreach (Material material in materialList) 
		{
			if(material.name == materialName) return material;
		}

		return null;
	}
}
然后新建立一个 C# 类,取名 RoleController.cs,主要代码如下:

using UnityEngine;
using System.Collections;

public class RoleController : MonoBehaviour 
{
	private SkinnedMeshRenderer skinnedMeshRenderer;

	private bool shiftStatus;

	void Awake()
	{
		skinnedMeshRenderer = this.GetComponentInChildren<SkinnedMeshRenderer> ();
	}

	void Update()
	{
		this.shiftStatus = false;

		if (Input.GetKey (KeyCode.LeftShift)) 
		{
			this.shiftStatus = true;
		}

		if(Input.GetMouseButtonDown(0) && !shiftStatus)
		{
			if(this.skinnedMeshRenderer == null) return;
			// 设置灰度材质
			MaterialController.SetGrayMaterial(skinnedMeshRenderer);
		}

		if(Input.GetMouseButtonUp(0) && !shiftStatus)
		{
			if(this.skinnedMeshRenderer == null) return;
			// 取消设置灰度材质
			MaterialController.CancelSetGrayMaterial(skinnedMeshRenderer);
		}

		if (Input.GetMouseButtonDown (1)) 
		{
			if(this.skinnedMeshRenderer == null) return;
			// 设置发光材质

			Hashtable shaderParams = new Hashtable();
			shaderParams.Add("_InnerColor", Color.yellow);
			shaderParams.Add("_RimColor", Color.yellow);
			shaderParams.Add("_InnerColorPower", 0.9f);
			shaderParams.Add("_RimPower", 4f);

			MaterialController.SetLightMaterial(skinnedMeshRenderer, Random.Range(1, 3), shaderParams);
		}
		
		if (Input.GetMouseButtonUp (1)) 
		{
			if(this.skinnedMeshRenderer == null) return;
			// 取消设置发光材质
			MaterialController.CancelSetLightMaterial(skinnedMeshRenderer);
		}
		
		if (Input.GetMouseButtonDown (0) && shiftStatus) 
		{
			if(this.skinnedMeshRenderer == null) return;
			// 设置边缘材质
			MaterialController.SetOutlineMaterial(skinnedMeshRenderer, Random.Range(1, 4));
		}
		
		if (Input.GetMouseButtonUp (0) && shiftStatus) 
		{
			if(this.skinnedMeshRenderer == null) return;
			// 取消设置边缘材质
			MaterialController.CancelSetOutlineMaterial(skinnedMeshRenderer);
		}
	}
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值