1

制作透明的东西并不难,但我需要根据对象的曲线使透明度有所不同,以使其看起来不仅仅是一个平面对象。有点像下图。

中心比圆柱体的侧面更透明,更黑,这是背景颜色。然后是挡板,顶部似乎有某种镜面照明以使其更加闪亮,但我不知道在这种情况下如何处理这种透明度。使用相对于眼睛位置的表面法线来确定透明度值?任何帮助,将不胜感激。

4

1 回答 1

3

(将评论移至答案并添加了更多细节)

使用(次表面)散射而不是透明度。

您可以简化很多事情,例如假设光源沿整个表面/体积是恒定的......所以您只需要视图光线积分而不是每条光线的整个体积积分......我在我的大气着色器中完成它看起来仍然非常棒,几乎与真实的东西没有区别。看到一些更新的屏幕截图......将它与地球和火星的照片进行了比较,结果非常接近,没有任何真正复杂的数学。

有更多选择如何实现这一点:

  1. 体素贴图(体积渲染)

    在体积渲染引擎中实现散射很容易,但需要大量内存和功率。

  2. 使用 2 个深度缓冲区(正面和背面)

    这需要 2 次通过 Cull face on 和 CW/CCW 设置。这也很容易实现,但这不能处理沿相机视图 Z 轴的同一视图中的多个对象。这个想法是将两个深度缓冲区传递给着色器并沿其路径整合像素射线,从而累积/吸收来自光源的光。像这样的东西:

    SSS 2 深度缓冲区

    1. 将几何图形作为 2 个纹理渲染到两个深度缓冲区。
    2. 渲染四边形覆盖整个屏幕
    3. 为每个片段计算射线线(绿色)
    4. 计算展位深度缓冲区中的交点获得“长度,角度”
    5. 使用散射沿长度积分计算像素颜色

      我使用这样的东西:

         vec3 p,p0,p1; // p0 front and p1 back face ray/depth buffer intersection points
         int n=16; // integration steps
         dl=(p1-p0)/float(n); // integration step vector
         vec3 c=background color;
         float q=dot(normalize(p1-p0),light)=fabs(cos(ang)); // normal light shading
      
         for (p=p1,i=0;i<n;p1-=dp,i++)                // p = p1 -> p0 path through object
              {
              b=B0.rgb*dl;  // B0 is saturated color of object
              c.r*=1.0-b.r; // some light is absorbed
              c.g*=1.0-b.g;
              c.b*=1.0-b.b;
              c+=b*q;       // some light is scattered in
              } // here c is the final fragment color
      

    在集成之后/期间,您应该对颜色进行归一化......以便生成的颜色在渲染材料的真实视图深度周围饱和。有关更多信息,请参见下面的大气散射链接(这段代码是从中提取的)

  3. 分析对象表示

    如果您知道表面方程,那么您可以计算着色器内部的光路交叉点,而无需深度缓冲区或体素贴图。我的这个Simple GLSL Atmospheric shader使用了这种方法,因为椭圆体真的很容易用这种方式处理。

  4. 光线追踪器

    如果您需要精度并且不能使用体素贴图,那么您可以尝试使用光线追踪引擎。但是所有散射渲染器/引擎(包括#1、#2、#3)无论如何都是光线追踪器......正如你所看到的,这里讨论的所有技术都是相同的,唯一的区别是获取光线/​​对象边界交点的方法.

于 2015-11-07T10:28:25.140 回答