Cesium关于实例的创建都是封装在类的静态函数中,这个习惯很好,方便创建和管理,对外只提供创建的方法,正如Material中的Material.fromType()函数一样,传递参数创建材质。

Material材质的中的几个概念是了解材质的关键,例如下面这段代码

var material = new Cesium.Material({fabric: {materials: {diffuseMaterial: {type: "DiffuseMap",uniforms: {image: "../images/bumpmap.png",},},bumpMaterial: {type: "BumpMap",uniforms: {image: "../images/bumpmap.png",strength: 0.8,},},},components: {diffuse: "diffuseMaterial.diffuse",specular: 0.01,normal: "bumpMaterial.normal",},},translucent: false});
new Cesium.Material({fabric: {                   //  材质模板                    type: "ElevationColorContour",materials: {                // 材质contourMaterial: {type: "ElevationContour",},elevationRampMaterial: {type: "ElevationRamp",},},components: {           // 组合diffuse:"contourMaterial.alpha == 0.0 ? elevationRampMaterial.diffuse : contourMaterial.diffuse",alpha:"max(contourMaterial.alpha, elevationRampMaterial.alpha)",},},translucent: false,     // 透明});

1、fabric:的内容是材质的模板json;

2、type:是材质的类型,主要用于在缓冲中查找之前创建的材质模板,模板中存储了渲染所需要的所有东西;

3、materials:这是子材质列表,渲染时会将子材质渲染后的结果作为当前材质的输入,且在当前材质的components属性中有相关的引用,例如contourMaterial.alpha中的contourMaterial即为子材质输出纹理,关于contourMaterial.alpha这条语句在Material类中还会做处理,最终会替换为czm_getMaterial_1(materialInput).alpha这条语句,而czm_getMaterial_1对应的时第1个子材质贡献的数据函数,czm_getMaterial_x代表第x个材质的贡献图像的函数;

4、components:这个对象中包含的内容与materials是对应的,例如components中的alpha成员与alphaMaterial子材质名称是对应关系,因为这两个单词都存在alpha关系,components["alpha"]的值就是用相对应的alphaMaterial子材质的结果拼成的字符串,而且"contourMaterial.alpha == 0.0 ? elevationRampMaterial.diffuse : contourMaterial.diffuse"这条语句会拼接到材质的glsl中进行编译;

5、translucent:透明,材质内部对其使用参考了三方面的值,json传入的translucent、fabric对应缓存中的translucent、各个子材质中中的translucent,三个方面只要有一方面为透明,就是最终的透明;

6、uniforms:Material会根据unfiorm中变量的成员名称,动态拼接glsl代码,例如uniforms["image"]中的image名称会在glsl中动态拼接,而且Material类会根据uniforms["image"]中的值判断是什么类型的,例如uniforms["image"]="../images/bumpmap.png"是2D图片类型,则在glsl中对应sampler2D,最终拼接的glsl代码是 uniform sampler2D image;

关键信息说完,下面分析以下源码:

// 模板包含以下属性
var templateProperties = ["type","materials","uniforms","components","source",
];// 组件包含以下属性
var componentProperties = ["diffuse","specular","shininess","normal","emission","alpha",
];function checkForTemplateErrors(material) {// 获取材质模板var template = material._template;// uniform、material、componentvar uniforms = template.uniforms;var materials = template.materials;var components = template.components;// Make sure source and components do not exist in the same template.//>>includeStart('debug', pragmas.debug);if (defined(components) && defined(template.source)) {throw new DeveloperError("fabric: cannot have source and components in the same template.");}//>>includeEnd('debug');// Make sure all template and components properties are valid.// 确保所有的模板和组件是有效的// 材质模板要符合模板的属性checkForValidProperties(template, templateProperties, invalidNameError, true);// 在规定的组件中查找自定义的组件是否符合规定的组件,找不到就会checkForValidProperties(components,componentProperties,invalidNameError,true);// Make sure uniforms and materials do not share any of the same names.// 或者材质数组var materialNames = [];for (var property in materials) {if (materials.hasOwnProperty(property)) {materialNames.push(property);}}// 材质数组中的材质名称包含 和 uniform成员的名字例如(alphaMaterial 和 components: {alpha: "alphaMaterial.alpha" })// 找到就会报错(因为子材质alphaMaterial的输出不能通过自定义的uniform设置给glsl)checkForValidProperties(uniforms, materialNames, duplicateNameError, false);
}

上面是关于fabric规格的检查,只有符合下面的规格,才是合法的。

// 模板包含以下属性
var templateProperties = ["type","materials","uniforms","components","source",
];// 组件包含以下属性
var componentProperties = ["diffuse","specular","shininess","normal","emission","alpha",
];

下面的代码,是用于拼接czm_getMaterial函数使用的,从中可以看出glsl代码是可以自定义的,其中针对多材质,添加了czm_gammaCorrect,可见如果是自己传入的纹理最后需要进行gamma矫正为线性纹理,而多材质已经假定子材质传出的就是线性纹理,没有必要在进行伽马矫正了。

// 创建czm_getMaterial方法体使用源码或者组件
function createMethodDefinition(material) {// 材质模板中的组件var components = material._template.components;// 获取模板的源码var source = material._template.source;// if (defined(source)) {// 用于自定义shader的顶点、像素着色器material.shaderSource += source + "\n";} else {// 给材质创建源码(获取材质)material.shaderSource +="czm_material czm_getMaterial(czm_materialInput materialInput)\n{\n";material.shaderSource +="czm_material material = czm_getDefaultMaterial(materialInput);\n";if (defined(components)) {// 多材质var isMultiMaterial =Object.keys(material._template.materials).length > 0;for (var component in components) {// 如果是自身的成员if (components.hasOwnProperty(component)) {if (component === "diffuse" || component === "emission") {  // 组件是漫反射或者自发光// 是否为融合(融合需要子材质,将子材质中的输出作为当前材质的输入)var isFusion =isMultiMaterial &&                                  // 有多个材质isMaterialFused(components[component], material);   // 为多个材质指定不同的组件// gamma矫正var componentSource = isFusion? components[component]                               //上一个材质传出的材质颜色已经经过了gamma矫正了: "czm_gammaCorrect(" + components[component] + ")";  //没有使用别的材质作为输入时,需要自己处理gamma矫正// 拼接漫反射或者自发光源码 material.diffuse = czm_gammaCorrect(custom.diffuse);material.shaderSource +="material." + component + " = " + componentSource + "; \n";} else if (component === "alpha") {                   // 组件是alpha通道//设置alpha参数 material.alpha = 1.0material.shaderSource +="material.alpha = " + components.alpha + "; \n";} else {// 设置组件  material.speculer = custom.speculermaterial.shaderSource +="material." + component + " = " + components[component] + ";\n";}}}}// 拼上返回值material.shaderSource += "return material;\n}\n";}
}

下面这段代码指定了glsl中uniform字符串的拼接,以及cpu中uniform的对应内存数据处理,其中针对纹理会另外传入纹理大小sample1Dimensions字段。

function createUniform(material, uniformId) {var strict = material._strict;// 拿到传入的uniform变量var materialUniforms = material._template.uniforms;var uniformValue = materialUniforms[uniformId];// 获取uniform类型,对应cpu的类型找到gpu的类型var uniformType = getUniformType(uniformValue);//>>includeStart('debug', pragmas.debug);if (!defined(uniformType)) {throw new DeveloperError("fabric: uniform '" + uniformId + "' has invalid type.");}//>>includeEnd('debug');var replacedTokenCount;if (uniformType === "channels") {// 如果是channels变量使用uniform的值替换glsl中的变量,返回替换的个数   例如:uniforms: {color: "rgba"}, 替换源码"uniform vec4 color" 为 "uniform vec4 rgba"replacedTokenCount = replaceToken(material, uniformId, uniformValue, false);//>>includeStart('debug', pragmas.debug);// 如果replacedTokenCount代表模板中设置了无用的uniformif (replacedTokenCount === 0 && strict) {throw new DeveloperError("strict: shader source does not use channels '" + uniformId + "'.");}//>>includeEnd('debug');} else {// Since webgl doesn't allow texture dimension queries in glsl, create a uniform to do it.// Check if the shader source actually uses texture dimensions before creating the uniform.// 由于webgl不允许在glsl中进行纹理维度查询,请创建一个统一的查询。在创建统一之前,检查着色器源是否实际使用纹理尺寸。if (uniformType === "sampler2D") {// 如果传入纹理,就必须传入纹理尺寸,添加纹理尺寸var imageDimensionsUniformName = uniformId + "Dimensions";// 如果glsl代码中存在纹理尺寸if (getNumberOfTokens(material, imageDimensionsUniformName) > 0) {// 在unfirom中添加ivec3的数据,绘制时传入数据使用materialUniforms[imageDimensionsUniformName] = {type: "ivec3",x: 1,y: 1,};// 创建unformcreateUniform(material, imageDimensionsUniformName);}}// Add uniform declaration to source code.// 在glsl中添加uniform的声明var uniformDeclarationRegex = new RegExp(// uniform vec4 color"uniform\\s+" + uniformType + "\\s+" + uniformId + "\\s*;");// unfiorm vec4 colorif (!uniformDeclarationRegex.test(material.shaderSource)) {// 如果没有找到上面的代码段,就在代码的前面加上var uniformDeclaration = "uniform " + uniformType + " " + uniformId + ";";material.shaderSource = uniformDeclaration + material.shaderSource;}// 例如:diffuse_1var newUniformId = uniformId + "_" + material._count++;// 将代码中的 uniform diffuse_1 替换为 uniform diffuse_11   ????replacedTokenCount = replaceToken(material, uniformId, newUniformId);//>>includeStart('debug', pragmas.debug);if (replacedTokenCount === 1 && strict) {throw new DeveloperError("strict: shader source does not use uniform '" + uniformId + "'.");}//>>includeEnd('debug');// Set uniform value// 设置变量值最后确定的uniform值,将这个值放在material.uniforms中而不是material._uniforms中material.uniforms[uniformId] = uniformValue;if (uniformType === "sampler2D") {// 设置2维图片material._uniforms[newUniformId] = function () {return material._textures[uniformId];};material._updateFunctions.push(createTexture2DUpdateFunction(uniformId));} else if (uniformType === "samplerCube") {// 设置cube图片material._uniforms[newUniformId] = function () {return material._textures[uniformId];};material._updateFunctions.push(createCubeMapUpdateFunction(uniformId));} else if (uniformType.indexOf("mat") !== -1) {// var scratchMatrix = new matrixMap[uniformType]();// 设置矩阵material._uniforms[newUniformId] = function () {return matrixMap[uniformType].fromColumnMajorArray(material.uniforms[uniformId],           // 在material.uniforms中取值scratchMatrix);};} else {// 设置其他值material._uniforms[newUniformId] = function () {return material.uniforms[uniformId];    // 在material.uniforms中取值};}}
}

下面是创建子材质的相关代码,子材质中的czm_getMaterial函数会根据会根据在当前材质中的排序自动改变名称为czm_getMaterial_x,并且与当前材质中相应的czm_getMaterial_x函数对应。

// 创建子材质
function createSubMaterials(material) {// 严格模式var strict = material._strict;// 子材质var subMaterialTemplates = material._template.materials;// 遍历子材质名称for (var subMaterialId in subMaterialTemplates) {if (subMaterialTemplates.hasOwnProperty(subMaterialId)) {// Construct the sub-material.// 构造子材质var subMaterial = new Material({strict: strict,fabric: subMaterialTemplates[subMaterialId],count: material._count,});// 子材质数量??material._count = subMaterial._count;// 合并所有的材质中的unfiormmaterial._uniforms = combine(material._uniforms,subMaterial._uniforms,true);// 子材质material.materials[subMaterialId] = subMaterial;// 透明度数组合并material._translucentFunctions = material._translucentFunctions.concat(subMaterial._translucentFunctions);// Make the material's czm_getMaterial unique by appending the sub-material type.// 针对子材质中的 czm_getMaterial创建新的方法: czm_getMaterial_0替换原来的方法var originalMethodName = "czm_getMaterial";var newMethodName = originalMethodName + "_" + material._count++;// 使用新的方法名,替换原来的所有方法名replaceToken(subMaterial, originalMethodName, newMethodName);// 子材质中的源码 与 材质源码 合并material.shaderSource = subMaterial.shaderSource + material.shaderSource;// Replace each material id with an czm_getMaterial method call.// 使用czm_getMaterial方法替换每一个材质var materialMethodCall = newMethodName + "(materialInput)";   // 将材质源码中的elevationRampMaterial.alpha子材质材质名称 使用 czm_getMaterial_1(materialInput).alpha 替换// 将材质中与子材质相关的名称,替换成方法,方法中就可以从子材质的输出图像中获取纹理了??var tokensReplacedCount = replaceToken(material,subMaterialId,materialMethodCall);//>>includeStart('debug', pragmas.debug);if (tokensReplacedCount === 0 && strict) {throw new DeveloperError("strict: shader source does not use material '" + subMaterialId + "'.");}//>>includeEnd('debug');}}
}

而材质的具体

Cesium 源码分析 Material相关推荐

  1. Cesium源码剖析---Clipping Plane

    之前就一直有写博客的想法,别人也建议写一写,但一直没有动手写,自己想了一下原因,就一个字:懒.懒.懒.为了改掉这个毛病,决定从今天开始写博客了,一方面对自己掌握的知识做一个梳理,另一方面和大家做一个交 ...

  2. Cesium源码解读系列(一):GeoJsonDataSource如何处理geojson格式的数据

    想写这个系列的文章起因,是因为项目上的"图层管理"模块功能进行了更改.里面涉及到了一种GeoJson格式的图层数据. 从接口获取到的数据,当时设计接口的时候就已经定好了数据格式.标 ...

  3. Android 11.0 Settings源码分析 - 主界面加载

    Android 11.0 Settings源码分析 - 主界面加载 本篇主要记录AndroidR Settings源码主界面加载流程,方便后续工作调试其流程. Settings代码路径: packag ...

  4. photoshop-v.1.0.1源码分析第三篇–FilterInterface.p

    photoshop-v.1.0.1源码分析第三篇–FilterInterface.p 总体预览 一.源码预览 二.语法解释 三.结构预览 四:语句分析 五:思维导图 六:疑留问题 一.源码预览 {Ph ...

  5. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

  6. SpringBoot-web开发(四): SpringMVC的拓展、接管(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) SpringBoot-web开发(二): 页面和图标定制(源码分析) SpringBo ...

  7. SpringBoot-web开发(二): 页面和图标定制(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) 目录 一.首页 1. 源码分析 2. 访问首页测试 二.动态页面 1. 动态资源目录t ...

  8. SpringBoot-web开发(一): 静态资源的导入(源码分析)

    目录 方式一:通过WebJars 1. 什么是webjars? 2. webjars的使用 3. webjars结构 4. 解析源码 5. 测试访问 方式二:放入静态资源目录 1. 源码分析 2. 测 ...

  9. Yolov3Yolov4网络结构与源码分析

    Yolov3&Yolov4网络结构与源码分析 从2018年Yolov3年提出的两年后,在原作者声名放弃更新Yolo算法后,俄罗斯的Alexey大神扛起了Yolov4的大旗. 文章目录 论文汇总 ...

最新文章

  1. 谷歌程序员少输一个“”,差点让全球Chrome笔记本变砖
  2. html给radio添加图片,使用纯CSS自定义radio(单选框)和checkbox(多选框)的样式
  3. 怎么在vue的@click里面直接写js_【转】为 Node.js 贡献你的力量 ———— 调试代码
  4. 技术人生——解决问题的规律
  5. how SAP OData supported option in odata eq ne lt gt?
  6. swift3.0 post Json解析
  7. mysql 数据库 额外_Manager额外参数怎么学?mysql数据库学习
  8. Linux中rename和mv命令用法学习修改文件名区别和总结
  9. DEVICE_ATTR设置0777引发血案
  10. safari使用canvas引入域外的图片
  11. python web框架 - Django
  12. BZOJ3994[SDOI2015] 约数个数和
  13. c语言根据日期求星期蔡勒公式,利用蔡勒公式获得给定日期的星期数
  14. 安卓如何隐藏root
  15. Python实现四子棋(四连环)游戏
  16. GridView自带分页 1/总页数 首页 下一页 上一页 尾页 X 页 go 实现方法
  17. 学生信息管理系统-数据结构课程设计
  18. 上云安全建设之CDN安全防护
  19. 第32节:Java中-构造函数,静态方法,继承,封装,多态,包
  20. 怎样管理可以明确职责分工

热门文章

  1. 林伟 刘念《曾经爱过我》
  2. java计算机毕业设计高校体育器材及场地管理MyBatis+系统+LW文档+源码+调试部署
  3. mysqlcount效率,总结到位
  4. POE交换机全方位解读(上)
  5. 请描述定时器初值的计算方式_51波特率发生器定时器初值计算方法[转载]
  6. 如何确定自己浏览器的User-Agent信息
  7. 广告归因:是什么和为什么
  8. WICC 广州高峰对话:为开发者标注「航海地图」
  9. 边缘计算:新瓶装旧酒?
  10. TPESD0502S4SOT-143工作电压5V用于高速线路保护的2线ESD保护二极管阵列管TPESD0502S4 USB端口和以太网端口保护TVS二极管阵列,低泄漏电流和箝位电压25V结电容1PF