Contoh Permukaan ShaderCara merampingkan naungan menulis untuk Pipeline Render Built-in. More info
Lihat di Glossary pada halaman ini menunjukkan cara menggunakan model pencahayaan built-in. Sebagai contoh tentang cara menerapkan model pencahayaan kustom, lihat Contoh Pencahayaan Shader Permukaan.
Di Pipelne Render Built-in, Surface ShadersProgram yang berjalan di GPU. More info
Lihat di Glossary adalah cara merampingkan naungan menulis yang berinteraksi dengan pencahayaan.
Feature name | Built-in Render PipelineA series of operations that take the contents of a Scene, and displays them on a screen. Unity lets you choose from pre-built render pipelines, or write your own. More info See in Glossary |
Universal Render Pipeline (URP) | High Definition Render Pipeline (HDRP) | Custom SRP |
---|---|---|---|---|
Surface Shaders | Yes | No Untuk cara merampingkan menciptakan benda-benda Shader di URP, lihat Shader Graph. |
No Untuk cara ramping menciptakan benda-benda Shader di HDRP, lihat Shader Graph. |
No |
Kita akan mulai dengan Shader yang sangat sederhana dan membangunnya. Ini adalah Shader yang mengatur warna permukaan untuk "putih". Ini menggunakan model pencahayaan Lambert built-in.
Shader "Example/Diffuse Simple" {
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : COLOR;
};
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = 1;
}
ENDCG
}
Fallback "Diffuse"
}
Berikut ini bagaimana terlihat seperti pada model dengan dua setelan Lights:
Objek all-white cukup membosankan, jadi mari tambahkan Tekstur. Kami akan menambahkan blok Properties ke Shader, jadi kami mendapatkan pemilih Tekstur dalam Bahan kami.
Shader "Example/Diffuse Texture" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
Mari kita tambahkan beberapa pemetaan normal:
Shader "Example/Diffuse Bump" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_BumpMap ("Bumpmap", 2D) = "bump" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
};
sampler2D _MainTex;
sampler2D _BumpMap;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
}
ENDCG
}
Fallback "Diffuse"
}
Sekarang, coba tambahkan beberapa Rim Lighting untuk menyoroti tepi GameObjectObjek mendasar dalam adegan Unity, yang dapat mewakili karakter, props, pemandangan, kamera, waypoints, dan banyak lagi. Fungsi GameObject didefinisikan oleh Komponen yang melekat padanya. More info
Lihat di Glossary. Kami akan menambahkan beberapa cahaya yang diizinkan berdasarkan sudut antara permukaan normal dan sudut pandang. Untuk itu, kami akan menggunakan variabel permukaan Shader built-in.viewDir
Surface Shader variable.
Shader "Example/Rim" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_BumpMap ("Bumpmap", 2D) = "bump" {}
_RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)
_RimPower ("Rim Power", Range(0.5,8.0)) = 3.0
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
float3 viewDir;
};
sampler2D _MainTex;
sampler2D _BumpMap;
float4 _RimColor;
float _RimPower;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
o.Emission = _RimColor.rgb * pow (rim, _RimPower);
}
ENDCG
}
Fallback "Diffuse"
}
Untuk efek yang berbeda, mari tambahkan Tekstur Detail yang dikombinasikan dengan Tekstur dasar. Tekstur Detail biasanya menggunakan UV yang sama tetapi Tiling yang berbeda dalam Bahan, sehingga kita perlu menggunakan masukan yang berbeda koordinasi UV.
Shader "Example/Detail" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_BumpMap ("Bumpmap", 2D) = "bump" {}
_Detail ("Detail", 2D) = "gray" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
float2 uv_Detail;
};
sampler2D _MainTex;
sampler2D _BumpMap;
sampler2D _Detail;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
o.Albedo *= tex2D (_Detail, IN.uv_Detail).rgb * 2;
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
}
ENDCG
}
Fallback "Diffuse"
}
Menggunakan checker Tekstur tidak selalu membuat rasa praktis, tetapi dalam contoh ini digunakan untuk menggambarkan apa yang terjadi:
Tekstur Detail di ruang layar tidak membuat rasa praktis untuk model kepala tentara, tetapi di sini digunakan untuk menggambarkan bagaimana input screenPos
built-in mungkin digunakan:
Shader "Example/ScreenPos" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_Detail ("Detail", 2D) = "gray" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float4 screenPos;
};
sampler2D _MainTex;
sampler2D _Detail;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
float2 screenUV = IN.screenPos.xy / IN.screenPos.w;
screenUV *= float2(8,6);
o.Albedo *= tex2D (_Detail, screenUV).rgb * 2;
}
ENDCG
}
Fallback "Diffuse"
}
Pemetaan normal telah dihapus dari Shader di atas, hanya untuk membuatnya lebih pendek:
Ini adalah seorang Shader yang melakukan refleksi cubemapped menggunakan input worldRefl
bawaan. Hal ini sangat mirip dengan built-in Reflective/Diffuse Shader:
Shader "Example/WorldRefl" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_Cube ("Cubemap", CUBE) = "" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float3 worldRefl;
};
sampler2D _MainTex;
samplerCUBE _Cube;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb * 0.5;
o.Emission = texCUBE (_Cube, IN.worldRefl).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
Karena itu menetapkan warna refleksi sebagai Emission, kita mendapatkan prajurit yang sangat mengkilap:
Jika Anda ingin melakukan refleksi yang dipengaruhi oleh normal mapsJenis tekstur Peta Bump yang memungkinkan Anda untuk menambahkan detail permukaan seperti benjolan, alur, dan goresan ke model yang menangkap cahaya seolah-olah mereka diwakili oleh geometri nyata.
Lihat di Glossary, perlu sedikit lebih terlibat: INTERNAL_DATA
perlu ditambahkan ke struktur Input
, dan fungsi WorldReflectionVector
digunakan untuk menghitung vektor refleksi per-pixel setelah Anda telah menulis output normal.
Shader "Example/WorldRefl Normalmap" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_BumpMap ("Bumpmap", 2D) = "bump" {}
_Cube ("Cubemap", CUBE) = "" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
float3 worldRefl;
INTERNAL_DATA
};
sampler2D _MainTex;
sampler2D _BumpMap;
samplerCUBE _Cube;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb * 0.5;
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
o.Emission = texCUBE (_Cube, WorldReflectionVector (IN, o.Normal)).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
Ini adalah tentara shiny maped normal:
Berikut adalah Shader yang “slices” GameObject dengan membuang pixelsUnit terkecil dalam gambar komputer. Ukuran piksel tergantung pada resolusi layar Anda. Pencahayaan pixel dihitung pada setiap piksel layar. More info
Lihat di Glossary dalam cincin hampir horisontal. Hal ini dilakukan dengan menggunakan fungsi clip()
Cg / HLSL berdasarkan posisi dunia pixel. Kita akan menggunakan variabel permukaan Shader built-in.worldPos
Surface Shader variable.
Shader "Example/Slices" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_BumpMap ("Bumpmap", 2D) = "bump" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
Cull Off
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
float3 worldPos;
};
sampler2D _MainTex;
sampler2D _BumpMap;
void surf (Input IN, inout SurfaceOutput o) {
clip (frac((IN.worldPos.y+IN.worldPos.z*0.1) * 5) - 0.5);
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
}
ENDCG
}
Fallback "Diffuse"
}
Hal ini dimungkinkan untuk menggunakan fungsi “vertex modifier” yang akan mengubah data simpul masuk dalam vertex ShaderProgram yang berjalan pada setiap simpul model 3D ketika model sedang diberikan. More info
Lihat di Glossary. Ini dapat digunakan untuk hal-hal seperti animasi prosedural dan ekstrusi sepanjang normal. Permukaan Shader kompilasi directive vertex:functionName
digunakan untuk itu, dengan fungsi yang mengambil parameter inout appdata_full
.
Berikut adalah Shader yang bergerak vertices sepanjang normal mereka dengan jumlah yang ditentukan dalam Bahan:
Shader "Example/Normal Extrusion" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_Amount ("Extrusion Amount", Range(-1,1)) = 0.5
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert vertex:vert
struct Input {
float2 uv_MainTex;
};
float _Amount;
void vert (inout appdata_full v) {
v.vertex.xyz += v.normal * _Amount;
}
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
Bergerak vertices sepanjang normal mereka membuat tentara lemak:
Menggunakan fungsi pengubah simpul, juga dimungkinkan untuk mengimbangi data kustom di Shader simpul, yang kemudian akan dilewatkan ke fungsi Shader Permukaan per-piksel. kompilasi yang sama directive vertex:functionName
digunakan, tetapi fungsi harus mengambil dua parameter: inout appdata_full
dan out Input
. Anda dapat mengisi setiap anggota Input yang bukan nilai bawaan di sana.
Sitemap Sitemap Anggota input yang digunakan dalam cara ini tidak harus memiliki nama dimulai dengan 'uv' atau mereka tidak akan bekerja dengan benar.Note: Custom Input members used in this way must not have names beginning with ‘uv’ or they won’t work properly.
Contoh di bawah ini mendefinisikan anggota float3 customColor
kustom, yang dihitung dalam fungsi simpul:
Shader "Example/Custom Vertex Data" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert vertex:vert
struct Input {
float2 uv_MainTex;
float3 customColor;
};
void vert (inout appdata_full v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input,o);
o.customColor = abs(v.normal);
}
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
o.Albedo *= IN.customColor;
}
ENDCG
}
Fallback "Diffuse"
}
Dalam contoh ini customColor
diatur ke nilai absolut normal:
Penggunaan yang lebih praktis bisa mengkomputasikan data per-vertex yang tidak disediakan oleh variabel input bawaan; atau mengoptimalkan komputasi Shader. Misalnya, dimungkinkan untuk mengimbangi pencahayaan Rim di simpul GameObject, alih-alih melakukan itu di permukaan Shader per-pixel.
Hal ini dimungkinkan untuk menggunakan fungsi pengubah warna akhir yang akan mengubah warna akhir yang dihitung oleh Shader. Permukaan Shader kompilasi directive finalcolor:functionName
digunakan untuk ini, dengan fungsi yang mengambil parameter Input IN, SurfaceOutput o, inout fixed4 color
.
Ini adalah Shader sederhana yang menerapkan warna akhir. Ini berbeda dari hanya menerapkan warna tint ke permukaan Albedo: kaleng ini juga akan mempengaruhi warna yang berasal dari LightmapsTekstur pra-render yang mengandung efek sumber cahaya pada objek statis di tempat kejadian. Lightmaps dilalui atas geometri adegan untuk menciptakan efek pencahayaan. More info
Lihat di Glossary, Light Probesprobe cahaya menyimpan informasi tentang bagaimana cahaya melewati ruang di tempat kejadian Anda. Koleksi probe cahaya yang diatur dalam ruang tertentu dapat meningkatkan pencahayaan pada objek bergerak dan pemandangan LOD statis dalam ruang itu. More info
Lihat di Glossary dan sumber ekstra serupa.
Shader "Example/Tint Final Color" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_ColorTint ("Tint", Color) = (1.0, 0.6, 0.6, 1.0)
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert finalcolor:mycolor
struct Input {
float2 uv_MainTex;
};
fixed4 _ColorTint;
void mycolor (Input IN, SurfaceOutput o, inout fixed4 color)
{
color *= _ColorTint;
}
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
Kasus umum untuk menggunakan pengubah warna akhir (lihat di atas) akan menerapkan Fog sepenuhnya kustom di forward renderingSebuah jalur rendering yang membuat setiap objek dalam satu atau lebih melewati, tergantung pada lampu yang mempengaruhi objek. Lampu sendiri juga diperlakukan berbeda dengan Rendering Maju, tergantung pada pengaturan dan intensitas mereka. More info
Lihat di Glossary. Fog perlu mempengaruhi akhir computed pixel Shader warna, yang persis apa modifier finalcolor
.
Ini adalah Shader yang menerapkan kaleng kabut berdasarkan jarak dari pusat layar. Ini menggabungkan modifier vertex dengan data vertex kustom (fog
) dan pengubah warna akhir. Ketika digunakan dalam lanjutan rendering aditif lulus, Fog perlu memudar ke hitam. Contoh ini menangani dan melakukan cek untuk UNITY_PASS_FORWARDADD
.
Shader "Example/Fog via Final Color" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_FogColor ("Fog Color", Color) = (0.3, 0.4, 0.7, 1.0)
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert finalcolor:mycolor vertex:myvert
struct Input {
float2 uv_MainTex;
half fog;
};
void myvert (inout appdata_full v, out Input data)
{
UNITY_INITIALIZE_OUTPUT(Input,data);
float4 hpos = UnityObjectToClipPos(v.vertex);
hpos.xy/=hpos.w;
data.fog = min (1, dot (hpos.xy, hpos.xy)*0.5);
}
fixed4 _FogColor;
void mycolor (Input IN, SurfaceOutput o, inout fixed4 color)
{
fixed3 fogColor = _FogColor.rgb;
#ifdef UNITY_PASS_FORWARDADD
fogColor = 0;
#endif
color.rgb = lerp (color.rgb, fogColor, IN.fog);
}
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
Shader "Example/Linear Fog" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert finalcolor:mycolor vertex:myvert
#pragma multi_compile_fog
sampler2D _MainTex;
uniform half4 unity_FogStart;
uniform half4 unity_FogEnd;
struct Input {
float2 uv_MainTex;
half fog;
};
void myvert (inout appdata_full v, out Input data) {
UNITY_INITIALIZE_OUTPUT(Input,data);
float pos = length(UnityObjectToViewPos(v.vertex).xyz);
float diff = unity_FogEnd.x - unity_FogStart.x;
float invDiff = 1.0f / diff;
data.fog = clamp ((unity_FogEnd.x - pos) * invDiff, 0.0, 1.0);
}
void mycolor (Input IN, SurfaceOutput o, inout fixed4 color) {
#ifdef UNITY_PASS_FORWARDADD
UNITY_APPLY_FOG_COLOR(IN.fog, color, float4(0,0,0,0));
#else
UNITY_APPLY_FOG_COLOR(IN.fog, color, unity_FogColor);
#endif
}
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
Decals umumnya digunakan untuk menambahkan rincian ke Bahan pada waktu lari (misalnya, dampak peluru). Mereka sangat berguna dalam rendering yang rusak, karena mereka mengubah GBuffer sebelum menyala, karena itu menghemat kinerja.
Dalam skenario yang khas, Decals harus diberikan setelah benda buram dan tidak boleh kasir bayangan, seperti yang terlihat pada "Tags" di contoh di bawah ini.ShaderLabBahasa Unity untuk mendefinisikan struktur benda-benda Shader. More info
Lihat di Glossary “Tags” in the example below.
Shader "Example/Decal" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry+1" "ForceNoShadowCasting"="True" }
LOD 200
Offset -1, -1
CGPROGRAM
#pragma surface surf Lambert decal:blend
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
}