我正在爲物理引擎(類似於this)做出相對簡單的渲染。我剛剛學習OpenGL並一直關注這個tutorial。我希望渲染器能夠處理從方向,點,聚光燈和區域燈中選擇的少量燈光。另外我想要使用陰影貼圖的簡單陰影。例如,一個場景可能包含兩個聚光燈或一個方向燈或一個點光源和一個聚光燈等。目前,我有一個較大的着色器可以處理所有的燈光,但現在我正在試驗陰影貼圖,看起來很光亮(從模塊化設計的角度來看)更好地爲每個燈或至少每種燈類型設置不同的着色器。我想知道從效率的角度來看這是否合理。爲了使這個更具體的我當前頂點的樣子:我應該爲OpenGL渲染器中的每種燈光類型使用不同的着色器
#version 130
in vec3 position;
in vec3 normal;
in vec2 atexture;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoord;
out vec4 FragPosLightSpace;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 lightView;
uniform mat4 lightProjection;
void main()
{
gl_Position = projection * view * model * vec4(position.x, position.y, position.z, 1.0);
FragPos = vec3(model * vec4(position, 1.0));
Normal = normalize(normal);
TexCoord = atexture;
FragPosLightSpace = lightProjection * lightView * vec4(FragPos, 1.0f);
}
和片段着色器:
#version 130
struct Material
{
float shininess;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct DirLight
{
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct PointLight
{
vec3 position;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct SpotLight {
vec3 position;
vec3 direction;
float cutOff;
float outerCutOff;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct AreaLight
{
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoord;
in vec4 FragPosLightSpace;
uniform Material material;
uniform DirLight dirLight;
uniform PointLight pointLight;
uniform SpotLight spotLight;
uniform AreaLight areaLight;
uniform vec3 cameraPos;
uniform sampler2D texture1;
uniform sampler2D shadowMap;
float CalcShadow(vec4 FragPosLightSpace);
vec3 CalcDirLight(Material material, DirLight light, vec3 normal, vec3 viewDir);
vec3 CalcPointLight(Material material, PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
vec3 CalcSpotLight(Material material, SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
vec3 CalcAreaLight(Material material, AreaLight light);
void main(void)
{
vec3 viewDir = normalize(cameraPos - FragPos);
vec3 finalLight = vec3(0.0f, 0.0f, 0.0f);
finalLight += CalcDirLight(material, dirLight, Normal, viewDir);
finalLight += CalcPointLight(material, pointLight, Normal, FragPos, viewDir);
finalLight += CalcSpotLight(material, spotLight, Normal, FragPos, viewDir);
finalLight += CalcAreaLight(material, areaLight);
FragColor = texture2D(texture1, TexCoord) * vec4(finalLight, 1.0f);
}
float CalcShadow(vec4 fragPosLightSpace)
{
// only actually needed when using perspective projection for the light
vec3 projCoords = fragPosLightSpace.xyz/fragPosLightSpace.w;
// projCoord is in [-1,1] range. Convert it ot [0,1] range.
projCoords = projCoords * 0.5 + 0.5;
float closestDepth = texture(shadowMap, projCoords.xy).r;
float currentDepth = projCoords.z;
float bias = 0.005f;
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
return shadow;
}
vec3 CalcDirLight(Material material, DirLight light, vec3 normal, vec3 viewDir)
{
vec3 lightDir = normalize(-light.direction);
vec3 reflectDir = reflect(-lightDir, normal);
float ambientStrength = 1.0f;
float diffuseStrength = max(dot(normal, lightDir), 0.0);
float specularStrength = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
float shadow = CalcShadow(FragPosLightSpace);
vec3 ambient = light.ambient * material.ambient * ambientStrength;
vec3 diffuse = (1.0f - shadow) * light.diffuse * material.diffuse * diffuseStrength;
vec3 specular = (1.0f - shadow) * light.specular * material.specular * specularStrength;
return (ambient + diffuse + specular);
}
vec3 CalcPointLight(Material material, PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
vec3 reflectDir = reflect(-lightDir, normal);
float ambientStrength = 1.0f;
float diffuseStrength = max(dot(normal, lightDir), 0.0);
float specularStrength = pow(max(dot(viewDir, reflectDir), 0.0f), material.shininess);
float attenuation = 1.0f/(1.0f + 0.01f*pow(length(light.position - fragPos), 2));
vec3 ambient = light.ambient * material.ambient * ambientStrength;
vec3 diffuse = light.diffuse * material.diffuse * diffuseStrength;
vec3 specular = light.specular * material.specular * specularStrength;
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return vec3(ambient + diffuse + specular);
}
vec3 CalcSpotLight(Material material, SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
vec3 reflectDir = reflect(-lightDir, normal);
float ambientStrength = 0.05f;
float diffuseStrength = max(dot(normal, lightDir), 0.0);
float specularStrength = pow(max(dot(viewDir, reflectDir), 0.0f), material.shininess);
float attenuation = 1.0f/(1.0f + 0.01f*pow(length(light.position - fragPos), 2));
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.cutOff - light.outerCutOff;
float intensity = clamp((theta - light.outerCutOff)/epsilon, 0.0f, 1.0f);
vec3 ambient = light.ambient * material.ambient * ambientStrength;
vec3 diffuse = light.diffuse * material.diffuse * diffuseStrength;
vec3 specular = light.specular * material.specular * specularStrength;
ambient *= attenuation * intensity;
diffuse *= attenuation * intensity;
specular *= attenuation * intensity;
return vec3(ambient + diffuse + specular);
}
vec3 CalcAreaLight(Material material, AreaLight light)
{
// return vec3(0.0f, 0.0f, 0.0f);
return vec3(2*material.ambient);
}
我想要做的是獨立的每個光打出來的不同的着色器等等,而不必一「ubershader」我會有一個方向性光着色器和聚光燈着色器等。這是一個好主意嗎?特別是我擔心每次渲染調用多次切換着色器可能會很昂貴?
對這個問題的回答將非常廣泛,視頻中沒有任何內容(您的問題中鏈接的視頻)是「*相對簡單*」。 – Rabbid76
視頻中的物理是複雜的,我不認爲是渲染器?也許你是對的,答案是廣泛的(儘管我不知道)。在每個渲染過程中使用多個着色器被認爲是一個好主意?還是那太依賴於其他因素? – James
很抱歉,您可能是指將水渲染爲複雜的。讓我簡化問題,說我只會使用剛體,所以我只渲染一堆物體。我將使用行軍立方體和SPH在我的發動機中加入水,但是我們可以假設它只是剛體而已。 – James