在OpenGL碎片着色器中绘制一个三角形[英] Drawing a triangle in OpenGL fragment shader

本文是小编为大家收集整理的关于在OpenGL碎片着色器中绘制一个三角形的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我正在尝试使用OpenGL片段着色器绘制三角形.

我成功地绘制了一个圆圈,但是我在处理方程/逻辑或代码绘制三角形方面有问题.

draw_triangle(vec2 v1 , vec2 v2, vec2 v3)

这是片段着色器:

#version 330 core

out vec4 frag_color;

void draw_circle(vec2 shift_val, int radius,int color)
{
    vec2 res = vec2(1280,720);
    vec2 norm_cord = gl_FragCoord.xy;
    float dist = length(norm_cord - (res*shift_val));
    if( dist < radius )
    {
        if( color ==1 )
            frag_color = vec4(1.0, 1.0, 1.0, 1.0);
            else
            frag_color = vec4(0.0, 0.0, 0.0, 1.0);
    }
}

void draw_triangle(vec2 v1 , vec2 v2, vec2 v3)
{
    vec2 res = vec2(1280,720)*vec2(0.58,0.4);
    vec2 v = vec2(gl_FragCoord.x,gl_FragCoord.y);

    float slope1 = abs((v1.y-v2.y)/(v1.x-v2.x)); //y2-y1/x2-x1
    float slope2 = abs((v2.y-v3.y)/(v2.x-v3.x)); //y2-y1/x2-x1
    float slope3 = abs((v1.y-v3.y)/(v1.x-v3.x)); //y2-y1/x2-x1

    float slope_ref1 = abs((v.y-v1.y)/(v.x-v1.x)); //y2-y1/x2-x1
    float slope_ref2 = abs((v.y-v2.y)/(v.x-v2.x)); //y2-y1/x2-x1
    float slope_ref3 = abs((v.y-v3.y)/(v.x-v3.x)); //y2-y1/x2-x1

    float slope_RES1 = abs((res.y-v1.y)/(res.x-v1.x)); //y2-y1/x2-x1
    float slope_RES2 = abs((res.y-v2.y)/(res.x-v2.x)); //y2-y1/x2-x1
    float slope_RES3 = abs((res.y-v3.y)/(res.x-v3.x)); //y2-y1/x2-x1

    if (slope_RES1 < slope1 )
    {
        if(slope_ref1 < slope1)// && slope_ref3 < slope2 )//slope_ref1 < slope1 &&
            frag_color = vec4(1.0, 0.0, 1.0, 1.0);
    }

    if (slope_RES2 > slope2)
        {
            if(slope_ref2 > slope2)
                frag_color = vec4(1.0, 0.5, 1.0, 1.0);
        }

    /*if (slope_RES3 < slope3)
        {
            if(slope_ref3 > slope3)
                frag_color = vec4(1.0, 0.0, 1.0, 1.0);
        }*/
}

// This is entry point of the fragment shader and it will be called for every fragment covered by the rasterized geometry
void main() {
    // Here we just output a constant color which is red (R=1, G=0, B=0, A=1)
    //frag_color = vec4(0.0, 0.0, 0.0, 1.0);
    draw_circle(vec2(0.5,0.5),100,1); //draws face of circle
    draw_circle(vec2(0.5,0.58),16,0); //draws eye (1 for white and anynumber for black)
    draw_triangle(vec2(0.5f,0.5f),vec2(-0.5,0.0f),vec2(0.5f,-0.5f));
}

推荐答案

要使用相同侧面的技术计算三角形在三角形中,您需要在三行上测试候选点,以查看其在每一行的哪一侧.如果它符合所有三行的侧面测试测试,则在三角形内.

条件测试将为C(0) && C(1) && C(2).

其中C(n)的意思是:"是边缘n的正确侧的点"

通常通过检查AB × AX的交叉产品的符号来检查"线AB的哪一侧".您可以按照惯例将绕组顺序分配给您的三角形,并始终检查该交叉产品的迹象是否为正. 当然,这取决于三角形的顶点的绕组顺序. (例如,顺时针顶点需要负跨产品,并且逆时针顶点需要正面的跨产品.根据多边形的定义,选择您喜欢或最方便的惯例.)

您可以使用Barycentric技术进行测试.

请参阅:此网站有关更多详细信息.

其他推荐答案

希望您正在渲染四边形覆盖视图/屏幕...

碎片着色器呈现三角形的友好方式是:

  1. 计算 barycentric s,t坐标 fragment

    在GLSL中获得mat3,vec3时,请选择矩阵方法...

  2. 确定它在内部还是外部

    仅通过测试s+t<=1.0

  3. 然后设置输出颜色或discard;

    但是,由于您有更多的形状,因此丢弃不是您的选择...

所以计算:

--------------------------------------------------------
| s |           | (p1.a - p0.a) , (p2.a - p0.a) , p0.a |   | p.a |
| t | = inverse | (p1.b - p0.b) , (p2.b - p0.b) , p0.b | * | p.b |
| 1 |           |       0       ,       0       ,   1  |   |  1  |
------------------------------------------------------------------
if (s+t<=1.0) set output color

您也可以使用s,t进行纹理(甚至是程序性的).

本文地址:https://www.itbaoku.cn/post/2091097.html

问题描述

I'm trying to draw a triangle using an OpenGL fragment shader.

I succeeded in drawing a circle but I have a problem with handling the equation/logic or the code to draw a triangle.

draw_triangle(vec2 v1 , vec2 v2, vec2 v3)

Here is the fragment shader:

#version 330 core

out vec4 frag_color;

void draw_circle(vec2 shift_val, int radius,int color)
{
    vec2 res = vec2(1280,720);
    vec2 norm_cord = gl_FragCoord.xy;
    float dist = length(norm_cord - (res*shift_val));
    if( dist < radius )
    {
        if( color ==1 )
            frag_color = vec4(1.0, 1.0, 1.0, 1.0);
            else
            frag_color = vec4(0.0, 0.0, 0.0, 1.0);
    }
}

void draw_triangle(vec2 v1 , vec2 v2, vec2 v3)
{
    vec2 res = vec2(1280,720)*vec2(0.58,0.4);
    vec2 v = vec2(gl_FragCoord.x,gl_FragCoord.y);

    float slope1 = abs((v1.y-v2.y)/(v1.x-v2.x)); //y2-y1/x2-x1
    float slope2 = abs((v2.y-v3.y)/(v2.x-v3.x)); //y2-y1/x2-x1
    float slope3 = abs((v1.y-v3.y)/(v1.x-v3.x)); //y2-y1/x2-x1

    float slope_ref1 = abs((v.y-v1.y)/(v.x-v1.x)); //y2-y1/x2-x1
    float slope_ref2 = abs((v.y-v2.y)/(v.x-v2.x)); //y2-y1/x2-x1
    float slope_ref3 = abs((v.y-v3.y)/(v.x-v3.x)); //y2-y1/x2-x1

    float slope_RES1 = abs((res.y-v1.y)/(res.x-v1.x)); //y2-y1/x2-x1
    float slope_RES2 = abs((res.y-v2.y)/(res.x-v2.x)); //y2-y1/x2-x1
    float slope_RES3 = abs((res.y-v3.y)/(res.x-v3.x)); //y2-y1/x2-x1

    if (slope_RES1 < slope1 )
    {
        if(slope_ref1 < slope1)// && slope_ref3 < slope2 )//slope_ref1 < slope1 &&
            frag_color = vec4(1.0, 0.0, 1.0, 1.0);
    }

    if (slope_RES2 > slope2)
        {
            if(slope_ref2 > slope2)
                frag_color = vec4(1.0, 0.5, 1.0, 1.0);
        }

    /*if (slope_RES3 < slope3)
        {
            if(slope_ref3 > slope3)
                frag_color = vec4(1.0, 0.0, 1.0, 1.0);
        }*/
}

// This is entry point of the fragment shader and it will be called for every fragment covered by the rasterized geometry
void main() {
    // Here we just output a constant color which is red (R=1, G=0, B=0, A=1)
    //frag_color = vec4(0.0, 0.0, 0.0, 1.0);
    draw_circle(vec2(0.5,0.5),100,1); //draws face of circle
    draw_circle(vec2(0.5,0.58),16,0); //draws eye (1 for white and anynumber for black)
    draw_triangle(vec2(0.5f,0.5f),vec2(-0.5,0.0f),vec2(0.5f,-0.5f));
}

推荐答案

To compute if a point is in a triangle using the same side technique, you need to test the candidate point against three lines to see which side of each line it is on. If it meets the sidedness test for all three lines, then it is inside the triangle.

The condition test will be C(0) && C(1) && C(2).

Where C(n) means: "Is the point on the correct side of edge n"

The condition "which side of the line AB is the point X" is typically checked by checking the sign of the cross product of AB × AX. You could, by convention, assign a winding order to your triangle, and always check that the sign of this cross product is positive. This, of course, depends on the winding order of the vertices of your triangle. (For example, clockwise vertices require a negative cross product, and counterclockwise vertices require a positive cross product. Choose whichever convention you like or is most convenient given the definition of your polygon.)

You can, alternatively, test using the barycentric technique.

See: this site for more details.

其他推荐答案

Hope you are rendering QUAD covering the view/screen...

The fragment shader friendly way of rendering triangle is to:

  1. compute barycentric s,t coordinates of fragment

    go for the matrix approach as you got mat3,vec3 in GLSL ...

  2. decide if it is inside or outside

    simply by testing s+t<=1.0

  3. then set output color or discard;

    however discard is not an option for you as you got more shapes...

So compute:

--------------------------------------------------------
| s |           | (p1.a - p0.a) , (p2.a - p0.a) , p0.a |   | p.a |
| t | = inverse | (p1.b - p0.b) , (p2.b - p0.b) , p0.b | * | p.b |
| 1 |           |       0       ,       0       ,   1  |   |  1  |
------------------------------------------------------------------
if (s+t<=1.0) set output color

You can also use the s,t for texturing (even procedural one).