import { GLShader, defaultValue } from "../../glCore";
import { WebglRenderer } from "../../2d/renderers/WebglRenderer";
import { BaseMaterial, EnvBlendType } from "../materials/BaseMaterial";
import { LightsConfig, ShadowType } from "../Scene3D"
import { generateUniformAccessObject, mapType } from "../../glCore/shader";
import { Mesh3D } from "..";


/**
 * 根据渲染器，材质，灯光获取着色器
 * @param render 
 * @param material 
 * @param lights 
 */
export function getCusShader(
    render: WebglRenderer,
    material: BaseMaterial,
    lights: LightsConfig,
    mesh: Mesh3D,
    maxBones?: number,
    useVertexTexture?: boolean,
    fog?: any,
    shadow?: any
) {
    //所有参数
    var parameters: ShaderParametersInt = {
        glUid: render.CONTEXT_UID,
        precision: getMaxPrecision(render),//也可能是材质上传的，再说了TODO
        pointLightsNum: lights.pointLights.length,
        dirLightsNum: lights.directionalLights.length,
        morphTargets: mesh.morphTargetInfluences && material.morphTargets,
        morphNormals: mesh.morphTargetInfluences && material.morphTargets && material.morphNormals,

        skinning: material.skinning && maxBones > 0,
        maxBones: maxBones || 0,
        useVertexTexture: useVertexTexture,

        lightAffect: material._lightAffect,

        useMap: !!material.map,
        useEnvMap: !!material.envMap,
        combine: material.combine,

        useVertexColor: !!material.useVertexColor,

        useFog: fog && material.useFog,

        useShadow: shadow && mesh.receiveShadow && material._lightAffect,
        shadowType: shadow && shadow.shadowType,
    }
    //计算code，
    var shaderKey = getShaderKey(parameters);
    var cusShader: CusShader;

    for (var i = 0; i < cacheShaders.length; i++) {
        if (cacheShaders[i]._glShaderKey === shaderKey) {
            cusShader = cacheShaders[i];
            ++cusShader.usedTimes;
            break;
        }
    }
    if (!cusShader) {
        cusShader = new CusShader(render.gl, parameters)
        cusShader._glShaderKey = shaderKey;
        //存下
        cacheShaders.push(cusShader)
    }
    return cusShader
}

/**
 * 根据参数获取shaderKey
 * @param parameters 
 */
function getShaderKey(parameters: ShaderParametersInt) {
    var array = [];
    for (var i = 0; i < parameterNames.length; i++) {
        array.push(parameters[parameterNames[i]]);
    }
    return array.join();
}

//根据渲染器的上下文id缓存的最大精度
const maxPrecisionCache: { [key: number]: string } = {}
/**
 * 获取最大精度，暂时不考虑缓存，性能有问题再说TODO
 * @param gl 
 */
function getMaxPrecision(render: WebglRenderer) {
    if (!maxPrecisionCache[render.CONTEXT_UID]) {
        maxPrecisionCache[render.CONTEXT_UID] = (() => {
            const gl = render.gl;
            if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT).precision > 0 &&
                gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT).precision > 0) {
                return 'highp';
            }
            if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT).precision > 0 &&
                gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT).precision > 0) {
                return 'mediump';
            }
            return 'lowp';
        })()
    }
    return maxPrecisionCache[render.CONTEXT_UID];
}


class CusShader extends GLShader {
    /**
     * 以后回收时用TODO
     */
    usedTimes: number;
    /**
     * 作为该着色器的标识
     */
    _glShaderKey: string;
    /**
     * 
     * @param gl 
     * @param parameters 
     */
    constructor(
        gl: WebGLRenderingContext,
        parameters: ShaderParametersInt
    ) {
        //预处理参数
        var frontVert = [
            'precision ' + parameters.precision + ' float;',
            'precision ' + parameters.precision + ' int;',
            parameters.lightAffect ? '#define USE_LIGHT' : '',
            parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
            parameters.morphNormals ? '#define USE_MORPHNORMALS' : '',
            parameters.skinning ? '#define USE_SKINNING' : '',
            parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
            '#define MAX_BONES ' + parameters.maxBones,
            parameters.useMap ? '#define USE_MAP' : '',
            parameters.useEnvMap ? '#define USE_ENVMAP' : '',
            parameters.useVertexColor ? '#define USE_VERTEXCOLOR' : '',
            parameters.useFog ? '#define USE_FOG' : '',
            parameters.useShadow ? '#define USE_SHADOW' : '',
            // parameters.useShadow ? '#define ' + parameters.shadowType : '',//貌似类型就片元用到
        ].filter(e => e !== '').join('\n');
        //不为空加个换行
        if (frontVert) frontVert += "\n";

        var frontFrag = [
            'precision ' + parameters.precision + ' float;',
            'precision ' + parameters.precision + ' int;',
            parameters.lightAffect ? '#define USE_LIGHT' : '',
            parameters.useMap ? '#define USE_MAP' : '',
            parameters.useEnvMap ? '#define USE_ENVMAP' : '',
            parameters.useEnvMap ? '#define ' + parameters.combine : '',
            parameters.useVertexColor ? '#define USE_VERTEXCOLOR' : '',
            parameters.useFog ? '#define USE_FOG' : '',
            parameters.useShadow ? '#define USE_SHADOW' : '',
            parameters.useShadow ? '#define ' + parameters.shadowType : '',
        ].filter(e => e !== '').join('\n');
        if (frontFrag) frontFrag += "\n";

        var frag = FRAG
            .replace(new RegExp(shaderReplaceStr.POINT_LIGHTS_NUM, "gm"), parameters.pointLightsNum + "")
            .replace(new RegExp(shaderReplaceStr.DIR_LIGHTS_NUM, "gm"), parameters.dirLightsNum + "")

        super(gl, frontVert + VERT, frontFrag + frag)

        //这两个需要重写下
        //修改uniform
        this.uniformData = extractUniforms(gl, this.program);
        //是否需要按照链式的点下去，链式的能点下去吧，但是数组索引自己拼字段
        this.uniforms = generateUniformAccessObject(gl, this.uniformData);

        //以后用
        this.usedTimes = 0;
    }
}

//部分属性不清除中括号（比如光照数据，链式结构赋值），
//有些清掉中括号，传纯数字数组（比如纹理通道数量uSamplers，变形权重morphTargetInfluences）

//复制一个不清除中括号的
function extractUniforms(gl: WebGLRenderingContext, program: WebGLProgram) {
    var uniforms = {};

    var totalUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);

    for (var i = 0; i < totalUniforms; i++) {//morphTargetInfluences
        var uniformData: WebGLActiveInfo = gl.getActiveUniform(program, i);

        //morphTargetInfluences直接传一个数组吧，还是说不区分，也直接按morphTargetInfluences[0]传
        var name = (uniformData.name.indexOf("morphTargetInfluences") == 0 || uniformData.name.indexOf("uBoneMatrices") == 0) ?
            uniformData.name.replace(/\[.*?\]/, "") : uniformData.name;
        var type = mapType(gl, uniformData.type);

        // console.log(name)
        uniforms[name] = {
            type: type,
            size: uniformData.size,
            location: gl.getUniformLocation(program, name),
            value: defaultValue(type, uniformData.size)
        };
    }

    return uniforms;
};


/**
 * 存储用过着色器程序
 * 根据自己的code取，code根据参数拼
 * 用数组吧，考虑为啥不用对象键值
 */
const cacheShaders: CusShader[] = [];


//////////////ShaderParametersInt和parameterNames这两个要对应的，否则缓存会出问题

/**
 * 影响着色器编译的所有的参数
 * 
 * 正反面影响法线和光照，还需要定义正反面光照及两面光照，以后再说
 * 环境贴图也需要法线，不止是光照需要，以后再说，到时normal必传吧
 */
const parameterNames = [
    "glUid",
    "precision",
    "pointLightsNum",
    "dirLightsNum",
    "morphTargets",
    "morphNormals",
    "skinning",
    "maxBones",
    "useVertexTexture",
    "lightAffect",
    "useMap",
    "useEnvMap",
    "combine",
    "useVertexColor",
    "useFog",
    "useShadow",
    "shadowType",
]

/**
 * 着色器编译参数接口
 */
interface ShaderParametersInt {
    glUid: number,
    precision: string,
    pointLightsNum: number,
    dirLightsNum: number,
    morphTargets: boolean,
    morphNormals: boolean,
    skinning: boolean,
    maxBones: number,
    useVertexTexture: boolean,
    lightAffect: boolean,
    useMap: boolean,
    useEnvMap: boolean,
    combine: EnvBlendType,
    useVertexColor: boolean,
    useFog: boolean,
    useShadow: boolean,
    shadowType: ShadowType,
}

/**
 * 着色器替换的一些文案
 */
enum shaderReplaceStr {
    POINT_LIGHTS_NUM = "POINT_LIGHTS_NUM",
    DIR_LIGHTS_NUM = "DIR_LIGHTS_NUM",
}

const VERT = [
    "attribute vec3 aPosition;",//顶点位置信息
    // "attribute vec3 aColor;",//顶点颜色数据
    // "attribute vec2 aTextureCoord;",//纹理坐标，
    // 'attribute vec3 aNormal;',//法线数据会和上述三个放在同一个数组里，但是不一定进attribute通道

    "uniform mat4 uViewMatrix;",//视图矩阵，camera的worldMatrixInverse
    "uniform mat4 uProjectionMatrix;",//投影矩阵，camera的projectionMatrix
    "uniform mat4 uModelMatrix;",//模型矩阵
    // "uniform mat4 uNormalMatrix;",//模型矩阵uModelMatrix的逆的转置，若正交就是模型矩阵，估计还要乘上视图举证，外面乘，先乘再逆转置

    "#ifdef USE_VERTEXCOLOR",
    "   attribute vec3 aColor;",//顶点颜色数据
    "   varying vec3 vColor;",//只有颜色数据需要传，或者考虑是否放材质里
    "#endif",
    //是否使用贴图
    "#ifdef USE_MAP",//有贴图才用到纹理坐标
    "   attribute vec2 aTextureCoord;",//纹理坐标，
    "   varying vec2 vTextureCoord;",//传到着色器的纹理坐标
    "   uniform mat3 uUvTransform;",//纹理uv偏移，为了图集
    "#endif",
    //使用环境贴图或灯光
    '#if defined( USE_ENVMAP ) || defined( USE_LIGHT )',
    '   attribute vec3 aNormal;',//法线数据会和上述三个放在同一个数组里，但是不一定进attribute通道
    "   uniform mat4 uNormalMatrix;",//模型矩阵uModelMatrix的逆的转置，若正交就是模型矩阵，估计还要乘上视图举证，外面乘，先乘再逆转置
    "   varying vec3 vNormal;",//计算所得法向量，已标准化，顶点着色器里计算少
    "   varying vec3 vWorldPosition;",//每个顶点的光线方向
    "   varying vec3 vViewPosition;", //传入计算镜面光
    '#endif',
    //环境贴图需要变量
    "#ifdef USE_ENVMAP",
    "   varying vec3 vReflect;",//反射向量
    "   uniform vec3 uCameraPosition;",//相机位置
    '#endif',

    //使用骨骼蒙皮
    "#ifdef USE_SKINNING",
    "   uniform mat4 uBindMatrix;",
    "   uniform mat4 uBindMatrixInverse;",
    "   #ifdef BONE_TEXTURE",
    "      uniform sampler2D uBoneTexture;",
    "      uniform int uBoneTextureSize;",
    "      mat4 getBoneMatrix( const in float i ) {",
    "         float j = i * 4.0;",
    "         float x = mod( j, float( uBoneTextureSize ) );",
    "         float y = floor( j / float( uBoneTextureSize ) );",
    "         float dx = 1.0 / float( uBoneTextureSize );",
    "         float dy = 1.0 / float( uBoneTextureSize );",
    "         y = dy * ( y + 0.5 );",
    "         vec4 v1 = texture2D( uBoneTexture, vec2( dx * ( x + 0.5 ), y ) );",
    "         vec4 v2 = texture2D( uBoneTexture, vec2( dx * ( x + 1.5 ), y ) );",
    "         vec4 v3 = texture2D( uBoneTexture, vec2( dx * ( x + 2.5 ), y ) );",
    "         vec4 v4 = texture2D( uBoneTexture, vec2( dx * ( x + 3.5 ), y ) );",
    "         mat4 bone = mat4( v1, v2, v3, v4 );",
    "         return bone;",
    "      }",
    "   #else",
    "      uniform mat4 uBoneMatrices[ MAX_BONES ];",
    "      mat4 getBoneMatrix( const in float i ) {",
    "         mat4 bone = uBoneMatrices[ int(i) ];",
    "         return bone;",
    "      }",
    "   #endif",
    '	attribute vec4 aSkinIndex;',
    '	attribute vec4 aSkinWeight;',
    "#endif",

    //变形顶点数据，单独建数组传，还是放入vao
    '#ifdef USE_MORPHTARGETS',
    '	attribute vec3 morphTarget0;',
    '	attribute vec3 morphTarget1;',
    '	attribute vec3 morphTarget2;',
    '	attribute vec3 morphTarget3;',
    '	#ifdef USE_MORPHNORMALS',
    '		attribute vec3 morphNormal0;',
    '		attribute vec3 morphNormal1;',
    '		attribute vec3 morphNormal2;',
    '		attribute vec3 morphNormal3;',
    "       uniform float morphTargetInfluences[ 4 ];",
    '	#else',
    '		attribute vec3 morphTarget4;',
    '		attribute vec3 morphTarget5;',
    '		attribute vec3 morphTarget6;',
    '		attribute vec3 morphTarget7;',
    "       uniform float morphTargetInfluences[ 8 ];",
    '	#endif',
    '#endif',

    //雾化
    '#ifdef USE_FOG',
    '    varying float vFogDepth;',
    '#endif',

    //阴影
    '#ifdef USE_SHADOW',
    // `   #if ${shaderReplaceStr.DIR_LIGHTS_NUM} > 0`,
    '      uniform mat4 uDirectionalShadowMatrix;',//现在就按一个影子算，以后改uDirectionalShadowMatrix[ DIR_LIGHTS_NUM ]
    '      varying vec4 vDirectionalShadowCoord;',//vDirectionalShadowCoord[ DIR_LIGHTS_NUM ]
    // '   #endif',
    '#endif',

    "void main() {",
    //赋值顶点坐标
    "   vec3 transformed = vec3( aPosition );",
    //考虑变形,顶点位置
    "   #ifdef USE_MORPHTARGETS",
    "      transformed += ( morphTarget0 - aPosition ) * morphTargetInfluences[ 0 ];",
    "      transformed += ( morphTarget1 - aPosition ) * morphTargetInfluences[ 1 ];",
    "      transformed += ( morphTarget2 - aPosition ) * morphTargetInfluences[ 2 ];",
    "      transformed += ( morphTarget3 - aPosition ) * morphTargetInfluences[ 3 ];",
    "      #ifndef USE_MORPHNORMALS",
    "         transformed += ( morphTarget4 - aPosition ) * morphTargetInfluences[ 4 ];",
    "         transformed += ( morphTarget5 - aPosition ) * morphTargetInfluences[ 5 ];",
    "         transformed += ( morphTarget6 - aPosition ) * morphTargetInfluences[ 6 ];",
    "         transformed += ( morphTarget7 - aPosition ) * morphTargetInfluences[ 7 ];",
    "      #endif",
    "   #endif",
    //使用蒙皮骨骼
    "   #ifdef USE_SKINNING",
    "      mat4 boneMatX = getBoneMatrix( aSkinIndex.x );",
    "      mat4 boneMatY = getBoneMatrix( aSkinIndex.y );",
    "      mat4 boneMatZ = getBoneMatrix( aSkinIndex.z );",
    "      mat4 boneMatW = getBoneMatrix( aSkinIndex.w );",
    "      vec4 skinVertex = uBindMatrix * vec4( transformed, 1.0 );",
    "      vec4 skinned = vec4( 0.0 );",
    "      skinned += boneMatX * skinVertex * aSkinWeight.x;",
    "      skinned += boneMatY * skinVertex * aSkinWeight.y;",
    "      skinned += boneMatZ * skinVertex * aSkinWeight.z;",
    "      skinned += boneMatW * skinVertex * aSkinWeight.w;",
    "      transformed = ( uBindMatrixInverse * skinned ).xyz;",
    "   #endif",
    //常规的
    "   vec4 mvPosition = uViewMatrix * uModelMatrix * vec4( transformed, 1.0 );",
    "   gl_Position = uProjectionMatrix * mvPosition;",
    //使用顶点颜色
    "   #ifdef USE_VERTEXCOLOR",
    "      vColor = aColor;",
    "   #endif",
    //纹理坐标
    "   #ifdef USE_MAP",
    // "      vTextureCoord = aTextureCoord;",
    "      vTextureCoord = ( uUvTransform * vec3( aTextureCoord, 1 ) ).xy;",//转换下uv
    "   #endif",
    //使用环境贴图或灯光
    '   #if defined( USE_ENVMAP ) || defined( USE_LIGHT )',
    "      vec3 objectNormal = vec3( aNormal );",
    //考虑变形，法线
    "      #ifdef USE_MORPHNORMALS",
    "         objectNormal += ( morphNormal0 - aNormal ) * morphTargetInfluences[ 0 ];",
    "         objectNormal += ( morphNormal1 - aNormal ) * morphTargetInfluences[ 1 ];",
    "         objectNormal += ( morphNormal2 - aNormal ) * morphTargetInfluences[ 2 ];",
    "         objectNormal += ( morphNormal3 - aNormal ) * morphTargetInfluences[ 3 ];",
    "      #endif",
    //骨骼蒙皮
    "      #ifdef USE_SKINNING",
    "         mat4 skinMatrix = mat4( 0.0 );",
    "         skinMatrix += aSkinWeight.x * boneMatX;",
    "         skinMatrix += aSkinWeight.y * boneMatY;",
    "         skinMatrix += aSkinWeight.z * boneMatZ;",
    "         skinMatrix += aSkinWeight.w * boneMatW;",
    "         skinMatrix  = uBindMatrixInverse * skinMatrix * uBindMatrix;",
    "         objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;",
    "      #endif",

    "      vViewPosition = -mvPosition.xyz;",
    "      vWorldPosition = vec3(uModelMatrix * vec4(transformed,1.0));",
    "      vec3 vTransformedNormal = vec3(uNormalMatrix * vec4(objectNormal,1.0));",
    "      vNormal = normalize(vTransformedNormal);",//标准化
    //环境贴图
    "      #ifdef USE_ENVMAP",
    "         vec3 cameraToVertex = normalize( vWorldPosition.xyz - uCameraPosition );",
    "         vec3 worldNormal = normalize( ( vec4( vTransformedNormal, 0.0 ) * uViewMatrix ).xyz );",
    "         vReflect = reflect(cameraToVertex, worldNormal);",
    '      #endif',
    '   #endif',
    //雾化深度
    '   #ifdef USE_FOG',
    '      vFogDepth = -mvPosition.z;',
    '   #endif',
    //阴影
    '   #ifdef USE_SHADOW',
    // `      #if ${shaderReplaceStr.DIR_LIGHTS_NUM} > 0`,
    '         vDirectionalShadowCoord = uDirectionalShadowMatrix * (uModelMatrix * vec4(transformed,1.0));',//以后vDirectionalShadowCoord是个数组
    // '      #endif',
    '   #endif',
    "}"
].join("\n")


const FRAG = [
    //材质通用参数
    "uniform vec3 uMatColor;", //材质上的颜色，以后区分发散颜色等等
    "uniform float uMatAlpha;", //材质上的透明度
    "#ifdef USE_MAP",
    '   uniform sampler2D uMap;',//纹理
    "   varying vec2 vTextureCoord;",//传到着色器的纹理坐标
    "#endif",

    "#ifdef USE_VERTEXCOLOR",
    "   varying vec3 vColor;",
    "#endif",

    '#if defined( USE_ENVMAP ) || defined( USE_LIGHT )',
    "   varying vec3 vNormal;",
    "   varying vec3 vWorldPosition;",
    "   varying vec3 vViewPosition;",
    "#endif",

    "#ifdef USE_ENVMAP",
    "   uniform sampler2D uEnvMap;",//环境贴图
    "   uniform float uReflectivity;",//反射率
    "   uniform mat4 uViewMatrix;",//环境贴图片元里也需要
    "   varying vec3 vReflect;",
    '#endif',


    //灯光参数
    '#ifdef USE_LIGHT',
    //计算镜面反射系数，前两个参数都应该是标准化过的
    "   float calcSpecular(vec3 lightDir, vec3 viewDir, vec3 normal) {",
    "      vec3 halfwayDir = normalize(lightDir + viewDir);",//用半程向量
    "      float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);",
    "      return spec;",
    "   }",
    //点光源参数
    `   #if ${shaderReplaceStr.POINT_LIGHTS_NUM} > 0`,
    "      #define saturate(a) clamp( a, 0.0, 1.0 )",
    "      float calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {",
    "         if ( decayExponent > 0.0 ) {",
    "            return pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );",
    "         }",
    "         return 1.0;",
    "      }",

    "      struct PointLight {",
    "         vec3 color;",//光源颜色
    "         vec3 position;",//点光源位置
    "         float distance;",//最大光源距离
    "         float decay;",//衰减系数，默认1，最佳2
    "      };",
    `      uniform PointLight pointLights[${shaderReplaceStr.POINT_LIGHTS_NUM}];`,
    "   #endif",

    //方向光参数
    `   #if ${shaderReplaceStr.DIR_LIGHTS_NUM} > 0`,
    "      struct DirectionalLight {",//反向光不会衰减
    "         vec3 direction;",
    "         vec3 color;",
    "         int shadow;",
    "         float shadowBias;",
    "	      float shadowRadius;",
    "	      vec2 shadowMapSize;",
    "      };",
    `      uniform DirectionalLight directionalLights[${shaderReplaceStr.DIR_LIGHTS_NUM}];`,
    "   #endif",

    //环境光
    "   uniform vec3 uAmbientLightColor;",//环境光颜色，多个环境光都是一起计算好传入的，不循环计算

    '#endif',

    //雾化声明量
    '#ifdef USE_FOG',
    '   uniform vec3 uFogColor;',
    '   varying float vFogDepth;',
    // '   uniform float uFogDensity;',
    '   uniform float uFogNear;',
    '   uniform float uFogFar;',
    '#endif',

    //阴影
    "#ifdef USE_SHADOW",
    // `   #if ${shaderReplaceStr.DIR_LIGHTS_NUM} > 0`,
    '      uniform sampler2D uDirectionalShadowMap;',
    '      varying vec4 vDirectionalShadowCoord;',
    // '   #endif',
    '      const float UnpackDownscale = 255. / 256.;',
    '      const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256.,  256. );',
    '      const vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );',
    '      float unpackRGBAToDepth( const in vec4 v ) {',
    '          return dot( v, UnpackFactors );',
    '      }',
    '   float texture2DCompare( sampler2D depths, vec2 uv, float compare ) {',
    '      return step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );',
    '   }',
    '   float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {',
    '      float shadow = 1.0;',
    '      shadowCoord.xyz /= shadowCoord.w;',
    //如果要出于性能优化考虑，把除二+0.5可以放到cpu里，像three
    // '      shadowCoord.xyz = (shadowCoord.xyz/shadowCoord.w)/2.0 + 0.5;',
    '      shadowCoord.z += shadowBias;',
    '      bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );',
    '      bool inFrustum = all( inFrustumVec );',
    '      bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );',
    '      bool frustumTest = all( frustumTestVec );',
    '      if ( frustumTest ) {',
    '         #if defined( SHADOWMAP_TYPE_PCF )',
    '            vec2 texelSize = vec2( 1.0 ) / shadowMapSize;',
    '            float dx0 = - texelSize.x * shadowRadius;',
    '	         float dy0 = - texelSize.y * shadowRadius;',
    '	         float dx1 = + texelSize.x * shadowRadius;',
    '	         float dy1 = + texelSize.y * shadowRadius;',
    '            shadow =(',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +',
    '               texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )',
    '            ) * ( 1.0 / 9.0 );',
    '         #elif defined( SHADOWMAP_TYPE_PCF_SOFT )',
    //这里暂时空。以后有需要再说
    '         #else',
    '            shadow = texture2DCompare(shadowMap, shadowCoord.xy, shadowCoord.z);',
    '         #endif',
    '      }',
    '      return shadow;',
    '   }',
    '#endif',

    "void main() {",
    //颜色计算，通用
    "   vec4 color = vec4( uMatColor, uMatAlpha );",
    "   color.rgb *= color.a;",//由于外面纹理的都预乘了，这里也坐下，如果以后确定了，直接颜色外面算好传入
    //纹理颜色
    "   #ifdef USE_MAP",
    "      vec4 mapColor = texture2D( uMap, vTextureCoord );",
    "      color *= mapColor;",
    "   #endif",
    //计算顶点颜色
    "   #ifdef USE_VERTEXCOLOR",
    "      color *= vec4(vColor,1.0);",
    "   #endif",

    "   vec3 colorRgb = color.rgb;",
    //光照颜色计算
    '   #ifdef USE_LIGHT',
    "      vec3 totalDiffuseLight = vec3( 0.0 );",
    "      vec3 totalSpecularLight = vec3( 0.0 );",
    "      vec3 viewDir = normalize(vViewPosition);",// 计算观察方向向量
    "      vec3 lightDirection;",//光照方向
    "      float diffuse;",//漫反射系数
    "      float specular;",//镜面反射系数  //到时改成乘自己的镜面反射颜色
    //计算点光源
    `      #if ${shaderReplaceStr.POINT_LIGHTS_NUM} > 0`,
    "         float attenuation;",//
    `         for ( int i = 0; i < ${shaderReplaceStr.POINT_LIGHTS_NUM}; i ++ ) {`,
    //漫反射
    "            lightDirection = pointLights[i].position + vViewPosition;", //-vWorldPosition
    "            attenuation = calcLightAttenuation( length( lightDirection ), pointLights[ i ].distance, pointLights[ i ].decay );",
    "            lightDirection = normalize(lightDirection);",
    "            diffuse = max( dot( vNormal, lightDirection ), 0.0 );",
    // "            float pointDiffuseWeightHalf = max( 0.5 * dot( vNormal, lightDirection ) + 0.5, 0.0 );",
    // "            vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), vec3(0.75, 0.375, 0.1875) );",
    "            totalDiffuseLight += pointLights[i].color * (diffuse * attenuation);",

    //镜面反射
    // "            vec3 reflectDir = reflect(-lightDirection, vNormal);",// 计算反射方向向量
    // "            float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0);",//发散系数待定
    "            specular = calcSpecular(lightDirection,viewDir,vNormal);",
    "            totalSpecularLight += pointLights[i].color *(specular * attenuation);",//反射强度系数待定
    "         }",
    "      #endif",

    //计算方向光
    `      #if ${shaderReplaceStr.DIR_LIGHTS_NUM} > 0`,
    '         DirectionalLight directionalLight;',
    `         for( int i = 0; i < ${shaderReplaceStr.DIR_LIGHTS_NUM}; i++ ) {`,
    '            directionalLight = directionalLights[ i ];',
    '            vec3 dColor = directionalLight.color;',//临时解决，到时抄three的
    '            #ifdef USE_SHADOW',
    '               dColor *= all( bvec2( directionalLight.shadow, 1.0 ) ) ? getShadow( uDirectionalShadowMap, directionalLight.shadowMapSize, directionalLight.shadowBias,directionalLight.shadowRadius, vDirectionalShadowCoord ) : 1.0;',
    '            #endif',
    //漫反射
    "            lightDirection = directionalLight.direction;",
    "            diffuse = max( dot( vNormal, lightDirection ), 0.0 );",
    // "            float dirDiffuseWeightHalf = max( 0.5 * dot( vNormal, dirVector ) + 0.5, 0.0 );",
    // "            vec3 dirDiffuseWeight = mix( vec3 ( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), vec3(0.75, 0.375, 0.1875) );",
    "            totalDiffuseLight += dColor * diffuse;",

    //镜面反射，貌似没有，
    // "            vec3 reflectDir1 = reflect(-directionalLight.direction, vNormal);",//待测试，是否加负号
    // "            float spec1 = pow(max(dot(viewDir, reflectDir1), 0.0), 32.0);",
    "            specular = calcSpecular(lightDirection,viewDir,vNormal);",
    //阴影下，讲道理不会有镜面放射
    // "            specular *= step(shadow, 1.0); " +
    "            totalSpecularLight += dColor * specular;",

    "         }",
    "      #endif",

    //计算环境光颜色，是否要乘材质本身颜色，待定，效果待调整，镜面反射是否要乘color.rgb，
    "      colorRgb = (totalDiffuseLight + uAmbientLightColor + totalSpecularLight) * colorRgb;",
    '   #endif',
    //计算环境贴图
    '   #ifdef USE_ENVMAP',
    //这种情况，环境贴图有问题，不随相机改变
    // '	   vec3 reflectView = normalize( ( uViewMatrix * vec4( normalize( vReflect ), 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );',
    // '	   vec2 envUv =  reflectView.xy * 0.5 + 0.5;',
    // '      envUv.y = 1.0- envUv.y;',//需要倒一下y
    //换种方式计算
    '      vec2 envUv;',
    "      vec3 reflectVec = normalize( vReflect );",
    "      envUv.y =0.5 - asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * 0.31830988618;",//1/PI
    "      envUv.x = atan( reflectVec.z, reflectVec.x ) * 0.15915494 + 0.5;",//1/PI/2
    //按照球坐标系计算，也正确，但是上面更简洁
    // 'vec3  rn=  normalize( vReflect );',
    // 'float l= atan(rn.x/rn.z);',//经度
    // 'float b = atan(rn.y/pow(1.0-rn.y*rn.y+0.001,0.5));',//纬度
    // "const float pp = 3.1415926;",
    // "if(rn.z == 0.0){",
    //    "l = sign(rn.x)*pp*0.5;",
    // "}else if(rn.z<0.0){",
    //    " l+= sign(rn.x)*pp;",
    // '}',
    // 'l = l/pp*0.5+0.25;',
    // 'l += step(0.0,-l);',
    // 'vec2 envUv = vec2(l,1.0-(b/3.1415926+0.5));',

    '	   vec4 envColor = texture2D( uEnvMap, envUv );',
    '      #ifdef ENVMAP_BLENDING_MULTIPLY',
    '         colorRgb = mix(colorRgb, colorRgb * envColor.xyz,  uReflectivity);',
    '      #elif defined( ENVMAP_BLENDING_MIX )',
    '         colorRgb = mix( colorRgb, envColor.xyz,   uReflectivity );',
    '      #elif defined( ENVMAP_BLENDING_ADD )',
    '         colorRgb += envColor.xyz  * uReflectivity;',
    '      #endif',
    '   #endif',
    '   gl_FragColor = vec4( colorRgb, color.a );',
    //雾化处理
    '#ifdef USE_FOG',
    // '   float fogFactor = 1.0 - clamp( exp2( - uFogDensity * uFogDensity * vFogDepth * vFogDepth * 1.442695 ), 0.0, 1.0 );',
    '   float fogFactor = smoothstep( uFogNear, uFogFar, vFogDepth );',
    '   gl_FragColor.rgb = mix( gl_FragColor.rgb, uFogColor*color.a, fogFactor );',//雾化的颜色*color.a
    '#endif',
    "}"
].join("\n")



