我正在为物理引擎(类似于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