zoukankan      html  css  js  c++  java
  • 【Unity Shaders】Transparency —— 使用alpha通道创建透明效果

    本系列主要参考《Unity Shaders and Effects Cookbook》一书(感谢原书作者),同时会加上一点个人理解或拓展。

    这里是本书所有的插图。这里是本书所需的代码和资源(当然你也可以从官网下载)。

    ========================================== 分割线 ==========================================



    写在前面



    从这篇开始是一个全新的章节:透明效果(Transparency)。之前在制作LOGO闪光效果的时候就一直调不出来背景透明,就是那个时候决定要学一下Shader的基础知识,不求成为多么厉害的大神,只望对渲染的内部原理有些许了解~


    开始正文。


    在我们学习如何编写透明的Surface Shader的开始,我们需要理解应该包含哪些代码使得我们可以开启透明效果。Unity再一次慷慨地为我们提供了一些内置参数,我们可以通过包含这些参数来快速得到透明效果。


    这是通过在Shader的#pragma声明中添加alpha参数来实现的。这句话告诉Unity我们想要在Shader中使用透明度。但当我们在创建透明Shaders时,需要仔细考虑一些事情,那就是代码中元素的绘制顺序。这篇文章将会讲述一些基本问题,来得到一个非常简单的透明物体。在下面的章节中,将会讲解其他有关透明度的问题。



    准备工作



    和以前一样,我们需要创建一个新的场景。

    1. 创建一个新的场景,添加一个平行光以及一个球体(Sphere)。
    2. 创建一个新的Shader和新的Material,可以命名为SimpleAlpha。把Shader赋给Material后,再把该Material赋给第一步中的球体。
    3. 最后,我们需要一张贴图作为控制隐私,来控制哪些部分是透明的,哪些部分是不透明的。
    下图是我们用到的贴图。这张贴图仅包含单纯的RGB和白色(自带资源中没有,可以自己画,很简单)。我们使用它的RGB通道作为一个取值为0或1的透明度值。


    实现


    这篇Shader非常简单。

    1. Properties块中添加一个新的property,这使得我们可以全局控制透明度。
      	Properties {
      		_MainTex ("Base (RGB)", 2D) = "white" {}
      		_TransVal ("Transparency Value", Range(0,1)) = 0.5
      	}
    2. 改变渲染队列:
      Tags { "Queue"="Transparent" }

      解释:这一步很重要,原书中没有添加这一句实际是错误的。

    3. 然后,我们在#pragma声明中添加一个新的参数:alpha参数。
      		CGPROGRAM
      		#pragma surface surf Lambert alpha

      解释:再解释一遍上面这句声明的意思。使用名为surf的Surface Function,使用内置的Lambert光照函数,开启透明通道。

    4. 最后,在surf()函数中添加控制透明度的代码。
      		void surf (Input IN, inout SurfaceOutput o) {
      			half4 c = tex2D (_MainTex, IN.uv_MainTex);
      			o.Albedo = c.rgb;
      			o.Alpha = c.b * _TransVal;
      		}

    完整代码如下:
    Shader "Custom/SimpleAlpha" {
    	Properties {
    		_MainTex ("Base (RGB)", 2D) = "white" {}
    		_TransVal ("Transparency Value", Range(0,1)) = 0.5
    	}
    	SubShader {
    		Tags { "RenderType"="Opaque" "Queue"="Transparent"}
    		LOD 200
    		
    		CGPROGRAM
    		#pragma surface surf Lambert alpha
    
    		sampler2D _MainTex;
    		float _TransVal;
    
    		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.b * _TransVal;
    		}
    		ENDCG
    	} 
    	FallBack "Diffuse"
    }
    


    如果没有透明效果,如下所示:

    最后效果如下(从左到右分别对应了o.Alpha = c.r * _TransVal, o.Alpha = c.g * _TransVal, o.Alpha = c.b * _TransVal):




    解释


    你可以看到,使用Unity的Surface Shaders得到透明效果是非常容易的。这类Shader依赖三个元素:正确设置Shader渲染队列,#pragma声明中的alpha参数,以及在SurfaceOutput结构体中的Alpha值。

    Tags { "Queue"="Transparent" }一步将决定半透明物体和不透明物体之间正确的渲染关系,如果没有正确设置,那么很有可能就会出现后面的物体跑到了透明物体的前面。具体解释可以参见这篇文章

    一旦我们在#pragma声明中添加了alpha参数,这就告诉了Unity:嘿,接下来你要允许我渲染一个透明的surface。然后,我们就仅仅需要逐像素地使用一个取值范围为0到1的值来填充SurfaceOutput结构体中的O.Alpha值。从颜色角度讲(这里的颜色指一个灰度值,因为透明度可以用一个单通道的灰度值来表示),一个为1的透明度,即白色,将会产出一个完全不透明的效果。而0值,即黑色,表示一个完全透明的效果。

    这就解释了上述的效果。例如,当我们使用如下语句控制透明度:
    o.Alpha = c.r * _TransVal

    则贴图中除了红色部分以及白色部分(白色的RGB通道值均为1)其R通道的值为1,其余(绿色和蓝色部分)均为0。因此只有红色和白色的部分才不透明。

    尽管关于透明度有很多东西,但我们要知道,上述是其最基本的实现。在下面的章节中,我们将开始如何在实时渲染中使用alpha通道或者半透明的Shader。


  • 相关阅读:
    数据库多表查询,左连接(入门)
    让弹出层始终显示在屏幕正中间
    jq中的ajax合集总结
    ajax之$.getScript()
    Jquery遮罩ShowLoading组件
    jquery中prop()方法和attr()方法的区别
    Bootstrap 响应式实用工具
    VS使用技巧
    ubuntu下postgreSQL安装配置
    基础设施即代码(Infrastructure as Code)
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6314689.html
Copyright © 2011-2022 走看看