物理エンジン用のレンダリングは比較的簡単です(thisと似ています)。私はOpenGLを学んでいて、これに続いていますtutorial。レンダラーは、方向、点、スポットライト、エリアライトの中から選択された少数のライトを処理できるようにします。また、シャドウマップを使用して簡単なシャドウが欲しいです。たとえば、シーンには2つのスポットライトや1つの指向性ライト、1つのポイントライト、1つのスポットライトなどが含まれている可能性があります。現在、私はすべてのライトを一緒に扱う1つの大きなシェーダを持っています。モジュール式の設計の観点からは、各ライトまたは少なくともライトの種類ごとに異なるシェーダを持つ方が良いでしょう。これが効率の観点から合理的な考えであるかどうか疑問に思います。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);
}
私は何をしたいのは、それぞれの光がとても代わりに、1つを有するの異なるシェーダに出タイプ別であります"ubershader"私はdirectionalLightシェーダとスポットライトシェーダなどがあります。これは良いアイデアですか?特に、レンダーコールごとにシェーダを何度も切り替えるのは高価かもしれないと私は心配していますか?
この質問に対する回答は非常に幅広く、ビデオ(あなたの質問にリンクされているビデオ)には何も「*比較的シンプル」ではありません。 – Rabbid76
ビデオの物理学は複雑ですが、レンダラは私がそうではないと思いますか?おそらくあなたは正しい答えが広がるだろう(私はそれを知らなかったが)。各レンダリングパスで複数のシェーダを使用するのは良い考えですか?それとも他の要因にも依存していますか? – James
申し訳ありませんあなたはおそらく水を複雑にすることを指していました。私が剛体だけを使用すると言って問題を簡略化しましょう。だから私はたくさんのオブジェクトをレンダリングしています。私は、マーチング・キューブとSPHを使って私のエンジンに水を入れていきますが、私たちはこの質問のためにちょうど剛体を仮定することができます。 – James