OpenGL中两圆重叠区域点的排除

djp7away  于 2022-11-23  发布在  其他
关注(0)|答案(2)|浏览(163)

我想画两个半径相同的圆,但不包括重叠的区域。

我想在灰色区域绘制或设置点。
我实现了它背后的数学方面,下面是我的代码:

void draw_venn(){   
        
float radian_to_degree_theta=2 * 3.14 / 360,
          r = 0.5,
          distance=0.3,
          theta=0.0,
          theta2=0.0,
          xR=0.0,
          yR=0.0,
          xG=0.0,
          yG=0.0,
          sum_radii=0,
          dis=0.0;

    sum_radii=r+r;
    for (r = 0.5; r >=0; r-=0.001)
    {
        for (float degree = 0; degree < 361; degree+=0.1)   
        {   
            theta =degree*radian_to_degree_theta;   
            xR=r*cos(theta)+distance;
            yR=r*sin(theta);
            
            xG=r*cos(theta)-distance;
            yG=r*sin(theta);

            dis=sqrt(pow(xR-xG,2) + pow(yR-yG,2));  
            if (dis <= sum_radii)   
            {
                set_point(xR,yR,0.1,1,0,0);
                set_point(xG,yG,0.1,0,1,0);
            }           
            
        }
    }
}
void set_point(float x,float y,float size,float R,float G,float B){
    glPointSize(size);
    glBegin (GL_POINTS);
    glColor3f (R, G, B);
    glVertex2f(x, y);   
    glEnd ();
}
void draw(void)
{
    glClearColor (1, 1, 1, 0);
    glClear (GL_COLOR_BUFFER_BIT);
   
    glPushMatrix(); 

    draw_ven();

    glPopMatrix ();     

    glFlush();
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE);
    glutInitWindowSize(1400, 1400);
    glutInitWindowPosition(700, 500);
    glutCreateWindow("GL Sample");
    glutDisplayFunc(draw);
    glutMainLoop();
    return 0;
}

结果如下:

如何确定点是否在重叠区域内?

o2gm4chl

o2gm4chl1#

我检查并测试了你的代码。三角学可能会变得有点棘手。下面是“draw_venn”函数,它做了一些改进以产生重叠效果。

void draw_venn()
{
    float   radian_to_degree_theta=2 * 3.141 / 360, 
            r = 0.5, 
            distance=0.3, 
            theta=0.0,
            theta2 = 0.0, 
            xR=0.0, 
            yR=0.0,
            xG=0.0, 
            yG=0.0,
            dis=0.0;

    glPointSize(1);
    glColor3f(1,0,0);
    glBegin(GL_POINTS);
    
    for (r = 0.5; r >=0; r-=0.001)
    {
        for (float degree = 0; degree < 361; degree+=0.1)
        {
            theta =degree*radian_to_degree_theta;
            theta2 = (180.0 - degree) * radian_to_degree_theta;
            xR=r*cos(theta2)+distance;
            yR=r*sin(theta2);

            xG=r*cos(theta)-distance;
            yG=r*sin(theta);

            dis = sqrt(pow((distance - xG), 2) + pow(yG, 2));
 
            if (dis < 0.5)
            {
                set_point(xR,yR,0.1,0,0,1); /* Color the overlap blue */
                set_point(xG,yG,0.1,0,0,1); /* This works due to symmetry */
            }
            else
            {
                set_point(xR,yR,0.1,1,0,0); /* Set the symmetrical circle colors */
                set_point(xG,yG,0.1,0,1,0);
            }
        }
    }
    glEnd();
}

指出两个重要的修改,首先,我推导了“theta”的镜像值,并将其放入变量“theta2”中。它用于绘制红色圆圈。这确保了圆圈图像是以相等但相反的方向构建的,以便坐标对称。其次,我修改了检查绿色图像坐标是否落在红色圆圈最外半径内的公式。使用勾股定理计算斜边,公式确定斜边值是否小于最外半径长度(0. 5)。如果斜边值小于最外半径长度,则将绿色圆的该点设置为蓝色,并且由于圆点是对称构建和着色的,因此也将红色圆的相应点设置为蓝色。
这些修订的结果是显示重叠的维恩图。

我希望这对你有所帮助,并给你一个跳板继续前进。
祝你好运

bd1hkmkf

bd1hkmkf2#

1.将8位Stencil Buffer添加到您的上下文
我是这样设置pixelformat的:

PIXELFORMATDESCRIPTOR pfd;
 ZeroMemory( &pfd, sizeof( pfd ) );      // set the pixel format for the DC
 pfd.nSize = sizeof( pfd );
 pfd.nVersion = 1;
 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
 pfd.iPixelType = PFD_TYPE_RGBA;
 pfd.cColorBits = 24;
 pfd.cDepthBits = 24;
 pfd.cStencilBits = 8;
 pfd.iLayerType = PFD_MAIN_PLANE;
 SetPixelFormat(hdc,ChoosePixelFormat(hdc, &pfd),&pfd);

1.使用0启用并清除模具,并将其设置为递增
1.禁用颜色和深度输出
1.渲染圆形
1.启用颜色和深度输出
1.将模具测试设置为不等于2
如果重叠的对象不止2个,也可以使用等于1
1.渲染圆形
1.禁用模具测试
我是这样看的:

//---------------------------------------------------------------------------
void glCircle(float x,float y,float r)
    {
    int e;
    float a,da=2.0*M_PI/72.0;
    glBegin(GL_TRIANGLE_FAN);
    glVertex2f(x,y);
    for (e=1,a=0.0;e;a+=da)
        {
        if (a>=2.0*M_PI) { e=0; a=0.0; }
        glVertex2f(x+(r*sin(a)),y+(r*cos(a)));
        }
    glEnd();
    }
//---------------------------------------------------------------------------
void gl_draw()
    {
    glClearColor(1.0,1.0,1.0,1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    float aspect=float(xs)/float(ys);   //xs,ys is screen resolution
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glScalef(1.0,aspect,1.0);
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);

    // turn off color,depth
    glStencilMask(0xFF);
    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    glDepthMask(GL_FALSE);
    // clear stencil and setup it for increment
    glEnable(GL_STENCIL_TEST);
    glClearStencil(0);
    glClear(GL_STENCIL_BUFFER_BIT);
    glStencilFunc(GL_ALWAYS,1,0xFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
    // render stencil
    glCircle(-0.3,0.0,0.6);
    glCircle(+0.3,0.0,0.6);
    // turn on color,depth
    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    glDepthMask(GL_TRUE);
    // render screen (where Stencil is not 2)
    glStencilFunc(GL_NOTEQUAL,2,0xFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    glColor3f(1.0,0.0,0.0); glCircle(-0.3,0.0,0.6);
    glColor3f(0.0,1.0,0.0); glCircle(+0.3,0.0,0.6);
    glDisable(GL_STENCIL_TEST);

    glFlush();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------

与输出:

如果你还想知道像素是否在两个圆圈内,你可以用途:

GLint a;
glReadPixels(X,ys-1-Y,1,1,GL_STENCIL_INDEX,GL_INT,&a);
if (a==2); // X,Y is inside both circles
else;      // X,Y is not inside both circles

如果你坚持一个像素一个像素地渲染东西,那么至少要正确地做因为你目前的方法是horibly缓慢的许多原因...例如,你可以这样做:

glClearColor(1.0,1.0,1.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranslatef(-1.0,-1.0,0.0);
glScalef(2.0/xs,2.0/ys,1.0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

int x0=(4*xs)/10,y0=ys/2,r0=xs/4;   // circle0
int x1=(6*xs)/10,y1=ys/2,r1=xs/4;   // circle1
int x,y,xx0,xx1,yy0,yy1,rr0=r0*r0,rr1=r1*r1;
glBegin(GL_POINTS);
glColor3f(1.0,0.0,0.0);
for (x=-r0;x<=r0;x++){ xx0=x; xx0*=xx0; xx1=x+x0-x1; xx1*=xx1;
 for (y=-r0;y<=r0;y++){ yy0=y; yy0*=yy0; yy1=y+y0-y1; yy1*=yy1;
  if (xx0+yy0<=rr0)
   if (xx1+yy1>=rr1)
    glVertex2i(x0+x,y0+y); }}
glColor3f(0.0,1.0,0.0);
for (x=-r1;x<=r1;x++){ xx1=x; xx1*=xx1; xx0=x+x1-x0; xx0*=xx0;
 for (y=-r1;y<=r1;y++){ yy1=y; yy1*=yy1; yy0=y+y1-y0; yy0*=yy0;
  if (xx1+yy1<=rr1)
   if (xx0+yy0>=rr0)
    glVertex2i(x1+x,y1+y); }}
glEnd();

glFlush();
SwapBuffers(hdc);

其中xs,ys是GL屏幕分辨率。
参见相关:

相关问题