OpenGL學習筆記(十二)多光源的使用

首先光源分爲三種,分別是平行光,點光源,聚光源。

平行光有些類似於我們自然界中見到的太陽。它的角度屬性,會對光照的實際渲染效果有一定的影響,但是他的位置屬性則完全無法影響光照的實際渲染效果。

在這裏插入圖片描述
點光源則是有點類似於我們的燈泡,就是以一個點向四周發光。與平行光相反,它的角度屬性會對光照的實際渲染效果毫無影響,但是他的位置屬性則會影響光照的實際渲染效果。
在這裏插入圖片描述
點光源衰減函數圖
在這裏插入圖片描述

聚光源則是類似於我們的手電筒,發射一道投射光出去,在這個圓錐體範圍內的纔會反射光。其實際渲染效果會被聚光源的位置和旋轉屬性所影響。
在這裏插入圖片描述
三角函數表:
在這裏插入圖片描述
上代碼:(提醒一下,這裏每個光源都可以拆分出來的。
否則一次性太多了。)

fragmentSrouce.txt

#version 330 core			
out vec4 FragColor;		
in vec3 FragPos;
in vec3 Normal;
in vec2 Texcoord;
//點光源結構體
struct LightPoint{
vec3 pos;//燈光位置
vec3 color;//燈光顏色
float constant;//衰減公式常量
float linear;//衰減公式一維常量
float quadratic;//衰減公式二維常量
};
//聚光源結構體
struct LightSpot{
vec3 dirToLight;
vec3 pos;//燈光位置
vec3 color;//燈光顏色
float cosPhyInner;//內圓錐體角度
float cosPhyOutter;//外圓錐體角度
};
//平行光源結構體
struct LightDirectional{
vec3 dirToLight;
vec3 pos;//燈光位置
vec3 color;//燈光顏色
};

struct Material{
vec3 ambient;
sampler2D diffuse;
sampler2D specular;
float shininess;
};
uniform Material material;

uniform LightPoint lightP; //輸入點光源數據
uniform LightSpot lightS;//輸入聚光源數據
uniform LightDirectional lightD;//輸入平行光數據

uniform vec3 objColor;//模型顏色
uniform vec3 ambientColor;//環境光顏色
uniform vec3 CameraPos;
//平行光漫反射與鏡面效果的計算
vec3 CalclLightDirectional(LightDirectional light,vec3 uNormal,vec3 dirToCamera)
{
//這裏面的計算就是我們以前使用的那種。就不做過多介紹了。
vec3 result=vec3(0.0f,0,0);
//diffuse=(max(dot(dl,n),0))
vec3 diffuse=max(dot(uNormal,-light.dirToLight),0)*light.color*texture(material.diffuse,Texcoord).rgb;
//specular=(max(dot(R,C),0))
vec3 R=reflect(light.dirToLight,uNormal);
vec3 specular=pow(max(dot(R,dirToCamera),0),material.shininess)*light.color*texture(material.specular,Texcoord).rgb;
result=diffuse+specular;
return result;
}
//點光源漫反射與鏡面效果的計算
vec3 CalclLightPoint(LightPoint light,vec3 uNormal,vec3 dirToCamera)
{
vec3 result=vec3(0.0f,0,0);
//計算一個衰減函數,就是離光源越遠的,越暗,可以參考前面的衰減函數圖,進行理解
float dist=length(light.pos-FragPos);
vec3 dirToLight=normalize(light.pos-FragPos);
float attenuation=1.0f / (light.constant + light.linear*dist +light.quadratic*(dist*dist));

//diffuse=(max(dot(dl,n),0))
vec3 diffuse=max(dot(uNormal,dirToLight),0)*light.color*texture(material.diffuse,Texcoord).rgb;
//specular=pow((max(dot(R,C),0)),shininess)
vec3 R=reflect(-dirToLight,uNormal);
vec3 specular=pow(max(dot(R,dirToCamera),0),material.shininess)*light.color*texture(material.specular,Texcoord).rgb;
result=(diffuse+specular)*attenuation;//最後將平行光乘上這個衰減函數
return result;
}
//聚光源漫反射與鏡面效果的計算
vec3 CalclLightSpot(LightSpot light,vec3 uNormal,vec3 dirToCamera)
{
vec3 result=vec3(0.0f,0,0);
vec3 dirToLight=normalize(light.pos-FragPos);
//diffuse=(max(dot(dl,n),0))
vec3 diffuse=max(dot(uNormal,-normalize(light.dirToLight)),0)*light.color*texture(material.diffuse,Texcoord).rgb;
//specular=(max(dot(R,C),0))
vec3 R=reflect(-light.dirToLight,uNormal);
vec3 specular=pow(max(dot(R,dirToCamera),0),material.shininess)*light.color*texture(material.specular,Texcoord).rgb;
float cosTheta=dot(normalize(FragPos-light.pos),light.dirToLight);
//計算一個圓錐體,我們知道兩個向量點乘得到的他兩的夾角的Cos值,
//而這裏我們計算出外圓錐體0.85和內圓錐體0.90的差,並用當前角度的cos值來減去這個外圓錐體,也就是聚光圓錐體能照射到最遠的位置。再使用clamp根據取值來給予0到1的值。其中大於我們預設內圓錐體的值,如1,0.95這些值,都將呈現出1,而在0.9到0.85之間的值則會呈現一個線性的變化,使得光影的轉換更加柔和,不至於那麼生硬。
//上面有三角函數的表,你可以去看看
float epsilon=(light.cosPhyInner-light.cosPhyOutter);
float intensity=clamp((cosTheta-light.cosPhyOutter)/epsilon,0,1.0f);
result=(diffuse+specular)*intensity;
return result;
}

void main()				
{
vec3 result=vec3(0);
vec3 uNormal=normalize(Normal);//將拿過來的法向量歸一化
vec3 dirToCamera=normalize(CameraPos-FragPos);//計算相機距離

result+=CalclLightDirectional(lightD,uNormal,dirToCamera)*objColor;//平行光漫反射與鏡面效果
result+=CalclLightPoint(lightP,uNormal,dirToCamera)*objColor;//點光源漫反射與鏡面效果
result+=CalclLightSpot(lightS,uNormal,dirToCamera)*objColor;//聚廣源漫反射與鏡面效果

 result+=ambientColor*texture(material.diffuse,Texcoord).rgb*objColor;//加上場景光

FragColor = vec4(result,1.0f);
}	

LightDirectional.h

#pragma once
#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
class LightDirectional
{
public:
	glm::vec3 position;//位置
	glm::vec3 angle;//角度
	glm::vec3 direction=glm::vec3(0,0,1.0f);
	glm::vec3 color;//顏色
	LightDirectional(glm::vec3 _position,glm::vec3 _angle,glm::vec3 _color = glm::vec3(1.0f, 1.0f, 1.0f));//構造函數
	void UpdateDirection();//刷新燈光方向值
};

LightDirectional.cpp

#include "LightDirectional.h"

LightDirectional::LightDirectional(glm::vec3 _position, glm::vec3 _angle, glm::vec3 _color )
:position(_position),angle(_angle),color(_color)
{
	UpdateDirection();
}

void LightDirectional::UpdateDirection()
{
	direction = glm::vec3(0,0,1.0f);
	direction = glm::rotateZ(direction, angle.z);//轉z的角度
	direction = glm::rotateY(direction, angle.y);
	direction = glm::rotateX(direction,angle.x);
	direction = -1.0f * direction;//取負值
}

LightPoint.h

#pragma once
#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
class LightPoint
{
public:
	glm::vec3 position;
	glm::vec3 angle;
	glm::vec3 direction = glm::vec3(0, 0, 1.0f);
	glm::vec3 color;
	float constant = 1.0f;//衰減公式常量
	float linear = 0.09f;//衰減公式一維常量
	float quadratic = 0.032f;//衰減公式二維常量
	LightPoint(glm::vec3 _position, glm::vec3 _angle, glm::vec3 _color = glm::vec3(1.0f, 1.0f, 1.0f));
};




LightPoint.cpp

#include "LightPoint.h"

LightPoint::LightPoint(glm::vec3 _position, glm::vec3 _angle, glm::vec3 _color)
:position(_position), angle(_angle), color(_color)
{
}

LightSpot.h

#pragma once
#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
class LightSpot
{
public:
	glm::vec3 position;
	glm::vec3 angle;
	glm::vec3 direction = glm::vec3(0, 0, 1.0f);
	glm::vec3 color;
	LightSpot(glm::vec3 _position, glm::vec3 _angle, glm::vec3 _color = glm::vec3(1.0f, 1.0f, 1.0f));
	void UpdateDirection();
	float cosPhyInner=0.9f;//聚光源內圓錐體cos值
	float cosPhyOutter=0.85f;//聚光源外圓錐體cos值
};

LightSpot.cpp

#include "LightSpot.h"

LightSpot::LightSpot(glm::vec3 _position, glm::vec3 _angle, glm::vec3 _color)
	:position(_position), angle(_angle), color(_color)
{
	UpdateDirection();
}

void LightSpot::UpdateDirection()
{
	direction = glm::vec3(0, 0, 1.0f);
	direction = glm::rotateZ(direction, angle.z);
	direction = glm::rotateY(direction, angle.y);
	direction = glm::rotateX(direction, angle.x);
	direction = -1.0f * direction;
}

main.cpp

申請三種光源,分別是平行光,點光源,聚光源,分別以藍,綠,紅三種色彩。

LightDirectional myLightD(glm::vec3(10.0f,10.0f,5.0f),glm::vec3(glm::radians(0.0f), glm::radians(0.0f),0),glm::vec3(0.0f,0.0f,1.0f));
LightPoint myLightP(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(glm::radians(0.0f), glm::radians(0.0f), 0), glm::vec3(0.0f, 1.0f, 0.0f));
LightSpot myLightS(glm::vec3(1.0f, 4.0f, -3.0f), glm::vec3(glm::radians(-90.0f), glm::radians(0.0f), 0), glm::vec3(1.0f, 0.0f, 0.0f));

渲染通道的使用,(傅老師才說這是渲染通道)
其實就是給予shader裏面的uniform值。

            glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "modelMat"), 1, GL_FALSE, glm::value_ptr(modelMat));
			glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "viewMat"), 1, GL_FALSE, glm::value_ptr(viewMat));
			glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "projMat"), 1, GL_FALSE, glm::value_ptr(projMat));
			
			glUniform3f(glGetUniformLocation(myShader->ID, "objColor"), 1.0f, 1.0f, 1.0f);
			glUniform3f(glGetUniformLocation(myShader->ID, "ambientColor"), 0.1f, 0.1f, 0.1f);
			glUniform3f(glGetUniformLocation(myShader->ID, "CameraPos"), myCamera->Position.x, myCamera->Position.y, myCamera->Position.z);

			glUniform3f(glGetUniformLocation(myShader->ID, "lightD.color"), myLightD.color.x, myLightD.color.y, myLightD.color.z);
			glUniform3f(glGetUniformLocation(myShader->ID, "lightD.pos"), myLightD.position.x, myLightD.position.y, myLightD.position.z);
			glUniform3f(glGetUniformLocation(myShader->ID, "lightD.dirToLight"), myLightD.direction.x, myLightD.direction.y, myLightD.direction.z);

	
			glUniform1f(glGetUniformLocation(myShader->ID, "lightS.cosPhyInner"), myLightS.cosPhyInner);
			glUniform1f(glGetUniformLocation(myShader->ID, "lightS.cosPhyOutter"), myLightS.cosPhyOutter);
			glUniform3f(glGetUniformLocation(myShader->ID, "lightS.color"), myLightS.color.x, myLightS.color.y, myLightS.color.z);
			glUniform3f(glGetUniformLocation(myShader->ID, "lightS.pos"), myLightS.position.x, myLightS.position.y, myLightS.position.z);
			glUniform3f(glGetUniformLocation(myShader->ID, "lightS.dirToLight"), myLightS.direction.x, myLightS.direction.y, myLightS.direction.z);

			glUniform3f(glGetUniformLocation(myShader->ID, "lightP.color"), myLightP.color.x, myLightP.color.y, myLightP.color.z);
			glUniform3f(glGetUniformLocation(myShader->ID, "lightP.pos"), myLightP.position.x, myLightP.position.y, myLightP.position.z);
			glUniform1f(glGetUniformLocation(myShader->ID, "lightP.constant"), myLightP.constant);
			glUniform1f(glGetUniformLocation(myShader->ID, "lightP.linear"), myLightP.linear);
			glUniform1f(glGetUniformLocation(myShader->ID, "lightP.quadratic"), myLightP.quadratic);

最終效果圖:
在這裏插入圖片描述
在這裏插入圖片描述
雖然很醜,但是我很開心。

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