Unity Shader 01 鼠标点击模型着色

更新1.0

我发现原来的解决方法好蠢。。。于是就来更新一下解决思路以及代码

思路:

  1. 不变
  2. 不变
  3. 在片元着色器中更改符合条件的片元颜色

实现效果:

Unity Shader 01 鼠标点击模型着色_第1张图片

shader源码

fixed4 frag(v2f i) : SV_Target{
	fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
	float3 worldNormal = normalize(i.worldNormal);
				
	fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
	fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));

	fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
	fixed3 halfDir = normalize(viewDir + worldLightDir);
	fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss);
	fixed3 color = ambient + diffuse + specular;
	//以上部分只是常规计算
	//下面部分是模型颜色更改
	//得到顶点坐标与点击的顶点坐标向量
	fixed3 distanceVec = i.worldPos - _ClickWorldPos;
	//得到向量模的平方
	float distance = dot(distanceVec, distanceVec);
				
	//对符合条件的顶点着色
	if (distance * 100 < _DistanceScale) {
		fixed3 color1 = fixed3(0, 0.5, 0);
		color *= color1;
	}

	return fixed4(color, 1.0);
}

其实只是将原来的逻辑放到片元着色器中实现,刚学shader不久,忘了可以在片元着色器中得到片元的世界坐标了2333

以下为原帖

描述:

鼠标点击模型,模型表面的指定(顶点)区域会进行着色,采用逐顶点着色

思路:

  1. 鼠标点击后得到模型点击位置在世界坐标系中的坐标
  2. 将坐标传入到 shader 中
  3. 用这个坐标在 shader 的顶点着色器中更改符合条件的顶点颜色

实现效果:

Unity Shader 01 鼠标点击模型着色_第2张图片

shader代码:

Shader "WorkShader/ChangeModelColor/Version1.0" {
	Properties{
		_Diffuse("Diffuse", Color) = (1, 1, 1, 1)
		_Specular("Specular", Color) = (1, 1, 1, 1)
		_Gloss("Gloss", Range(8.0, 256)) = 20
		_DistanceScale("DistanceScale", Range(0, 300)) = 160
	}
	SubShader{
		Pass{
			Tags{ "LightMode" = "ForwardBase" }
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"

			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;
			float _DistanceScale;
			//用于接收脚本中传递的模型世界坐标
			float3 _ClickWorldPos;

			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};

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

			v2f vert(a2v v) {
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);

				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
				fixed3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));

				fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - worldPos.xyz);
				fixed3 halfDir = normalize(viewDir + worldLightDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss);
				o.color = ambient + diffuse + specular;
				//以上部分只是常规计算
				//下面部分是模型颜色更改
				//得到顶点坐标与点击的顶点坐标向量
				fixed3 distanceVec = worldPos - _ClickWorldPos;
				//得到向量模的平方
				float distance = dot(distanceVec, distanceVec);
				//对符合条件的顶点着色
				if (distance < 0.01f * _DistanceScale) {
					o.color = fixed3(0.5, 0, 0);
				}
				return o;
			}

			fixed4 frag(v2f i) : SV_Target{
				return fixed4(i.color, 1.0);
			}
		ENDCG
		}
	}
}

//.cs 中关键部分
Vector4 temp = Vector4.positiveInfinity;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
    {
        print(temp);
    }
if (Input.GetMouseButton(0))
    {
        //向 shader 中的 “_ClickWorldPos” 传值
        mat.SetVector("_ClickWorldPos", temp);
    }

注意:

如果发现 Physics.Raycast() 不工作,很可能是模型中没有添加 mesh collider, 这个是 mesh collider 的方法

问题:

  1. 如果距离限制设置不合适,很可能出现当前只对左侧顶点着色,但是鼠标稍微移动后即对左侧顶点着色,又对右侧顶点着色的现象。
  2. 能否在片元着色中对着色进一步控制以消除锯齿感

 

 

你可能感兴趣的:(Unity,Shader)