Este exemplo demonstra como integrar diferentes componentes de iluminação em um único shader de fragmento. O shader calcula a luz ambiente, reflexão difusa, brilho especular e até quatro luzes pontuais simultaneamente.
Shader "Tutorial/FragmentoIluminacao" {
properties
{
_DiffuseTint("Cor Difusa",color)=(1,1,1,1)
_HighlightColor("Cor Especular",color)=(1,1,1,1)
_HighlightPower("Potência Especular",range(1,32))=8
}
Subshader
{
pass{
tags{"LightMode"="Forwardbase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
#include "lighting.cginc"
float4 _DiffuseTint;
float4 _HighlightColor;
float _HighlightPower;
struct Interpolators
{
float4 clipPos:POSITION;
float3 worldNormal:TEXCOORD1;
float3 objPos:COLOR;
};
Interpolators vert(appdata_base v)
{
Interpolators o;
o.clipPos=UnityObjectToClipPos(v.vertex);
o.worldNormal=v.normal;
o.objPos=v.vertex;
return o;
}
float4 frag(Interpolators IN):COLOR
{
//Luz ambiente global
fixed4 finalColor=UNITY_LIGHTMODEL_AMBIENT;
//Componente difusa - produto escalar entre normal e direção da luz
float3 normalWorld=UnityObjectToWorldNormal(IN.worldNormal);
float3 lightDir=normalize(WorldSpaceLightDir(IN.objPos));
float diffuseFactor=saturate(dot(normalWorld,lightDir));
finalColor+=_LightColor0*_DiffuseTint*diffuseFactor;
//Componente especular - reflexão da luz
float3 viewDir=normalize(WorldSpaceViewDir(IN.objPos));
float3 reflectionDir=2*dot(normalWorld,lightDir)*normalWorld-lightDir;
float specularFactor=saturate(dot(reflectionDir,viewDir));
finalColor+=_HighlightColor*pow(specularFactor,_HighlightPower);
//Contribuição das luzes pontuais
float3 worldPosition=mul(unity_ObjectToWorld,IN.objPos).xyz;
finalColor.rgb+=Shade4PointLights
(
unity_4LightPosX0,unity_4LightPosY0,unity_4LightPosZ0,
unity_LightColor[0].rgb,unity_LightColor[1].rgb,unity_LightColor[2].rgb,unity_LightColor[3].rgb,
unity_4LightAtten0,
worldPosition,normalWorld
);
return finalColor;
}
ENDCG
}
}
}
- Suporte a Sombras Projetadas
Para habilitar sombras em um shader personalizado, uma abordagem prática é utilizar o fallback para o shader padrão Diffuse, que já implementa a geração de sombras para luzes direcionais e pontuais.
Shader "Tutorial/FragmentoComSombras" {
properties
{
_DiffuseTint("Cor Difusa",color)=(1,1,1,1)
_HighlightColor("Cor Especular",color)=(1,1,1,1)
_HighlightPower("Potência Especular",range(1,32))=8
}
Subshader
{
pass{
tags{"LightMode"="Forwardbase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
#include "lighting.cginc"
float4 _DiffuseTint;
float4 _HighlightColor;
float _HighlightPower;
struct Interpolators
{
float4 clipPos:POSITION;
float3 worldNormal:TEXCOORD1;
float3 objPos:COLOR;
};
Interpolators vert(appdata_base v)
{
Interpolators o;
o.clipPos=UnityObjectToClipPos(v.vertex);
o.worldNormal=v.normal;
o.objPos=v.vertex;
return o;
}
float4 frag(Interpolators IN):COLOR
{
fixed4 finalColor=UNITY_LIGHTMODEL_AMBIENT;
float3 normalWorld=UnityObjectToWorldNormal(IN.worldNormal);
float3 lightDir=normalize(WorldSpaceLightDir(IN.objPos));
float diffuseFactor=saturate(dot(normalWorld,lightDir));
finalColor+=_LightColor0*_DiffuseTint*diffuseFactor;
float3 viewDir=normalize(WorldSpaceViewDir(IN.objPos));
float3 reflectionDir=2*dot(normalWorld,lightDir)*normalWorld-lightDir;
float specularFactor=saturate(dot(reflectionDir,viewDir));
finalColor+=_HighlightColor*pow(specularFactor,_HighlightPower);
float3 worldPosition=mul(unity_ObjectToWorld,IN.objPos).xyz;
finalColor.rgb+=Shade4PointLights
(
unity_4LightPosX0,unity_4LightPosY0,unity_4LightPosZ0,
unity_LightColor[0].rgb,unity_LightColor[1].rgb,unity_LightColor[2].rgb,unity_LightColor[3].rgb,
unity_4LightAtten0,
worldPosition,normalWorld
);
return finalColor;
}
ENDCG
}
}
//O fallback para Diffuse permite sombras tanto de luzes direcionais quanto pontuais
fallback "Diffuse"
}
- Efeito de Transparência Baseado em Ângulo de Visão
Este shader produz um efeito de transparência que varia conforme a orientação da superfície em relação à câmera. Áreas que apontam diretamente para o observador ficam opacas, enquanto as bordas se tornam translúcidas.
Subshader
{
Tags{"Queue"="Transparent"}
pass{
blend srcAlpha oneMinusSrcAlpha
zwrite off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
float _Intensity;
struct Interpolators
{
float4 clipPos:POSITION;
float3 surfNormal:TEXCOORD0;
float3 surfPos:TEXCOORD1;
};
Interpolators vert(appdata_base v)
{
Interpolators o;
o.clipPos=UnityObjectToClipPos(v.vertex);
o.surfNormal=v.normal;
o.surfPos=v.vertex;
return o;
}
float4 frag(Interpolators IN):COLOR
{
float3 n=UnityObjectToWorldNormal(IN.surfNormal);
float3 v=UnityWorldSpaceViewDir(IN.surfPos);
float rimFactor=1.0-saturate(dot(n,v));
rimFactor=pow(rimFactor,_Intensity);
return fixed4(1,1,1,1)*rimFactor;
}
ENDCG
}
}
}
- Contorno Estilizado com Multiplas Passagens
Esta técnica utiliza três passagens de renderização para criar um contorno visível ao redor do objeto. A primeira passagem expande os vértices ao longo das normais e desenha o contorno, a segunda limpa o buffer alfa, e a terceira renderiza a superfície principal.
Shader "Tutorial/ContornoEstilizado" {
properties
{
_SurfaceColor("Cor da Superfície",color)=(1,1,1,1)
_EdgeIntensity("Intensidade da Borda",range(1,8))=2
_ExpandAmount("Expansão do Contorno",range(0,1))=0.2
}
Subshader
{
Tags{"Queue"="Transparent"}
//Passagem 1: Desenha o contorno expandido
pass{
blend srcAlpha oneMinusSrcAlpha
zwrite off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
float4 _SurfaceColor;
float _EdgeIntensity;
float _ExpandAmount;
struct Interpolators
{
float4 clipPos:POSITION;
float3 surfNormal:TEXCOORD0;
float3 surfPos:TEXCOORD1;
};
Interpolators vert(appdata_base v)
{
v.vertex.xyz+=v.normal*_ExpandAmount;
Interpolators o;
o.clipPos=UnityObjectToClipPos(v.vertex);
o.surfNormal=v.normal;
o.surfPos=v.vertex;
return o;
}
float4 frag(Interpolators IN):COLOR
{
float3 n=UnityObjectToWorldNormal(IN.surfNormal);
float3 v=UnityWorldSpaceViewDir(IN.surfPos);
float edge=saturate(dot(n,v));
edge=pow(edge,_EdgeIntensity);
_SurfaceColor.a*=edge;
return _SurfaceColor;
}
ENDCG
}
//Passagem 2: Limpa o canal alfa
pass{
blendop revsub
blend dstalpha one
zwrite off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
struct Interpolators
{
float4 clipPos:POSITION;
};
Interpolators vert(appdata_base v)
{
Interpolators o;
o.clipPos=UnityObjectToClipPos(v.vertex);
return o;
}
float4 frag(Interpolators IN):COLOR
{
return fixed4(1,1,1,1);
}
ENDCG
}
//Passagem 3: Renderiza a superfície interna
pass{
blend srcAlpha oneMinusSrcAlpha
zwrite off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
float _EdgeIntensity;
struct Interpolators
{
float4 clipPos:POSITION;
float3 surfNormal:TEXCOORD0;
float3 surfPos:TEXCOORD1;
};
Interpolators vert(appdata_base v)
{
Interpolators o;
o.clipPos=UnityObjectToClipPos(v.vertex);
o.surfNormal=v.normal;
o.surfPos=v.vertex;
return o;
}
float4 frag(Interpolators IN):COLOR
{
float3 n=UnityObjectToWorldNormal(IN.surfNormal);
float3 v=UnityWorldSpaceViewDir(IN.surfPos);
float rim=saturate(dot(n,v));
rim=pow(rim,_EdgeIntensity);
return fixed4(1,1,1,1)*rim;
}
ENDCG
}
}
}
- Mapeamento de Textura com Lightmap
Este shader combina uma textura albedo com uma lightmap pré-calculada. As coordenadas UV são transformadas utilizando as variáveis de escala e deslocamento (_ST) para que as propiredades Tiling e Offset do Inspector funcionem corretamente.
Shader "Tutorial/TexturaComLightmap" {
Properties {
_AlbedoMap ("Textura Base", 2D) = "white" {}
}
SubShader {
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
sampler2D _AlbedoMap;
float4 _AlbedoMap_ST;
struct Interpolators{
float4 clipPos:POSITION;
float2 baseUV:TEXCOORD0;
float2 lightmapUV:TEXCOORD1;
};
Interpolators vert(appdata_full v)
{
Interpolators o;
o.clipPos=UnityObjectToClipPos(v.vertex);
o.baseUV=TRANSFORM_TEX(v.texcoord,_AlbedoMap);
o.lightmapUV=v.texcoord1.xy*unity_LightmapST.xy+unity_LightmapST.zw;
return o;
}
fixed4 frag(Interpolators IN):COLOR
{
float3 illumination=DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap,IN.lightmapUV));
fixed4 surfaceColor=tex2D(_AlbedoMap,IN.baseUV);
surfaceColor.rgb*=illumination;
return surfaceColor;
}
ENDCG
}
}
}
- Efeito de Ondulação na Textura
Este shader aplica distorções nas coordenadas UV para criar efeitos visuais como ondulações de água ou ondas concêntricas. A deformação é animada utilizando o tempo global do shader (_Time.y).
Shader "Tutorial/EfeitoOndulacao" {
Properties {
_BaseTexture ("Textura Base", 2D) = "white" {}
_Frequency("Frequência",range(1,30))=10
_Amplitude("Amplitude",range(0,0.1))=0.01
_Radius("Raio",range(0,1))=0
}
SubShader {
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
sampler2D _BaseTexture;
float4 _BaseTexture_ST;
float _Frequency;
float _Amplitude;
float _Radius;
struct Interpolators{
float4 clipPos:POSITION;
float2 texUV:TEXCOORD0;
};
Interpolators vert(appdata_full v)
{
Interpolators o;
o.clipPos=UnityObjectToClipPos(v.vertex);
o.texUV=TRANSFORM_TEX(v.texcoord,_BaseTexture);
return o;
}
fixed4 frag(Interpolators IN):COLOR
{
float2 currentUV=IN.texUV;
float distFromCenter=distance(currentUV,float2(0.5,0.5));
float waveOffset=0;
float adjustedAmp=_Amplitude*saturate(1-distFromCenter/_Radius);
waveOffset=adjustedAmp*sin(-distFromCenter*3.14*_Frequency+_Time.y);
currentUV=currentUV+currentUV*waveOffset;
fixed4 result=tex2D(_BaseTexture,currentUV);
return result;
}
ENDCG
}
}
}
- Desfoque por Distância (Mipmap Controlado por Derivadas)
Este shader utiliza derivadas parciais (ddx e ddy) para controlar o nível de mipmap aplicado à textura. Superfícies voltadas diretamente para a câmera aparecem nítidas, enquanto superfícies anguladas ou distentes recebem um desfoque natural.
Shader "Tutorial/DesfoqueDistancia" {
Properties {
_BaseTexture ("Textura Base", 2D) = "white" {}
}
SubShader {
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
#pragma target 3.0
sampler2D _BaseTexture;
float4 _BaseTexture_ST;
struct Interpolators{
float4 clipPos:POSITION;
float2 texUV:TEXCOORD0;
float depthZ:TEXCOORD1;
};
Interpolators vert(appdata_full v)
{
Interpolators o;
o.clipPos=UnityObjectToClipPos(v.vertex);
o.texUV=TRANSFORM_TEX(v.texcoord,_BaseTexture);
o.depthZ=mul(unity_ObjectToWorld,v.vertex).z;
return o;
}
fixed4 frag(Interpolators IN):COLOR
{
float2 gradX=ddx(IN.depthZ)*10;
float2 gradY=ddy(IN.depthZ)*10;
fixed4 sampledColor=tex2D(_BaseTexture,IN.texUV,gradX,gradY);
return sampledColor;
}
ENDCG
}
}
}