使用模具缓冲区绘制三维模型的轮廓



首先我想说的是,我发现了我认为完全相同的问题,不幸的是,没有答案,在这里:Java使用OpenGL模板创建轮廓

我将在下面发布我的代码,但首先是问题:从这个捕获**中,您可以看到整个帧结构正在显示,而不是球体周围的一行。我想去掉里面的所有线条!

**显然,我无法添加图片:请看这个链接-想象一个球体,四边形的所有边缘都以3像素的大线可见
http://srbwks36224-03.engin.umich.edu/kdi/images/gs_sphere_with_frame.jpg


以下是给出该结果的代码:

// First render the sphere:
// inside "show" is all the code to display a textured sphere
// looking like earth
sphe->show();
// Now get ready for stencil buffer drawing pass:
// 1. Clear and initialize it
// 2. Activate stencil buffer
// 3. On the first rendering pass, we want to "SUCCEED ALWAYS"
//    and write a "1" into the stencil buffer accordingly
// 4. We don't need to actually render the object, hence disabling RGB mask
glClearStencil(0);   //Edit: swapped this line and below
glClear(GL_STENCIL_BUFFER_BIT);                 
glEnable(GL_STENCIL_TEST);                  
glStencilFunc(GL_NEVER, 0x1, 0x1);          //Edit: GL_ALWAYS
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);  //Edit: GL_KEEP, GL_KEEP, GL_REPLACE                    
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);   // As per Andon's comment
sphe->show();
// At this point, I expect to have "1" on the entire
// area covered by the sphere, so...
// 1. Stencil test should fail for anything, but 0 value
// RM: commented is another option that should work too I believe                       
// 2. The stencil op instruction at the point is somewhat irrelevant 
//    (if my understanding is correct), because we won't do anything 
//    else with the stencil buffer after that.
// 3. Re-enable RGB mask, because we want to draw this time  
// 4. Switch to LINE drawing instead of FILL and 
// 5. set a bigger line width, so it will exceed the model boundaries. 
//    We do want this, otherwise the line would not show 
// 6. Don't mind the "uniform" setting instruction, this is so
//    that my shader knows it should draw in plain color
// 7. Draw the sphere's frame
// 8. The principle, as I understand it is that all the lines should
//    find themselves matched to a "1" in the stencil buffer and therefore
//    be ignored for rendering. Only lines on the edges of the model should
//    have half their width not failing the stencil test.
glStencilFunc(GL_EQUAL, 0x0, 0x1);
//glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
glLineWidth(3);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);  
psa::shader::setUniform("outlining", 1);
sphe->show();
psa::shader::setUniform("outlining", 0);

现在,为了证明这一点,我厌倦了使用模版缓冲区做一些不同的事情——我只想确保代码中的一切都到位,让它发挥作用。

**同样不幸的是,我无法显示我得到的结果的屏幕截图:场景如下
http://mathworld.wolfram.com/images/eps-gif/SphereSphereInterGraphic_700.gif
但较小的球体是不可见的(RGB遮罩被禁用),人们可以通过孔看到世界背景(而不是较大球体的内部-人脸剔除被禁用)。

这就是代码。。。有趣的是,我可以更改很多事情,比如激活/停用STENCIL_TEST,在任何地方将操作更改为GL_KEEP,甚至将第二个stencilFunc更改为"NOT EQUAL 0"。。。结果总是一样的!我想我错过了一些基本的东西。

void testStencil()
{
    // 1. Write a 1 in the Stencil buffer for 
    // every pixels of the first sphere:
    // All colors disabled, we don't need to see that sphere
    glEnable(GL_STENCIL_TEST);
    glStencilFunc(GL_ALWAYS, 0x1, 0x1);
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    glDepthMask(GL_FALSE);   // Edit: added this
    {
        sphe->W = mat4::trans(psa::vec4(1.0, 1.0, 1.0)) * mat4::scale(0.9);
        sphe->show();
    }
    // 2. Draw the second sphere with the following rule:
    // fail the stencil test for every pixels with a 1.
    // This means that  any pixel from first sphere will
    // not be draw as part of the second sphere.
    glStencilFunc(GL_EQUAL, 0x0, 0x1);
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    glDepthMask(GL_TRUE);    // Edit: added this
    {
        sphe->W = mat4::trans(psa::vec4(1.2, 1.2, 1.2)) * mat4::scale(1.1);
        sphe->show();
    }
}

瞧!如果有人能为我指明正确的方向,我将不胜感激。我也会确保将你的答案提交给我找到的另一篇帖子。

这个问题中发布的OpenGL代码是有效的。问题的原因在于窗口初始化/创建:

下面分别是SDL1.2和SDL2版本的代码。请注意,在这两种情况下,SetAttribute语句都放置在窗口创建之前。主要的问题是,未放置的语句在运行时不一定会失败,但也不起作用。

SDL1.2:

if(SDL_Init(SDL_INIT_EVERYTHING) < 0) 
{
    throw "Video initialization failed";
}
SDL_GL_SetAttribute(SDL_GL_RED_SIZE,     5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,   5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,    5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,  24);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES,16);  
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
const SDL_VideoInfo * i;
if((i = SDL_GetVideoInfo()) == NULL)  
{
    throw "Video query failed";
}
int flag = (fs ? SDL_OPENGL | SDL_FULLSCREEN : SDL_OPENGL);
if(SDL_SetVideoMode(w, h, i->vfmt->BitsPerPixel, flag) == 0)
{
    throw "Video mode set failed";
}
glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK)
{
    throw "Could not initialize GLEW";
}
if(!glewIsSupported("GL_VERSION_3_3"))
{
    throw "OpenGL 3.3 not supported";
}

SDL2(本质上是相同的代码,只是窗口创建功能发生了变化):

if(SDL_Init(SDL_INIT_EVERYTHING) < 0) 
{
    throw "Video initialization failed";
}
SDL_GL_SetAttribute(SDL_GL_RED_SIZE,     5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,   5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,    5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,  24);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES,16);  
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
int flag = SDL_WINDOW_OPENGL;
if((win = SDL_CreateWindow("engine", 100, 100, w, h, flag)) == NULL)
{
    throw "Create SDL Window failed";
}
context = SDL_GL_CreateContext(win);
glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK)
{
    throw "Could not initialize GLEW";
}
if(!glewIsSupported("GL_VERSION_3_3"))
{
    throw "OpenGL 3.3 not supported";
}

有几点值得一提:
1。尽管我知道这不是建议,SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,1)也能工作
2。在SDL2中,SDL_GL_SetAttribute SDL_GL_MULTISAMPLESAMPLES对我来说上升到16,在glewInit()失败之后,但是,在窗口创建后移动多采样设置,glewInit突然停止抱怨:我猜它只是被忽略了。
3。在SDL1.2中,多重采样的任何值"似乎"都有效
4。考虑到模具缓冲区功能,只有下面的代码也可以工作,但我发布它本质上是为了提出一个问题:有多少属性设置实际上可以工作?既然代码编译和运行没有明显的问题,那么如何知道呢?

// PROBABLY WRONG:
// ----
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
const SDL_VideoInfo * i;
if((i = SDL_GetVideoInfo()) == NULL)  
{
        throw "Video query failed";
}
int flag = (fs ? SDL_OPENGL | SDL_FULLSCREEN : SDL_OPENGL);
if(SDL_SetVideoMode(w, h, i->vfmt->BitsPerPixel, flag) == 0)
{
    throw "Video mode set failed";
}
// No idea if the below is actually applied!
SDL_GL_SetAttribute(SDL_GL_RED_SIZE,     5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,   5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,    5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,  24);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 16); 
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);

最新更新