Skip to content

**** ****

for my bad memories..

Solid 섹션 컷 구현


OpenGL로 우리가 표현하는 솔리드 (tetra, hexa…) 들은 triangle의 조합으로 이루어져있음.
실제는 내부가 차있는 형상은 아니란 말임.
어쨌건 보통 랜더링 할때는 내부를 볼일이 없어 문제가 없지만 섹션컷을 수행하면..
안이 비어 보이게 되어 흉함..
보통은 그래서 섹션컷 수행후에 특별한 방법으로 해당 면을 덮어씌워줌.

플레인 앞쪽은 짤린 부분으로 오른쪽에 짤린 부분을 채워주는 효과를 묘사해주고 있음.

출처: https://gist.github.com/jtsiomb/43b5da0515d4786a80a861369d35097c

컴파일

gcc xsection.c -lopengl32 -lfreeglut -lglu32

코드

/* Example of rendering cross-sections of closed non-self-intersecting geometry
 * with the stencil buffer. See draw_cross_section for details.
 *
 * Controls:
 *  - rotate object by dragging with the left mouse button
 *  - move cross-section plane back and forth by dragging up/down with the right
 *    mouse button
 *
 * Compile with: cc -o xsection xsection.c -lGL -lGLU -lglut
 *
 *                              - Nuclear / Mindlapse <nuclear@member.fsf.org>
 */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <GL/glut.h>

void disp(void);
void draw_regular(void);
void draw_cross_section(void);
void draw_object(void);
void reshape(int x, int y);
void keyb(unsigned char key, int x, int y);
void mouse(int bn, int st, int x, int y);
void motion(int x, int y);

int win_width, win_height;
float theta, phi, clipz;

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitWindowSize(1024, 600);
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_STENCIL | GLUT_DOUBLE);
    glutCreateWindow("GL cross-section hack");

    glutDisplayFunc(disp);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyb);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);

    /* we're going to need backface culling for this */
    glEnable(GL_CULL_FACE);

    glutMainLoop();
    return 0;
}

void disp(void)
{
    glViewport(0, 0, win_width, win_height);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    /* ----- render the regular view on the left ----- */
    glViewport(0, 0, win_width / 2, win_height);
    /* set up perspective projection matrix */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, win_width * 0.5 / win_height, 0.5, 50.0);

    draw_regular();

    /* ----- render the cross-section on the right ----- */
    glViewport(win_width / 2, 0, win_width / 2, win_height);
    /* set up an orthographic projection matrix */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-2, 2, -2, 2, -10, 10);

    draw_cross_section();

    /* draw a separator, just to make it clear that we have two viewports */
    glViewport(0, 0, win_width, win_height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, win_width, 0, win_height, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glColor3f(0.7, 0.7, 0.7);
    glRectf(win_width / 2 - 2, 0, win_width / 2 + 2, win_height);

    glutSwapBuffers();
    assert(glGetError() == GL_NO_ERROR);
}

void draw_regular(void)
{
    int i;

    /* set up a view matrix */
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0, 0, -6);
    glRotatef(20, 1, 0, 0);

    glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_LINE_BIT);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    draw_object();

    /* also draw a quad to visualize the cross-section plane */
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glDisable(GL_LIGHTING);
    glDepthMask(0);
    glLineWidth(2.0);

    for(i=0; i<2; i++) {
        glBegin(i ? GL_QUADS : GL_LINE_LOOP);
        glColor4f(1, 0, 0, i ? 0.25 : 0.5);
        glVertex3f(-1.8, -1.8, clipz);
        glVertex3f(1.8, -1.8, clipz);
        glVertex3f(1.8, 1.8, clipz);
        glVertex3f(-1.8, 1.8, clipz);
        glEnd();
    }

    glPopAttrib();
}

void draw_cross_section(void)
{
    double plane[] = {0, 0, -1, 0};

    /* just identity for the view matrix */
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glPushAttrib(GL_ENABLE_BIT);
    glEnable(GL_STENCIL_TEST);    /* enable stencil testing */

    /* initially we don't care about the stencil buffer, we always want to draw */
    glStencilFunc(GL_ALWAYS, 0, 0);

    /* set up a clip plane to cut everything from the plane Z to the user */
    plane[3] = clipz;
    glClipPlane(GL_CLIP_PLANE0, plane);
    glEnable(GL_CLIP_PLANE0);

    glColorMask(0, 0, 0, 1); /* disable color writing, we only want to affect the stencil buffer */

    /* render back faces and increment stencil where we draw */
    glStencilOp(GL_INCR, GL_INCR, GL_INCR);
    glCullFace(GL_FRONT);
    draw_object();

    /* render front faces and decrement stencil where we draw */
    glStencilOp(GL_DECR, GL_DECR, GL_DECR);
    glCullFace(GL_BACK);
    draw_object();

    /* now everywhere outside the cross-section the stencil is 0, and inside the
     * cross-section the stencil is 1
     */

    glColorMask(1, 1, 1, 1);    /* re-enable color writing */
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);    /* don't modify the stencil buffer further */
    glStencilFunc(GL_LEQUAL, 1, 0xffffffff); /* test passes only where stencil >= 1 */

    /* just draw a fullscreen quad, will be drawn only inside the cross-section
     * (stencil == 1) area
     */
    glLoadIdentity();
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glDisable(GL_CLIP_PLANE0);    /* disable the clip plane, we don't want the quad to be clipped */

    glBegin(GL_QUADS);
    glColor3f(1, 0.3, 0.2);    /* color of the cross-section */
    glVertex2f(-1, -1);
    glVertex2f(1, -1);
    glVertex2f(1, 1);
    glVertex2f(-1, 1);
    glEnd();

    glPopAttrib();
}

void draw_object(void)
{
    glPushMatrix();
    glRotatef(phi, 1, 0, 0);
    glRotatef(theta, 0, 1, 0);

    glutSolidTorus(0.25, 1.0, 8, 28);
    glutSolidSphere(0.5, 16, 8);

    glPopMatrix();
}

void reshape(int x, int y)
{
    win_width = x;
    win_height = y;
}

void keyb(unsigned char key, int x, int y)
{
    switch(key) {
    case 27:
        exit(0);
    }
}

int bnstate[16];
int prev_x, prev_y;

void mouse(int bn, int st, int x, int y)
{
    int bidx = bn - GLUT_LEFT_BUTTON;
    bnstate[bidx] = st == GLUT_DOWN ? 1 : 0;
    prev_x = x;
    prev_y = y;
}

void motion(int x, int y)
{
    int dx = x - prev_x;
    int dy = y - prev_y;
    prev_x = x;
    prev_y = y;

    if(!dx && !dy) return;

    if(bnstate[0]) {
        theta += dx * 0.5;
        phi += dy * 0.5;

        if(phi < -90) phi = -90;
        if(phi > 90) phi = 90;
        glutPostRedisplay();
    }

    if(bnstate[2]) {
        clipz += dy * 0.01;

        if(clipz < -2) clipz = -2;
        if(clipz > 2) clipz = 2;
        glutPostRedisplay();
    }
}

Categorized as: Programming



답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다


이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.