Source: SolidMLMaterial.js

/**
 * @file Extention for three.js. SolidMLMaterial.js depends on three.js and SolidML.js. Import after these dependent files.
 */
/** 
 *  Physical Model Material with vertex alpha
 */
SolidML.Material = class extends THREE.ShaderMaterial {
  constructor(parameters) {
    super();
    // behaives as MeshPhysicalMaterial
    this.isMeshStandardMaterial = true;
    this.isMeshPhysicalMaterial = true;
    this.defines = { 'PHYSICAL': '' };
    // copy from THREE.MeshStandardMaterial
    this.color = new THREE.Color( 0xffffff ); // diffuse
    this.roughness = 0.5;
    this.metalness = 0.5;
    this.map = null;
    this.lightMap = null;
    this.lightMapIntensity = 1.0;
    this.aoMap = null;
    this.aoMapIntensity = 1.0;
    this.emissive = new THREE.Color( 0x000000 );
    this.emissiveIntensity = 0.0;
    this.emissiveMap = null;
    this.bumpMap = null;
    this.bumpScale = 1;
    this.normalMap = null;
    this.normalMapType = THREE.TangentSpaceNormalMap;
    this.normalScale = new THREE.Vector2( 1, 1 );
    this.displacementMap = null;
    this.displacementScale = 1;
    this.displacementBias = 0;
    this.roughnessMap = null;
    this.metalnessMap = null;
    this.alphaMap = null;
    this.envMap = null;
    this.envMapIntensity = 1.0;
    this.refractionRatio = 0.98;
    this.wireframe = false;
    this.wireframeLinewidth = 1;
    this.wireframeLinecap = 'round';
    this.wireframeLinejoin = 'round';
    this.skinning = false;
    this.morphTargets = false;
    this.morphNormals = false;
    // copy from THREE.MeshPhysicalMaterial
    this.reflectivity = 0.25; // maps to F0 = 0.04
    this.clearCoat = 0.3;
    this.clearCoatRoughness = 0.2;
    // set uniforms
    this.uniforms = THREE.UniformsUtils.merge([
      THREE.ShaderLib.standard.uniforms,
      {
        clearCoat: { value: 0.3 },
        clearCoatRoughness: { value: 0.2 },
      }
    ]);
    // set original shader
    const shaders = SolidML.Material._shaders();
    this.vertexShader = shaders.vert;
    this.fragmentShader = shaders.frag;
    // custom depth map for shadowmap
    this.customDepthMaterial = new THREE.ShaderMaterial({
      defines: {
        'INSTANCED': "",
        'DEPTH_PACKING': THREE.RGBADepthPacking
      },
      vertexShader: shaders.depthVert,
      fragmentShader: shaders.depthFrag,
    });
    this.shadowSide = THREE.FrontSide;
    // transparent
    this.fog = true;
    this.lights = true;
    this.opacity = 1;
    this.transparent = true;
    // set values by hash
    this.setValues( parameters );
  }
  copy(source) {
    THREE.MeshPhysicalMaterial.prototype.copy.call(this, source);
    return this;
  }
  static _shaders() {
    const include = libs=>libs.map(lib=>"#include <"+lib+">").join("\n");
    const varying = vars=>vars.map(v  =>"varying "+v+";").join("\n");
    const uniform = unis=>unis.map(uni=>"uniform "+uni+";").join("\n");
    const rsm_packing = [ // packing functions for reflective shadow map
      "float unpackRGBAToRSMDepth(const in vec4 v) {",
        "return v.z * 255. / 65536. + v.w;",
      "}",
      "vec4 unpackRGBAToRSMAlbedo(const in vec4 v) {",
        "vec2 w = v.xy * 255. / 16.;",
        "return vec4(floor(w.x), fract(w.x)*16., floor(w.y), fract(w.y)*16.) / 15.;",
      "}",
      "vec4 packRSMtoRGBA(const in float depth, const in vec4 albedo, const in float glow){",
        "vec4 r = vec4(",
          "(floor(albedo.x * 15.) * 16. + floor(albedo.y * 15.)) / 256.,",
          "(floor(albedo.z * 15.) * 16. + floor(albedo.w * 15.)) / 256.,",
          "fract(depth*256.), depth);",
        "r.w -= r.z * ShiftRight8; // tidy overflow",
        "return r * PackUpscale;",
      "}"
    ].join("\n");
    const rsm_pars_fragment = [
      "#ifdef USE_SHADOWMAP",
        "#if NUM_DIR_LIGHTS > 0",
          "uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];",
          "varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];",
        "#endif",
        "#if NUM_SPOT_LIGHTS > 0",
          "uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];",
          "varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];",
        "#endif",
        "#if NUM_POINT_LIGHTS > 0",
          "uniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];",
          "varying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];",
        "#endif",
        "float texture2DCompare( sampler2D depths, vec2 uv, float compare ) {",
          "return step( compare, unpackRGBAToRSMDepth( texture2D( depths, uv ) ) );",
        "}",
        "float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {",
          "float shadow = 1.0;",
          "vec4 v;",
          "shadowCoord.xyz /= shadowCoord.w;",
          "shadowCoord.z += shadowBias;",
          "bool inFrustum = all(bvec4(shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0));",
          "if (all(bvec2(inFrustum, shadowCoord.z <= 1.0))) {",
            "#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )",
              "float texelSize = 1. / shadowMapSize.x;",
              "vec3 d = vec3(-texelSize, texelSize, 0)*shadowRadius;",
              "shadow = (",
                "texture2DCompare( shadowMap, shadowCoord.xy + d.xz, shadowCoord.z ) +",
                "texture2DCompare( shadowMap, shadowCoord.xy + d.zx, shadowCoord.z ) +",
                "texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +",
                "texture2DCompare( shadowMap, shadowCoord.xy + d.yz, shadowCoord.z ) +",
                "texture2DCompare( shadowMap, shadowCoord.xy + d.zy, shadowCoord.z )",
              ") * ( 1.0 / 5.0 );",
            "#else // no percentage-closer filtering:",
              "shadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );",
            "#endif",
          "}",
          "return shadow;",
        "}",
        "vec2 cubeToUV( vec3 v, float texelSizeY ) { return vec2(0); }",
      "#endif"
    ].join("\n");
    return {
      vert: [
        include([
          "common",
          "uv_pars_vertex",
          "uv2_pars_vertex",
          "displacementmap_pars_vertex",
          "fog_pars_vertex",
          "morphtarget_pars_vertex",
          "skinning_pars_vertex",
          "shadowmap_pars_vertex",
          "logdepthbuf_pars_vertex",
          "clipping_planes_pars_vertex"
        ]),
        varying([
          "vec3 vViewPosition", 
          "vec3 vNormal", 
          "vec4 vColor"
        ]),
        "attribute vec4 color;",
        "void main() {",
          include([
            "uv_vertex", 
            "uv2_vertex"
          ]),
          "vColor = color;",
          include([
            "beginnormal_vertex", 
            "morphnormal_vertex", 
            "skinbase_vertex", 
            "skinnormal_vertex", 
            "defaultnormal_vertex"
          ]),
          "vNormal = normalize(transformedNormal);",
          include([
            "begin_vertex",
            "morphtarget_vertex",
            "skinning_vertex",
            "displacementmap_vertex",
            "project_vertex",
            "logdepthbuf_vertex",
            "clipping_planes_vertex"
          ]),
          "vViewPosition = -mvPosition.xyz;",
          include([
            "worldpos_vertex", 
            "shadowmap_vertex", 
            "fog_vertex"
          ]),
        "}"
      ].join("\n"),
      frag: [
        uniform([
          "vec3 diffuse", 
          "vec3 emissive", 
          "float roughness", 
          "float metalness", 
          "float opacity", 
          "float clearCoat", 
          "float clearCoatRoughness"
        ]),
        varying([
          "vec3 vViewPosition", 
          "vec3 vNormal", 
          "vec4 vColor"
        ]),
        include([
          "common",
          "packing",
          "dithering_pars_fragment",
          "uv_pars_fragment",
          "uv2_pars_fragment",
          "map_pars_fragment",
          "alphamap_pars_fragment",
          "aomap_pars_fragment",
          "lightmap_pars_fragment",
          "emissivemap_pars_fragment",
          "bsdfs",
          "cube_uv_reflection_fragment",
          "envmap_pars_fragment",
          "envmap_physical_pars_fragment",
          "fog_pars_fragment",
          "lights_pars_begin",
          "lights_physical_pars_fragment",
          //"shadowmap_pars_fragment", // <= change getShadow() call 
          "bumpmap_pars_fragment",
          "normalmap_pars_fragment",
          "roughnessmap_pars_fragment",
          "metalnessmap_pars_fragment",
          "logdepthbuf_pars_fragment",
          "clipping_planes_pars_fragment"
        ]),
        rsm_packing,
        rsm_pars_fragment,
        "void main() {",
          include(["clipping_planes_fragment"]),
          "vec4 diffuseColor = vec4(diffuse, opacity);",
          "ReflectedLight reflectedLight = ReflectedLight(vec3(0), vec3(0), vec3(0), vec3(0));",
          "vec3 totalEmissiveRadiance = emissive;",
          include([
            "logdepthbuf_fragment",
            "map_fragment"
          ]),
          "diffuseColor.rgba *= vColor;",
          "float metalnessFactor = metalness;",
          "float roughnessFactor = roughness;",
          include([
            "alphamap_fragment",
            "alphatest_fragment",
            "normal_fragment_begin",
            "normal_fragment_maps",
            "emissivemap_fragment",
            "lights_physical_fragment",
            "lights_fragment_begin", // <= change getShadow() call 
          ]),
            /* insert irradiance caluration here */
          //"irradiance += shadowAlbedo.xyz * (1.-shadowAlbedo.a);",
          include([
            "lights_fragment_maps",
            "lights_fragment_end"
          ]),
          "vec3 outgoingLight",
          " = reflectedLight.directDiffuse",
          " + reflectedLight.indirectDiffuse",
          " + reflectedLight.directSpecular",
          " + reflectedLight.indirectSpecular",
          " + totalEmissiveRadiance;",
          "gl_FragColor = vec4(outgoingLight, diffuseColor.a);",
          include([
            "tonemapping_fragment", 
            "encodings_fragment", 
            "fog_fragment", 
            "premultiplied_alpha_fragment", 
            "dithering_fragment"
          ]),
        "}"
      ].join("\n"),
      "depthVert" : [
        include([
          "common",
          "uv_pars_vertex",
          "displacementmap_pars_vertex",
          "morphtarget_pars_vertex",
          "skinning_pars_vertex",
          "logdepthbuf_pars_vertex",
          "clipping_planes_pars_vertex",
          "uv_vertex",
          "skinbase_vertex"
        ]),
        "attribute vec4 color;",
        "varying vec4 vColor;",
        "void main() {",
          "vColor = color;",
          "#ifdef USE_DISPLACEMENTMAP",
          include([
            "beginnormal_vertex",
            "morphnormal_vertex",
            "skinnormal_vertex"
          ]),
          "#endif",
          include([
            "begin_vertex",
            "morphtarget_vertex",
            "skinning_vertex",
            "displacementmap_vertex",
            "project_vertex",
            "logdepthbuf_vertex",
            "clipping_planes_vertex"
          ]),
        "}"
      ].join("\n"), 
      "depthFrag" : [
        "#if DEPTH_PACKING == 3200",
          "uniform float opacity;",
        "#endif",
        "varying vec4 vColor;",
        include([
          "common",
          "packing",
          "uv_pars_fragment",
          "map_pars_fragment",
          "alphamap_pars_fragment",
          "logdepthbuf_pars_fragment",
          "clipping_planes_pars_fragment"
        ]),
        rsm_packing,
        "void main() {",
          include([
            "clipping_planes_fragment"
          ]),
          "vec4 diffuseColor = vec4( 1.0 );",
          "#if DEPTH_PACKING == 3200",
            "diffuseColor.a = opacity;",
          "#endif",
          include([
            "map_fragment",
            "alphamap_fragment",
            "alphatest_fragment",
            "logdepthbuf_fragment"
          ]),
          "#if DEPTH_PACKING == 3200",
            "gl_FragColor = vec4( vec3( 1.0 - (gl_FragCoord.z) ), opacity );",
          "#elif DEPTH_PACKING == 3201",
            "gl_FragColor = packRSMtoRGBA( gl_FragCoord.z, vColor, 0.);",
          "#endif",
        "}"
      ].join("\n")
    };
  }
}