当前位置: 首页 > 知识库问答 >
问题:

GLSL:如何将alpha混合包含到带有照明的片段着色器中

张亦
2023-03-14

我设法用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);
}

计划是,左边的球体是云层。纹理包含一个alpha通道,这应该会产生一个透明的球体,上面有可见的云。不要困惑:当一切恢复正常时,云球体将被移回地球上方。

在实现环境、漫反射和镜面照明之前,我使用了以下片段着色器:

#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;
}

这个着色器考虑了alpha通道,它确实按预期工作。重要的是,云和地球是独立的球体对象。旧着色器中的texture 1根本没有使用。所以唯一相关的纹理是texture 0。

所以“目标”应该是将alpha通道添加到新着色器(带有照明的着色器)中。

如果你觉得这个问题很愚蠢,我很抱歉。我是OpenGL新手,还在学习。提前谢谢!

共有2个答案

白云
2023-03-14

我自己找到了解决办法。下面是修复着色器:

#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 = result;
}

如果你有更好的主意,我很乐意尝试一下:)

卜鹏
2023-03-14

您必须混合依赖于云层的alpha通道的纹理。假设“texture 1”是云层:

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

FragColor = outputColor;
 类似资料:
  • 假设我遇到这样的问题:现在我有一个帧缓冲区,一个纹理只包含一个颜色组件(例如,GL_RED)已经绑定到它。碎片着色器会是什么样子?我想答案是: ...浮出ex_color; 颜色=。。。; 我的问题来了:着色器会自动检测帧缓冲区的格式并向其写入值吗?如果片段着色器输出浮点值但帧缓冲区格式GL_RGBA怎么办? 顺便问一下,创建只有一个组件的纹理的正确方法是什么?我阅读了g-truc的示例,其示例如

  • 我希望在2D OpenGL应用程序上实现着色器。我的计划是将场景渲染到帧缓冲区对象,然后使用着色器将该帧缓冲区对象渲染到屏幕。 这是我绘制到帧缓冲区对象的场景,然后从那里绘制到屏幕。使用箭头键可以让月亮四处移动(我很自豪!) 但是,当我尝试使用着色器程序将帧缓冲区对象渲染到屏幕上时,我得到以下结果: 这是非常可悲的。这个片段着色器是我从一个教程中得到的,我相信问题一定是统一变量。 以下是片段着色器

  • 在一个简单的hello world OpenGL程序中,它只是在窗口上绘制一个静态三角形,当我将三角形的3个顶点设置为红色、绿色和蓝色时,三角形将填充渐变。 但是当我使用这样的着色器时: 顶点着色器: 其中属性和来自顶点缓冲区,通过的调用传递。 片段着色器: 三角形仍然充满了梯度,问题来了: 如果顶点着色器是按顶点计算的,则应为的每个实例指定顶点的颜色。顶点颜色应为红色、绿色或蓝色,如顶点缓冲区中

  • 我正在做一个游戏,我现在正在写一个着色器来反射光从一个物体,我不断得到错误消息: 任何帮助都将不胜感激。

  • 下面代码中的两个字符串 vertexShaderSource和fragShaderSource 是 WebGL 的着色器代码,着色器代码通过着色器语言GLSL ES编写,对于前端工程来说学习 WebGL,还需要学习一门新的语言着色器语言GLSL ES。关于着色器语言的学习,可以跟着课程一边写案例,一边去学习,这样更容易理解。 着色器语言用于计算机图形编程,运行在GPU中,平时所说的大多数语言编写的

  • 我在Mac OSX下工作,试图通过GLSL着色器在立方体上映射图像。 我显示立方体(以及图像,当它不通过着色器时)的方法是: 正如你所看到的,我正在检查,在这个测试中,是否有一个着色器应用到我的对象上(它是一个包装,效果非常好) 如果没有着色器,我只启用GL_纹理_坐标_数组,如果有,我尝试将图像绑定到着色器中的采样2D均匀。 我使用的着色器非常简单:它只显示纹理。我在Quartz Compose