0

我正在片段着色器中编写一个基本的 Sphere-Tracer,如果我只是根据它们的表面法线为点着色,一切都很好,但是一旦我尝试实现反射算法,编译需要更长的时间,而且只是黑屏。fps 从 1 开始,但很快上升到 1000,这是我设置的代码限制,告诉我着色器实际上没有做任何事情,只是忽略了我的代码,这应该比这慢得多。我最初以为我达到了 GPU 的指令限制,但我不认为这是问题所在,因为使用正常着色代码,我可以设置MAX_MARCH为高值,如 1000,但使用反射,即使使用MAX_REFLECTIONSMAX_AA到一个,这应该类似于正常着色的指令量(可能更多〜50,我认为不重要)。但是我需要将其设置MAX_MARCH为 1 才能渲染,即使将其设置为 2 也会导致该错误。

顶点着色器:

//Draw a quad on the whole display and calculates sky color
#version 400 core

in vec3 position;
out vec2 uvPos;
out vec4 backColor;

void main(void){
    gl_Position = vec4(position, 1.0);
    uvPos = position.xy*0.5+0.5;
    backColor = mix(vec4(1, 1, 1, 1), vec4(0.5, 0.7, 1, 1), uvPos.y);
}

片段着色器:

#version 400 core

#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
#define DBL_MAX 1.7976931348623158e+308
#define DBL_MIN 2.2250738585072014e-308
#define PI 3.141592653589793115997963468544185161590576171875

#define MAX_AA 1
#define MAX_MARCH 1000
#define MAX_REFLECTIONS 10
#define MAX_DIST 10

in vec2 uvPos;
in vec4 backColor;
out vec4 outColor;

int randomIterator = 0;
//############################################################  Structure definitions   #########################################################################
struct Material{
    int type;
    vec3 albedo;
};

struct Object{
    int type; //1:Sphere, 2:Box
    vec3 center;
    float radius;
    vec3 size;

    Material material;
};

struct Scene{
    Object objects[3];
};

struct Ray{
    vec3 origin;
    vec3 dir;
};

struct HitRecord{
    vec3 p;
    vec3 n;
    Object o;
    Material mat;
    float closest;
};
struct Camera{
    vec3 origin;
    vec3 lowerLeftCorner;
    vec3 horizontal;
    vec3 vertical;
};
//############################################################  Uniforms    ####################################################################################
uniform float random[2048];
uniform vec2 resolution;
uniform Camera cam;
uniform Scene scene;
uniform int objectAmount;
//############################################################  Tools   
float randf(){
    return random[randomIterator++];
}
Ray getRay(Camera cam, vec2 v){
    return Ray(cam.origin, normalize(cam.lowerLeftCorner+cam.horizontal*v.s+cam.vertical*v.t-cam.origin));
}
vec3 randOnBall(){
    vec3 p;
    do{
        p = vec3(randf(), randf(), randf())*2-1;
    }while(p.length() >= 1);
    return p;
}
//############################################################  Signed Distance Functions   
float sphereSDF(vec3 p, Object o){
    return length(p-o.center)-o.radius;
}
float boxSDF(vec3 p, Object o){
    vec3 q = abs(p-o.center) - o.size;
    return (length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0));
}
float sceneSDF(vec3 p, Scene s){
    float dist = FLT_MAX;
    for(int i = 0; i < objectAmount; i++){
        switch(s.objects[i].type){
            case 1:
                dist = min(dist, sphereSDF(p, s.objects[i]));
                break;
            case 2:
                dist = min(dist, boxSDF(p, s.objects[i]));
                break;
            default:
                break;
        }
    }
    return dist;
}
float sceneSDF(vec3 p, Scene s, inout HitRecord rec){
    float dist = FLT_MAX;
    for(int i = 0; i < objectAmount; i++){
        float tmpDist=FLT_MAX; 
        switch(s.objects[i].type){
            case 1:
                tmpDist = sphereSDF(p, s.objects[i]);
                break;
            case 2:
                tmpDist = boxSDF(p, s.objects[i]);
                break;
            default:
                break;
        }
        if(tmpDist<dist){
            dist = tmpDist;
            rec.o = s.objects[i];
            rec.mat = s.objects[i].material;
        }
    }
    return dist;
}
//############################################################  Material Scatter Function   
bool scatterDiffuse(Ray r, HitRecord rec, inout vec3 tmpAtt, inout Ray scattered){
    tmpAtt = vec3(rec.mat.albedo);
    scattered = Ray(rec.p, rec.n+randOnBall());
    return true;
}

bool scatter(Ray r, HitRecord rec, inout vec3 tmpAtt, inout Ray scattered){
    return scatterDiffuse(r, rec, tmpAtt, scattered);  //Starting out with diffuse materials, planned to 
    add switch-case for different materials
}
//############################################################  Main    
vec3 findSceneNormal(Scene s, vec3 p){
    const float h = 0.0001; // replace by an appropriate value
    const vec2 k = vec2(1,-1);
    return normalize( k.xyy*sceneSDF( p + k.xyy*h, s ) + 
                      k.yyx*sceneSDF( p + k.yyx*h, s ) + 
                      k.yxy*sceneSDF( p + k.yxy*h, s ) + 
                      k.xxx*sceneSDF( p + k.xxx*h, s ) );
}

float findSceneIntersect(Ray r, Scene scene, inout HitRecord rec){
    float t = 0.005;
    vec3 p;
    for(int i = 0; i < MAX_MARCH; i++){
        p = r.origin+t*r.dir;
        float dist = abs(sceneSDF(p, scene, rec));
        if(dist < 0.001){
            rec.n = findSceneNormal(scene, p);
            rec.p = p;
            return t;
        }else{
            t += dist;
            if(t >= MAX_DIST){
                rec.p = r.origin+t*r.dir;
                rec.n = vec3(0, 0, 0);
                return -1;
            }
        }
    }
    return -1;
}
vec3 calcColor(Ray r){
    vec3 color;
    Material emptyMat = Material(0, vec3(0));
    Object emptyO = Object(0, vec3(0), 0, vec3(0), emptyMat);
    HitRecord rec = HitRecord(vec3(0), vec3(0), emptyO, emptyMat, 0);
    float t = findSceneIntersect(r, scene, rec);
    int reflections = 0;
    vec3 att = vec3(1, 1, 1);
    for(int ref = 0; ref < MAX_REFLECTIONS; ref++){
        if(t != -1){
            vec3 tmpAtt = vec3(0);
            if(scatter(r, rec, tmpAtt, r)){
                att *= tmpAtt;
                t = findSceneIntersect(r, scene, rec);
                reflections++;
            }else {
                att *= tmpAtt;
                t = -1;
            }
        }else {
            color = backColor.xyz*att;
            break;
        }
    }
    return color;
}

void main(void){
    HitRecord rec = HitRecord(vec3(0), vec3(0), Object(-1, vec3(0), 0, vec3(0), Material(-1, vec3(0))), Material(-1, vec3(1, 1, 1)), 0);
    #if 1  //Reflection rendering
        vec3 color = vec3(0);
        for(int s = 0; s < MAX_AA; s++){
            vec2 uv = uvPos+(vec2(randf(), randf())*2-1)/resolution;
            color += calcColor(getRay(cam, uv));
        }
        outColor = vec4(color/MAX_AA, 1);

    #else  //Coloring based on normals
        Ray r = getRay(cam, uvPos);
        float t = findSceneIntersect(r, scene, rec);
        if(t == -1){
            outColor = backColor;
        }else {
            outColor = vec4(rec.n*0.5+0.5, 1);
        }
    #endif
}

我加载和编译着色器的 Java 代码(使用 LWJGL):

    private static int loadShader(String file, int type) {
        System.out.println("Loading shader at path: " + file);
        StringBuilder shaderSource = new StringBuilder();
        try{
            BufferedReader reader = new BufferedReader(new FileReader(file));
            String line;
            while((line = reader.readLine())!=null){
                shaderSource.append(line).append("//\n");
            }
            reader.close();
        }catch(IOException e){
            e.printStackTrace();
            System.exit(-1);
        }
        int shaderID = glCreateShader(type);
        glShaderSource(shaderID, shaderSource);
        glCompileShader(shaderID);
        if(glGetShaderi(shaderID, GL_COMPILE_STATUS )== GL_FALSE){
            System.out.println(glGetShaderInfoLog(shaderID, 500));
            System.err.println("Could not compile shader!");
            System.exit(-1);
        }
        return shaderID;
    }

我的代码中的函数 loadShader 不会像语法错误那样给我任何错误,并且不会退出程序,因此GL_COMPILE_STATUS不是错误的。

我完全意识到嵌套的 for 循环,并且我对条件的使用远非高效的性能,但我希望它会很慢,而不是完全破坏。我在英特尔 UHD 630 上运行它,根据https://www.intel.ca/content/www/ca/en/support/products/98909/graphics/graphics-for-7th-generation-intel-processors /intel-hd-graphics-630.html支持 openGL 4.4。因此,根据GLSL 最大指令数,我应该可以在我的片段着色器和完全动态分支中访问 65536 条指令。由于这些原因,我不认为指令限制是问题,任何帮助将不胜感激。如果您需要更多信息,我会尽快添加。如果需要 CPU 代码,我也可以添加它,但我认为这不是问题,因为仅更改着色器会触发此错误。

编辑 1:在程序经过验证和链接后调用时,两者都没有返回任何内容glGetShaderInfoLogglGetProgramInfoLog

4

0 回答 0