Cesium開發(fā)高級篇 | 05場景后期處理

為實現(xiàn)三維模型的更炫、更酷、更美觀,Cesium在1.46的版本中新增了場景的后期處理(Post Processing)功能,包括模型描邊、黑白圖、明亮度調(diào)整、夜市效果、環(huán)境光遮蔽,也包括雷達掃描、原型擴散等一些特效。今天我們來學習一下場景后期處理的基礎(chǔ)知識和實現(xiàn)流程。

場景后期處理流程

場景的后期處理這個詞比較陌生,但說起照片的PS大家都很熟悉,這兩個過程非常類似。日常生活中我們拍攝完照片之后,發(fā)現(xiàn)太亮或太暗,又或者是皮膚不夠白、臉上痘痘明顯,我們可以調(diào)整亮度、修復一下嫩白的臉蛋,經(jīng)過幾波操作之后,得到了一張我們非常滿意的照片。

image210.png

我們可以把照片的修復過程簡單理解成場景的后期處理過程,修圖的過程就比喻成對三維場景中初始渲染的效果進行再處理,比如添加物體描邊、明暗度調(diào)整、夜市效果等,最終把綜合之后的效果在場景中渲染出來。Cesium中的場景后期處理的大概流程如下圖所示:

image209.png

下面結(jié)合Cesium本身的PostProcess類,詳細的說明一下處理流程:
第一步:通過PostProcessStageLibrary創(chuàng)建一個或者多個后處理效果對象,得到多個PostProcessStage或PostProcessStageComposite;
第二步:將他們加入到PostProcessStageCollection對象中,并設(shè)置PostProcessStage或PostProcessStageComposite一些參數(shù),如uniforms;
第三步:PostProcessStageCollection對象就會按照加入的順序進行屏幕后期處理,在所有的效果都處理完畢后,最后繪制到屏幕上。
當然也可以省略第一步,直接利用PostProcessStageCollection實例化對象中已有的處理效果去實現(xiàn),如ambientOcclusion、bloom、fxaa。

場景后期處理相關(guān)類

上述提到了PostProcess類,基本上涉及到4個類文件,具體每個類的作用又是什么呢?我們來說明一下。
(1)PostProcessStage
對應于某個具體的后期處理效果,它的輸入為場景渲染圖或者上一個后期處理的結(jié)果圖,輸出結(jié)果是一張?zhí)幚砗蟮膱D片。

// Simple stage to change the colorvar 
fs =
    'uniform sampler2D colorTexture;\n' +
    'varying vec2 v_textureCoordinates;\n' +
    'uniform float scale;\n' +
    'uniform vec3 offset;\n' +
    'void main() {\n' +
    '    vec4 color = texture2D(colorTexture, v_textureCoordinates);\n' +
    '    gl_FragColor = vec4(color.rgb * scale + offset, 1.0);\n' +
    '}\n';
scene.postProcessStages.add(new Cesium.PostProcessStage({
    fragmentShader : fs,
    uniforms : {
        scale : 1.1,
        offset : function() {
            return new Cesium.Cartesian3(0.1, 0.2, 0.3);
        }
    }}));

fragmentShader:片源著色器代碼字符串,它是GLSL代碼語言,需要成對配置頂點著色器和片元著色器。
uniforms:片源著色器代碼字符串中需要在前端傳入的變量。
(2)PostProcessStageComposite
一個集合對象,按順序存儲了不同的場景處理對象,存儲類型為PostProcessStage或者PostProcessStageComposite的元素,并存儲在stages屬性中。

// Example 1: separable blur filter
// The input to blurXDirection is the texture rendered to by the scene or the output of the previous stage.
// The input to blurYDirection is the texture rendered to by blurXDirection.
scene.postProcessStages.add(new Cesium.PostProcessStageComposite({
    stages : [blurXDirection, blurYDirection]}));

(3)PostProcessStageLibrary
負責創(chuàng)建具體的后期處理效果,提供了一些創(chuàng)建常用場景特效的方法,包括createBlackAndWhiteStage-黑色和白色漸變渲染、createBlurStage-高斯模、createBrightnessStage-紋理飽和、createDepthOfFieldStage-景深效果等,創(chuàng)建返回的結(jié)果是PostProcessStageComposite或者PostProcessStage類型。相對來說比較簡單,直接調(diào)用即可。

var stages = viewer.scene.postProcessStages;
  var silhouette = stages.add(
    Cesium.PostProcessStageLibrary.createSilhouetteStage()
  );

(4)PostProcessStageCollection
是一個集合類型的類,負責管理和維護放到集合中的PostProcessStage或PostProcessStageComposite類型對象,實例化對象可通過viewer.scene.postProcessStages直接獲取,提供了一些常用的方法,如add、contains、destroy、remove等。
但需要注意的是,該集合中也設(shè)定了三個ambientOcclusion、bloom、fxaa效果,如果此類中的環(huán)境光遮擋-ambientOcclusion或發(fā)光效果-bloom被啟用,它們將在所有其他階段之前執(zhí)行,優(yōu)先級最高;如果近似抗鋸齒-fxaa被啟用,它將在所有其他階段之后執(zhí)行,優(yōu)先級最低。

場景后期處理效果

Cesium為我們提供了一些默認的示例效果,但基本上可分為如下三類:
(1)利用PostProcessStageCollection集合類提供的三個效果
包括ambientOcclusion環(huán)境光遮擋、bloom發(fā)光效果、fxaa近似抗鋸齒,我們挑選前兩個為例進行說明。

  • ambientOcclusion環(huán)境光遮擋
function updatePostProcess() {
  const ambientOcclusion =
    viewer.scene.postProcessStages.ambientOcclusion;
  ambientOcclusion.enabled =
    Boolean(viewModel.show) || Boolean(viewModel.ambientOcclusionOnly);
  ambientOcclusion.uniforms.ambientOcclusionOnly = Boolean(
    viewModel.ambientOcclusionOnly
  );
  ambientOcclusion.uniforms.intensity = Number(viewModel.intensity);
  ambientOcclusion.uniforms.bias = Number(viewModel.bias);
  ambientOcclusion.uniforms.lengthCap = Number(viewModel.lengthCap);
  ambientOcclusion.uniforms.stepSize = Number(viewModel.stepSize);
  ambientOcclusion.uniforms.blurStepSize = Number(
    viewModel.blurStepSize
  );
}

image212.png

沒有開啟AO效果如上圖一,開啟AO效果如上圖二,單純的AO圖如上圖三

  • bloom發(fā)光效果
function updatePostProcess() {
  const bloom = viewer.scene.postProcessStages.bloom;
  bloom.enabled = Boolean(viewModel.show);
  bloom.uniforms.glowOnly = Boolean(viewModel.glowOnly);
  bloom.uniforms.contrast = Number(viewModel.contrast);
  bloom.uniforms.brightness = Number(viewModel.brightness);
  bloom.uniforms.delta = Number(viewModel.delta);
  bloom.uniforms.sigma = Number(viewModel.sigma);
  bloom.uniforms.stepSize = Number(viewModel.stepSize);
}

image214.png

(2)直接調(diào)用PostProcessStageLibrary中提供的方法去渲染場景特效
Cesium在場景處理庫中默認為我們提供了如下8個效果,其實也是非常簡單的,直接調(diào)用即可。

下面是一個切換動畫小人效果的簡單示例:

const stages = viewer.scene.postProcessStages;
const silhouette = stages.add(
  Cesium.PostProcessStageLibrary.createSilhouetteStage()
);
const blackAndWhite = stages.add(
  Cesium.PostProcessStageLibrary.createBlackAndWhiteStage()
);
const brightness = stages.add(
  Cesium.PostProcessStageLibrary.createBrightnessStage()
);
const nightVision = stages.add(
  Cesium.PostProcessStageLibrary.createNightVisionStage()
);

function updatePostProcess() {
  silhouette.enabled = Boolean(viewModel.silhouette);
  silhouette.uniforms.color = Cesium.Color.YELLOW;
  blackAndWhite.enabled = Boolean(viewModel.blackAndWhiteShow);
  blackAndWhite.uniforms.gradations = Number(
    viewModel.blackAndWhiteGradations
  );
  brightness.enabled = Boolean(viewModel.brightnessShow);
  brightness.uniforms.brightness = Number(viewModel.brightnessValue);
  nightVision.enabled = Boolean(viewModel.nightVisionShow);
}

物體描邊.gif

(3)編寫自定義Shader實現(xiàn)場景特效
要想實現(xiàn)自定義Shader,不僅需要開發(fā)者了解頂點著色器和片元著色器,openGL,還需要會編寫GLSL(GL Shading Language)語言,通過自定義Shader可以表達更多的場景特效。關(guān)于GLSL編程語法,這里就不多贅述了,感興趣的可以查看其官網(wǎng)。下面是一個簡單的給動畫小人打馬賽克的示例:

const fragmentShaderSource = `
  uniform sampler2D colorTexture; 
  varying vec2 v_textureCoordinates; 
  const int KERNEL_WIDTH = 16; 
  void main(void) 
  { 
      vec2 step = czm_pixelRatio / czm_viewport.zw; 
      vec2 integralPos = v_textureCoordinates - mod(v_textureCoordinates, 8.0 * step); 
      vec3 averageValue = vec3(0.0); 
      for (int i = 0; i < KERNEL_WIDTH; i++) 
      { 
          for (int j = 0; j < KERNEL_WIDTH; j++) 
          { 
              averageValue += texture2D(colorTexture, integralPos + step * vec2(i, j)).rgb; 
          } 
      } 
      averageValue /= float(KERNEL_WIDTH * KERNEL_WIDTH); 
      gl_FragColor = vec4(averageValue, 1.0); 
  }
  `;
viewer.scene.postProcessStages.add(
  new Cesium.PostProcessStage({
    fragmentShader: fragmentShaderSource,
  })

圖片1.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容