<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [OpenGL ES 08]Per-Pixel Light及卡通效果

      [OpenGL ES 08]Per-Pixel Light及卡通效果

      羅朝輝 (http://www.rzrgm.cn/kesalin/)

      本文遵循“署名-非商業用途-保持一致”創作公用協議

       

      這是《OpenGL ES 教程》的第九篇,前八篇請參考如下鏈接:

      [OpenGL ES 01]iOS上OpenGL ES之初體驗
      [OpenGL ES 02]OpenGL ES渲染管線與著色器
      [OpenGL ES 03]3D變換:模型,視圖,投影與Viewport
      [OpenGL ES 04]3D變換實踐篇:平移,旋轉,縮放
      [OpenGL ES 05]相對空間變換及顏色
      [OpenGL ES 06]使用VBO:頂點緩存

      [OpenGL ES 07-1]光照原理
      [OpenGL ES 07-2]Per-Vertex Light及深度緩存

      前言

      本文是基于前文《光照原理》以及《Per-Vertex Light及深度緩存》兩篇文章的,如果你還不熟悉光照相關的基礎知識,請先閱讀那兩篇文章。在今天的這篇文章中,我們來研究 Per-Pixel 光照效果以及卡通效果。Per-Pixel 光照效果就是在片元著色階段針對每個像素進行光照計算,而卡通效果是將散射光因子“分級”從而不再是連續(打個比方說,考試成績上百分制是連續的,而分級制:好/良好/及格/不及格就不是連續的),這樣就能獲得漫反射跳躍的卡通效果。Per-Pixel Light 示例源碼在這里,運行效果如下:

       

      一,創建工程

      Per-Vertex light 與 Per-Pixel 的光照計算基本上相同,只是進行的時機不同,Per-Vertex Light 在頂點著色階段針對每個頂點進行光照計算,而 Per-Pixel 是在片元著色階段針對每個像素進行光照計算。因此,本文將在前文《Per-Vertex Light及深度緩存》源碼的基礎上繼續進行。

       

      二,Per-Pixel Light

      1,修改頂點著色

      這次,頂點著色腳本非常簡單,因為光照計算工作都將轉移到片元著色腳本中進行。為了方便與前文中的腳本進行對比,在這里,保留前文中的腳本,新建 PerPixelVertex.glsl 以及 PerPixelFragment.glsl 腳本。

      PerPixelVertex.glsl 腳本內容如下:

      uniform mat4 projection;
      uniform mat4 modelView;
      uniform mat3 normalMatrix;
      
      attribute vec4 vPosition;
      attribute vec3 vNormal;
      attribute vec3 vDiffuseMaterial;
      
      varying vec3 vEyeSpaceNormal;
      varying vec3 vDiffuse;
      
      void main(void)
      {
          gl_Position = projection * modelView * vPosition;
          
          vEyeSpaceNormal = normalMatrix * vNormal;
          vDiffuse = vDiffuseMaterial;
      }

      從上面的代碼中可以看到,頂點著色器只是簡單地轉換 local space 中的法線到 view space,然后將相關 varying 傳遞給片元著色器。

      PerPixelFragment.glsl 腳本內容如下:

      varying mediump vec3 vEyeSpaceNormal;
      varying mediump vec3 vDiffuse;
      
      uniform highp vec3 vLightPosition;
      uniform highp vec3 vAmbientMaterial;
      uniform highp vec3 vSpecularMaterial;
      uniform highp float shininess;
      
      void main()
      {
          highp vec3 N = normalize(vEyeSpaceNormal);
          highp vec3 L = normalize(vLightPosition);
          highp vec3 E = vec3(0, 0, 1);
          highp vec3 H = normalize(L + E);
      
          highp float df = max(0.0, dot(N, L));
          highp float sf = max(0.0, dot(N, H));
          sf = pow(sf, shininess);
      
          mediump vec3 color = vAmbientMaterial + df * vDiffuse + sf * vSpecularMaterial;
          
          gl_FragColor = vec4(color, 1);
      }

      從上面的代碼可以看到,原先在頂點著色器中進行的光照計算被轉移到片元著色器中了。這里沒有什么特別的,光照計算過程還是前面兩篇文章介紹的那些內容,因此在這里就不再累述了。

      為了方便在不同著色腳本之間進行切換,我定義了一個 LightMode 枚舉:

      enum LightMode {
          PerVertex,
          PerPixel,
          PerPixelToon,
      };
      const LightMode CurrentLightMode = PerPixel;

      并在 setProgram 中根據當前的光照計算模式來載入對應的腳本:

      - (void)setupProgram
      {
          // Load shaders
          //
          NSString * vertexShaderPath = nil;
          NSString * fragmentShaderPath = nil;
      
          if (CurrentLightMode == PerVertex) {
              vertexShaderPath = [[NSBundle mainBundle] pathForResource:@"VertexShader"
                                                                 ofType:@"glsl"];
              fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"FragmentShader"
                                                                   ofType:@"glsl"];
          }
          else if (CurrentLightMode == PerPixelToon) {
              vertexShaderPath = [[NSBundle mainBundle] pathForResource:@"PerPixelVertex"
                                                                 ofType:@"glsl"];
              fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"PerPixelToonFragment"
                                                                   ofType:@"glsl"];
          }
          else  {
              // default per-pixel light
              vertexShaderPath = [[NSBundle mainBundle] pathForResource:@"PerPixelVertex"
                                                                 ofType:@"glsl"];
              fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"PerPixelFragment"
                                                                   ofType:@"glsl"];
          }
          
          //......
      }

      編譯運行,效果如下圖。細心的童鞋可以比較 Per-Vertex 與 Per-Pixel 兩種光照的效果。Per-Vertex 光照計算是在頂點著色階段進行,然后在光柵化階段進行線性插值;而 Per-Pixel 光照計算是在片元著色階段針對每一個像素進行,因此后者要比前者更加細致逼真,效果更好一些,當然計算量自然也要大。

       

      三,卡通效果

      前面說過,卡通效果是將散射光因子“分級”從而不再是連續的,打個比方說,考試成績上百分制是連續的,而分級制:好/良好/及格/不及格就不是連續的,這樣就能獲得漫反射跳躍的卡通效果。

      新建 PerPixelToonFragment.glsl 腳本,其內容如下:

      varying mediump vec3 vEyeSpaceNormal;
      varying mediump vec3 vDiffuse;
      
      uniform highp vec3 vLightPosition;
      uniform highp vec3 vAmbientMaterial;
      uniform highp vec3 vSpecularMaterial;
      uniform highp float shininess;
      
      void main()
      {
          highp vec3 N = normalize(vEyeSpaceNormal);
          highp vec3 L = normalize(vLightPosition);
          highp vec3 E = vec3(0, 0, 1);
          highp vec3 H = normalize(L + E);
      
          highp float df = max(0.0, dot(N, L));
          highp float sf = max(0.0, dot(N, H));
          sf = pow(sf, shininess);
          
          if (df < 0.1)
              df = 0.0;
          else if (df < 0.2)
              df = 0.2;
          else if (df < 0.4)
              df = 0.4;
          else if (df < 0.6)
              df = 0.6;
          else if (df < 0.8)
              df = 0.8;
          else
              df = 1.0;
      
          mediump vec3 color = vAmbientMaterial + df * vDiffuse + sf * vSpecularMaterial;
          
          gl_FragColor = vec4(color, 1);
      }

      注意看粗體部分,這就是新增的部分。這部分代碼將漫反射因子調整為五個級別:0.0,0.2,0.6,0.8,1.0,因此漫反射就有層次效果了。如下圖所示:

       

      四,總結

      Per-Vertex 與 Per-Pixel 兩種光照的異同:兩者都是基于相同的光照原理來進行光照計算的,Per-Vertex 光照計算是在頂點著色階段進行,然后在光柵化階段進行線性插值;而 Per-Pixel 光照計算是在片元著色階段針對每一個像素進行。因此后者要比前者效果更好,看上去更加細致逼真,當然計算量自然也要多一些。

      卡通效果是將漫反射因子分級,從而形成不連續的跳躍的漫反射效果。在本文中,是在片元著色階段進行卡通效果處理的,它也可以在頂點著色階段進行。

      在這個系列的介紹中,只提及了一些簡單的光照效果,還有很多更加逼真的光照算法或技巧沒有涉及,比如菲涅爾效果或使用光照貼圖。

      菲涅爾效果:根據觀察者的觀察表面來調整反射率來實現的。比如你從水面,油漆表面或者絲綢的正上方看,反射光澤的柔和效果基本沒有,如果側著或平著看的話,反射光澤的柔和效果就很明顯。

      光照貼圖:使用預先處理好的明暗紋理來模擬光照,這樣可以減少實時的光照計算,但這樣的技巧只適用于靜態場景。

       

      posted @ 2013-01-11 20:52  飄飄白云  閱讀(2579)  評論(6)    收藏  舉報
      本博客遵循 Creative Commons License “署名-非商業用途-保持一致”創作共用協議。 與我聯系
      主站蜘蛛池模板: 亚洲人成网站18禁止无码| 日本一区不卡高清更新二区| 亚洲av色香蕉一区二区| 国产成人8X人网站视频| 婷婷六月色| 九九成人免费视频| 亚洲无人区码一二三区别| 精品无码久久久久成人漫画| 好紧好湿太硬了我太爽了视频| 国产美女直播亚洲一区色| 九九热在线视频免费观看| 亚洲av专区一区| 风韵丰满妇啪啪区老老熟女杏吧 | 国产成人精彩在线视频50| 洛扎县| 99久久精品国产一区二区| 日本午夜精品一区二区三区电影| 永久免费无码av网站在线观看 | 国产AV无码专区亚洲AV漫画| 国产精品丝袜亚洲熟女| 加查县| 久久zyz资源站无码中文动漫| 国产乱码1卡二卡3卡四卡5| 国产69久久精品成人看| 伊人色综合一区二区三区| 五月丁香啪啪| 真人作爱90分钟免费看视频| 自拍视频亚洲精品在线| 动漫av网站免费观看| 国产普通话对白刺激| 深夜免费av在线观看| 亚洲综合一区国产精品| 亚洲另类激情专区小说图片| 亚洲色大成网站www永久一区| 亚洲精品日本一区二区| 布尔津县| 国产AV巨作丝袜秘书| 性无码专区无码| 欧美日韩精品一区二区视频| 久久精品一偷一偷国产| 中文字幕日韩视频欧美一区|