一、前面心情
1.公司我的架构发生变动,从技术中心到项目组了,但不管怎么样,该看的还要看,总会用到
二、实现
三、参考:
http://blog.csdn.net/cubesky/article/details/38588723
四、代码和关键流程
1.使用surface shader实现:
首先:viewDir:世界坐标系下,vertex为起点,Camera为终点的向量,即Camera到vertex的反向量。
Shader "Custom/outLineTest" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _OutLineColor("outLineColor",Color)=(1.0,0.0,0.0,1.0) _threshold("outLine threshold ",Range(0.0,1.0))=0.21 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; float4 _OutLineColor; float _threshold; struct Input { float2 uv_MainTex; float3 worldNormal; float3 viewDir; }; void surf (Input IN, inout SurfaceOutput o) { half4 c = tex2D (_MainTex, IN.uv_MainTex); float angleF=dot(normalize(IN.worldNormal),normalize(IN.viewDir));//求dot是否很小,如果很小,则说明normal和viewDir为90度,达到边缘。 o.Emission =_OutLineColor.rgb*step(angleF,_threshold); o.Albedo = c.rgb; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
2.vs ps实现:
当Camera位置变化时,cs文件传递pos到shader中去:
cs绑定到球体上:
using UnityEngine; using System.Collections; public class cameraCoordTest : MonoBehaviour { // Use this for initialization public GameObject camer; const float cameraSpeed = 10.0f; Vector4 SetTempV() { Vector4 tempV = Vector4.zero; tempV.x = camer.transform.position.x; tempV.y = camer.transform.position.y; tempV.z = camer.transform.position.z; tempV.w = 1; return tempV; } // Update is called once per frame void Update () { if (Input.GetKey(KeyCode.W)) { camer.transform.Translate(Vector3.forward * Time.deltaTime * cameraSpeed); transform.renderer.material.SetVector("_camPos", SetTempV()); } else if (Input.GetKey(KeyCode.S)) { camer.transform.Translate(Vector3.forward * Time.deltaTime * -cameraSpeed); transform.renderer.material.SetVector("_camPos", SetTempV()); } else if (Input.GetKey(KeyCode.A)) { camer.transform.Translate(Vector3.left * Time.deltaTime * cameraSpeed); transform.renderer.material.SetVector("_camPos", SetTempV()); } else if(Input.GetKey(KeyCode.D)) { camer.transform.Translate(Vector3.left * Time.deltaTime * -cameraSpeed); transform.renderer.material.SetVector("_camPos", SetTempV()); } } }
shader中,把surface修改为vs ps实现方式:
Shader "Custom/outLineTest" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _threshold("outLine threshold ",Range(0.0,1.0))=0.1 _camPos("cam pos",Vector)=(0,0,-10.0,1.0) } SubShader{ Pass{ Fog{Mode Off} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" uniform float _threshold; uniform float4 _camPos; struct v2f1{ float4 pos :SV_POSITION; float3 norm : TEXCOORD1; float3 verToViewDir : TEXCOORD2; }; v2f1 vert(appdata_base inV) { v2f1 o; o.pos = mul(UNITY_MATRIX_MVP,inV.vertex); o.norm = mul ((float3x3)_Object2World, inV.normal);//normal转化到世界坐标系下 o.verToViewDir = normalize(_camPos.xyz-mul(_Object2World,inV.vertex).xyz); return o; } float4 frag(v2f1 inV):SV_Target { float4 reColor; reColor.a = 1.0f; float angleF=dot(normalize(inV.norm),normalize(inV.verToViewDir)); reColor.rgb=float3(0,0,0)+float3(1,1,1)*step(angleF,0.3); return reColor; } ENDCG } } Fallback off }
五、下一步
这种方式对平滑曲面有效,当立方体或非渐变的法线物体,此法无效,比如说plane,由于背面没有normal,无法获取
以前轮廓边检测生成阴影时,可以通过GS来判断邻边,判断line是否是轮廓边。作为以后学习内容吧。
六:注意点:
1.appdata_base 类中全是本地坐标系下的数据,需要转化到worldSpace下,所以,normal需要进行object2World的转化;
2.为了达到surface中viewDir数据,需要Camera的pos和vertex的pos进行处理,
3.如果写好surface实现,vs ps写不好,参考surface编译后的代码,仔细看,总会写好vs ps实现