转 https://willweissman.wordpress.com/tutorials/shaders/unity-shaderlab-object-outlines/

Unity Shaderlab: Object Outlines

One of the simplest and most useful effects that isn’t already present in Unity is object outlines.

Screenshot from Left 4 Dead. Image Source: http://gamedev.stackexchange.com/questions/16391/how-can-i-reduce-aliasing-in-my-outline-glow-effect

There are a couple of ways to do this, and the Unity Wiki covers one of these. But, the example demonstrated in the Wiki cannot make a “blurred” outline, and it requires smoothed normals for all vertices. If you need to have an edge on one of your outlined objects, you will get the following result:

The WRONG way to do outlines

While the capsule on the left looks fine, the cube on the right has artifacts. And to the beginners: the solution is NOT to apply smoothing groups or smooth normals out, or else it will mess with the lighting of the object. Instead, we need to do this as a simple post-processing effect. Here are the basic steps:

  1. Render the scene to a texture(render target)
  2. Render only the selected objects to another texture, in this case the capsule and box
  3. Draw a rectangle across the entire screen and put the texture on it with a custom shader
  4. The pixel/fragment shader for that rectangle will take samples from the previous texture, and add color to pixels which are near the object on that texture
  5. Blur the samples

Step 1: Render the scene to a texture

First things first, let’s make our C# script and attach it to the camera gameobject:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using UnityEngine;
using System.Collections;
 
public class PostEffect : MonoBehaviour
{
    Camera AttachedCamera;
    public Shader Post_Outline;
 
    void Start ()
    {
        AttachedCamera = GetComponent<Camera>();
    }
 
    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
 
    }
 
}

OnRenderImage() works as follows: After the scene is rendered, any component attached to the camera that is drawing receives this message, and a rendertexture containing the scene is passed in, along with a rendertexture that is to be output to, but the scene is not drawn to the screen. So, that’s step 1 complete.

Here’s the scene by itself

Step 2: Render only the selected objects to another texture

There are again many ways to select certain objects to render, but I believe this is the cleanest way. We are going to create a shader that ignores lighting or depth testing, and just draws the object as pure white. Then we re-draw the outlined objects, but with this shader.

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
//This shader goes on the objects themselves. It just draws the object as white, and has the "Outline" tag.
 
Shader "Custom/DrawSimple"
{
    SubShader
    {
        ZWrite Off
        ZTest Always
        Lighting Off
        Pass
        {
            CGPROGRAM
            #pragma vertex VShader
            #pragma fragment FShader
 
            struct VertexToFragment
            {
                float4 pos:SV_POSITION;
            };
 
            //just get the position correct
            VertexToFragment VShader(VertexToFragment i)
            {
                VertexToFragment o;
                o.pos=mul(UNITY_MATRIX_MVP,i.pos);
                return o;
            }
 
            //return white
            half4 FShader():COLOR0
            {
                return half4(1,1,1,1);
            }
 
            ENDCG
        }
    }
}

Now, whenever the object is drawn with this shader, it will be white. We can make the object get drawn by using Unity’s Camera.RenderWithShader() function. So, our new camera code needs to render the objects that reside on a special layer, rendering them with this shader, to a texture. Because we can’t use the same camera to render twice in one frame, we need to make a new camera. We also need to handle our new RenderTexture, and work with binary briefly.

Our new C# code is as follows:

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
using UnityEngine;
using System.Collections;
 
public class PostEffect : MonoBehaviour
{
    Camera AttachedCamera;
    public Shader Post_Outline;
    public Shader DrawSimple;
    Camera TempCam;
   // public RenderTexture TempRT;
 
 
    void Start ()
    {
        AttachedCamera = GetComponent<Camera>();
        TempCam = new GameObject().AddComponent<Camera>();
        TempCam.enabled = false;
    }
 
    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        //set up a temporary camera
        TempCam.CopyFrom(AttachedCamera);
        TempCam.clearFlags = CameraClearFlags.Color;
        TempCam.backgroundColor = Color.black;
 
        //cull any layer that isn't the outline
        TempCam.cullingMask = 1 << LayerMask.NameToLayer("Outline");
 
        //make the temporary rendertexture
        RenderTexture TempRT = new RenderTexture(source.width, source.height, 0, RenderTextureFormat.R8);
 
        //put it to video memory
        TempRT.Create();
 
        //set the camera's target texture when rendering
        TempCam.targetTexture = TempRT;
 
        //render all objects this camera can render, but with our custom shader.
        TempCam.RenderWithShader(DrawSimple,"");
 
        //copy the temporary RT to the final image
        Graphics.Blit(TempRT, destination);
 
        //release the temporary RT
        TempRT.Release();
    }
 
}

Bitmasks

The line:

1
        TempCam.cullingMask = 1 << LayerMask.NameToLayer("Outline");

means that we are shifting the value (Decimal: 1, Binary: 00000000000000000000000000000001) a number of bits to the left, in this case the same number of bits as our layer’s decimal value. This is because binary value “01” is the first layer and value “010” is the second, and “0100” is the third, and so on, up to a total of 32 layers(because we have 32 bits up here). Unity uses this order of bits to mask what it draws, in other words, this is a Bitmask.

So, if our “Outline” layer is 8, to draw it, we need a bit in the 8th spot. We shift a bit that we know to be in the first spot over to the 8th spot. Layermask.NameToLayer() will return the decimal value of the layer(8), and the bit shift operator will shift the bits that many over(8).

To the beginners: No, you cannot just set the layer mask to “8”. 8 in decimal is actually 1000, which, when doing bitmask operations, is the 4th slot, and would result in the 4th layer being drawn.

Q: Why do we even do bitmasks?

A: For performance reasons.

Moving along…

Make sure that at render time, the objects you need outlined are on the outline layer. You could do this by changing the object’s layer in LateUpdate(), and setting it back in OnRenderObject(). But out of laziness, I’m just setting them to the outline layer in the editor.

Objects to be outlined are rendered to a texture

The above screenshot shows what the scene should look like with our code. So that’s step 2; we rendered those objects to a texture.

Step 3: Draw a rectangle to the screen and put the texture on it with a custom shader.

Except that’s already what’s going on in the code; Graphics.Blit() copies a texture over to a rendertexture. It draws a full-screen quad(vertex coordinates 0,0, 0,1, 1,1, 1,0) an puts the texture on it.

And, you can pass in a custom shader for when it draws this.

So, let’s make a new shader:

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
Shader "Custom/Post Outline"
{
    Properties
    {
        //Graphics.Blit() sets the "_MainTex" property to the texture passed in
        _MainTex("Main Texture",2D)="black"{}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
     
            sampler2D _MainTex;
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
             
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;
            };
             
            v2f vert (appdata_base v)
            {
                v2f o;
                 
                //Despite the fact that we are only drawing a quad to the screen, Unity requires us to multiply vertices by our MVP matrix, presumably to keep things working when inexperienced people try copying code from other shaders.
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                 
                //Also, we need to fix the UVs to match our screen space coordinates. There is a Unity define for this that should normally be used.
                o.uvs = o.pos.xy / 2 + 0.5;
                 
                return o;
            }
             
             
            half4 frag(v2f i) : COLOR
            {
                //return the texture we just looked up
                return tex2D(_MainTex,i.uvs.xy);
            }
             
            ENDCG
 
        }
        //end pass        
    }
    //end subshader
}
//end shader

If we put this shader onto a new material, and pass that material into Graphics.Blit(), we can now re-draw our rendered texture with our custom shader.

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
using UnityEngine;
using System.Collections;
 
public class PostEffect : MonoBehaviour
{
    Camera AttachedCamera;
    public Shader Post_Outline;
    public Shader DrawSimple;
    Camera TempCam;
    Material Post_Mat;
   // public RenderTexture TempRT;
 
 
    void Start ()
    {
        AttachedCamera = GetComponent<Camera>();
        TempCam = new GameObject().AddComponent<Camera>();
        TempCam.enabled = false;
        Post_Mat = new Material(Post_Outline);
    }
 
    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        //set up a temporary camera
        TempCam.CopyFrom(AttachedCamera);
        TempCam.clearFlags = CameraClearFlags.Color;
        TempCam.backgroundColor = Color.black;
 
        //cull any layer that isn't the outline
        TempCam.cullingMask = 1 << LayerMask.NameToLayer("Outline");
 
        //make the temporary rendertexture
        RenderTexture TempRT = new RenderTexture(source.width, source.height, 0, RenderTextureFormat.R8);
 
        //put it to video memory
        TempRT.Create();
 
        //set the camera's target texture when rendering
        TempCam.targetTexture = TempRT;
 
        //render all objects this camera can render, but with our custom shader.
        TempCam.RenderWithShader(DrawSimple,"");
 
        //copy the temporary RT to the final image
        Graphics.Blit(TempRT, destination,Post_Mat);
 
        //release the temporary RT
        TempRT.Release();
    }
 
}

Which should lead to the results above, but the process is now using our own shader.

Step 4: add color to pixels which are near white pixels on the texture.

For this, we need to get the relevant texture coordinate of the pixel we are rendering, and look up all adjacent pixels for existing objects. If an object exists near our pixel, then we should draw a color at our pixel, as our pixel is within the outlined radius.

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
Shader "Custom/Post Outline"
{
    Properties
    {
        _MainTex("Main Texture",2D)="black"{}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
     
            sampler2D _MainTex;
 
            //<SamplerName>_TexelSize is a float2 that says how much screen space a texel occupies.
            float2 _MainTex_TexelSize;
 
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
             
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;
            };
             
            v2f vert (appdata_base v)
            {
                v2f o;
                 
                //Despite the fact that we are only drawing a quad to the screen, Unity requires us to multiply vertices by our MVP matrix, presumably to keep things working when inexperienced people try copying code from other shaders.
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                 
                //Also, we need to fix the UVs to match our screen space coordinates. There is a Unity define for this that should normally be used.
                o.uvs = o.pos.xy / 2 + 0.5;
                 
                return o;
            }
             
             
            half4 frag(v2f i) : COLOR
            {
                //arbitrary number of iterations for now
                int NumberOfIterations=9;
 
                //split texel size into smaller words
                float TX_x=_MainTex_TexelSize.x;
                float TX_y=_MainTex_TexelSize.y;
 
                //and a final intensity that increments based on surrounding intensities.
                float ColorIntensityInRadius;
 
                //for every iteration we need to do horizontally
                for(int k=0;k<NumberOfIterations;k+=1)
                {
                    //for every iteration we need to do vertically
                    for(int j=0;j<NumberOfIterations;j+=1)
                    {
                        //increase our output color by the pixels in the area
                        ColorIntensityInRadius+=tex2D(
                                                      _MainTex,
                                                      i.uvs.xy+float2
                                                                   (
                                                                        (k-NumberOfIterations/2)*TX_x,
                                                                        (j-NumberOfIterations/2)*TX_y
                                                                   )
                                                     ).r;
                    }
                }
 
                //output some intensity of teal
                return ColorIntensityInRadius*half4(0,1,1,1);
            }
             
            ENDCG
 
        }
        //end pass        
    }
    //end subshader
}
//end shader

And then, if an object exists under the pixel, discard the pixel:

1
2
3
4
5
                //if something already exists underneath the fragment, discard the fragment.
                if(tex2D(_MainTex,i.uvs.xy).r>0)
                {
                    discard;
                }

And finally, add a blend mode to the shader:

1
    Blend SrcAlpha OneMinusSrcAlpha

And the resulting shader:

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
90
Shader "Custom/Post Outline"
{
    Properties
    {
        _MainTex("Main Texture",2D)="white"{}
    }
    SubShader
    {
    Blend SrcAlpha OneMinusSrcAlpha
        Pass
        {
            CGPROGRAM
     
            sampler2D _MainTex;
 
            //<SamplerName>_TexelSize is a float2 that says how much screen space a texel occupies.
            float2 _MainTex_TexelSize;
 
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
             
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;
            };
             
            v2f vert (appdata_base v)
            {
                v2f o;
                 
                //Despite the fact that we are only drawing a quad to the screen, Unity requires us to multiply vertices by our MVP matrix, presumably to keep things working when inexperienced people try copying code from other shaders.
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                 
                //Also, we need to fix the UVs to match our screen space coordinates. There is a Unity define for this that should normally be used.
                o.uvs = o.pos.xy / 2 + 0.5;
                 
                return o;
            }
             
             
            half4 frag(v2f i) : COLOR
            {
                //arbitrary number of iterations for now
                int NumberOfIterations=9;
 
                //split texel size into smaller words
                float TX_x=_MainTex_TexelSize.x;
                float TX_y=_MainTex_TexelSize.y;
 
                //and a final intensity that increments based on surrounding intensities.
                float ColorIntensityInRadius;
 
                //if something already exists underneath the fragment, discard the fragment.
                if(tex2D(_MainTex,i.uvs.xy).r>0)
                {
                    discard;
                }
 
                //for every iteration we need to do horizontally
                for(int k=0;k<NumberOfIterations;k+=1)
                {
                    //for every iteration we need to do vertically
                    for(int j=0;j<NumberOfIterations;j+=1)
                    {
                        //increase our output color by the pixels in the area
                        ColorIntensityInRadius+=tex2D(
                                                      _MainTex,
                                                      i.uvs.xy+float2
                                                                   (
                                                                        (k-NumberOfIterations/2)*TX_x,
                                                                        (j-NumberOfIterations/2)*TX_y
                                                                   )
                                                     ).r;
                    }
                }
 
                //output some intensity of teal
                return ColorIntensityInRadius*half4(0,1,1,1);
            }
             
            ENDCG
 
        }
        //end pass        
    }
    //end subshader
}
//end shader

Step 5: Blur the samples

Now, at this point, we don’t have any form of blur or gradient. There also exists the problem of performance: If we want an outline that is 3 pixels thick, there are 3×3, or 9, texture lookups per pixel. If we want to increase the outline radius to 20 pixels, that is 20×20, or 400 texture lookups per pixel!

We can solve both of these problems with our upcoming method of blurring, which is very similar to how most gaussian blurs are performed. It is important to note that we are not doing a gaussian blur in this tutorial, as the method of weight calculation is different. I recommend that if you are experienced with shaders, you should do a gaussian blur here, but color it one single color.

We start with a pixel:

Which we can sample all neighboring pixels in a circle and weight them based on their distance to the sample input:

Which looks really good! But again, that’s a lot of samples once you reach a higher radius.

Fortunately, there’s a cool trick we can do.

We can blur the texel horizontally to a texture….

And then read from that new texture, and blur vertically…

Which leads to a blur as well!

And now, instead of an exponential increase in samples with radius, the increase is now linear. When the radius is 5 pixels, we blur 5 pixels horizontally, then 5 pixels vertically. 5+5 = 10, compared to our other method, where 5×5 = 25.

To do this, we need to make 2 passes. Each pass will function like the shader code above, but remove one “for” loop. We also don’t bother with the discarding in the first pass, and instead leave it for the second.

The first pass also uses a single channel for the fragment shader; No colors are needed at that point.

Because we are using two passes, we can’t simply use a blend mode over the existing scene data. Now, we need to do blending ourselves, instead of leaving it to the hardware blending operations.

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
Shader "Custom/Post Outline"
{
    Properties
    {
        _MainTex("Main Texture",2D)="black"{}
        _SceneTex("Scene Texture",2D)="black"{}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
     
            sampler2D _MainTex;
 
            //<SamplerName>_TexelSize is a float2 that says how much screen space a texel occupies.
            float2 _MainTex_TexelSize;
 
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
             
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;
            };
             
            v2f vert (appdata_base v)
            {
                v2f o;
                 
                //Despite the fact that we are only drawing a quad to the screen, Unity requires us to multiply vertices by our MVP matrix, presumably to keep things working when inexperienced people try copying code from other shaders.
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                 
                //Also, we need to fix the UVs to match our screen space coordinates. There is a Unity define for this that should normally be used.
                o.uvs = o.pos.xy / 2 + 0.5;
                 
                return o;
            }
             
             
            half frag(v2f i) : COLOR
            {
                //arbitrary number of iterations for now
                int NumberOfIterations=20;
 
                //split texel size into smaller words
                float TX_x=_MainTex_TexelSize.x;
 
                //and a final intensity that increments based on surrounding intensities.
                float ColorIntensityInRadius;
 
                //for every iteration we need to do horizontally
                for(int k=0;k<NumberOfIterations;k+=1)
                {
                    //increase our output color by the pixels in the area
                    ColorIntensityInRadius+=tex2D(
                                                    _MainTex,
                                                    i.uvs.xy+float2
                                                                (
                                                                    (k-NumberOfIterations/2)*TX_x,
                                                                    0
                                                                )
                                                    ).r/NumberOfIterations;
                }
 
                //output some intensity of teal
                return ColorIntensityInRadius;
            }
             
            ENDCG
 
        }
        //end pass    
         
        GrabPass{}
         
        Pass
        {
            CGPROGRAM
 
            sampler2D _MainTex;
            sampler2D _SceneTex;
             
            //we need to declare a sampler2D by the name of "_GrabTexture" that Unity can write to during GrabPass{}
            sampler2D _GrabTexture;
 
            //<SamplerName>_TexelSize is a float2 that says how much screen space a texel occupies.
            float2 _GrabTexture_TexelSize;
 
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
             
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;
            };
             
            v2f vert (appdata_base v)
            {
                v2f o;
                 
                //Despite the fact that we are only drawing a quad to the screen, Unity requires us to multiply vertices by our MVP matrix, presumably to keep things working when inexperienced people try copying code from other shaders.
                o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
 
                //Also, we need to fix the UVs to match our screen space coordinates. There is a Unity define for this that should normally be used.
                o.uvs = o.pos.xy / 2 + 0.5;
                 
                return o;
            }
             
             
            half4 frag(v2f i) : COLOR
            {
                //arbitrary number of iterations for now
                int NumberOfIterations=20;
 
                //split texel size into smaller words
                float TX_y=_GrabTexture_TexelSize.y;
 
                //and a final intensity that increments based on surrounding intensities.
                half ColorIntensityInRadius=0;
 
                //if something already exists underneath the fragment (in the original texture), discard the fragment.
                if(tex2D(_MainTex,i.uvs.xy).r>0)
                {
                    return tex2D(_SceneTex,float2(i.uvs.x,1-i.uvs.y));
                }
 
                //for every iteration we need to do vertically
                for(int j=0;j<NumberOfIterations;j+=1)
                {
                    //increase our output color by the pixels in the area
                    ColorIntensityInRadius+= tex2D(
                                                    _GrabTexture,
                                                    float2(i.uvs.x,1-i.uvs.y)+float2
                                                                                    (
                                                                                        0,
                                                                                        (j-NumberOfIterations/2)*TX_y
                                                                                    )
                                                    ).r/NumberOfIterations;
                }
 
 
                //this is alpha blending, but we can't use HW blending unless we make a third pass, so this is probably cheaper.
                half4 outcolor=ColorIntensityInRadius*half4(0,1,1,1)*2+(1-ColorIntensityInRadius)*tex2D(_SceneTex,float2(i.uvs.x,1-i.uvs.y));
                return outcolor;
            }
             
            ENDCG
 
        }
        //end pass    
    }
    //end subshader
}
//end shader

And the final result:

Where you can go from here

First of all, the values, iterations, radius, color, etc are all hardcoded in the shader. You can set them as properties to be more code and designer friendly.

Second, my code has a falloff based on the number of filled texels in the area, and not the distance to each texel. You could create a gaussian kernel table and multiply the blurs with your values, which would run a little bit faster, but also remove the artifacts and uneven-ness you can see at the corners of the cube.

Don’t try to generate the gaussian kernel at runtime, though. That is super expensive.

I hope you learned a lot from this! If you have any questions or comments, please leave them below.

Unity Shaderlab: Object Outlines 转的更多相关文章

  1. Unity ShaderLab学习总结

    http://www.jianshu.com/p/7b9498e58659 Unity ShaderLab学习总结 Why Bothers? 为什么已经有ShaderForge这种可视化Shader编 ...

  2. unity中object 对象之间用c# delegate方式进行通信

    unity 3D经常需要设计到不同object之间数据通信和事件信息触发.这里可以利用C#本身的事件和代理的方法来实现. 这里实现了在GUI上点击按钮,触发事件,移动object cube移动的例子. ...

  3. unity ShaderLab 编辑器——sublime text 2

    sublime text 2,支持unity shader关键字高亮显示,智能提示功能.这个脚本编辑器的售价是70美元,不过作者很厚道地给了我们永久的免费试用期. 1)下载sublime text 2 ...

  4. Unity——ShaderLab实现玻璃和镜子效果

    在这一篇中会实现会介绍折射和反射,以及菲尼尔反射:并且实现镜子和玻璃效果: 这里和之前不同的地方在于取样的是一张CubeMap: demo里的cubemap使用的一样,相机所在位置拍出来的周围环境图: ...

  5. unity shaderlab Blend操作

    原文链接: http://www.tiankengblog.com/?p=84 Blend混合操作是作用于在所有计算之后,是Shader渲染的最后一步,进行Blend操作后就可以显示在屏幕上.shad ...

  6. Unity ShaderLab 光照随笔

    unity camera默认3种渲染路径,unity5.50里面有4种 camera Rendering Path 1 vertexLit(逐顶点,一般在vert中处理)  2 forward (前向 ...

  7. Unity ShaderLab 学习笔记(一)

    因为项目的问题,有个效果在iOS上面无法实现出来- 因为shader用的HardSurface的,在android上面跑起来没有问题- 以为在iOS上也不会有问题,但是悲剧啊,技能效果一片漆黑- 而且 ...

  8. Unity获取object所有属性的一个方法,一些界面上没有开放的属性可以用该方法编辑

    static void PrintProperty () { if(Selection.activeObject == null) return; SerializedObject so = new ...

  9. Unity——ShaderLab基础

    1.格式 Shader "Custom/MyShader" //命名+右键创建shader路径 { //属性必须在代码里声明才能使用 Properties{ //属性,会出现在in ...

随机推荐

  1. 源码下载:74个Android开发开源项目汇总

    1. ActionBarSherlock ActionBarSherlock应该算得上是GitHub上最火的Android开源项目了,它是一个独立的库,通过一个API和主题,开发者就可以很方便地使用所 ...

  2. php中生成标准uuid(guid)的方法

    );// "}"        return $uuid;    }}echo guid();?>

  3. SSM的理解

    SSM(Spring+SpringMVC+MyBatis)框架集由Spring.SpringMVC.MyBatis三个开源框架整合而成,常作为数据源较简单的web项目的框架.其中spring是一个轻量 ...

  4. 018.07 New BMW ICOM A3+B+C+D Plus EVG7 Controller Tablet PC with WIFI Function

    2018.07 New BMW ICOM A3+B+C+D Plus EVG7  Controller Tablet PC with WIFI Function Software Version : ...

  5. AURO OtoSys IM100 vs Lonsdor K518ISE: which better?

    Comparison: AURO OtoSys IM100 and Lonsdor K518ISE It’s aimed to help make a purchase of decent auto ...

  6. Python3自定义日志类 mylog

    #encoding=utf-8 import os, sysimport datetimeimport time class Mylog(object): # 根文件夹    root_dir = s ...

  7. WTL CHyperLink类的使用(超链接)

    1.包含atlctrlx.h头文件: 2.声明一个CHyperLink类的变量: CHyperLink        m_linkIntro; 3.在OnInitDialog函数里: m_linkIn ...

  8. 【javascript】对原型对象、原型链的理解

    原型对象,原型链这些知识属于基础类知识.但是平时开发过程中也很少用到. 看网上的意思,原型链用于es5开发场景下的继承.es6有了类语法糖之后,就自带继承了. 通过理解,个人画了一张原型链解构的关系图 ...

  9. Docker学习笔记之搭建Docker运行环境

    0x00 概述 既然 Docker 是一款实用软件,我们就不得不先从它的安装说起,只有让 Docker 运行在我们的计算机上,才能更方便我们对 Docker 相关知识和使用方式的学习.得益于与商业性的 ...

  10. A-作业01

    #1 简单作业 1. 系统的日志文件/var/log/secure /var/log/messages /var/log/cron会自动的进行轮询,系统是通过什么实现的? 2. 写出下面特殊符号在定时 ...