当前位置:   article > 正文

unity表面着色器_Unity 3技术–表面着色器

lighting_coords(3,4)

unity表面着色器

In Unity you can write your own custom shaders, but it’s no secret that writing them is hard, especially when you need shaders that interact with per-pixel lights & shadows. In Unity 3, that would be even harder because in addition to all the old stuff, your shaders would have to support the new Deferred Lighting renderer. We decided it’s time to make shaders somewhat easier to write.

在Unity中,您可以编写自己的自定义着色器,但是编写它们很困难并不是什么秘密,尤其是当您需要与每像素的灯光和阴影交互的着色器时。 在Unity 3中,这将变得更加困难,因为除了所有旧内容之外,您的着色器还必须支持新的Deferred Lighting渲染器。 我们认为是时候使着色器更容易编写了。

Warning: a technical post ahead with almost no pictures!

警告:前面的技术文章几乎没有图片!

Over a year ago I had a thought that “Shaders must die” (part 1, part 2, part 3). And what do you know – turns out we’re doing this in Unity 3. We call this Surface Shaders cause I’ve a suspicion “shaders must die” as a feature name wouldn’t have flied very far.

一年多以前,我想到了“着色器必须死”( 第1 部分第2 部分第3部分 )。 您所知道的–事实证明,我们正在Unity 3中执行此操作。我们之所以将它称为Surface Shaders,是因为我怀疑“着色器必须死掉”,因为功能名称不会飞得很远。

Idea

理念

The main idea is that 90% of the time I just want to declare surface properties. This is what I want to say:

主要思想是90%的时间我只想声明表面特性。 这就是我想说的:

Hey, albedo comes from this texture mixed with this texture, and normal comes from this normal map. Use Blinn-Phong lighting model please, and don’t bother me again!

嘿,反照率来自此纹理和该纹理的混合,法线来自此法线贴图。 请使用Blinn-Phong照明模型,不要再打扰我了!

With the above, I don’t have to care whether this will be used in a forward or deferred rendering, or how various light types will be handled, or how many lights per pass will be done in a forward renderer, or how some indirect illumination SH probes will come in, etc. I’m not interested in all that! These dirty bits are job of rendering programmers, just make it work dammit!

有了上面的内容,我不必在乎是否将其用于正向或延迟渲染中,或者将如何处理各种灯光类型,或者在正向渲染器中每遍将处理多少灯,或者间接地照明SH探头将插入,等等。我对所有这些都不感兴趣! 这些肮脏的东西是渲染程序员的工作只是使它工作该死

This is not a new idea. Most graphical shader editors that make sense do not have “pixel color” as the final output node; instead they have some node that basically describes surface parameters (diffuse, specularity, normal, …), and all the lighting code is usually not expressed in the shader graph itself. OpenShadingLanguage is a similar idea as well (but because it’s targeted at offline rendering for movies, it’s much richer & more complex).

这不是一个新的想法。 大多数有意义的图形着色器编辑器都不将“像素颜色”作为最​​终输出节点。 取而代之的是,它们具有一些基本上描述表面参数(散射,镜面反射,法线等)的节点,并且通常不在着色器图形本身中表示所有照明代码。 OpenShadingLanguage也是一个类似的想法(但是因为它的目标是电影的离线渲染,所以它更加丰富和复杂)。

Example

Here’s a simple – but full & complete – Unity 3.0 shader that does diffuse lighting with a texture & a normal map.

这是一个简单但完整的Unity 3.0着色器,可以通过纹理和法线贴图进行漫反射照明。

1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  <span style="color:gray">Shader "Example/Diffuse Bump" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _BumpMap ("Bumpmap", 2D) = "bump" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM</span>
      #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));
      }
      <span style="color:gray">ENDCG
    }
    Fallback "Diffuse"
  }</span>

1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   < span style = "color:gray" > Shader "Example/Diffuse Bump" {
     Properties {
       _MainTex ( "Texture" , 2D ) = "white" { }
       _BumpMap ( "Bumpmap" , 2D ) = "bump" { }
     }
     SubShader {
       Tags { "RenderType" = "Opaque" }
       CGPROGRAM < / span >
       #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 ) ) ;
       }
       < span style = "color:gray" > ENDCG
     }
     Fallback "Diffuse"
   } < / span >
Surface Shader: Diffuse Normalmapped

I grayed out bits that are not really interesting (declaration of serialized shader properties & their UI names, shader fallback for older machines etc.). What’s left is Cg/HLSL code, which is then augmented by tons of auto-generated code that deals with lighting & whatnot.

我将不那么有趣的部分变灰(声明序列化着色器属性及其UI名称,旧机器的着色器回退等)。 剩下的就是Cg / HLSL代码,然后再添加大量自动生成的代码来处理照明和其他方面的代码。

This surface shader dissected into pieces:

该表面着色器被分解为以下几部分:

  • #pragma surface surf Lambert: this is a surface shader with main function “surf”, and a Lambert lighting model. Lambert is one of predefined lighting models, but you can write your own.

    #pragma surface surf Lambert :这是具有主要功能“ surf”的表面着色器,并且具有Lambert照明模型。 Lambert是预定义的照明模型之一,但是您可以编写自己的模型。

  • struct Input: input data for the surface shader. This can have various predefined inputs that will be computed per-vertex & passed into your surface function per-pixel. In this case, it’s two texture coordinates.

    struct Input :表面着色器的输入数据。 它可以具有各种预定义的输入,这些输入将按每个顶点计算,并按像素传递到您的曲面函数中。 在这种情况下,它是两个纹理坐标。

  • surf function: actual surface shader code. It takes Input, and writes into SurfaceOutput (a predefined structure). It is possible to write into custom structures, provided you use lighting models that operate on those structures. The actual code just writes Albedo and Normal to the output.

    冲浪功能:实际的表面着色器代码。 它接受Input,然后写入SurfaceOutput (预定义的结构)。 如果您使用在那些结构上运行的照明模型,则可以写入自定义结构。 实际的代码只是将Albedo和Normal写入输出。

What is generated

产生了什么

Unity’s “surface shader code generator” would take this, generate actual vertex & pixel shaders, and compile them to various target platforms. With default settings in Unity 3.0, it would make this shader support:

Unity的“表面着色器代码生成器”将以此为基础,生成实际的顶点和像素着色器,并将其编译为各种目标平台。 使用Unity 3.0中的默认设置,它将支持此着色器:

    For example, here’s code that would be compiled for a forward-rendered base pass with one directional light, 4 per-vertex point lights, 3rd order SH lights; optional lightmaps (I suggest just scrolling down):

    例如,以下代码将针对具有一个方向灯,每个顶点4个点光源,3阶SH光源的正向渲染基本遍进行编译; 可选的光照贴图(我建议您向下滚动)

    1

    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    #pragma vertex vert_surf
    #pragma fragment frag_surf
    #pragma fragmentoption ARB_fog_exp2
    #pragma fragmentoption ARB_precision_hint_fastest
    #pragma multi_compile_fwdbase
    #include "HLSLSupport.cginc"
    #include "UnityCG.cginc"
    #include "Lighting.cginc"
    #include "AutoLight.cginc"
    struct Input {
    float2 uv_MainTex : TEXCOORD0;
    };
    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_MainTex));
    }
    struct v2f_surf {
      V2F_POS_FOG;
      float2 hip_pack0 : TEXCOORD0;
      #ifndef LIGHTMAP_OFF
      float2 hip_lmap : TEXCOORD1;
      #else
      float3 lightDir : TEXCOORD1;
      float3 vlight : TEXCOORD2;
      #endif
      LIGHTING_COORDS(3,4)
    };
    #ifndef LIGHTMAP_OFF
    float4 unity_LightmapST;
    #endif
    float4 _MainTex_ST;
    v2f_surf vert_surf (appdata_full v) {
      v2f_surf o;
      PositionFog( v.vertex, o.pos, o.fog );
      o.hip_pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
      #ifndef LIGHTMAP_OFF
      o.hip_lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
      #endif
      float3 worldN = mul((float3x3)_Object2World, SCALED_NORMAL);
      TANGENT_SPACE_ROTATION;
      #ifdef LIGHTMAP_OFF
      o.lightDir = mul (rotation, ObjSpaceLightDir(v.vertex));
      #endif
      #ifdef LIGHTMAP_OFF
      float3 shlight = ShadeSH9 (float4(worldN,1.0));
      o.vlight = shlight;
      #ifdef VERTEXLIGHT_ON
      float3 worldPos = mul(_Object2World, v.vertex).xyz;
      o.vlight += Shade4PointLights (
        unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
        unity_LightColor0, unity_LightColor1, unity_LightColor2, unity_LightColor3,
        unity_4LightAtten0, worldPos, worldN );
      #endif // VERTEXLIGHT_ON
      #endif // LIGHTMAP_OFF
      TRANSFER_VERTEX_TO_FRAGMENT(o);
      return o;
    }
    #ifndef LIGHTMAP_OFF
    sampler2D unity_Lightmap;
    #endif
    half4 frag_surf (v2f_surf IN) : COLOR {
      Input surfIN;
      surfIN.uv_MainTex = IN.hip_pack0.xy;
      SurfaceOutput o;
      o.Albedo = 0.0;
      o.Emission = 0.0;
      o.Specular = 0.0;
      o.Alpha = 0.0;
      o.Gloss = 0.0;
      surf (surfIN, o);
      half atten = LIGHT_ATTENUATION(IN);
      half4 c;
      #ifdef LIGHTMAP_OFF
      c = LightingLambert (o, IN.lightDir, atten);
      c.rgb += o.Albedo * IN.vlight;
      #else // LIGHTMAP_OFF
      half3 lmFull = DecodeLightmap (tex2D(unity_Lightmap, IN.hip_lmap.xy));
      #ifdef SHADOWS_SCREEN
      c.rgb = o.Albedo * min(lmFull, atten*2);
      #else
      c.rgb = o.Albedo * lmFull;
      #endif
      c.a = o.Alpha;
      #endif // LIGHTMAP_OFF
      return c;
    }

    1

    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    #pragma vertex vert_surf
    #pragma fragment frag_surf
    #pragma fragmentoption ARB_fog_exp2
    #pragma fragmentoption ARB_precision_hint_fastest
    #pragma multi_compile_fwdbase
    #include "HLSLSupport.cginc"
    #include "UnityCG.cginc"
    #include "Lighting.cginc"
    #include "AutoLight.cginc"
    struct Input {
    float2 uv_MainTex : TEXCOORD0 ;
    } ;
    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_MainTex ) ) ;
    }
    struct v2f_surf {
       V2F_POS_FOG ;
       float2 hip_pack0 : TEXCOORD0 ;
       #ifndef LIGHTMAP_OFF
       float2 hip_lmap : TEXCOORD1 ;
       #else
       float3 lightDir : TEXCOORD1 ;
       float3 vlight : TEXCOORD2 ;
       #endif
       LIGHTING_COORDS ( 3 , 4 )
    } ;
    #ifndef LIGHTMAP_OFF
    float4 unity_LightmapST ;
    #endif
    float4 _MainTex_ST ;
    v2f_surf vert_surf ( appdata _ full v ) {
       v2f _ surf o ;
       PositionFog ( v . vertex , o . pos , o . fog ) ;
       o . hip_pack0 . xy = TRANSFORM_TEX ( v . texcoord , _MainTex ) ;
       #ifndef LIGHTMAP_OFF
       o . hip_lmap . xy = v . texcoord1 . xy * unity_LightmapST . xy + unity_LightmapST . zw ;
       #endif
       float3 worldN = mul ( ( float3x3 ) _Object2World , SCALED_NORMAL ) ;
       TANGENT_SPACE_ROTATION ;
       #ifdef LIGHTMAP_OFF
       o . lightDir = mul ( rotation , ObjSpaceLightDir ( v . vertex ) ) ;
       #endif
       #ifdef LIGHTMAP_OFF
       float3 shlight = ShadeSH9 ( float4 ( worldN , 1.0 ) ) ;
       o . vlight = shlight ;
       #ifdef VERTEXLIGHT_ON
       float3 worldPos = mul ( _Object2World , v . vertex ) . xyz ;
       o . vlight += Shade4PointLights (
         unity_4LightPosX0 , unity_4LightPosY0 , unity_4LightPosZ0 ,
         unity_LightColor0 , unity_LightColor1 , unity_LightColor2 , unity_LightColor3 ,
         unity_4LightAtten0 , worldPos , worldN ) ;
       #endif // VERTEXLIGHT_ON
       #endif // LIGHTMAP_OFF
       TRANSFER_VERTEX_TO_FRAGMENT ( o ) ;
       return o ;
    }
    #ifndef LIGHTMAP_OFF
    sampler2D unity_Lightmap ;
    #endif
    half4 frag_surf ( v2f_surf IN ) : COLOR {
       Input surfIN ;
       surfIN . uv_MainTex = IN . hip_pack0 . xy ;
       SurfaceOutput o ;
       o . Albedo = 0.0 ;
       o . Emission = 0.0 ;
       o . Specular = 0.0 ;
       o . Alpha = 0.0 ;
       o . Gloss = 0.0 ;
       surf ( surfIN , o ) ;
       half atten = LIGHT_ATTENUATION ( IN ) ;
       half4 c ;
       #ifdef LIGHTMAP_OFF
       c = LightingLambert ( o , IN . lightDir , atten ) ;
       c . rgb += o . Albedo * IN . vlight ;
       #else // LIGHTMAP_OFF
       half3 lmFull = DecodeLightmap ( tex2D ( unity_Lightmap , IN . hip_lmap . xy ) ) ;
       #ifdef SHADOWS_SCREEN
       c . rgb = o . Albedo * min ( lmFull , atten* 2 ) ;
       #else
       c . rgb = o . Albedo * lmFull ;
       #endif
       c . a = o . Alpha ;
       #endif // LIGHTMAP_OFF
       return c ;
    }

    Of those 90 lines of code, 10 are your original surface shader code; the remaining 80 would have to be pretty much written by hand in Unity 2.x days (well ok, less code would have to be written because 2.x had less rendering features). But wait, that was only base pass of the forward renderer! It also generates code for additive pass, for deferred base pass, deferred final pass, optionally for shadow caster pass and so on.

    在这90行代码中,有10行是您原始的表面着色器代码。 其余的80个必须在Unity 2.x天内用手工编写(好吧,因为2.x具有较少的渲染功能,因此必须编写更少的代码)。 但是,等等 ,这只是前向渲染器的基本操作! 它还会生成用于加性传递,延迟的基础传递,延迟的最终传递(可选地,用于阴影投射器传递)的代码。

    So this should be an easier to write lit shaders (it is for me at least). I hope this will also increase the number of Unity users who can write shaders at least 3 times (i.e. to 30 up from 10!). It should be more future proof to accomodate changes to the lighting pipeline we’ll do in Unity next.

    因此,编写带阴影的着色器应该更容易(至少对我而言)。 我希望这还将增加可以编写着色器至少3次(即从10个增加到30个!)的Unity用户数量。 适应我们接下来将在Unity中进行的照明管道的更改, 应该是将来的证明。

    Predefined Input values

    预定义的输入值

    The Input structure can contain texture coordinates and some predefined values, for example view direction, world space position, world space reflection vector and so on. Code to compute them is only generated if they are actually used. For example, if you use world space reflection to do some cubemap reflections (as emissive term) in your surface shader, then in Deferred Lighting base pass the reflection vector will not be computed (since it does not output emission, so by extension does not need reflection vector).

    Input结构可以包含纹理坐标和一些预定义值,例如视图方向,世界空间位置,世界空间反射向量等。 仅在实际使用它们的情况下才会生成用于计算它们的代码。 例如,如果使用世界空间反射在曲面着色器中进行某些立方体贴图反射(作为发射术语),则在Deferred Lighting base pass中将不计算反射矢量(因为它不输出发射,因此扩展时不输出)需要反射向量)。

    Surface Shader: Rim Lighting

    1

    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
      <span style="color:gray">#pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
          float2 uv_BumpMap;</span>
          float3 viewDir;
      <span style="color:gray">};
      sampler2D _MainTex;
      sampler2D _BumpMap;</span>
      float4 _RimColor;
      float _RimPower;
      <span style="color:gray">void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
          o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));</span>
          half rim =
              1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
          o.Emission = _RimColor.rgb * pow (rim, _RimPower);
      <span style="color:gray">}</span>

    1

    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
       < span style = "color:gray" > #pragma surface surf Lambert
       struct Input {
           float2 uv_MainTex ;
           float2 uv_BumpMap ; < / span >
           float3 viewDir ;
       < span style = "color:gray" > } ;
       sampler2D _MainTex ;
       sampler2D _BumpMap ; < / span >
       float4 _RimColor ;
       float _RimPower ;
       < span style = "color:gray" > void surf ( Input IN , inout SurfaceOutput o ) {
           o . Albedo = tex2D ( _MainTex , IN . uv_MainTex ) . rgb ;
           o . Normal = UnpackNormal ( tex2D ( _BumpMap , IN . uv_BumpMap ) ) ; < / span >
           half rim =
               1.0 - saturate ( dot ( normalize ( IN . viewDir ) , o . Normal ) ) ;
           o . Emission = _RimColor . rgb * pow ( rim , _RimPower ) ;
       < span style = "color:gray" > } < / span >

    Vertex shader modifiers

    顶点着色器修改器

    Surface Shader: Normal Extrusion

    My favorite vertex modifier? Moving vertices along their normals.

    我最喜欢的顶点修饰符? 沿法线移动顶点。

    Custom Lighting Models

    定制照明模型

    There are a couple simple lighting models built-in, but it’s possible to specify your own. A lighting model is nothing more than a function that will be called with the filled SurfaceOutput structure and per-light parameters (direction, attenuation and so on). Different functions would have to be called in forward & deferred rendering cases; and naturally the deferred one has much less flexibility. So for any fancy effects, it is possible to say “do not compile this shader for deferred”, in which case it will be rendered via forward rendering.

    内置了几个简单的照明模型,但是可以指定您自己的模型。 照明模型不过是一个函数,该函数将使用填充的SurfaceOutput结构和每个照明参数(方向,衰减等)来调用。 在正向和延迟渲染情况下,必须调用不同的功能; 而且自然而然地,递延的灵活性就差很多。 因此,对于任何奇特的效果,可以说“不要为延迟而编译此着色器”,在这种情况下,它将通过正向渲染进行渲染。

    Surface Shader: Wrapped Lambert lighting

    1

    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
      #pragma surface surf WrapLambert
      half4 LightingWrapLambert (SurfaceOutput s, half3 dir, half atten) {
          dir = normalize(dir);
          half NdotL = dot (s.Normal, dir);
          half diff = NdotL * 0.5 + 0.5;
          half4 c;
          c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
          c.a = s.Alpha;
          return c;
      }
      <span style="color:gray">struct Input {
          float2 uv_MainTex;
      };
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }</span>

    1

    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
       #pragma surface surf WrapLambert
       half4 LightingWrapLambert ( SurfaceOutput s , half3 dir , half atten ) {
           dir = normalize ( dir ) ;
           half NdotL = dot ( s . Normal , dir ) ;
           half diff = NdotL * 0.5 + 0.5 ;
           half4 c ;
           c . rgb = s . Albedo * _LightColor0 . rgb * ( diff * atten * 2 ) ;
           c . a = s . Alpha ;
           return c ;
       }
       < span style = "color:gray" > struct Input {
           float2 uv_MainTex ;
       } ;
       sampler2D _MainTex ;
       void surf ( Input IN , inout SurfaceOutput o ) {
           o . Albedo = tex2D ( _MainTex , IN . uv_MainTex ) . rgb ;
       } < / span >

    Behind the scenes

    幕后花絮

    We’re using HLSL parser from Ryan Gordon’s mojoshader to parse the original surface shader code and infer some things from the abstract syntax tree mojoshader produces. This way we can figure out what members are in what structures, go over function prototypes and so on. At this stage some error checking is done to tell the user his surface function is of wrong prototype, or his structures are missing required members – which is much better than failing with dozens of compile errors in the generated code later.

    我们正在使用Ryan Gordon的mojoshader的 HLSL解析器来解析原始的表面着色器代码,并从mojoshader产生的抽象语法树中推断出一些东西。 这样,我们可以找出哪些成员位于什么结构中,遍历函数原型等等。 在此阶段,将执行一些错误检查以告知用户他的表面函数错误的原型,或者他的结构缺少必需的成员-这比以后在生成的代码中失败并产生数十个编译错误要好得多。

    To figure out which surface shader inputs are actually used in the various lighting passes, we’re generating small dummy pixel shaders, compile them with Cg and use Cg’s API to query used inputs & outputs. This way we can figure out, for example, that a normal map nor it’s texture coordinate is not actually used in Deferred Lighting final pass, and save some vertex shader instructions & a texcoord interpolator.

    为了弄清楚在各种光照遍中实际使用了哪些表面着色器输入,我们生成了小的虚拟像素着色器,使用Cg对其进行编译,并使用Cg的API查询使用过的输入和输出。 例如,通过这种方式,我们可以确定在Deferred Lighting最终遍历中并未实际使用法线贴图或其纹理坐标,并保存了一些顶点着色器指令和texcoord插值器。

    The code that is ultimately generated is compiled with various shader compilers depending on the target platform (Cg for Windows/Mac, XDK HLSL for Xbox 360, PS3 Cg for PS3, and our own fork of HLSL2GLSL for iPhone, Android and upcoming NativeClient port of Unity).

    最终生成的代码将根据目标平台(使用Windows / Mac的Cg,用于Xbox 360的XDK HLSL,用于PS3的PS3 Cg以及我们自己用于iPhone,Android 的HLSL2GLSL分支以及即将推出的NativeClient端口)使用各种着色器编译器进行编译。团结 )。

    So yeah, that’s it. We’ll see where this goes next, or what happens when Unity 3 will be released. I hope more folks will try to write shaders!

    是的,就是这样。 我们将看到下一步的发展,或者发布Unity 3时会发生什么。 我希望更多的人会尝试编写着色器!

    翻译自: https://blogs.unity3d.com/2010/07/17/unity-3-technology-surface-shaders/

    unity表面着色器

    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/107796
    推荐阅读
    相关标签
      

    闽ICP备14008679号