上文:
Shader从入门到跑路:朴实无华的图形学基础
上节课后作业答案
只需要将返回颜色的蓝色通道更改为1,就可以得到课后作业的渲染结果
- float4 frag(v2f i) : SV_Target
- {
- float4 color = float4(i.uv.r, i.uv.g, 1, 1);
- return color;
- }
复制代码
课后作业渲染结果
前言
实在是手残,不小心把这篇文章删掉了,问了客服好像并没有解决办法,希望知乎以后可以提供恢复误删文章的功能...只能再手打一遍了,欲哭无泪。
正文
上一章我们都是指挥unity来获取渲染信息,那么接下来就介绍如何将图片输出到物体上。
背景为透明的我老婆
为了展示接下来的内容,我在PS内制作了一张带有透明通道的PNG图片,正确的渲染效果应该是显示人像,而背景部分则显示图片后面的场景物体(即应该为透明的)。
现于SubShader区块上面新增一个Properties区块,并在其中定义一个MainTexture的二维属性。
- Properties{
- _MainTex("Main Texture", 2D) = "white" {}
- }
复制代码
注意,在属性区块内被定义的数据在CGPROGRAM内被使用之前都要预定义一遍,不然会报错。在CGPROGRAM内加入纹理的定义:
sampler2D _MainTex;
在这里的sampler2D是一个GLSL的类型,表示用来存储一个2D纹理
https://www.khronos.org/opengl/wiki/Sampler_(GLSL)
接下来,在frag函数中利用tex2D这个方法来获取纹理中的颜色,并直接使用颜色进行着色。这个方法其实就是在一张纹理中对一个点进行采样,我们要得到整个纹理的颜色,就需要所有像素对应的uv点,代码如下:
- float4 frag(v2f i) : SV_Target
- {
- return tex2D(_MainTex, i.uv);
- }
复制代码
然而我们却得到了一些奇怪的渲染结果,来看一看为什么。
与预期不符的渲染结果,背景应该是透明的
可见得出的渲染结果并不符合我们的预期,本来在PNG里背景被设置为透明的图片,背景变成了白色。这是因为tex2D在处理纹理的时候会计算每一个对应uv点的像素颜色,但是本应是透明的内容是不会有”颜色“这一属性的,然而tex2D还是将它们视为待计算的颜色,这才出现了错误。
为了解决这个问题,我们需要一种叫Transparent Blend的技术。其实就是定义一下在shader里面,目前处理的像素如何与它后面像素混合。混合模式有很多种:
https://docs.unity3d.com/Manual/SL-Blend.html
我们这次用的是一种叫做Alpha Blend的东西,定义CGPROGRAM外面,它长这样:
Blend SrcAlpha OneMinusSrcAlpha
它的意思是将源颜色乘上源颜色的透明度,与目标颜色乘(1 - 原颜色的透明度)的结果相加,公式如下:
OutColor = SrcColor * ScrAlpha + DstColor * (1 - SrcAlpha)
或许这有些难以理解,但只要稍微思考一下就好了,将两个颜色的减淡后叠加在一起,便产生了一种中间色,看起来就好像透过目前的物体看到了后面的物体一样。
下一步则是要在SubShader的tag区块内设置shader的渲染通道,以确保在非透明的物体渲染结束后才渲染我们的透明物体。
- Tags
- {
- "Queue" = "Transparent"
- }
复制代码
如果你跳过了这一步,那么就会出现一些奇怪的渲染效果。对于好奇心重的同学,欢迎跳过设置渲染通道来看看错误效果。
正确的渲染结果,可以透过透明部分看到后面的物体
完整的shader代码:
- Shader "Custom/ShaderLearning"
- {
- Properties{
- _MainTex("Main Texture", 2D) = "white"
- }
- SubShader
- {
- Tags
- {
- "Queue" = "Transparent"
- }
- Pass
- {
- Blend SrcAlpha OneMinusSrcAlpha
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- sampler2D _MainTex;
- #include "UnityCG.cginc"
- struct appdata
- {
- float4 vertex : POSITION;
- float2 uv: TEXCOORD0;
- };
- struct v2f
- {
- float4 vertex : SV_POSITION;
- float2 uv: TEXCOORD1;
- };
- v2f vert(appdata v)
- {
- v2f o;
- o.vertex = UnityObjectToClipPos(v.vertex);
- o.uv = v.uv;
- return o;
- }
- float4 frag(v2f i) : SV_Target
- {
- return tex2D(_MainTex, i.uv);
- }
- ENDCG
- }
- }
- }
复制代码
作者:俊铭
专栏地址:https://zhuanlan.zhihu.com/p/86096949