You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

几何着色器中叠加图形失败:仅显示单一图形问题求助

OpenGL图形叠加失败问题及解决方案

问题描述

我编写了一个OpenGL程序,期望实现以下目标:

  • 绘制一个点
  • 通过顶点着色器对该点进行变换
  • 通过几何着色器生成正方形与三角形
  • 通过片段着色器填充两个图形

但目前无法实现图形叠加,仅能看到三角形或正方形中的一个,调整z值也无效果。

现象展示

当几何着色器main函数包含正方形和三角形代码时:

void main(void) {
    finalColour = vec4(1.0, 0.5, 0.5, 1.0);
    square(1.0, 0.0);

    finalColour = vec4(0.0, 1.0, 1.0, 0.0);
    triangle(vec3(0.0, 0.0, 0.0), angle[0], 1.0);
    EndPrimitive();
}

仅能看到正方形:
仅显示正方形

当注释掉正方形代码,仅保留三角形时:

void main(void) {
    // finalColour = vec4(1.0, 0.5, 0.5, 1.0);
    // square(1.0, 0.0);

    finalColour = vec4(0.0, 1.0, 1.0, 0.0);
    triangle(vec3(0.0, 0.0, 0.0), angle[0], 1.0);
    EndPrimitive();
}

可以看到三角形:
仅显示三角形

完整代码

Main代码

#include <SFML/Graphics.hpp>
#include <GL/glew.h>
#include <vector>

#define WIDTH 800
int main() {
    sf::RenderWindow window(sf::VideoMode(WIDTH, WIDTH), "Test");

    sf::Shader shader;
    shader.loadFromFile("shader.vert", "shader.geom", "shader.frag");
    sf::Transform matrix = sf::Transform::Identity;
    matrix.scale(1.0 / WIDTH, 1.0 / WIDTH);
    sf::Glsl::Mat4 projectionViewMatrix = matrix;

    shader.setUniform("projectionViewMatrix", projectionViewMatrix);

    std::vector<GLfloat> vertices;

    vertices.push_back(0.0); vertices.push_back(0.0); vertices.push_back(0.0);

    while (window.isOpen()) {
        sf::Event currEvent;
        while (window.pollEvent(currEvent)) {
            switch (currEvent.type) {
            case(sf::Event::Closed):
                window.close(); break;
            }
        }

        window.clear(sf::Color::Black);
        glEnable(GL_BLEND);
        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
        glVertexPointer(3, GL_FLOAT, 0, vertices.data());
        glEnableClientState(GL_VERTEX_ARRAY);
        glDrawArrays(GL_POINTS, 0, vertices.size() / 3);
        glDisableClientState(GL_VERTEX_ARRAY);

        sf::Shader::bind(&shader);

        window.display();
    }
}

顶点着色器(Vertex)代码

#version 150
in vec3 position;

out float angle;

uniform mat4 projectionViewMatrix;

void main(void){
    gl_Position = projectionViewMatrix * vec4(position.xy, 0.0 ,1.0);
    angle = position.z;
}

几何着色器(Geometry)代码

#version 150

layout (points) in;
layout (triangle_strip, max_vertices = 6) out;

in float angle[];

out vec4 finalColour;

uniform mat4 projectionViewMatrix;

void createVertex(vec3 offset) {
    vec4 actualOffset = vec4(offset, 1.0);
    vec4 worldPosition = gl_in[0].gl_Position + actualOffset;
    gl_Position = worldPosition;
    EmitVertex();
}

void createAngularVertex(vec3 offset, float angle, float radius) {
    vec4 actualOffset = vec4(offset, 1.0);
    vec4 worldPosition = gl_in[0].gl_Position + actualOffset;
    gl_Position = worldPosition;
    gl_Position.x += cos(angle) * radius;
    gl_Position.y += sin(angle) * radius;
    EmitVertex();
}

void square(float size, float z) {
    createVertex(vec3(-size, -size, z));
    createVertex(vec3(size, -size, z));
    createVertex(vec3(-size, size, z));
    createVertex(vec3(size, size, z));
    createVertex(vec3(size, -size, z));
    createVertex(vec3(-size, size, z));
    EndPrimitive();
}

void triangle(vec3 offset, float angle, float radius) {
    float pi = 3.1415;
    float angleOffset = 0.5;
    createAngularVertex(offset, angle, radius);
    createAngularVertex(offset, angle + pi + angleOffset, radius);
    createAngularVertex(offset, angle + pi - angleOffset, radius);
    EndPrimitive();
}

void main(void) {
    finalColour = vec4(1.0, 0.5, 0.5, 1.0);
    square(1.0, 0.0);

    finalColour = vec4(0.0, 1.0, 1.0, 0.0);
    triangle(vec3(0.0, 0.0, 0.0), angle[0], 0.1);
    EndPrimitive();
}

片段着色器(Fragment)代码

#version 150
in vec4 finalColour;
out vec4 out_Colour;

void main(void){
    out_Colour = vec4(finalColour.rgb, 1.0);
}

问题原因及修复方案

1. 几何着色器最大顶点数不足

几何着色器中声明max_vertices = 6,但生成正方形需要6个顶点,三角形还需要3个,总共9个顶点超过了上限,导致三角形的顶点被OpenGL丢弃,只能看到正方形。

修复:修改几何着色器的输出布局,将最大顶点数调整为9:

layout (triangle_strip, max_vertices = 9) out;

2. 片段着色器强制覆盖Alpha值

片段着色器中out_Colour = vec4(finalColour.rgb, 1.0);将所有片段的Alpha值强制设为1.0,即使几何着色器设置了透明的三角形,也会变成完全不透明,导致图形无法叠加。

修复:保留原Alpha值,修改片段着色器:

void main(void){
    out_Colour = finalColour;
}

如果需要半透明效果,可以调整几何着色器中三角形的颜色,比如改为vec4(0.0, 1.0, 1.0, 0.5)。

3. 着色器绑定时机错误

Main函数中sf::Shader::bind(&shader);放在了glDrawArrays之后,导致绘制时未使用自定义着色器,而是使用默认管线,这也是图形显示异常的原因之一。

修复:将着色器绑定移到绘制操作之前,修改Main函数的渲染循环:

window.clear(sf::Color::Black);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

sf::Shader::bind(&shader); // 先绑定着色器

glVertexPointer(3, GL_FLOAT, 0, vertices.data());
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_POINTS, 0, vertices.size() / 3);
glDisableClientState(GL_VERTEX_ARRAY);

sf::Shader::bind(nullptr); // 绘制完成后解绑(可选)

window.display();

4. 可选:开启深度测试控制前后顺序

如果需要通过z值控制图形的前后遮挡关系,可以开启深度测试:

// 在窗口创建后添加以下代码
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);

注意:OpenGL默认右手坐标系中,z值越大的图形离相机越远,若想三角形在正方形前面,需将三角形的z值设为更小(比如正方形z=0.1,三角形z=0.0)。


内容的提问来源于stack exchange,提问作者nowox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 14:30:55