Cesium principle chapter: Material [turn]

https://www.cnblogs.com/fuckgiser/p/6171245.html

Shader

First, before the beginning of this article, we first look at the popularity of the concept of the material, is recommended materials , the popularity of the content is intercepted material from the site, I think he's good enough to write. Before starting the popularity of the concept, I recommended a moment think of a song "Light --- Chen grain."

       In the real world, every object will have the light generated different reactions. Steel look more shiny than the ceramic vase, a wooden box as a box of steel is not as strong reflections of light. Each object of the specular highlights also react differently. Some objects do not scatter (The Scatter) has many light will be reflected (the Reflect) lot of light, the result looks like there is a smaller highlight dots (the Highlight), some many scattering objects, which will produce a larger radius highlights . If we want to simulate a variety of types of objects in OpenGL, we must define the material (Material) properties for each object.

       We specify a color of a light object and to define the object image output, and the binding environment (the Ambient) and specular intensity (Specular Intensity) element. When describing the object, we can use three kinds of light elements: ambient light (Ambient Lighting), diffuse lighting (Diffuse Lighting), the specular light (Specular Lighting) defines a color material. By specifying a color for each element, we have the output of the color of an object with precise control. Now add a specular highlights elements of these three colors, this is all we need material properties:

Copy the code
struct Material
{
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float shininess;
};
Copy the code

       The above is a brief summary of the most material, we enter the following aspects of Cesium. Let's look at the definition of Material Cesium in the Shader:

Copy the code
struct czm_material
{
    vec3 diffuse;
    float specular;
    float shininess;
    vec3 normal;
    vec3 emission;
    float alpha;
};
Copy the code

       And a structure substantially the same as given above, except that the ambient light Ambient less, but more than a normal vector normal, self-luminous emission and alpha, with this question we look Cesium fragment shader processing materials:

Copy the code
varying vec3 v_positionEC;
varying vec3 v_normalEC;
void main()
{
    vec3 positionToEyeEC = -v_positionEC;
    vec3 normalEC = normalize(v_normalEC);
#ifdef FACE_FORWARD
    normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);
#endif
    czm_materialInput materialInput;
    materialInput.normalEC = normalEC;
    materialInput.positionToEyeEC = positionToEyeEC;
    czm_material material = czm_getDefaultMaterial(materialInput);
    gl_FragColor = czm_phong(normalize(positionToEyeEC), material);
}
Copy the code

       At this time, the camera coordinate system is the central point, and the position acquired first normal vector of the current point, a default texture object acquired through czm_getMaterial, gl_FragColor czm_phong obtained by a method corresponding to the color. For Phong, the OpenGL SuperBible which is described in detail, probably by the material properties of the color light and the position of the light, corresponding to the finally calculated at the current point of impact of the environment and the color of the material itself. Let's look at the implementation of czm_phong:

Copy the code
vec4 czm_phong(vec3 toEye, czm_material material)
{
    
    float diffuse = czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 0.0, 1.0), material);
    if (czm_sceneMode == czm_sceneMode3D) {
        diffuse += czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 1.0, 0.0), material);
    }

    float specular = czm_private_getSpecularOfMaterial(czm_sunDirectionEC, toEye, material) + czm_private_getSpecularOfMaterial(czm_moonDirectionEC, toEye, material);

    vec3 materialDiffuse = material.diffuse * 0.5;
    
    vec3 ambient = materialDiffuse;
    vec3 color = ambient + material.emission;
    color += materialDiffuse * diffuse;
    color += material.specular * specular;

    return vec4(color, material.alpha);
}
Copy the code

       As phong color calculation algorithm is, I do not give getLambertDiffuse getSpecular and the specific code, the basic physical laws are light. Here it is that getLambertDiffuse parameter, if it is a spherical object, the calls czm_private_phong, this time parameter is czm_sunDirectionEC, is the position of the sun, and here think the position of the light source is a point close to the camera, in addition, ambient light ambient the default is half of the reflected light, this is also said in the past, we have seen the last bit alpha final color is material.alpha.

       Shader above are involved in the process one of the most simple materials: the ultimate impact of the material is color gl_FragColor fragment shader, and all are beginning czm_ Cesium built-in methods and objects, Cesium has helped us provide better optics model and calculation methods, we do not need to worry about, and we have to do is to specify the object corresponding to the material properties, by modifying the attribute values ​​of the material to influence the final result. So, the next question is how to specify the material properties of the object.

       There are many styles of materials, shapes are not the same, different surface line, for which, Cesium provide Material objects, to help us set the material.

Fabric

       Let's look at what Cesium provides built-in material type, and how to create the corresponding Material, I also refer to the Fabric of Cesium on github wike description , more details can see for yourself. In the Cesium, Fabric json a format described material. Material can be very simple, it is a texture of the object surface may be a pattern, such as a checkerboard or stripe.

1

       For example ImageType type, Cesium provides two ways to set the following:

Copy the code
// 方法一
primitive.appearance.material = new Cesium.Material({
    fabric : {
        type : 'Image',
        uniforms : {
            image : '../images/Cesium_Logo_Color.jpg'
        }
    }
});
// 方法二
primitive.appearance..material = Material.fromType('Image');
primitive.appearance..uniforms.image = 'image.png';
Copy the code

       Cesium provided by default eighteen Type:

  • ColorType
  • ImageType
  • DiffuseMapType
  • AlphaMapType
  • SpecularMapType
  • EmissionMapType
  • BumpMapType
  • NormalMapType
  • GridType
  • StripeType
  • CheckerboardType
  • DotType
  • WaterType
  • RimLightingType
  • fade type
  • PolylineArrowType
  • PolylineGlowType
  • PolylineOutlineType

       Of course, a plurality of Type Cesium supports a synergistic effect, as a superposition of DiffuseMap and NormalMap, diffuse components specified in the Material's, specular, normal value and the mapping relationship:

Copy the code
primitive.appearance.material = new Cesium.Material({
    fabric : {
        materials : {
            applyDiffuseMaterial : {
                type : 'DiffuseMap',
                uniforms : {
                    image : '../images/bumpmap.png'
                }
            },
            normalMap : {
                type : 'NormalMap',
                uniforms : {
                    image : '../images/normalmap.png',
                    strength : 0.6
                }
            }
        },
        components : {
            diffuse : 'diffuseMaterial.diffuse',
            specular : 0.01,
            normal : 'normalMap.normal'
        }
    }
});
Copy the code

       Of course, these are not satisfy your desire? You can also customize an own MaterialType, we first understand the internal Cesium.Material implementation, look at the Custom Material.

Material

       Users usually only need to specify the type, uniforms, components three attributes, building a Fabric of JSON. This is because during initialization Material, loads above default eighteen types, such as the code corresponding ColorType:

Copy the code
Material.ColorType = 'Color';
Material._materialCache.addMaterial(Material.ColorType, {
    fabric : {
        type : Material.ColorType,
        uniforms : {
            color : new Color(1.0, 0.0, 0.0, 0.5)
        },
        components : {
            diffuse : 'color.rgb',
            alpha : 'color.a'
        }
    },
    translucent : function(material) {
        return material.uniforms.color.alpha < 1.0;
    }
});
// 创建material
polygon.material = Cesium.Material.fromType('Color');
polygon.material.uniforms.color = new Cesium.Color(1.0, 1.0, 0.0, 1.0);
Copy the code

       Other types are also about the same, have all been constructed during initialization. Therefore, users create, have a ColorMaterial, just some of the attributes which modify their expectations for the process. Specifically, we Material.fromType specific content:

Copy the code
Material.fromType = function(type, uniforms) {
    var material = new Material({
        fabric : {
            type : type
        }
    });

    return material;
};

function Material(options) {
    initializeMaterial(options, this);
    
    if (!defined(Material._uniformList[this.type])) {
        Material._uniformList[this.type] = Object.keys(this._uniforms);
    }
}

function initializeMaterial(options, result) {
    var cachedMaterial = Material._materialCache.getMaterial(result.type);
    
    createMethodDefinition(result);
    createUniforms(result);
    
    // translucent
}
Copy the code

        initializeMaterial is one of the key, there are three key points: 1createMethodDefinition, 2createUniforms, 3translucent, we look at what has been done

Copy the code
function createMethodDefinition(material) {
    // 获取components属性
    // ColorType:{ diffuse : 'color.rgb', alpha : 'color.a'}
    var components = material._template.components;
    var source = material._template.source;
    if (defined(source)) {
        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)) {
            for ( var component in components) {
                if (components.hasOwnProperty(component)) {
                    // The components attributes, modifying attributes corresponding Material Obtaining 
                    material.shaderSource + = 'Material's.' + + Component '=' + components [Component] + '; \ n-'; 
                } 
            } 
        } 
        // get the package fragment shader material acquires a function 
        material.shaderSource + = 'return material; \ n-} \ n-'; 
    } 
}
Copy the code

       As the role of Key1, assembled fragment shader function to get the material, if Type Color is, the function code is obtained as follows:

Copy the code
czm_material czm_getMaterial(czm_materialInput materialInput)
{
    czm_material material = czm_getDefaultMaterial(materialInput);
    material.diffuse = color.rgb;
    material.alpha = color.a;
    return material;
}
Copy the code

       ColorType can control the properties of FabricComponents condemnation. Here is a resolution process for uniforms of the property Fabric: createUniforms. Here there are two effects, first, according Uniforms, uniform variables declared in the sheet corresponding to the source shader, such ColorType in uniform color corresponding to the variable, the variable declaration is required, of course, cesium made a special treatment to them a label, guaranteed to be unique: the updated code as follows:

Copy the code
uniform vec4 color_0;
czm_material czm_getMaterial(czm_materialInput materialInput)
{
    czm_material material = czm_getDefaultMaterial(materialInput);
    material.diffuse = color_0.rgb;
    material.alpha = color_0.a;
    return material;
}
Copy the code

      The second purpose is to prepare for the following uniformMap, declare variables, of course, need to be ready for that variable assignment, have built up this key-value process, save it to material._uniforms array:

Copy the code
function createUniform(material, uniformId) {
    // 根据变量的类型,建立对应的return value方法
    if (uniformType === 'sampler2D') {
        material._uniforms[newUniformId] = function() {
            return material._textures[uniformId];
        };
        material._updateFunctions.push(createTexture2DUpdateFunction(uniformId));
    } else if (uniformType === 'samplerCube') {
        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], scratchMatrix);
        };
    } else {
        material._uniforms[newUniformId] = function() {
            return material.uniforms[uniformId];
        };
    }
}
Copy the code

       After createUniforms treatment method is translucent, and this will affect the Pimitive create RenderState, and render settings queue. The translucent Fabric method of preservation in material._translucentFunctions in.

Primitive

       At this point, we have created a color type of Material, which is assigned to the corresponding Primitive, code is as follows:

primitive.appearance.material = Cesium.Material.fromType('Color');

       Here there is a new object: Appearance. Here, Material's only responsible for the fragment shader, the code portion of the material, and is responsible for the Primitvie Appearance Shader entire code consists of two parts vertex shader and fragment shader, while the need to set the corresponding RenderState according to the state of Appearance It can be said to be on top of Material Appearance after layer of packaging. A total of MaterialAppearance, EllipsoidSurfaceAppearance six types, similar, different property values ​​of each object, but there is a unified Appearance responsible logically. We look to create a following of Primitive:

Copy the code
var rectangle = scene.primitives.add(new Cesium.Primitive({
    geometryInstances : new Cesium.GeometryInstance({
        geometry : new Cesium.RectangleGeometry({
            rectangle : Cesium.Rectangle.fromDegrees(-120.0, 20.0, -60.0, 40.0),
            vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
        })
    }),
    appearance : new Cesium.EllipsoidSurfaceAppearance({
        aboveGround : false
    })
}));
Copy the code

       As you are creating a EllipsoidSurfaceAppearance, Material if not specified, the internal defaults ColorTyoe material when creating. When performing Primitive.update, Appearance on to play their worth:

Primitive.prototype.update = function(frameState) {
    createRenderStates(this, context, appearance, twoPasses);
    createShaderProgram(this, frameState, appearance);
    createCommands(this, appearance, material, translucent, twoPasses, this._colorCommands, this._pickCommands, frameState);
}

       First Appearance base class provides default defaultRenderState, getRenderState also provides a method, as follows:

Copy the code
Appearance.getDefaultRenderState = function(translucent, closed, existing) {
    var rs = {
        depthTest : {
            enabled : true
        }
    };

    if (translucent) {
        rs.depthMask = false;
        rs.blending = BlendingState.ALPHA_BLEND;
    }

    if (closed) {
        rs.cull = {
            enabled : true,
            face : CullFace.BACK
        };
    }

    if (defined(existing)) {
        rs = combine(existing, rs, true);
    }

    return rs;
};

Appearance.prototype.getRenderState = function() {
    var translucent = this.isTranslucent();
    var rs = clone(this.renderState, false);
    if (translucent) {
        rs.depthMask = false;
        rs.blending = BlendingState.ALPHA_BLEND;
    } else {
        rs.depthMask = true;
    }
    return rs;
};
Copy the code

       Then, each of the subclasses according to their needs, to see whether the base class, or they have a special use, such as EllipsoidSurfaceAppearance categories:

Copy the code
function EllipsoidSurfaceAppearance(options) {
    this._vertexShaderSource = defaultValue(options.vertexShaderSource, EllipsoidSurfaceAppearanceVS);
    this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, EllipsoidSurfaceAppearanceFS);
    this._renderState = Appearance.getDefaultRenderState(translucent, !aboveGround, options.renderState);
}
EllipsoidSurfaceAppearance.prototype.getRenderState = Appearance.prototype.getRenderState;

function createRenderStates(primitive, context, appearance, twoPasses) {
    var renderState = appearance.getRenderState();
}
Copy the code

       Thus, EllipsoidSurfaceAppearance uses its own vertex shader and fragment shader code, but RenderState getRenderState and base class methods are directly used, and therefore, when the invoked primitive createRenderStates method, although the type of the current appearance may vary, but to ensure that all there are a set of unified call interface, RS eventually created to meet current needs, of course, is the main difference here is translucent.

       Next, it is to create ShaderProgram:

Copy the code
function createShaderProgram(primitive, frameState, appearance) {
    var vs = primitive._batchTable.getVertexShaderCallback()(appearance.vertexShaderSource);
    var fs = appearance.getFragmentShaderSource();
}

Appearance.prototype.getFragmentShaderSource = function() {
    var parts = [];
    if (this.flat) {
        parts.push('#define FLAT');
    }
    if (this.faceForward) {
        parts.push('#define FACE_FORWARD');
    }
    if (defined(this.material)) {
        parts.push(this.material.shaderSource);
    }
    parts.push(this.fragmentShaderSource);

    return parts.join('\n');
};
Copy the code

       这里代码比较清楚,就是通过Appearance获取vs和fs,这里多了一个batchTable,这是因为该Primitive可能是批次的封装,因此需要把batch部分的vs和appearance的vs合并,batchTable后面有时间的话,在单独介绍。这里可以看到getFragmentShaderSource,增加了一下宏,同时,在Appearance中,不仅有自己的fragmentShaderSource,同时也把我们之前在Material中封装的material.shaderSource也追加进去。真的是海纳百川的历程。

       这样,就来到最后一步,构建Command:

Copy the code
function createCommands(primitive, appearance, material, translucent, twoPasses, colorCommands, pickCommands, frameState) {
    var uniforms = combine(appearanceUniformMap, materialUniformMap);
    uniforms = primitive._batchTable.getUniformMapCallback()(uniforms);
    var pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE;
    // ……
    colorCommand.uniformMap = uniforms;
    colorCommand.pass = pass;
    //……    
}
Copy the code

      Visible, the Material's uniforms merged bound to uniformMap command, the further translucent be used to determine the render queue. So far, Material-> Appearance-> Renderer of the whole process is over. Visible, Material mainly related to the initialization and Primitive.update section.

       Of course, before we introduced, by way of creation of Entity, can eventually create Primitive and added to PrimitiveCollection DataSourceDisplay this way by this process. This is built directly Primitive similar, but more around the circle. Of course, this is not white circle around, as do similar batch processing to merge multiple style Geometry. Of course, this involves the relationship between Batch, Appearance and subsequent re-introduce our MaterialProperty different from the way in this creation.

Guess you like

Origin www.cnblogs.com/mazhenyu/p/11482237.html