日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

unity入门精要之第6 章 Unity 中的基础光照--环境光和自发光

發(fā)布時間:2023/12/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 unity入门精要之第6 章 Unity 中的基础光照--环境光和自发光 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Unity系列文章目錄

文章目錄

  • Unity系列文章目錄
  • 前言
  • 一、Unity 中的環(huán)境光和自發(fā)光
  • 二、在Unity Shader 中實現(xiàn)漫反射光照模型
  • 參考

前言

但這種模型有很多局限性。首先,有很多重要的物理現(xiàn)象無法用Blinn-Phong 模型表現(xiàn)出來,
例如菲涅耳反射(Fresnel reflection)。其次,Blinn-Phong 模型是各項同性(isotropic)的,也就
是說,當(dāng)我們固定視角和光源方向旋轉(zhuǎn)這個表面時,反射不會發(fā)生任何改變。但有些表面是具有
各向異性(anisotropic)反射性質(zhì)的,例如拉絲金屬、毛發(fā)等。在第18 章中,我們將學(xué)習(xí)基于物
理的光照模型,這些光照模型更加復(fù)雜,同時也可以更加真實地反映光和物體的交互。

一、Unity 中的環(huán)境光和自發(fā)光

在標(biāo)準(zhǔn)光照模型中,環(huán)境光和自發(fā)光的計算
是最簡單的。
在Unity 中,場景中的環(huán)境光可以在Window ->
Lighting -> Ambient Source/Ambient Color/Ambient
Intensity 中控制,如圖6.5 所示。在Shader 中,我
們只需要通過Unity 的內(nèi)置變量UNITY_LIGHTM
ODEL_AMBIENT 就可以得到環(huán)境光的顏色和強
度信息。
而大多數(shù)物體是沒有自發(fā)光特性的,因此在
本書絕大部分的Shader 中都沒有計算自發(fā)光部
分。如果要計算自發(fā)光也非常簡單,我們只需要
在片元著色器輸出最后的顏色之前,把材質(zhì)的自
發(fā)光顏色添加到輸出顏色上即可。

二、在Unity Shader 中實現(xiàn)漫反射光照模型

在了解了上述的理論后,我們現(xiàn)在來看一下如何在Unity 中實現(xiàn)這些基本光照模型。首先,
我們來實現(xiàn)標(biāo)準(zhǔn)光照模型中的漫反射光照部分。
在6.2.3 節(jié)中,我們給出了基本光照模型中漫反射部分的計算公式:
從公式可以看出,要計算漫反射需要知道4 個參數(shù):入射光線的顏色和強度clight,材質(zhì)的漫
反射系數(shù)mdiffuse,表面法線?n 以及光源方向?l 。
為了防止點積結(jié)果為負(fù)值,我們需要使用max 操作,而Cg 提供了這樣的函數(shù)。在本例中,
使用Cg 的另一個函數(shù)可以達(dá)到同樣的目的,即saturate 函數(shù)。
函數(shù):saturate(x)
參數(shù):x:為用于操作的標(biāo)量或矢量,可以是float、float2、float3 等類型。
描述:把x 截取在[0, 1]范圍內(nèi),如果x 是一個矢量,那么會對它的每一個分量進行這樣的操作。
6.4.1 實踐:逐頂點光照
我們首先來看如何實現(xiàn)一個逐頂點的漫反射光照效果。在學(xué)習(xí)完本節(jié)后,我們會得到類似
圖6.6 中的效果。
為此,我們進行如下準(zhǔn)備工作。
(1)在Unity 中新建一個場景。在本書資源中,該場景名為Scene_6_4。在Unity 5.2 中,默
認(rèn)情況下場景將包含一個攝像機和一個平行光,并且使用了內(nèi)置的天空盒子。在Window ->
Lighting -> Skybox 中去掉場景中的天空盒子。
(2)新建一個材質(zhì)。在本書資源中,該材質(zhì)名為DiffuseVertexLevelMat。
(3)新建一個Unity Shader。在本書資源中,該Shader
名為Chapter6-DiffuseVertexLevel。把新的Shader 賦給
第2 步中創(chuàng)建的材質(zhì)。
(4)在場景中創(chuàng)建一個膠囊體,并把第2 步中的材
質(zhì)賦給該膠囊體。
(5)保存場景。
下面,我們需要編寫自己的Shader 來實現(xiàn)一個逐頂
點的漫反射效果。打開第3 步中創(chuàng)建的Unity Shader,
刪除所有已有代碼,并進行如下修改。
(1)首先,我們需要為這個Shader 起一個名字:
Shader “Unity Shaders Book/Chapter 6/Diffuse Vertex-Level” {
(2)為了得到并且控制材質(zhì)的漫反射顏色,我們首先在Shader 的Properties 語義塊中聲明了
一個Color 類型的屬性,并把它的初始值設(shè)為白色:
Properties {
_Diffuse (“Diffuse”, Color) = (1, 1, 1, 1)
}
(3)然后,我們在SubShader 語義塊中定義了一個Pass 語義塊。這是因為頂點/片元著色器的
代碼需要寫在Pass 語義塊,而非SubShader 語義塊中。而且,我們在Pass 的第一行指明了該Pass
的光照模式:
SubShader {
Pass {
Tags { “LightMode”=“ForwardBase” }
LightMode 標(biāo)簽是Pass 標(biāo)簽中的一種,它用于定義該Pass 在Unity 的光照流水線中的角色,
在第9 章中我們會更加詳細(xì)地解釋它。在這里,我們只需要知道,只有定義了正確的LightMode,
我們才能得到一些Unity 的內(nèi)置光照變量,例如下面要講到的_LightColor0。
(4)然后,我們使用CGPROGRAM 和ENDCG 來包圍Cg 代碼片,以定義最重要的頂點著色
器和片元著色器代碼。首先,我們使用#pragma 指令來告訴Unity,我們定義的頂點著色器和片元
著色器叫什么名字。在本例中,它們的名字分別是vert 和frag:
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
(5)為了使用Unity 內(nèi)置的一些變量,如后面要講到的_LightColor0,還需要包含進Unity 的
內(nèi)置文件Lighting.cginc:
#include “Lighting.cginc”
(6)為了在Shader 中使用Properties 語義塊中聲明的屬性,我們需要定義一個和該屬性類型
相匹配的變量:
fixed4 _Diffuse;
通過這樣的方式,我們就可以得到漫反射公式中需要的參數(shù)之一—材質(zhì)的漫反射屬性。由
于顏色屬性的范圍在0 到1 之間,因此我們可以使用fixed 精度的變量來存儲它。

(7)然后,我們定義了頂點著色器的輸入和輸出結(jié)構(gòu)體(輸出結(jié)構(gòu)體同時也是片元著色器的
輸入結(jié)構(gòu)體):
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
fixed3 color : COLOR;
};
為了訪問頂點的法線,我們需要在a2v 中定義一個normal 變量,并通過使用NORMAL 語義
來告訴Unity 要把模型頂點的法線信息存儲到normal 變量中。為了把在頂點著色器中計算得到的
光照顏色傳遞給片元著色器,我們需要在v2f 中定義一個color 變量,且并不是必須使用COLOR
語義,一些資料中會使用TEXCOORD0 語義。
(8)接下來是關(guān)鍵的頂點著色器。由于本小節(jié)關(guān)注如何實現(xiàn)一個逐頂點的漫反射光照,因此
漫反射部分的計算都將在頂點著色器中進行:
v2f vert(a2v v) {
v2f o;
// Transform the vertex from object space to projection space
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
// Get ambient term
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
// Transform the normal fram object space to world space
fixed3 worldNormal = normalize(mul(v.normal, (float3x3)_World2Object));
// Get the light direction in world space
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
// Compute diffuse term
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,
worldLight));
o.color = ambient + diffuse;
return o;
}
在第一行,我們首先定義了返回值o。我們已經(jīng)重復(fù)過很多次,頂點著色器最基本的任務(wù)就
是把頂點位置從模型空間轉(zhuǎn)換到裁剪空間中,因此我們需要使用Unity 內(nèi)置的模型世界投影矩
陣UNITY_MATRIX_MVP 來完成這樣的坐標(biāo)變換。接下來,我們通過Unity 的內(nèi)置變量
UNITY_LIGHTMODEL_AMBIENT 得到了環(huán)境光部分。
然后,就是真正計算漫反射光照的部分。回憶一下,為了計算漫反射光照我們需要知道4 個
參數(shù)。在前面的步驟中,我們已經(jīng)知道了材質(zhì)的漫反射顏色_Diffuse 以及頂點法線v.normal。我們
還需要知道光源的顏色和強度信息以及光源方向。Unity 提供給我們一個內(nèi)置變量_LightColor0 來
訪問該Pass 處理的光源的顏色和強度信息(注意,想要得到正確的值需要定義合適的LightMode
標(biāo)簽),而光源方向可以由_WorldSpaceLightPos0 來得到。需要注意的是,這里對光源方向的計算
并不具有通用性。在本節(jié)中,我們假設(shè)場景中只有一個光源且該光源的類型是平行光。但如果場
景中有多個光源并且類型可能是點光源等其他類型,直接使用_WorldSpaceLightPos0 就不能得到
正確的結(jié)果。我們將在6.6 節(jié)中學(xué)習(xí)如何使用內(nèi)置函數(shù)來處理更復(fù)雜的光源類型。
在計算法線和光源方向之間的點積時,我們需要選擇它們所在的坐標(biāo)系,只有兩者處于同一
坐標(biāo)空間下,它們的點積才有意義。在這里,我們選擇了世界坐標(biāo)空間。而由a2v 得到的頂點法
線是位于模型空間下的,因此我們首先需要把法線轉(zhuǎn)換到世界空間中。在4.7 節(jié)中,我們已經(jīng)知
道可以使用頂點變換矩陣的逆轉(zhuǎn)置矩陣對法線進行相同的變換,因此我們首先得到模型空間到世
界空間的變換矩陣的逆矩陣_World2Object,然后通過調(diào)換它在mul 函數(shù)中的位置,得到和轉(zhuǎn)置矩
陣相同的矩陣乘法。由于法線是一個三維矢量,因此我們只需要截取_World2Object 的前三行前三
列即可。
在得到了世界空間中的法線和光源方向后,我們需要對它們進行歸一化操作。在得到它們點
積的結(jié)果后,我們需要防止這個結(jié)果為負(fù)值。為此,我們使用了saturate 函數(shù)。saturate 函數(shù)是Cg
提供的一種函數(shù),它的作用是可以把參數(shù)截取到[0, 1]的范圍內(nèi)。最后,再與光源的顏色和強度以
及材質(zhì)的漫反射顏色相乘即可得到最終的漫反射光照部分。
最后,我們對環(huán)境光和漫反射光部分相加,得到最終的光照結(jié)果。
(9)由于所有的計算在頂點著色器中都已經(jīng)完成了,因此片元著色器的代碼很簡單,我們只
需要直接把頂點顏色輸出即可:
fixed4 frag(v2f i) : SV_Target {
return fixed4(i.color, 1.0);
}
(10)最后,我們需要把這個Unity Shader 的回調(diào)shader 設(shè)置為內(nèi)置的Diffuse:
Fallback “Diffuse”
至此,我們已經(jīng)詳細(xì)解釋了逐頂點的漫反射光照的實現(xiàn)。對于細(xì)分程度較高的模型,逐頂點
光照已經(jīng)可以得到比較好的光照效果了。但對于一些細(xì)分程度較低的模型,逐頂點光照就會出現(xiàn)
一些視覺問題,例如我們可以在圖6.6 中看到在膠囊體的背光面與向光面交界處有一些鋸齒。為
了解決這些問題,我們可以使用逐像素的漫反射光照。
6.4.2 實踐:逐像素光照
我們只需要對Shader 進行一些更改就可以實現(xiàn)逐像素的漫反射效果,如圖6.7 所示。


為此,我們進行如下準(zhǔn)備工作。
(1)使用6.4.1 節(jié)中使用的場景。
(2)新建一個材質(zhì)。在本書資源中,該材質(zhì)名為DiffusePixelLevelMat。
(3)新建一個Unity Shader。在本書資源中,該Shader 名為Chapter6-DiffusePixelLevel。把新
的Shader 賦給第2 步中創(chuàng)建的材質(zhì)。
(4)把第2 步中創(chuàng)建的材質(zhì)賦給膠囊體。

Chapter6-DiffusePixelLevel 的代碼和6.4.1 小節(jié)中的非常相似,因此我們首先把6.4.1 節(jié)中的
代碼直接粘貼到Chapter6-DiffusePixelLevel 中,并進行如下修改。
(1)修改頂點著色器的輸出結(jié)構(gòu)體v2f:
struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
};
(2)頂點著色器不需要計算光照模型,只需要把世界空間下的法線傳遞給片元著色器即可:
v2f vert(a2v v) {
v2f o;
// Transform the vertex from object space to projection space
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
// Transform the normal fram object space to world space
o.worldNormal = mul(v.normal, (float3x3)_World2Object);
return o;
}
(3)片元著色器需要計算漫反射光照模型:
fixed4 frag(v2f i) : SV_Target {
// Get ambient term
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
// Get the normal in world space
fixed3 worldNormal = normalize(i.worldNormal);
// Get the light direction in world space
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
// Compute diffuse term
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,
worldLightDir));
fixed3 color = ambient + diffuse;
return fixed4(color, 1.0);
}
上面的計算過程和6.4.1 節(jié)完全相同,這里不再贅述。
逐像素光照可以得到更加平滑的光照效果。但是,即便使用了逐像素漫反射光照,有一個問
題仍然存在。在光照無法到達(dá)的區(qū)域,模型的外觀通常是全黑的,沒有任何明暗變化,這會使模
型的背光區(qū)域看起來就像一個平面一樣,失去了模型細(xì)節(jié)表現(xiàn)。實際上我們可以通過添加環(huán)境光
來得到非全黑的效果,但即便這樣仍然無法解決背光面明暗一樣的缺點。為此,有一種改善技術(shù)
被提出來,這就是半蘭伯特(Half Lambert)光照模型。
6.4.3 半蘭伯特模型
在6.4.1 小節(jié)中,我們使用的漫反射光照模型也被稱為蘭伯特光照模型,因為它符合蘭伯特定
律—在平面某點漫反射光的光強與該反射點的法向量和入射光角度的余弦值成正比。為了改善
6.4.2 小節(jié)最后提出的問題,Valve 公司在開發(fā)游戲《半條命》時提出了一種技術(shù),由于該技術(shù)是
在原蘭伯特光照模型的基礎(chǔ)上進行了一個簡單的修改,因此被稱為半蘭伯特光照模型。
廣義的半蘭伯特光照模型的公式如下:
可以看出,與原蘭伯特模型相比,半蘭伯特光照模型沒有使用max 操作來防止?n 和?l 的點積
為負(fù)值,而是對其結(jié)果進行了一個?倍的縮放再加上一個?大小的偏移。絕大多數(shù)情況下,?和?
的值均為0.5,即公式為:
通過這樣的方式,我們可以把?n · ?l 的結(jié)果范圍從[?1, 1]映射到[0, 1]范圍內(nèi)。也就是說,對于
模型的背光面,在原蘭伯特光照模型中點積結(jié)果將映射到同一個值,即0 值處;而在半蘭伯特模
型中,背光面也可以有明暗變化,不同的點積結(jié)果會映射到不同的值上。
需要注意的是,半蘭伯特是沒有任何物理依據(jù)的,它僅僅是一個視覺加強技術(shù)。
對6.4.2 小節(jié)中得到的代碼做一些修改就可以實現(xiàn)半蘭伯特漫反射光照效果。
(1)仍然使用6.4.1 小節(jié)中使用的場景。
(2)新建一個材質(zhì)。在本書資源中,該材質(zhì)名為HalfLambertMat。
(3)新建一個Unity Shader。在本書資源中,該Shader 名為Chapter6-HalfLambert。把新的
Shader 賦給第2 步中創(chuàng)建的材質(zhì)。
(4)把第2 步中創(chuàng)建的材質(zhì)賦給膠囊體。
打開Chapter6-HalfLambert,刪除已有的Shader 代碼,把6.4.2小節(jié)的Chapter6-DiffusePixelLevel
代碼粘貼進去,并使用半蘭伯特公式修改片元著色器中計算漫反射光照的部分:
fixed4 frag(v2f i) : SV_Target {

// Compute diffuse term
fixed halfLambert = dot(worldNormal, worldLightDir) * 0.5 + 0.5;
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;
fixed3 color = ambient + diffuse;
return fixed4(color, 1.0);
}
在上面的代碼中,我們使用半蘭伯特模型代替了原有的蘭伯特模型。圖6.8 給出了逐頂點漫
反射光照、逐像素漫反射光照和半蘭伯特光照的對比效果。

參考

Unity Shader入門精要
作者:馮樂樂

總結(jié)

以上是生活随笔為你收集整理的unity入门精要之第6 章 Unity 中的基础光照--环境光和自发光的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产一区二区免费看 | 国产不卡在线 | 日本免费网站视频 | 久久青草免费视频 | 国产第一草草影院 | 5个黑人躁我一个视频 | 五月婷婷丁香在线 | 欧美色激情 | 成都免费高清电影 | 亚洲影院在线播放 | 青青毛片 | 男人天堂视频网 | 亚洲最大成人网站 | 一级啪啪片 | 视频在线国产 | 亚洲毛片视频 | 韩国中文字幕 | 免费黄色资源 | 欧美精品欧美精品系列 | 欧美成人三级在线播放 | 亚洲丁香花色 | 东方影库av | 高清乱码免费网 | 亚洲国产果冻传媒av在线观看 | 成人免费av片| 久久久资源网 | 国产精品日日夜夜 | 日日干,夜夜操 | 欧美激情国产日韩精品一区18 | 人人看人人澡 | 国产成人超碰人人澡人人澡 | 国产免费不卡 | 日日夜夜操操 | 丁香啪啪| 亚洲女人毛片 | 欧洲做受高潮免费看 | 亚洲精品高清在线观看 | 看一级黄色 | 草逼网站| 国产极品免费 | 天天摸夜夜 | 国产做爰视频免费播放 | 国产无套内射又大又猛又粗又爽 | 黄网免费视频 | 99久久久久成人国产免费 | 久久精品毛片 | 亚洲黄色网址 | 四虎一区二区 | 年代下乡啪啪h文 | ts人妖在线 | 1024亚洲 | 五月花婷婷 | 嫩草嫩草嫩草嫩草嫩草 | 一区二区三区在线免费观看 | 日本午夜电影 | av污| 香蕉影院在线观看 | 羞辱狗奴的句子有哪些 | 日韩精品免费一区二区夜夜嗨 | 国产乱码精品一区二区三区不卡 | 天天射夜夜 | 一本色道久久88 | 好吊色这里只有精品 | 激情视频网站 | 国产黄a三级 | 国产男女无遮挡猛进猛出 | 国产视频观看 | 一级片免费网站 | 中国一级特黄毛片 | 毛片手机在线 | 性高潮久久久久久久久 | 中文字幕在线视频播放 | 天海翼中文字幕 | 亚洲天堂av一区二区 | 女人下面流白浆的视频 | 国产自在线 | 香蕉污视频在线观看 | 精品无码久久久久国产 | 国产午夜电影 | 好吊妞无缓冲视频观看 | 国产成人在线免费视频 | 国产精品国产三级国产在线观看 | av五月天在线 | 少妇免费视频 | 羞羞网站在线观看 | 亚洲熟伦熟女新五十路熟妇 | 成年人黄色av | 婷婷亚洲五月 | 国产在线观看中文字幕 | 免费又黄又爽又色的视频 | 日本欧美国产在线 | 日日干夜夜干 | 亚洲天堂中文字幕在线观看 | 嫩草精品 | 91精品国产91久久久久久 | 欧美成人一二三区 | 美女福利在线视频 | 亚洲色图50p| 色哟哟一区二区三区四区 |