为啥保守光栅化无法为某些三角形调用片段着色器?

Posted

技术标签:

【中文标题】为啥保守光栅化无法为某些三角形调用片段着色器?【英文标题】:Why does conservative rasterization fail to call the fragment shader for some triangles?为什么保守光栅化无法为某些三角形调用片段着色器? 【发布时间】:2018-05-11 22:48:36 【问题描述】:

我在 g3.4xlarge AWS EC2 实例上使用保守光栅化。以下代码应在片段着色器中增加一个原子计数器(在 RenderFunction() 中读取)并将片段坐标存储在着色器存储缓冲区对象中。以下三角形不会增加原子计数器。其他三角形确实会导致原子计数器递增。

nvcc --version 输出: Cuda编译工具,发布9.0,V9.0.176 信息:OpenGL 版本:4.0.0 NVIDIA 384.111

以下代码修改自https://github.com/daw42/glslcookbook

// g++ -std=gnu++0x  -g -I ./glslcookbook/ingredients/glad/include -I ./glslcookbook/ingredients  dbg1.cpp ./glslcookbook/ingredients/glad/src/glad.c ./glslcookbook/ingredients/glslprogram.cpp -ldl -lglut -lGLU

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "glslprogram.h"
#include <GL/freeglut.h>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/ext.hpp>

#define WINDOW_TITLE_PREFIX "Chapter 2"

using namespace glm;

    int
    CurrentWidth = 576,
    CurrentHeight = 576,
    WindowHandle = 0;

unsigned FrameCount = 0;

GLuint
    VertexShaderId,
    FragmentShaderId,
    ProgramId,
    VaoId,
    VboId,
    ColorBufferId;

void Initialize(int, char*[]);
void InitWindow(int, char*[]);
void ResizeFunction(int, int);
void RenderFunction(void);
void TimerFunction(int);
void IdleFunction(void);
void Cleanup(void);
void CreateVBO(void);
void DestroyVBO(void);
void CreateShaders(void);
void DestroyShaders(void);

enum BufferNames 
    COUNTER_BUFFER = 0,
    LINKED_LIST_BUFFER
;

int main(int argc, char* argv[])

    Initialize(argc, argv);
    glutMainLoop();
    exit(EXIT_SUCCESS);


GLuint buffers[2];
int width=576;
int height= width;
int gLog2SL=20;
int maxV=603979776;
GLuint maxNodes=66000;

void Initialize(int argc, char* argv[])

    if(gladLoadGL()) 
        // you need an OpenGL context before loading glad
        printf("I did load GL with no context!\n");
        exit(-1);
    

    InitWindow(argc, argv);

    if(!gladLoadGL()) 
        printf("Something went wrong!\n");
        exit(-1);
    

    fprintf(
        stdout,
        "INFO: OpenGL Version: %s\n",
        glGetString(GL_VERSION)
    );

    glEnable(GL_CONSERVATIVE_RASTERIZATION_NV);
    GLenum ErrorCheckValue = glGetError();
    if (ErrorCheckValue != GL_NO_ERROR)
    
        fprintf(
            stderr,
            "ERROR: after calling glEnable(GL_CONSERVATIVE_RASTERIZATION_NV) : %s \n",
            gluErrorString(ErrorCheckValue)
        );
        exit(-1);
    

    CreateShaders();
    CreateVBO();
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);


void InitWindow(int argc, char* argv[])

    glutInit(&argc, argv);

    glutInitContextVersion(4, 0);
    glutInitContextFlags(GLUT_FORWARD_COMPATIBLE);
    glutInitContextProfile(GLUT_CORE_PROFILE);

    glutSetOption(
        GLUT_ACTION_ON_WINDOW_CLOSE,
        GLUT_ACTION_GLUTMAINLOOP_RETURNS
    );


    glutInitWindowSize(CurrentWidth, CurrentHeight);

    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);

    WindowHandle = glutCreateWindow(WINDOW_TITLE_PREFIX);

    if(WindowHandle < 1) 
        fprintf(
          stderr,
          "ERROR: Could not create a new rendering window.\n"
        );
        exit(EXIT_FAILURE);
    

    glutReshapeFunc(ResizeFunction);
    glutDisplayFunc(RenderFunction);
    glutIdleFunc(IdleFunction);
    glutTimerFunc(0, TimerFunction, 0);
    glutCloseFunc(Cleanup);


void ResizeFunction(int Width, int Height)

    CurrentWidth = width;
    CurrentHeight = height;
    glViewport(0, 0, width, height);


void RenderFunction(void)

    ++FrameCount;
     GLuint atomicVal=4352;
    glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffers[COUNTER_BUFFER]);
    glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &atomicVal);

    GLuint zero = 0;
    glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, buffers[COUNTER_BUFFER] );
    glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &zero);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glDrawArrays(GL_TRIANGLES, 0, 3);

    glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffers[COUNTER_BUFFER]);
    glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &atomicVal);

    struct NodeType 
        vec4 color;
    ;

    //  NodeType nodeRA[maxNodes];
    NodeType nodeRA[66000];
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[LINKED_LIST_BUFFER]);
    //  glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, maxNodes * sizeof(NodeType), &nodeRA[0]);
    glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, 66000 * sizeof(NodeType), &nodeRA[0]);


    for (int i=0; i<atomicVal; i++) 
        printf("index= %d, %f, %f, %f, %f\n",i, nodeRA[i].color[0], nodeRA[i].color[1], nodeRA[i].color[2], nodeRA[i].color[3]);
    
    glutSwapBuffers();


void IdleFunction(void)

  glutPostRedisplay();


void TimerFunction(int Value)

    if (0 != Value) 
        char* TempString = (char*)
            malloc(512 + strlen(WINDOW_TITLE_PREFIX));

        sprintf(
            TempString,
            "%s: %d Frames Per Second @ %d x %d",
            WINDOW_TITLE_PREFIX,
            FrameCount * 4,
            CurrentWidth,
            CurrentHeight
        );

        glutSetWindowTitle(TempString);
        free(TempString);
    

    FrameCount = 0;
    glutTimerFunc(250, TimerFunction, 1);


void Cleanup(void)

    DestroyShaders();
    DestroyVBO();


void CreateVBO(void)

    glGenBuffers(2, buffers);
    GLint nodeSize = 5 * sizeof(GLfloat) + sizeof(GLuint); // The size of a linked list node

    // Our atomic counter
    glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, buffers[COUNTER_BUFFER]);
    glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);

    // The buffer of linked lists
    glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffers[LINKED_LIST_BUFFER]);
    glBufferData(GL_SHADER_STORAGE_BUFFER, maxNodes * nodeSize, NULL, GL_DYNAMIC_DRAW);
    double pixSL= 1<<(gLog2SL);
    int m=11, n=13, p=15;
    GLfloat z= p*pixSL;
    GLfloat vertX1= 435275968, vertY1= 328189312, vertX2= 435275712, vertY2= 328189312,vertX3= 435275712, vertY3= 328189056;

    GLfloat Vertices[] = 
        vertX1, vertY1, z, 1.0f,
        vertX2, vertY2, z, 1.0f,
        vertX3, vertY3, z, 1.0f
    ;

    GLfloat Colors[] = 
        1.0f, 0.0f, 0.0f, 1.0f,
        0.0f, 1.0f, 0.0f, 1.0f,
        0.0f, 0.0f, 1.0f, 1.0f
    ;

    GLenum ErrorCheckValue = glGetError();

    glGenVertexArrays(1, &VaoId);
    glBindVertexArray(VaoId);

    glGenBuffers(1, &VboId);
    glBindBuffer(GL_ARRAY_BUFFER, VboId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    glGenBuffers(1, &ColorBufferId);
    glBindBuffer(GL_ARRAY_BUFFER, ColorBufferId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Colors), Colors, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(1);

    ErrorCheckValue = glGetError();
    if (ErrorCheckValue != GL_NO_ERROR)
    
        fprintf(
            stderr,
            "ERROR: Could not create a VBO: %s \n",
            gluErrorString(ErrorCheckValue)
        );
        exit(-1);
    


void DestroyVBO(void)

    GLenum ErrorCheckValue = glGetError();

    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glDeleteBuffers(1, &ColorBufferId);
    glDeleteBuffers(1, &VboId);

    glBindVertexArray(0);
    glDeleteVertexArrays(1, &VaoId);

    ErrorCheckValue = glGetError();
    if (ErrorCheckValue != GL_NO_ERROR)
    
        fprintf(
            stderr,
            "ERROR: Could not destroy the VBO: %s \n",
            gluErrorString(ErrorCheckValue)
        );
        exit(-1);
    


void CreateShaders(void)

    GLenum ErrorCheckValue = glGetError();

    GLSLProgram prog;

    try 
        prog.compileShader("oit.vs");
        prog.compileShader("oit.fs");
        prog.link();
        prog.use();
     catch(GLSLProgramException &e ) 
        std::cerr << e.what() << std::endl;
        exit( EXIT_FAILURE );
    
    prog.setUniform("MaxNodes", maxNodes);
    // modelview matrix is a scaling by 1/max(x,y,z)
    double scale= 1.0/maxV, maxV1= maxV;
    const mat4 mv= glm::ortho(0.0, maxV1, 0.0, maxV1, 0.0, -maxV1);
    prog.setUniform("ModelViewMatrix", mv);
    glViewport(0.0,0.0,width, height);


void DestroyShaders(void)

    GLenum ErrorCheckValue = glGetError();
    glUseProgram(0);

这里是 oit.fs

#version 430


layout (pixel_center_integer) in vec4 gl_FragCoord;

struct NodeType 
  vec4 color;
  //float depth;
  //uint primID;
;

layout( binding = 0, offset = 0) uniform atomic_uint nextNodeCounter;
layout( binding = 0, std430 ) buffer linkedLists 
  NodeType nodes[];
;
uniform uint MaxNodes;


in vec4 ex_Color;
out vec3 out_Color;
void main(void)
    uint nodeIdx = atomicCounterIncrement(nextNodeCounter);

  // Is our buffer full?  If so, we don't add the fragment
  // to the list.
  if( (nodeIdx < MaxNodes-1) ) 
    float t2= float(nodeIdx);
    vec4 t1= vec4(gl_FragCoord.x, gl_FragCoord.y, gl_FragCoord.z, 0.0);
    nodes[nodeIdx].color= t1;
  

  out_Color = vec3(1.0, 1.0,0.0);

这里是 oit.vs

#version 430

layout (location = 0) in vec3 VertexPosition;

uniform mat4 ModelViewMatrix;

void main()

    gl_Position = ModelViewMatrix * vec4(VertexPosition,1.0);


【问题讨论】:

你确定这些荒谬的值,在通过一些浮点运算对它们进行修改并最终将结果捕捉到某个定点之后,会产生一个非零角三角形吗? 是否指定了这种荒谬值的概念,以便我可以确定三角形何时是这样的?如果三角形在管道操作中的某个点为零角度,为什么应该忽略它?如果我创建一个边界多边形,例如developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter42.html,即使是一个点也会变成一个像素那么大。我希望我使用的保守光栅化实现能够处理上面链接中描述的方法的所有情况。 " 如果三角形在管道操作中的某个点为零角度,为什么要忽略它?"根据GL_NV_conservative_raster:“面积为零的多边形不生成片段,即使对于包含零面积多边形的顶点或边缘的像素也是如此。 还要注意同一文档中问题 (2) 中的讨论。 【参考方案1】:

CreateShaders 中的评论“模型视图矩阵是按 1/max(x, y, z) 缩放的”,但这并不是正交矩阵的实际作用 >。我对 Python 中 vertX1 的数学运算的快速检查表明它在视口之外。如果所有三个顶点都被裁剪,没有三角形,所以没有着色器输出。

建议仔细阅读正交矩阵的描述,或者改用比例构造函数/函数。

【讨论】:

以上是关于为啥保守光栅化无法为某些三角形调用片段着色器?的主要内容,如果未能解决你的问题,请参考以下文章

光栅化阶段:三角形设置、三角形遍历、像素着色、合并

渲染管道光栅阶段四“片元着色器”

渲染管道光栅阶段四“片元着色器”

OpenGL

OpenGL

为啥片段着色器没有附加?