GLSL: как включить альфа-смешивание в шейдер фрагментов с подсветкой

#c# #winforms #opengl #glsl #opentk

#c# #winforms #opengl #glsl #opentk

Вопрос:

Мне удалось создать хорошо освещенную сцену с помощью OpenGL (OpenTK, потому что я использую C # и Winforms), используя следующий шейдер фрагментов:

 #version 420 core

in vec3 FragPos;
in vec3 Normal;
in vec2 texCoord;

out vec4 FragColor;

uniform sampler2D texture0;
uniform sampler2D texture1;

struct Material {
    sampler2D diffuse;
    sampler2D specular;
    float     shininess;
};
struct Light {
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

uniform Material material;
uniform Light light;
uniform vec3 viewPos;

void main()
{
    // Ambient
    vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));

    // Diffuse 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(vec3(light.position - FragPos));
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));

    // Specular
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));

    vec3 result = ambient   diffuse   specular;    
    FragColor = vec4(result, 1.0);
}
  

К сожалению, это решение, похоже, не учитывает альфа-канал текстур. В результате получается такая сцена:
введите описание изображения здесь

План состоит в том, что левая сфера — это облачный слой. Текстура содержит альфа-канал, который должен привести к прозрачной сфере с видимыми облаками. Не путайте: облачная сфера будет перемещена обратно над землей, когда все снова заработает.

Прежде чем я реализовал окружающее, рассеянное и зеркальное освещение, я использовал следующий шейдер фрагментов:

 #version 420 core

in vec2 texCoord;

out vec4 FragColor;

uniform sampler2D texture0;
uniform sampler2D texture1;

void main()
{
    vec4 outputColor = mix(texture(texture0, texCoord), texture(texture1, texCoord), 0.2);
    if(outputColor.a < 0.1)
        discard;

    FragColor = outputColor;
}
  

Этот шейдер учитывает альфа-канал, и он работал так, как предполагалось. Важно сказать, что облака и земля являются отдельными объектами сферы. texture1 в старом шейдере вообще не используется. Итак, единственной релевантной текстурой является texture0.

Итак, «целью» должно быть добавление альфа-канала в новый шейдер (тот, у которого есть освещение).

Извините, если этот вопрос кажется вам глупым. Я новичок в OpenGL и все еще учусь. Заранее спасибо!

Ответ №1:

У вас должны быть mix текстуры, зависящие от альфа-канала облачного слоя. Предположим, что «texture1» — это облачный слой:

 vec4 groundColor = texture(texture0, texCoord);
vec4 cloudColor  = texture(texture1, texCoord);
vec4 outputColor = vec4(mix(grundColor.rgb, cloudColor.rgb, cloudColor.a), 1.0);

FragColor = outputColor;
  

Комментарии:

1. Привет, спасибо за ваш ответ. Я забыл упомянуть кое-что в объяснении (я добавлю это сейчас): облака и земля — это отдельные объекты сферы. texture1 в старом шейдере вообще не используется. Итак, единственной релевантной текстурой является texture0.

2. @BanditBloodwyn я в замешательстве и понятия не имею, чего ты хочешь. У вас есть 2 прохода, один для земли и один для облаков? Используете ли вы один и тот же шейдер для обоих проходов? Смешивание не достигается в программе шейдеров. Смешивание — это этап, и его необходимо включить. Прочитайте Blening .

3. Чтобы упростить: я почти уверен, что мой шейдер (первый здесь) не поддерживает альфа-смешивание, потому что альфа-канал не учитывается. Я вижу важное различие между старым шейдером и новым: старый дает FragColor vec4 (RGBA), а новый — vec3 (RGB) 1.0 в качестве четвертого для создания vec4. Итак, вопрос в том, как повторно включить четвертый канал (альфа) вместо использования только 1.0? Надеюсь, теперь это понятно

Ответ №2:

Я нашел решение самостоятельно. Здесь исправлен шейдер:

 #version 420 core

in vec3 FragPos;
in vec3 Normal;
in vec2 texCoord;

out vec4 FragColor;

struct Material {
    sampler2D diffuse;
    sampler2D specular;
    float     shininess;
};
struct Light {
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

uniform Material material;
uniform Light light;
uniform vec3 viewPos;

void main()
{
    // Ambient
    vec4 ambient = vec4(light.ambient, 1.0) * texture(material.diffuse, texCoord);

    // Diffuse 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(vec3(light.position - FragPos));
    float diff = max(dot(norm, lightDir), 0.0);
    vec4 diffuse = vec4(light.diffuse, 1.0) * diff * texture(material.diffuse, texCoord);

    // Specular
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec4 specular = vec4(light.specular, 1.0) * spec * texture(material.specular, texCoord);

    vec4 result = ambient   diffuse   specular;   

    if(result.a < 0.1)
        discard;    
    
    FragColor = resu<
}
  

Если у вас есть идея получше, я был бы рад попробовать ее 🙂