Shader实现漫反射、高光反射、纹理映射

来源:互联网 发布:黑巧克力 减肥 数据 编辑:程序博客网 时间:2024/05/02 01:19

使用Unity有一段时间了,越来越发现shader的重要性,之前也有一篇文章提了编写shader基本语法

最近重操旧业,准备继续深入学习shader

漫反射效果

漫反射几何计算公式:

Diffuse = 直射光颜色 * max(0,cos夹角(光和法线的夹角) )    Tip:cosθ = 光方向· 法线方向


代码如下:

Shader "LJL/02_DiffuseVert" {Properties {_Color("_Color",Color)=(1,1,1,1)}SubShader {Pass{CGPROGRAM#include "UnityCG.cginc"//_LightColor0 从Unity获取第一个直射光颜色  _WorldSpaceLightPos0  从Unity获取第一个直射光世界位置#include "Lighting.cginc"  #pragma vertex vert#pragma fragment fragstruct a2v{//将Unity模型空间下的顶点位置填充给positionfloat4 position:POSITION ;//将Unity模型空间下的法线填充给normalfloat3 normal:NORMAL;};struct v2f{float4 position:SV_POSITION;fixed3 color:COLOR;}; fixed4 _Color;v2f vert(a2v v){v2f f;f.position = mul(UNITY_MATRIX_MVP,v.position);//获取单位法线向量,并将向量在模型坐标转化为世界位置fixed3  normalDir=normalize(mul(v.normal,(float3x3)_World2Object));//获取世界位置下直射光单位向量(由于是平行光,在世界坐标下和在物体坐标方向一致)fixed3  lightDir=normalize(_WorldSpaceLightPos0.xyz);//漫反射计算公式:直射光颜色*max(cos0,0)  cos0是发现与直射光方向fixed3 diffuse= _LightColor0.rgb * max(dot(normalDir,lightDir),0) * _Color;//获取环境光fixed3 ambient= UNITY_LIGHTMODEL_AMBIENT.rgb;//加上环境光颜色f.color=ambient + diffuse;return f;}fixed4 frag(v2f f):SV_Target{return fixed4 (f.color,1);}ENDCG}}Fallback "Diffuse"}


其效果如下图所示:


但是发现阴影部分和高亮部分过渡的不够平滑,这是如果需要的话可以在片元函数里实现漫反射效果

Shader如下:

Shader "LJL/03_DiffuseFrag" {Properties {_Color("_Color",Color)=(1,1,1,1)}SubShader {Pass {CGPROGRAM#include "UnityCG.cginc"#include "Lighting.cginc"  #pragma vertex vert#pragma fragment frag fixed4 _Color;struct a2v{float4 position:POSITION ;float3 normal:NORMAL;}; struct v2f{float4 position:SV_POSITION;float3 color:COLOR;};v2f vert(a2v v){v2f f;f.position=mul(UNITY_MATRIX_MVP,v.position);f.color=v.normal;return f;}float4 frag(v2f f):SV_Target{float3 normalDir=normalize(mul(f.color,(float3x3)_World2Object));float3 lightDir=normalize(_WorldSpaceLightPos0.xyz);//计算法线float3 diffuse = _LightColor0.rgb*max(dot(normalDir,lightDir),0)*_Color;//获取环境光float3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;return float4(diffuse+ambient,1);}ENDCG}}Fallback "Diffuse"}


效果就更加平滑



高光反射效果

漫反射几何计算公式:
Specular=直射光  * pow( max(cosθ,0),10)  θ:是反射光方向和视野方向的夹角

代码如下:
Shader "LJL/04_SpecularVert" {Properties {_Color("_Color",Color)=(1,1,1,1)_Range ("_Range", Range(0.0, 10.0)) = 2.0}SubShader {Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag #include "Lighting.cginc" float4 _Color;float _Range;struct a2v{float4 position:POSITION ;//将模型空间下的位置坐标填充给positionfloat3 normal:NORMAL ;//将模型空间下的顶点法线填充normal};struct v2f{float4 position:SV_POSITION ;float3 color:COLOR;};v2f vert(a2v v){v2f f;f.position=mul(UNITY_MATRIX_MVP,v.position);float4 vertexPos=mul(v.position,(float4x4)_World2Object);//获取视野方向float3 cameraDir=normalize(_WorldSpaceCameraPos.xyz - vertexPos);//获取灯光方向//float3 lightDir=_WorldSpaceLightPos0.xyz;float3 lightDir = WorldSpaceLightDir(vertexPos);float3 normalDir=normalize(mul(v.normal,(float3x3)_World2Object));//获取反射光位置float3 reflectDir = normalize(reflect(-lightDir,normalDir));float3 specular = _LightColor0.rgb * pow(max(dot(reflectDir,cameraDir),0),_Range) * _Color;float3 diffuse = _LightColor0.rgb * max(dot(lightDir,normalDir),0)*_Color;f.color=specular+UNITY_LIGHTMODEL_AMBIENT.rgb+diffuse;return f;}fixed4 frag(v2f f): SV_Target{return fixed4(f.color,1);}ENDCG}}Fallback "Diffuse"}



效果图如下:


纹理映射效果

映射原理:
在顶点函数中取得在顶点对应的纹理坐标,在片元函数中获取该纹理左边的像素颜色值并与漫反射融合,赋给SV_Target

代码如下:
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'Shader "LJL/Texture" {Properties {_Color("_Color",Color)=(1,1,1,1)_MainTex("_MainTex",2D)="white"{}}SubShader {Pass{CGPROGRAM#include "UnityCG.cginc" #include "Lighting.cginc" #pragma vertex vert#pragma fragment frag sampler2D _MainTex;float4 _MainTex_ST;//固定写法,用于获取纹理的缩放大小和偏移大小fixed4 _Color;struct a2v{//从语义里获取的值都是在模型坐标float4 position:POSITION ;//将顶点位置填充给positionfloat3 normal:NORMAL ;//将模型的法线填充给normalfloat4 texcoord:TEXCOORD0 ; //将该顶点的纹理坐标位置填充给texcoord}; struct v2f{float4 position:SV_POSITION ;//屏幕位置float3 wordNormal:COLOR0;//存储世界坐标下的法线方向float4 wordPosition:TEXCOORD0 ; //存储在世界坐标下的顶点位置float2 uv:TEXCOORD1 ; }; v2f vert(a2v v){v2f f;f.position=mul(UNITY_MATRIX_MVP,v.position);f.wordPosition=mul(v.position,(float4x4)unity_WorldToObject);//转化为世界坐标f.wordNormal=mul(v.normal,(float3x3)unity_WorldToObject);//同上//获取纹理坐标f.uv=v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;return f;}float4 frag(v2f f):SV_Target{//获取该顶点所对应的纹理uv像素值fixed3 color = tex2D(_MainTex,f.uv)*_Color.rgb;//获取灯光单位方向float3 lightDir=normalize(WorldSpaceLightDir(f.wordPosition));//获取法线单位方向float3 normalDir=normalize(f.wordNormal);//将像素颜色值与漫反射颜色融合float3 diffuse=_LightColor0.rgb*color*max(dot(lightDir,normalDir),0);//加上环境光渲染float3 tempColor=diffuse+color*UNITY_LIGHTMODEL_AMBIENT.rgb;return fixed4(tempColor,1);}ENDCG}}Fallback "Diffuse"}


最终成功映射纹理同时支持纹理的缩放和偏移,效果图如下:



阅读全文
0 0