Vulkan_Shader_Day05—光照(投光物_Light casters)

投光物(Light casters)

我們目前使用的光照都來自於空間中的一個點。它能給我們不錯的效果,但現實世界中,我們有很多種類的光照,每種的表現都不同。將光投射(Cast)到物體的光源叫做投光物(Light Caster)。在這一節中,我們將會討論幾種不同類型的投光物。學會模擬不同種類的光源是又一個能夠進一步豐富場景的工具。

我們首先將會討論定向光(Directional Light),接下來是點光源(Point Light),它是我們之前學習的光源的拓展,最後我們將會討論聚光(Spotlight)。在下一節中我們將討論如何將這些不同種類的光照類型整合到一個場景之中。

一、平行光

當一個光源處於很遠的地方時,來自光源的每條光線就會近似於互相平行。不論物體和/或者觀察者的位置,看起來好像所有的光都來自於同一個方向。當我們使用一個假設光源處於無限遠處的模型時,它就被稱爲定向光,因爲它的所有光線都有着相同的方向,它與光源的位置是沒有關係的。

定向光非常好的一個例子就是太陽。太陽距離我們並不是無限遠,但它已經遠到在光照計算中可以把它視爲無限遠了。所以來自太陽的所有光線將被模擬爲平行光線,我們可以在下圖看到:
在這裏插入圖片描述
因爲所有的光線都是平行的,所以物體與光源的相對位置是不重要的,因爲對場景中每一個物體光的方向都是一致的。由於光的位置向量保持一致,場景中每個物體的光照計算將會是類似的。

我們可以定義一個光線方向向量而不是位置向量來模擬一個定向光。着色器的計算基本保持不變,但這次我們將直接使用光的direction向量而不是通過direction來計算lightDir向量。


glm::vec3 lightDir = glm::vec3(0.0f, 0.0f, -1.0f);
...
struct UniformBufferObject {
	 ...
	 glm::vec3 viewPos;
	 float foo = 0.0f;
	 glm::vec3 lightDirect;
};

首先定義一個全局的光照方向,之後在UniformBufferObject中添加新的數據lightDirect,此數據之前添加了float foo = 0.0f爲了適應vulkan內存對齊
接下來我們更新更新頂點着色器,

...
layout(binding = 0) uniform UniformBufferObject {
    ...
	vec3 viewPos;
	vec3 lightDirect;
} ubo;
...
layout(location = 13) out vec3 lightDirect;
...
void main() {
    ...
	lightDirect= ubo.lightDirect;
}

再下一步我們更新片元着色器,

#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(binding = 1) uniform sampler2D texSampler;

layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec3 fragNormal;
layout(location = 2) in vec2 fragTexCoord;
layout(location = 3) in vec3 fragBaseLight;
layout(location = 4) in float ambientStrength;
layout(location = 5) in vec3 lightPos;
layout(location = 6) in vec3 fragPos;
layout(location = 7) in float specularStrength;
layout(location = 8) in vec3 viewPos;
//Material
layout(location = 9) in vec3 m_ambient;
layout(location = 10) in vec3 m_diffuse;
layout(location = 11) in vec3 m_specular;
layout(location = 12) in float m_shininess;

layout(location = 13) in vec3 lightDirect;

layout(location = 0) out vec4 outColor;

void main() {

    ...

    // Ambient Light
    vec3 ambient = ambientStrength * fragBaseLight * lightAmbient ;

	// Diffuse Light
	vec3 norm = normalize(fragNormal);
    //vec3 lightDir = normalize(lightPos - fragPos);
    vec3 lightDir = normalize(-lightDirect);
	float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * fragBaseLight * lightDiffuse;
	

    vec3 result = ambient + diffuse ;
    outColor = texture(texSampler, fragTexCoord)* vec4(result, 1.0);
   ...
}

注意我們首先對light.direction向量取反。我們目前使用的光照計算需求一個從片段至光源的光線方向,但人們更習慣定義定向光爲一個從光源出發的全局方向。所以我們需要對全局光照方向向量取反來改變它的方向,它現在是一個指向光源的方向向量了。而且,記得對向量進行標準化,假設輸入向量爲一個單位向量是很不明智的。

編譯運行,可以看到:
在這裏插入圖片描述

二、點光源

定向光對於照亮整個場景的全局光源是非常棒的,但除了定向光之外我們也需要一些分散在場景中的點光源(Point Light)。點光源是處於世界中某一個位置的光源,它會朝着所有方向發光,但光線會隨着距離逐漸衰減。想象作爲投光物的燈泡和火把,它們都是點光源。
在這裏插入圖片描述
在之前的教程中,我們一直都在使用一個(簡化的)點光源。我們在給定位置有一個光源,它會從它的光源位置開始朝着所有方向散射光線。然而,我們定義的光源模擬的是永遠不會衰減的光線,這看起來像是光源亮度非常的強。在大部分的3D模擬中,我們都希望模擬的光源僅照亮光源附近的區域而不是整個場景。
首先我們在片元着色器中加上鏡面光照:

void main() {
    ...
	// Specular Lighting
	vec3 viewDir = normalize(viewPos - fragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
	float spec = pow(max(dot(viewDir, reflectDir), 0.0), m_shininess);
    vec3 specular = spec * fragBaseLight * lightSpecular * lightSpecular;

    vec3 result = ambient + diffuse + specular ;
    outColor = texture(texSampler, fragTexCoord)* vec4(result, 1.0);
}

編譯運行,可以看到:
在這裏插入圖片描述
調整一下角度,再次觀察:
在這裏插入圖片描述
你會注意到在最後面的箱子和在燈面前的箱子都以相同的強度被照亮,並沒有定義一個公式來將光隨距離衰減。我們希望在後排的箱子與前排的箱子相比僅僅是被輕微地照亮。

1.衰減

隨着光線傳播距離的增長逐漸削減光的強度通常叫做衰減(Attenuation)。隨距離減少光強度的一種方式是使用一個線性方程。這樣的方程能夠隨着距離的增長線性地減少光的強度,從而讓遠處的物體更暗。然而,這樣的線性方程通常會看起來比較假。在現實世界中,燈在近處通常會非常亮,但隨着距離的增加光源的亮度一開始會下降非常快,但在遠處時剩餘的光強度就會下降的非常緩慢了。所以,我們需要一個不同的公式來減少光的強度。

幸運的是一些聰明的人已經幫我們解決了這個問題。下面這個公式根據片段距光源的距離計算了衰減值,之後我們會將它乘以光的強度向量:
在這裏插入圖片描述
在這裏d代表了片段距光源的距離。接下來爲了計算衰減值,我們定義3個(可配置的)項:常數項Kc、一次項Kl和二次項Kq。

  • 常數項通常保持爲1.0,它的主要作用是保證分母永遠不會比1小,否則的話在某些距離上它反而會增加強度,這肯定不是我們想要的效果。
  • 一次項會與距離值相乘,以線性的方式減少強度。
  • 二次項會與距離的平方相乘,讓光源以二次遞減的方式減少強度。二次項在距離比較小的時候影響會比一次項小很多,但當距離值比較大的時候它就會比一次項更大了。

由於二次項的存在,光線會在大部分時候以線性的方式衰退,直到距離變得足夠大,讓二次項超過一次項,光的強度會以更快的速度下降。這樣的結果就是,光在近距離時亮度很高,但隨着距離變遠亮度迅速降低,最後會以更慢的速度減少亮度。下面這張圖顯示了在100的距離內衰減的效果:
在這裏插入圖片描述
你可以看到光在近距離的時候有着最高的強度,但隨着距離增長,它的強度明顯減弱,並緩慢地在距離大約100的時候強度接近0。這正是我們想要的。
選擇正確的值:
但是,該對這三個項設置什麼值呢?正確地設定它們的值取決於很多因素:環境、希望光覆蓋的距離、光的類型等。在大多數情況下,這都是經驗的問題,以及適量的調整。下面這個表格顯示了模擬一個(大概)真實的,覆蓋特定半徑(距離)的光源時,這些項可能取的一些值。第一列指定的是在給定的三項時光所能覆蓋的距離。這些值是大多數光源很好的起始點,它們由Ogre3D的Wiki所提供:
在這裏插入圖片描述
你可以看到,常數項Kc在所有的情況下都是1.0。一次項Kl爲了覆蓋更遠的距離通常都很小,二次項Kq甚至更小。嘗試對這些值進行實驗,看看它們在你的實現中有什麼效果。在我們的環境中,32到100的距離對大多數的光源都足夠了。

2.實現衰減

爲了實現衰減,在片段着色器中我們還需要三個額外的值:也就是公式中的常數項、一次項和二次項。由於這三個係數我們很少修改,大部分場景此組合固定值效果最佳,所以我們和光照相關屬性類似硬編碼在片元着色器中.

void main() {
    ...
	float constant = 1.0f;
    float linear =  0.09f;
    float quadratic = 0.032f;
    ...
}

在片段着色器中實現衰減還是比較直接的:我們根據公式計算衰減值,之後再分別乘以環境光、漫反射和鏡面光分量。

我們仍需要公式中距光源的距離,還記得我們是怎麼計算一個向量的長度的嗎?我們可以通過獲取片段和光源之間的向量差,並獲取結果向量的長度作爲距離項。我們可以使用GLSL內建的length函數來完成這一點:

void main() {
    ...
   	float distance = length(lightPos - fragPos);
    float attenuation = 1.0 / (constant + linear * distance +  quadratic * (distance * distance));
    ...
}

接下來,我們將包含這個衰減值到光照計算中,將它分別乘以環境光、漫反射和鏡面光顏色。

void main() {
    ...
    vec3 result = (ambient + diffuse + specular) * attenuation ;
    outColor = texture(texSampler, fragTexCoord)* vec4(result, 1.0);
    ...
}

再次運行,並調整視角:
在這裏插入圖片描述
你可以看到,只有前排的箱子被照亮的,距離最近的箱子是最亮的。後排的箱子一點都沒有照亮,因爲它們離光源實在是太遠了。

點光源就是一個能夠配置位置和衰減的光源。它是我們光照工具箱中的又一個光照類型。

三、聚光

我們要討論的最後一種類型的光是聚光(Spotlight)。聚光是位於環境中某個位置的光源,它只朝一個特定方向而不是所有方向照射光線。這樣的結果就是只有在聚光方向的特定半徑內的物體纔會被照亮,其它的物體都會保持黑暗。聚光很好的例子就是路燈或手電筒。

Vulkan中聚光是用一個世界空間位置、一個方向和一個切光角(Cutoff Angle)來表示的,切光角指定了聚光的半徑(譯註:是圓錐的半徑不是距光源距離那個半徑)。對於每個片段,我們會計算片段是否位於聚光的切光方向之間(也就是在錐形內),如果是的話,我們就會相應地照亮片段。下面這張圖會讓你明白聚光是如何工作的:
在這裏插入圖片描述

  • LightDir:從片段指向光源的向量。
  • SpotDir:聚光所指向的方向。
  • Phiϕ:指定了聚光半徑的切光角。落在這個角度之外的物體都不會被這個聚光所照亮。
  • Thetaθ:LightDir向量和SpotDir向量之間的夾角。在聚光內部的話θ值應該比ϕ值小。

所以我們要做的就是計算LightDir向量和SpotDir向量之間的點積(還記得它會返回兩個單位向量夾角的餘弦值嗎?),並將它與切光角ϕ值對比。你現在應該瞭解聚光究竟是什麼了,下面我們將以手電筒的形式創建一個聚光。

1.手電筒

手電筒(Flashlight)是一個位於觀察者位置的聚光,通常它都會瞄準玩家視角的正前方。基本上說,手電筒就是普通的聚光,但它的位置和方向會隨着玩家的位置和朝向不斷更新。

所以,在片段着色器中我們需要的值有聚光的位置向量(來計算光的方向向量)、聚光的方向向量和一個切光角。我們可以將它們儲存在UniformBufferObject 結構體中:

struct UniformBufferObject {
	 ...
	 glm::vec3 lightDirect;
	 float foo2 = 0.0f;
	 glm::vec3 flashPos;
	 float outerCutOff;
	 glm::vec3 flashDir;
	 float flashCutOff ;
};

在updateUniformBuffer函數中更新這些數據:

void updateUniformBuffer() {
		...
		ubo.flashPos = camera.Position;
		ubo.flashDir = camera.Forward;
		ubo.flashCutOff = glm::cos(glm::radians(12.5f));
		ubo.outerCutOff = glm::cos(glm::radians(14.5f));
		...
	}

接下來更新頂點着色器和片元着色器

layout(binding = 0) uniform UniformBufferObject {
    ...
	vec3 flashPos;
	float outerCutOff;
	vec3 flashDir;
	float flashCutOff ;
} ubo;

...
layout(location = 14) out vec3 flashPos;
layout(location = 15) out vec3 flashDir;
layout(location = 16) out float flashCutOff;
layout(location = 17) out float outerCutOff;
...
void main() {
    ...
	flashPos= ubo.flashPos;
	flashDir= ubo.flashDir;
	flashCutOff= ubo.flashCutOff;
	outerCutOff= ubo.outerCutOff;
}
layout(location = 14) in vec3 flashPos;
layout(location = 15) in vec3 flashDir;
layout(location = 16) in float flashCutOff;
layout(location = 17) in float outerCutOff;

你可以看到,我們並沒有給切光角設置一個角度值,反而是用角度值計算了一個餘弦值,將餘弦結果傳遞到片段着色器中。這樣做的原因是在片段着色器中,我們會計算LightDir和SpotDir向量的點積,這個點積返回的將是一個餘弦值而不是角度值,所以我們不能直接使用角度值和餘弦值進行比較。爲了獲取角度值我們需要計算點積結果的反餘弦,這是一個開銷很大的計算。所以爲了節約一點性能開銷,我們將會計算切光角對應的餘弦值,並將它的結果傳入片段着色器中。由於這兩個角度現在都由余弦角來表示了,我們可以直接對它們進行比較而不用進行任何開銷高昂的計算。

接下來就是計算θ值,並將它和切光角ϕ對比,來決定是否在聚光的內部:

void main() {

    vec3 lightAmbient  = vec3( 0.2f, 0.2f, 0.2f);
    vec3 lightDiffuse  = vec3( 0.5f, 0.5f, 0.5f);
    vec3 lightSpecular = vec3( 1.0f, 1.0f, 1.0f);
	

	float theta = dot(normalize(lightPos - fragPos), normalize(-flashDir));
	if(theta > flashCutOff) // 執行光照計算
    {       
       // Ambient Lighting
       vec3 ambient = ambientStrength * fragBaseLight * lightAmbient ;
	   
	   // Diffuse Lighting
	   vec3 norm = normalize(fragNormal);
       // lightDir = normalize(lightPos - fragPos);
       vec3 lightDir = normalize(-lightDirect);
	   float diff = max(dot(norm, lightDir), 0.0);
       vec3 diffuse = diff * fragBaseLight * lightDiffuse;
	   
	   // Specular Lighting
	   vec3 viewDir = normalize(viewPos - fragPos);
       vec3 reflectDir = reflect(-lightDir, norm);
	   float spec = pow(max(dot(viewDir, reflectDir), 0.0), m_shininess);
       vec3 specular = spec * fragBaseLight * lightSpecular * lightSpecular;

	   float constant = 1.0f;
       float linear =  0.09f;
       float quadratic = 0.032f;
	   float distance = length(lightPos - fragPos);
       float attenuation = 1.0 / (constant + linear * distance +  quadratic * (distance * distance));
	   vec3 result =ambient + (diffuse + specular) * attenuation ;
       outColor = texture(texSampler, fragTexCoord)* vec4(result, 1.0);
    }
    else  // 否則,使用環境光,讓場景在聚光之外時不至於完全黑暗
      outColor = vec4(lightAmbient * vec3(texture(texSampler, fragTexCoord)), 1.0);
}

我們首先計算了lightDir和取反的direction向量(取反的是因爲我們想讓向量指向光源而不是從光源出發)之間的點積。記住要對所有的相關向量標準化。
運行程序,你將會看到一個聚光,它僅會照亮聚光圓錐內的片段。看起來像是這樣的:
在這裏插入圖片描述
但這仍看起來有些假,主要是因爲聚光有一圈硬邊。當一個片段遇到聚光圓錐的邊緣時,它會完全變暗,沒有一點平滑的過渡。一個真實的聚光將會在邊緣處逐漸減少亮度。

2.平滑/軟化邊緣

爲了創建一種看起來邊緣平滑的聚光,我們需要模擬聚光有一個內圓錐(Inner Cone)和一個外圓錐(Outer Cone)。我們可以將內圓錐設置爲上一部分中的那個圓錐,但我們也需要一個外圓錐,來讓光從內圓錐逐漸減暗,直到外圓錐的邊界。

爲了創建一個外圓錐,我們只需要再定義一個餘弦值來代表聚光方向向量和外圓錐向量(等於它的半徑)的夾角。然後,如果一個片段處於內外圓錐之間,將會給它計算出一個0.0到1.0之間的強度值。如果片段在內圓錐之內,它的強度就是1.0,如果在外圓錐之外強度值就是0.0。
我們可以用下面這個公式來計算這個值:
在這裏插入圖片描述
這裏ϵ(Epsilon)是內(ϕ)和外圓錐(γ)之間的餘弦值差(ϵ=ϕ−γ)。最終的I值就是在當前片段聚光的強度。

很難去表現這個公式是怎麼工作的,所以我們用一些實例值來看看:
在這裏插入圖片描述
你可以看到,我們基本是在內外餘弦值之間根據θ插值。如果你仍不明白髮生了什麼,不必擔心,只需要記住這個公式就好了,在你更聰明的時候再回來看看。

我們現在有了一個在聚光外是負的,在內圓錐內大於1.0的,在邊緣處於兩者之間的強度值了。如果我們正確地約束(Clamp)這個值,在片段着色器中就不再需要if-else了,我們能夠使用計算出來的強度值直接乘以光照分量:

void main() {

    ...
	// spotlight (soft edges)
    float theta = dot(normalize(lightPos - fragPos), normalize(-flashDir));
    float epsilon = (flashCutOff - outerCutOff);
    float intensity = clamp((theta - outerCutOff) / epsilon, 0.0, 1.0);
    // 將不對環境光做出影響,讓它總是能有一點光
    diffuse  *= intensity;
    specular *= intensity;
		...

注意我們使用了clamp函數,它把第一個參數約束(Clamp)在了0.0到1.0之間。這保證強度值不會在[0, 1]區間之外。

確定你將outerCutOff值添加到了UniformBufferObject結構體之中,並在程序中設置它的值。下面的圖片中,我們使用的內切光角是12.5,外切光角是14.5:
你可以在上述的更新數據代碼中找到對應的更新。
運行,可以看到:
在這裏插入圖片描述
這樣看起來就好多了。稍微對內外切光角實驗一下,嘗試創建一個更能符合你需求的聚光。

這樣的手電筒/聚光類型的燈光非常適合恐怖遊戲,結合定向光和點光源,環境就會開始被照亮了。在下一節的教程中,我們將會結合我們至今討論的所有光照和技巧。

附:着色器源碼

頂點着色器

#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(binding = 0) uniform UniformBufferObject {
    mat4 model;
    mat4 view;
    mat4 proj;
	vec3 baseLight;
	float ambientStrength;
	vec3 lightPos;
	float specularStrength ;
	vec3 viewPos;
	vec3 lightDirect;
	vec3 flashPos;
	float outerCutOff;
	vec3 flashDir;
	float flashCutOff ;
} ubo;

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec3 inNormal;
layout(location = 3) in vec2 inTexCoord;
layout(location = 4) in vec3 inM_ambient;
layout(location = 5) in vec3 inM_diffuse;
layout(location = 6) in vec3 inM_specular;
layout(location = 7) in float inM_shininess;

layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec3 fragNormal;
layout(location = 2) out vec2 fragTexCoord;
layout(location = 3) out vec3 fragBaseLight;
layout(location = 4) out float ambientStrength;
layout(location = 5) out vec3 lightPos;
layout(location = 6) out vec3 fragPos;
layout(location = 7) out float specularStrength;
layout(location = 8) out vec3 viewPos;
//Material
layout(location = 9) out vec3 m_ambient;
layout(location = 10) out vec3 m_diffuse;
layout(location = 11) out vec3 m_specular;
layout(location = 12) out float m_shininess;
layout(location = 13) out vec3 lightDirect;
layout(location = 14) out vec3 flashPos;
layout(location = 15) out vec3 flashDir;
layout(location = 16) out float flashCutOff;
layout(location = 17) out float outerCutOff;

layout(push_constant) uniform PushConsts {
	vec3 objPos;
} pushConsts;

void main() {
    gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition + pushConsts.objPos, 1.0);
	fragPos =vec3( ubo.model * vec4(inPosition+ pushConsts.objPos, 1.0));;
    fragColor = inColor;
    fragNormal = mat3(transpose(inverse(ubo.model))) *inNormal;
	fragTexCoord = inTexCoord;
	fragBaseLight = ubo.baseLight;
	ambientStrength= ubo.ambientStrength;
	lightPos=ubo.lightPos;
	specularStrength=ubo.specularStrength;
	viewPos=ubo.viewPos;
	m_ambient = inM_ambient;
	m_diffuse = inM_diffuse;
	m_specular = inM_specular;
	m_shininess = inM_shininess;
	lightDirect= ubo.lightDirect;
	flashPos= ubo.flashPos;
	flashDir= ubo.flashDir;
	flashCutOff= ubo.flashCutOff;
	outerCutOff= ubo.outerCutOff;
}

片元着色器

#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(binding = 1) uniform sampler2D texSampler;

layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec3 fragNormal;
layout(location = 2) in vec2 fragTexCoord;
layout(location = 3) in vec3 fragBaseLight;
layout(location = 4) in float ambientStrength;
layout(location = 5) in vec3 lightPos;
layout(location = 6) in vec3 fragPos;
layout(location = 7) in float specularStrength;
layout(location = 8) in vec3 viewPos;
//Material
layout(location = 9) in vec3 m_ambient;
layout(location = 10) in vec3 m_diffuse;
layout(location = 11) in vec3 m_specular;
layout(location = 12) in float m_shininess;
layout(location = 13) in vec3 lightDirect;
layout(location = 14) in vec3 flashPos;
layout(location = 15) in vec3 flashDir;
layout(location = 16) in float flashCutOff;
layout(location = 17) in float outerCutOff;

layout(location = 0) out vec4 outColor;

void main() {

    vec3 lightAmbient  = vec3( 0.2f, 0.2f, 0.2f);
    vec3 lightDiffuse  = vec3( 0.5f, 0.5f, 0.5f);
    vec3 lightSpecular = vec3( 1.0f, 1.0f, 1.0f);
	  
    // Ambient Lighting
    vec3 ambient = ambientStrength * fragBaseLight * lightAmbient ;
	 
	// Diffuse Lighting
	vec3 norm = normalize(fragNormal);
    // lightDir = normalize(lightPos - fragPos);
    vec3 lightDir = normalize(-lightDirect);
	float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * fragBaseLight * lightDiffuse;
	 
	// Specular Lighting
	vec3 viewDir = normalize(viewPos - fragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
	float spec = pow(max(dot(viewDir, reflectDir), 0.0), m_shininess);
    vec3 specular = spec * fragBaseLight * lightSpecular * lightSpecular;

	// spotlight (soft edges)
	float theta = dot(normalize(lightPos - fragPos), normalize(-flashDir));
    float epsilon = (flashCutOff - outerCutOff);
    float intensity = clamp((theta - outerCutOff) / epsilon, 0.0, 1.0);
	// 將不對環境光做出影響,讓它總是能有一點光
    diffuse  *= intensity;
    specular *= intensity;

	// attenuation
	float constant = 1.0f;
    float linear =  0.09f;
    float quadratic = 0.032f;
	float distance = length(lightPos - fragPos);
    float attenuation = 1.0 / (constant + linear * distance +  quadratic * (distance * distance));
	vec3 result =ambient + (diffuse + specular) * attenuation ;
    outColor = texture(texSampler, fragTexCoord)* vec4(result, 1.0);

    
    //outColor = vec4(fragTexCoord, 0.0, 1.0);
	//outColor = vec4(fragColor * texture(texSampler, fragTexCoord).rgb, 1.0);
    //outColor = texture(texSampler, fragTexCoord)* vec4(fragBaseLight, 1.0);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章