用osgEarth实现Cesium的后处理特效(1)

写这个博客的初衷:开源的数字地球发展,从最开始的worldWind(纯正的NASA血统,大约从2006年开始流行,当我还是学生的时候用这个框架实现了中石油的林火蔓延模拟系统,以及在这个球上实现救援应急响应的模拟,当时拿了集团的一个奖项,所以我个人对这个版本情有独钟,从软件架构上将,NASA的工作确实非常了不起,整个软件的框架层次分明,而又十分简洁,目前的cesium版本里面能还能找到worldwind的影子,可惜的是JAVA语言开发的这个版本没有得到维护,全网也找不到几个用wwd来开发应用的人,原因可能是JAVA在桌面端的萎缩,JAVA实现OpenGL的特效这方面有限制,当WebGL刚推出的时候,我给NASA开发小组的大佬写了个邮件,咨询是否有计划开发下一代的WebGL版本,得到了大牛的回复,大意是WEB端也需要下载js文件,一样的耗费时间,后来NASA推出了ActiveX 版本的WWJ, 只不过响应者寥寥),到第二代数字地球(OSGEarth大约从2010年以后流行开来,这个版本基于OSG开发的,总体感觉是,软件的架构太复杂。因为OSG本身是通用的三维引擎软件,并非为数字地球量身定制,这个引擎本身就存在过度设计、过度包装的问题,随便在代码里下一个断点,函数调用栈几十层,看得人眼花缭乱,感觉这个软件的作者在抖小聪明,虽然这样评价要得罪部分OSG粉丝)。目前的CESIUM软件大行其道,如日中天,从项目案例上看,NASA已经完全放弃自家的WWJ, 也转移到CESIUM平台做开发。CESIUM社区的繁荣和OSGEARTH社区的没落形成了鲜明的对比,作为一位怀旧的技术人员,我花了点时间将CESIUM后处理特效的炫目效果移植到OSGEARTH,做一个尝试。于是有了这几篇博文。

PostProcessStage的效果:

标题雷达扫描,圆形扩散

 

场景泛光

 

cesium 中shader的管理机制:

定义一个shaderSouce, option参数里面重要的两个参数 defines 和 sources.   defines 定义的shader里面的宏,我猜应该是对shader里面的'#define'  做了一种替换。而sources应该是各种vs fs 的代码段。

function ShaderSource(options) {
  options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  var pickColorQualifier = options.pickColorQualifier;

  //>>includeStart('debug', pragmas.debug);
  if (
    defined(pickColorQualifier) &&
    pickColorQualifier !== "uniform" &&
    pickColorQualifier !== "varying"
  ) {
    throw new DeveloperError(
      "options.pickColorQualifier must be 'uniform' or 'varying'."
    );
  }
  //>>includeEnd('debug');

  this.defines = defined(options.defines) ? options.defines.slice(0) : [];
  this.sources = defined(options.sources) ? options.sources.slice(0) : [];
  this.pickColorQualifier = pickColorQualifier;
  this.includeBuiltIns = defaultValue(options.includeBuiltIns, true);
}

通过上面的代码,定义了两个shaderSource,  只是它们还没有被编译和链接,接着看下面的代码段,

    var vs = new ShaderSource({
      defines: defines.concat("SKY_FROM_SPACE"),
      sources: [SkyAtmosphereCommon, SkyAtmosphereVS],
    });

    var fs = new ShaderSource({
      defines: defines.concat("SKY_FROM_SPACE"),
      sources: [SkyAtmosphereCommon, SkyAtmosphereFS],
    });

定义出两个具体的shader。

this._spSkyFromSpace = ShaderProgram.fromCache({
      context: context,
      vertexShaderSource: vs,
      fragmentShaderSource: fs,
    });

这里才是正在创建经过编译和链接的shader.  vs 和 fs 总是成双出现。从名字,不难猜出Cesium 对各种shader做了缓存。继续深入到ShaderProgram.fromCache的底层代码

ShaderCache.prototype.getShaderProgram = function (options) {
  // convert shaders which are provided as strings into ShaderSource objects
  // because ShaderSource handles all the automatic including of built-in functions, etc.

  var vertexShaderSource = options.vertexShaderSource;
  var fragmentShaderSource = options.fragmentShaderSource;
  var attributeLocations = options.attributeLocations;

  if (typeof vertexShaderSource === "string") {
    vertexShaderSource = new ShaderSource({
      sources: [vertexShaderSource],
    });
  }

  if (typeof fragmentShaderSource === "string") {
    fragmentShaderSource = new ShaderSource({
      sources: [fragmentShaderSource],
    });
  }

  var vertexShaderText = vertexShaderSource.createCombinedVertexShader(
    this._context
  );
  var fragmentShaderText = fragmentShaderSource.createCombinedFragmentShader(
    this._context
  );

  var keyword =
    vertexShaderText + fragmentShaderText + JSON.stringify(attributeLocations);
  var cachedShader;

  if (defined(this._shaders[keyword])) {
    cachedShader = this._shaders[keyword];

    // No longer want to release this if it was previously released.
    delete this._shadersToRelease[keyword];
  } else {
    var context = this._context;
    var shaderProgram = new ShaderProgram({
      gl: context._gl,
      logShaderCompilation: context.logShaderCompilation,
      debugShaders: context.debugShaders,
      vertexShaderSource: vertexShaderSource,
      vertexShaderText: vertexShaderText,
      fragmentShaderSource: fragmentShaderSource,
      fragmentShaderText: fragmentShaderText,
      attributeLocations: attributeLocations,
    });

    cachedShader = {
      cache: this,
      shaderProgram: shaderProgram,
      keyword: keyword,
      derivedKeywords: [],
      count: 0,
    };

    // A shader can't be in more than one cache.
    shaderProgram._cachedShader = cachedShader;
    this._shaders[keyword] = cachedShader;
    ++this._numberOfShaders;
  }

  ++cachedShader.count;
  return cachedShader.shaderProgram;
};

以上代码,从各种 shaderSource的合并,计算出一个keyWord(为啥不搞个hash?), 然后根据keyword 在缓存里面查找是不是已经有这样的shader,如果有的话就直接用这个已有的shader返回。否则创建一个新的ShaderProgram, 并且放入缓存,以备下次查找。

Cesium中的shader:

基本顶点shader

  globe._surfaceShaderSet.baseVertexShaderSource = new ShaderSource({
    sources: [GroundAtmosphere, GlobeVS],
    defines: defines,
  });

  globe._surfaceShaderSet.baseFragmentShaderSource = new ShaderSource({
    sources: fragmentSources,
    defines: defines,
  });

关于大气的shader

    var vs = new ShaderSource({
      defines: defines.concat("SKY_FROM_SPACE"),
      sources: [SkyAtmosphereCommon, SkyAtmosphereVS],
    });

    var fs = new ShaderSource({
      defines: defines.concat("SKY_FROM_SPACE"),
      sources: [SkyAtmosphereCommon, SkyAtmosphereFS],
    });

天空盒的shader

    var fs = new ShaderSource({
      defines: [useHdr ? "HDR" : ""],
      sources: [SkyBoxFS],
    });
    command.shaderProgram = ShaderProgram.fromCache({
      context: context,
      vertexShaderSource: SkyBoxVS,
      fragmentShaderSource: fs,
      attributeLocations: this._attributeLocations,
    });

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值