Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Opengl 如何在片段着色器中实现折射光?_Opengl_Glsl_Fragment Shader_Raytracing_Fresnel - Fatal编程技术网

Opengl 如何在片段着色器中实现折射光?

Opengl 如何在片段着色器中实现折射光?,opengl,glsl,fragment-shader,raytracing,fresnel,Opengl,Glsl,Fragment Shader,Raytracing,Fresnel,我正在开发一个OpenGL光线跟踪器,它能够加载obj文件并对其进行光线跟踪。我的应用程序使用assimp加载obj文件,然后使用着色器存储对象将所有三角形面(以及基本体坐标和te材质系数)发送到片段着色器。基本结构将从片段着色器将结果渲染到四元体 我对片段着色器中的光线跟踪部分有问题,但首先让我们介绍一下它。 对于漫反射光,使用朗伯余弦定律,对于镜面反射光,使用Phong-Blinn模型。在全反射的情况下,权重变量用于使反射光对其他物体产生影响。采用Schlick方法近似菲涅耳方程计算重量。在

我正在开发一个OpenGL光线跟踪器,它能够加载obj文件并对其进行光线跟踪。我的应用程序使用assimp加载obj文件,然后使用着色器存储对象将所有三角形面(以及基本体坐标和te材质系数)发送到片段着色器。基本结构将从片段着色器将结果渲染到四元体

我对片段着色器中的光线跟踪部分有问题,但首先让我们介绍一下它。 对于漫反射光,使用朗伯余弦定律,对于镜面反射光,使用Phong-Blinn模型。在全反射的情况下,
权重
变量用于使反射光对其他物体产生影响。采用Schlick方法近似菲涅耳方程计算重量。在下图中,您可以看到,该平面的工作原理类似于一面反射上方立方体图像的镜子

我想让立方体看起来像一个玻璃物体(像一个玻璃球),它也有折射和反射效果。或者至少折射光线。在上面的图像中,您可以看到立方体上的折射效果,但它并不像应该的那样好。我搜索了如何实现它的示例,但直到现在,我认识到菲涅耳方程必须像反射部分一样使用

下面是我的着色器片段:

 vec3 Fresnel(vec3 F0, float cosTheta) {
    return F0 + (vec3(1, 1, 1) - F0) * pow(1-cosTheta, 5);
}

float schlickApprox(float Ni, float cosTheta){
    float F0=pow((1-Ni)/(1+Ni), 2);
    return F0 + (1 - F0) * pow((1 - cosTheta), 5);
}


vec3 trace(Ray ray){
    vec3 weight = vec3(1, 1, 1);
    const float epsilon = 0.0001f;
    vec3 outRadiance = vec3(0, 0, 0);
    int maxdepth=5;

    for (int i=0; i < maxdepth; i++){
        Hit hit=traverseBvhTree(ray);

        if (hit.t<0){ return weight * lights[0].La; }

        vec4 textColor = texture(texture1, vec2(hit.u, hit.v));
        Ray shadowRay;
        shadowRay.orig = hit.orig + hit.normal * epsilon;
        shadowRay.dir  = normalize(lights[0].direction);

        // Ambient Light
        outRadiance+= materials[hit.mat].Ka.xyz * lights[0].La*textColor.xyz * weight;


        // Diffuse light based on Lambert's cosine law
        float cosTheta = dot(hit.normal, normalize(lights[0].direction));
        if (cosTheta>0 && traverseBvhTree(shadowRay).t<0) {
            outRadiance +=lights[0].La * materials[hit.mat].Kd.xyz * cosTheta * weight;

            // Specular light based on Phong-Blinn model
            vec3 halfway = normalize(-ray.dir + lights[0].direction);
            float cosDelta = dot(hit.normal, halfway);

            if (cosDelta > 0){
                outRadiance +=weight * lights[0].Le * materials[hit.mat].Ks.xyz * pow(cosDelta, materials[hit.mat].shininess); }
        }

        float fresnel=schlickApprox(materials[hit.mat].Ni, cosTheta);

        // For refractive materials
        if (materials[hit.mat].Ni < 3)
        {

         /*this is the under contruction part.*/



            ray.orig = hit.orig - hit.normal*epsilon;
            ray.dir = refract(ray.dir, hit.normal, materials[hit.mat].Ni);
        }

        // If the refraction index is more than 15, treat the material as mirror.
        else if (materials[hit.mat].Ni >= 15) {
            weight *= fresnel;
            ray.orig=hit.orig+hit.normal*epsilon;
            ray.dir=reflect(ray.dir, hit.normal);
        }
    }
    return outRadiance;
}
以下是连接到更新的快照。我想稍微好一点


更新2: 我发现了一个迭代算法,它使用堆栈在opengl中可视化折射光线和反射光线:

我根据这个修改了我的frag着色器。几乎没问题,除了背面是全黑的。附上一些照片

以下是我的frag着色器的跟踪方法:

vec3 trace(Ray ray){
    vec3 color;
    float epsilon=0.001;
    Stack stack[8];// max depth
    int stackSize = 0;// current depth
    int bounceCount = 0;
    vec3 coeff = vec3(1, 1, 1);
    bool continueLoop = true;

    while (continueLoop){
        Hit hit = traverseBvhTree(ray);
        if (hit.t>0){

            bounceCount++;
            //----------------------------------------------------------------------------------------------------------------
            Ray shadowRay;
            shadowRay.orig = hit.orig + hit.normal * epsilon;
            shadowRay.dir  = normalize(lights[0].direction);

            color+= materials[hit.mat].Ka.xyz * lights[0].La * coeff;
            // Diffuse light
            float cosTheta = dot(hit.normal, normalize(lights[0].direction));// Lambert-féle cosinus törvény alapján.
            if (cosTheta>0 && traverseBvhTree(shadowRay).t<0) {
                color +=lights[0].La * materials[hit.mat].Kd.xyz * cosTheta * coeff;
                vec3 halfway = normalize(-ray.dir + lights[0].direction);
                float cosDelta = dot(hit.normal, halfway);

                // Specular light
                if (cosDelta > 0){
                    color +=coeff * lights[0].Le * materials[hit.mat].Ks.xyz * pow(cosDelta, materials[hit.mat].shininess); }
            }
            //---------------------------------------------------------------------------------------------------------------
              if (materials[hit.mat].indicator > 3.0 && bounceCount <=2){

                  float eta = 1.0/materials[hit.mat].Ni;
                  Ray refractedRay;
                  refractedRay.dir = dot(ray.dir, hit.normal) <= 0.0 ? refract(ray.dir, hit.normal, eta) : refract(ray.dir, -hit.normal, 1.0/eta);
                  bool totalInternalReflection = length(refractedRay.dir) < epsilon;
                  if(!totalInternalReflection){

                      refractedRay.orig = hit.orig + hit.normal*epsilon*sign(dot(ray.dir, hit.normal));
                      refractedRay.dir = normalize(refractedRay.dir);

                          stack[stackSize].coeff = coeff *(1 - schlickApprox(materials[hit.mat].Ni, dot(ray.dir, hit.normal)));
                          stack[stackSize].depth = bounceCount;
                          stack[stackSize++].ray = refractedRay;

                  }

                  else{

                      ray.dir = reflect(ray.dir, -hit.normal);
                      ray.orig = hit.orig - hit.normal*epsilon;
                  }
              }

            else if (materials[hit.mat].indicator == 0){
                coeff *= schlickApprox(materials[hit.mat].Ni, dot(-ray.dir, hit.normal));
                ray.orig=hit.orig+hit.normal*epsilon;
                ray.dir=reflect(ray.dir, hit.normal);
            }


            else { //Diffuse Material
                continueLoop=false;
            }
        }

        else {
            color+= coeff * lights[0].La;
            continueLoop=false;
        }

        if (!continueLoop && stackSize > 0){
            ray = stack[stackSize--].ray;
            bounceCount = stack[stackSize].depth;
            coeff = stack[stackSize].coeff;
            continueLoop = true;
        }
    }
    return color;
}
vec3跟踪(光线){
vec3颜色;
浮点数ε=0.001;
堆栈[8];//最大深度
int stackSize=0;//当前深度
int bounceCount=0;
vec3系数=vec3(1,1,1);
bool continueLoop=true;
while(continueLoop){
Hit Hit=遍历树(射线);
如果(命中率t>0){
bounceCount++;
//----------------------------------------------------------------------------------------------------------------
射线阴影射线;
shadowRay.orig=hit.orig+hit.normal*epsilon;
shadowRay.dir=规格化(灯光[0]。方向);
颜色+=材质[hit.mat].Ka.xyz*灯光[0].La*系数;
//漫射光
float cosTheta=dot(hit.normal,normalize(lights[0]。direction));//Lambert-féle cosinus törvény alapján。
if(cosTheta>0&&traverseBvhTree(shadowRay).t0){
颜色+=系数*灯光[0].Le*材质[hit.mat].Ks.xyz*pow(COSDERTA,材质[hit.mat].shininess);}
}
//---------------------------------------------------------------------------------------------------------------

如果(materials[hit.mat].indicator>3.0&&bounceCount我看不到你分割光线(你的折射中有
继续
跳过反射代码),但我可能会错,因为它是外来的,对我来说很难读取代码。而且权重看起来很有用(分割期间如何(重新)存储它们)?看看这个:没有菲涅耳非常简单,但是它可以正确地分割光束。你的另一个选择是使用随机分割。你知道50%的反射概率和50%的折射概率,以防可能的折射。我添加了一个使用堆栈存储光线的算法,但出现了新的故障。我不知道我看不到你分割光线(你的折射中有
continue
跳过反射代码),但我可能错了,因为它是外来的,对我来说代码很难读懂。而且权重看起来很有用(分割期间如何(重新)存储)?看看这个:没有菲涅耳非常简单,但是它可以正确地分割光束。你的另一个选择是使用随机分割。你知道50%的反射概率和50%的折射概率,以防可能的折射。我添加了一个使用堆栈存储光线的算法,但出现了新的问题。
vec3 trace(Ray ray){
    vec3 color;
    float epsilon=0.001;
    Stack stack[8];// max depth
    int stackSize = 0;// current depth
    int bounceCount = 0;
    vec3 coeff = vec3(1, 1, 1);
    bool continueLoop = true;

    while (continueLoop){
        Hit hit = traverseBvhTree(ray);
        if (hit.t>0){

            bounceCount++;
            //----------------------------------------------------------------------------------------------------------------
            Ray shadowRay;
            shadowRay.orig = hit.orig + hit.normal * epsilon;
            shadowRay.dir  = normalize(lights[0].direction);

            color+= materials[hit.mat].Ka.xyz * lights[0].La * coeff;
            // Diffuse light
            float cosTheta = dot(hit.normal, normalize(lights[0].direction));// Lambert-féle cosinus törvény alapján.
            if (cosTheta>0 && traverseBvhTree(shadowRay).t<0) {
                color +=lights[0].La * materials[hit.mat].Kd.xyz * cosTheta * coeff;
                vec3 halfway = normalize(-ray.dir + lights[0].direction);
                float cosDelta = dot(hit.normal, halfway);

                // Specular light
                if (cosDelta > 0){
                    color +=coeff * lights[0].Le * materials[hit.mat].Ks.xyz * pow(cosDelta, materials[hit.mat].shininess); }
            }
            //---------------------------------------------------------------------------------------------------------------
              if (materials[hit.mat].indicator > 3.0 && bounceCount <=2){

                  float eta = 1.0/materials[hit.mat].Ni;
                  Ray refractedRay;
                  refractedRay.dir = dot(ray.dir, hit.normal) <= 0.0 ? refract(ray.dir, hit.normal, eta) : refract(ray.dir, -hit.normal, 1.0/eta);
                  bool totalInternalReflection = length(refractedRay.dir) < epsilon;
                  if(!totalInternalReflection){

                      refractedRay.orig = hit.orig + hit.normal*epsilon*sign(dot(ray.dir, hit.normal));
                      refractedRay.dir = normalize(refractedRay.dir);

                          stack[stackSize].coeff = coeff *(1 - schlickApprox(materials[hit.mat].Ni, dot(ray.dir, hit.normal)));
                          stack[stackSize].depth = bounceCount;
                          stack[stackSize++].ray = refractedRay;

                  }

                  else{

                      ray.dir = reflect(ray.dir, -hit.normal);
                      ray.orig = hit.orig - hit.normal*epsilon;
                  }
              }

            else if (materials[hit.mat].indicator == 0){
                coeff *= schlickApprox(materials[hit.mat].Ni, dot(-ray.dir, hit.normal));
                ray.orig=hit.orig+hit.normal*epsilon;
                ray.dir=reflect(ray.dir, hit.normal);
            }


            else { //Diffuse Material
                continueLoop=false;
            }
        }

        else {
            color+= coeff * lights[0].La;
            continueLoop=false;
        }

        if (!continueLoop && stackSize > 0){
            ray = stack[stackSize--].ray;
            bounceCount = stack[stackSize].depth;
            coeff = stack[stackSize].coeff;
            continueLoop = true;
        }
    }
    return color;
}