Permukaan Shader dan jalur rendering
Model pencahayaan khusus di Permukaan Shaders

Contoh Shader permukaan

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.

Kompatibilitas pipa Render

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

sederhana naungan contoh

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:

Texture

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"
  }

Pemetaan normal

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"
  }

Pencahayaan Rim

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"
  }

Detail Tekstur

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

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:

Catalog

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:

Slices melalui Posisi Ruang Dunia

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"
  }

Ekstrusi normal dengan pengubah Vertex

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:

Data kustom computed per-vertex

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.

Pengubah Warna Akhir

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"
  }

Fog kustom dengan pengubah warna akhir

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"
  }

Fog

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

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
    }
}
Permukaan Shader dan jalur rendering
Model pencahayaan khusus di Permukaan Shaders