Я вперше реалізував базове тіньове відображення в OpenGL за допомогою шейдерів, і я стикаюся з деякими проблемами. Нижче ви можете побачити приклад моєї відображеної сцени:
Наступний процес тіньового відображення полягає в тому, що я відтворюю сцену до кадру кадрів, використовуючи матрицю перегляду зі світлової точки зору, а також матриці проекції та моделі, які використовуються для нормального відображення.
У другому проході я надсилаю вищевказану матрицю MVP зі світлової точки зору до вершинного шейдера, який перетворює положення у світлий простір. Шейдер фрагмента робить розділення точки зору і змінює положення на координати текстури.
Ось мій вершинний шейдер,
#version 150 core
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 MVPMatrix;
uniform mat4 lightMVP;
uniform float scale;
in vec3 in_Position;
in vec3 in_Normal;
in vec2 in_TexCoord;
smooth out vec3 pass_Normal;
smooth out vec3 pass_Position;
smooth out vec2 TexCoord;
smooth out vec4 lightspace_Position;
void main(void){
pass_Normal = NormalMatrix * in_Normal;
pass_Position = (ModelViewMatrix * vec4(scale * in_Position, 1.0)).xyz;
lightspace_Position = lightMVP * vec4(scale * in_Position, 1.0);
TexCoord = in_TexCoord;
gl_Position = MVPMatrix * vec4(scale * in_Position, 1.0);
}
І мій фрагмент шейдер,
#version 150 core
struct Light{
vec3 direction;
};
uniform Light light;
uniform sampler2D inSampler;
uniform sampler2D inShadowMap;
smooth in vec3 pass_Normal;
smooth in vec3 pass_Position;
smooth in vec2 TexCoord;
smooth in vec4 lightspace_Position;
out vec4 out_Color;
float CalcShadowFactor(vec4 lightspace_Position){
vec3 ProjectionCoords = lightspace_Position.xyz / lightspace_Position.w;
vec2 UVCoords;
UVCoords.x = 0.5 * ProjectionCoords.x + 0.5;
UVCoords.y = 0.5 * ProjectionCoords.y + 0.5;
float Depth = texture(inShadowMap, UVCoords).x;
if(Depth < (ProjectionCoords.z + 0.001)) return 0.5;
else return 1.0;
}
void main(void){
vec3 Normal = normalize(pass_Normal);
vec3 light_Direction = -normalize(light.direction);
vec3 camera_Direction = normalize(-pass_Position);
vec3 half_vector = normalize(camera_Direction + light_Direction);
float diffuse = max(0.2, dot(Normal, light_Direction));
vec3 temp_Color = diffuse * vec3(1.0);
float specular = max( 0.0, dot( Normal, half_vector) );
float shadowFactor = CalcShadowFactor(lightspace_Position);
if(diffuse != 0 && shadowFactor > 0.5){
float fspecular = pow(specular, 128.0);
temp_Color += fspecular;
}
out_Color = vec4(shadowFactor * texture(inSampler, TexCoord).xyz * temp_Color, 1.0);
}
Однією з проблем є самозатінення, як ви бачите на малюнку, ящик має власну тінь, накинуту на себе. Те, що я спробував, - це зміщення полігону (тобто glEnable (POLYGON_OFFSET_FILL), glPolygonOffset (GLfloat, GLfloat)), але воно не змінилося сильно. Як ви бачите в шейдері фрагмента, я поставив статичне значення зміщення 0,001, але мені потрібно змінити значення залежно від відстані світла, щоб отримати більш бажані ефекти, що не дуже зручно. Я також спробував використати відсікання передньої частини обличчя, коли я передавався на фреймбуфер, який теж не змінився.
Інша проблема полягає в тому, що пікселі поза межами виду Світла фрустують затіненими. Єдиний об’єкт, який, як передбачається, здатний кидати тіні - це ящик. Я думаю, я повинен вибрати більш відповідні проекції та переглянути матриці, але я не впевнений, як це зробити. Які існують звичайні практики, я повинен вибрати ортографічну проекцію?
З трохи погуглившись, я розумію, що ці питання не такі дрібниці. Хтось має прості втілити рішення цих проблем. Не могли б ви дати мені кілька додаткових порад?
Запитайте, будь ласка, чи вам потрібна додаткова інформація щодо мого коду.
Ось порівняння з і без тіньового картографування крупним планом ящика. Самозатінення видніше.