import { GLShader, defaultValue } from "../../glCore";
import { WebglRenderer } from "../../2d/renderers/WebglRenderer";
import { BaseMaterial, EnvBlendType } from "../materials/BaseMaterial";
import { LightsConfig } 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
) {
    //所有参数
    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
    }
    //计算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' : '',
        ].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' : '',
        ].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[] = [];

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

/**
 * 着色器编译参数接口
 */
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,
}

/**
 * 着色器替换的一些文案
 */
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;",//传到着色器的纹理坐标
    "#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',

    "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;",
    "   #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',
    "}"
].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;",
    "      };",
    `      uniform DirectionalLight directionalLights[${shaderReplaceStr.DIR_LIGHTS_NUM}];`,
    "   #endif",

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

    '#endif',

    "void main() {",
    //颜色计算，通用
    "   vec4 color = vec4( uMatColor, uMatAlpha );",
    //纹理颜色
    "   #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`,
    `         for( int i = 0; i < ${shaderReplaceStr.DIR_LIGHTS_NUM}; i++ ) {`,
    //漫反射
    "            lightDirection = directionalLights[ i ].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 += directionalLights[ i ].color * diffuse;",

    //镜面反射，貌似没有，
    // "            vec3 reflectDir1 = reflect(-directionalLights[ i ].direction, vNormal);",//待测试，是否加负号
    // "            float spec1 = pow(max(dot(viewDir, reflectDir1), 0.0), 32.0);",
    "            specular = calcSpecular(lightDirection,viewDir,vNormal);",
    "            totalSpecularLight += directionalLights[i].color * 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 );',
    "}"
].join("\n")



