Cesium開(kāi)發(fā)高級(jí)篇 | 05場(chǎng)景后期處理

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

場(chǎng)景后期處理流程

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

image210.png

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

image209.png

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

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

上述提到了PostProcess類,基本上涉及到4個(gè)類文件,具體每個(gè)類的作用又是什么呢?我們來(lái)說(shuō)明一下。
(1)PostProcessStage
對(duì)應(yīng)于某個(gè)具體的后期處理效果,它的輸入為場(chǎng)景渲染圖或者上一個(gè)后期處理的結(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代碼語(yǔ)言,需要成對(duì)配置頂點(diǎn)著色器和片元著色器。
uniforms:片源著色器代碼字符串中需要在前端傳入的變量。
(2)PostProcessStageComposite
一個(gè)集合對(duì)象,按順序存儲(chǔ)了不同的場(chǎng)景處理對(duì)象,存儲(chǔ)類型為PostProcessStage或者PostProcessStageComposite的元素,并存儲(chǔ)在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
負(fù)責(zé)創(chuàng)建具體的后期處理效果,提供了一些創(chuàng)建常用場(chǎng)景特效的方法,包括createBlackAndWhiteStage-黑色和白色漸變渲染、createBlurStage-高斯模、createBrightnessStage-紋理飽和、createDepthOfFieldStage-景深效果等,創(chuàng)建返回的結(jié)果是PostProcessStageComposite或者PostProcessStage類型。相對(duì)來(lái)說(shuō)比較簡(jiǎn)單,直接調(diào)用即可。

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

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

場(chǎng)景后期處理效果

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

  • 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

沒(méi)有開(kāi)啟AO效果如上圖一,開(kāi)啟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中提供的方法去渲染場(chǎng)景特效
Cesium在場(chǎng)景處理庫(kù)中默認(rèn)為我們提供了如下8個(gè)效果,其實(shí)也是非常簡(jiǎn)單的,直接調(diào)用即可。

下面是一個(gè)切換動(dòng)畫(huà)小人效果的簡(jiǎn)單示例:

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)編寫(xiě)自定義Shader實(shí)現(xiàn)場(chǎng)景特效
要想實(shí)現(xiàn)自定義Shader,不僅需要開(kāi)發(fā)者了解頂點(diǎn)著色器和片元著色器,openGL,還需要會(huì)編寫(xiě)GLSL(GL Shading Language)語(yǔ)言,通過(guò)自定義Shader可以表達(dá)更多的場(chǎng)景特效。關(guān)于GLSL編程語(yǔ)法,這里就不多贅述了,感興趣的可以查看其官網(wǎng)。下面是一個(gè)簡(jiǎn)單的給動(dòng)畫(huà)小人打馬賽克的示例:

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)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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