xushiting 5 سال پیش
والد
کامیت
7e7c32ecc3

+ 21 - 0
.gitignore

@@ -0,0 +1,21 @@
+.DS_Store
+node_modules
+/dist
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 97 - 0
examples/Fdage2.html


BIN
examples/data/sintel.mp4


BIN
examples/data/sintel.ogv


+ 74 - 0
examples/test1.html

@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - geometry - cube</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="main.css">
+	</head>
+	<body>
+
+		<script type="module">
+
+			import * as THREE from '../build/three.module.js';
+
+			var camera, scene, renderer;
+			var mesh;
+
+			init();
+			animate();
+            setClearColor();
+			function init() {
+
+				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.z = 400;
+
+				scene = new THREE.Scene();
+
+				var texture = new THREE.TextureLoader().load( 'textures/crate.gif' );
+
+				var geometry = new THREE.BoxBufferGeometry( 200, 200, 200 );
+				var material = new THREE.MeshBasicMaterial( { map: texture } );
+
+				mesh = new THREE.Mesh( geometry, material );
+				scene.add( mesh );
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				//
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				mesh.rotation.x += 0.005;
+				mesh.rotation.y += 0.01;
+
+				renderer.render( scene, camera );
+
+			}
+
+            function setClearColor() {
+				renderer.setClearColor2(0.0582, 0.06772, 0.07805, 1)
+			}
+
+		</script>
+
+	</body>
+</html>

+ 181 - 0
examples/test2.html

@@ -0,0 +1,181 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Threejs使用canvas更新纹理</title>
+    <style type="text/css">
+        html, body {
+            margin: 0;
+            height: 100%;
+        }
+
+        canvas {
+            display: block;
+        }
+
+        #video{
+            position: fixed;
+            left:0;
+            bottom:0;
+        }
+    </style>
+</head>
+
+<body onload="draw();">
+<video id="video" autoplay controls >
+    <source src="data/sintel.ogv" type='video/ogg; codecs="theora, vorbis"'>
+    <source src="data/sintel.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
+</video>
+</body>
+<script src="../build/three.js"></script>
+<script src="js/controls/OrbitControls.js"></script>
+<script src="js/libs/stats.min.js"></script>
+<script src="https://cdn.bootcss.com/dat-gui/0.7.1/dat.gui.min.js"></script>
+<script src="js/Detector.js"></script>
+
+<script>
+    var renderer, camera, scene, gui, light, stats, controls;
+
+    function initRender() {
+        renderer = new THREE.WebGLRenderer({antialias: true});
+        renderer.setPixelRatio(window.devicePixelRatio);
+        renderer.setSize(window.innerWidth, window.innerHeight);
+        renderer.setClearColor(0xeeeeee);
+        renderer.shadowMap.enabled = true;
+        //告诉渲染器需要阴影效果
+        document.body.appendChild(renderer.domElement);
+    }
+
+    function initCamera() {
+        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
+        camera.position.set(0, 0, 15 );
+    }
+
+    function initScene() {
+        scene = new THREE.Scene();
+    }
+
+    //初始化dat.GUI简化试验流程
+    function initGui() {
+        //声明一个保存需求修改的相关数据的对象
+        gui = {
+        };
+        var datGui = new dat.GUI();
+        //将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值)
+    }
+
+    function initLight() {
+        scene.add(new THREE.AmbientLight(0x444444));
+
+        light = new THREE.DirectionalLight(0xffffff);
+        light.position.set(0, 20, 20 );
+
+        light.castShadow = true;
+        light.shadow.camera.top = 10;
+        light.shadow.camera.bottom = -10;
+        light.shadow.camera.left = -10;
+        light.shadow.camera.right = 10;
+
+        //告诉平行光需要开启阴影投射
+        light.castShadow = true;
+
+        scene.add(light);
+    }
+
+    function initModel() {
+
+        //辅助工具
+        var helper = new THREE.AxesHelper(50);
+        scene.add(helper);
+
+        //添加立方体
+        var geometry = new THREE.BoxBufferGeometry( 10, 5, 5 );
+
+        //获取到video对象
+        var video = document.querySelector("#video");
+        //通过video对象实例化纹理
+        var texture = new THREE.VideoTexture(video);
+        texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
+        texture.minFilter = THREE.LinearFilter;
+        material = new THREE.MeshBasicMaterial( { map: texture } );
+
+        scene.add(new THREE.Mesh(geometry, material));
+    }
+
+    //初始化性能插件
+    function initStats() {
+        stats = new Stats();
+        document.body.appendChild(stats.dom);
+    }
+
+    function initControls() {
+
+        controls = new THREE.OrbitControls(camera, renderer.domElement);
+        //设置控制器的中心点
+        //controls.target.set( 0, 5, 0 );
+        // 如果使用animate方法时,将此函数删除
+        //controls.addEventListener( 'change', render );
+        // 使动画循环使用时阻尼或自转 意思是否有惯性
+        controls.enableDamping = true;
+        //动态阻尼系数 就是鼠标拖拽旋转灵敏度
+        //controls.dampingFactor = 0.25;
+        //是否可以缩放
+        controls.enableZoom = true;
+        //是否自动旋转
+        controls.autoRotate = false;
+        controls.autoRotateSpeed = 0.5;
+        //设置相机距离原点的最远距离
+        controls.minDistance = 1;
+        //设置相机距离原点的最远距离
+        controls.maxDistance = 2000;
+        //是否开启右键拖拽
+        controls.enablePan = true;
+    }
+
+    function render() {
+
+    }
+
+    //窗口变动触发的函数
+    function onWindowResize() {
+
+        camera.aspect = window.innerWidth / window.innerHeight;
+        camera.updateProjectionMatrix();
+        renderer.setSize(window.innerWidth, window.innerHeight);
+
+    }
+
+    function animate() {
+        //更新控制器
+        render();
+
+        //更新性能插件
+        stats.update();
+
+        controls.update();
+
+        renderer.render(scene, camera);
+
+        requestAnimationFrame(animate);
+    }
+
+    function draw() {
+        //兼容性判断
+        if (!Detector.webgl) Detector.addGetWebGLMessage();
+
+        initGui();
+        initRender();
+        initScene();
+        initCamera();
+        initLight();
+        initModel();
+        initControls();
+        initStats();
+
+        animate();
+        window.onresize = onWindowResize;
+    }
+
+
+</script>
+</html>

+ 21 - 0
src/lights/FdageLight.js

@@ -0,0 +1,21 @@
+import { Light } from './Light.js';
+import { Object3D } from '../core/Object3D.js';
+import { Vector3 } from '../math/Vector3.js';
+
+function FdageLight( color ) {
+    Light.call( this, color );
+
+	this.type = 'FdageLight';
+	this.position.copy( Object3D.DefaultUp );
+	this.updateMatrix();
+
+	this.direction = new Object3D();
+    //this.shadow = undefined;
+    this.parameters = new Vector3();
+    this.spot = new Vector3();
+    //确定都是这个值?
+    this.rotation = 93;
+    this.matrixWeights = null;
+}
+
+export { FdageLight };

+ 211 - 0
src/lights/FdageLights.js

@@ -0,0 +1,211 @@
+// import { Matrix4 } from '../math/Matrix4.js';
+// import { Vector2 } from '../math/Vector2.js';
+
+/**
+ * 
+ * @param {json} lightInfo
+ *  比如:{
+	"count": 3,
+	"shadowCount": 3,
+	"rotation": 217,
+	"positions": [0.300016, 0.575976, 0.760422, 0, -0.431842, 0.294622, -0.852473, 0, -0.806823, 0.414129, -0.421348, 0],
+	"directions": [0.300016, 0.575976, 0.760422, -0.431842, 0.294622, -0.852473, -0.806823, 0.414129, -0.421348],
+	"colors": [5, 5, 5, 5.27104, 40, 24.3306, 85.7826, 79.3486, 44.3031],
+	"parameters": [-1, 0, 0, -1, 0, 0, -1, 0, 0],
+	"spot": [-1, 1, 0, -1, 1, 0, -1, 1, 0],
+	"matrixWeights": [2, 2, 2]
+}
+ * @param {json} camera 
+ */
+function FdageLights( lightInfo,camera ) {
+
+	this.rotation = this.shadowCount = this.count = 0;
+    this.positions = [];
+    this.directions = [];
+    this.matrixWeights = [];
+    this.matrix = Matrix.identity();
+    this.invMatrix = Matrix.identity();
+    this.defaultmatrix = Matrix.identity();
+    this.defaultviewmatrix = Matrix.identity();
+    for (var key in lightInfo)
+        this[key] = lightInfo[key];
+    this.count = this.positions.length / 4;
+    this.count = Math.min(6, this.count);
+    this.shadowCount = Math.min(3, this.shadowCount);
+    this.positions = new Float32Array(this.positions);
+    this.positionBuffer = new Float32Array(this.positions);
+    this.directions = new Float32Array(this.directions);
+    this.directionBuffer = new Float32Array(this.directions);
+    this.colors = new Float32Array(this.colors);
+    this.colorsBuffer = new Float32Array(this.colors);
+    this.modelViewBuffer = new Float32Array(16 * this.shadowCount);
+    this.projectionBuffer = new Float32Array(16 * this.shadowCount);
+    this.finalTransformBuffer = new Float32Array(16 * this.shadowCount);
+    this.inverseTransformBuffer = new Float32Array(16 * this.shadowCount);
+    this.shadowTexelPadProjections = new Float32Array(4 * this.shadowCount);
+    this.shadowsNeedUpdate = new Uint8Array(this.shadowCount);
+    for (var d = 0; d < this.shadowsNeedUpdate.length; ++d)
+    {
+        this.shadowsNeedUpdate[d] = 1;
+    }
+    Matrix.rotation(this.matrix, this.rotation, 1);
+    Matrix.transpose(this.invMatrix, this.matrix);
+    Matrix.copy(this.defaultmatrix, this.matrix);
+    Matrix.copy(this.defaultviewmatrix, camera.viewMatrix);
+    for (d = 0; d < this.count; ++d) {
+        b = this.positions.subarray(4 * d, 4 * d + 4);
+        var e = this.directions.subarray(3 * d, 3 * d + 3);
+        1 == this.matrixWeights[d] ? (Matrix.mul4(b, this.matrix, b[0], b[1], b[2], b[3]),
+        Matrix.mulVec(e, this.matrix, e[0], e[1], e[2])) : 2 == this.matrixWeights[d] && (Matrix.mul4(b, camera.viewMatrix, b[0], b[1], b[2], b[3]),
+        Matrix.mulVec(e, camera.viewMatrix, e[0], e[1], e[2]))
+    }
+
+}
+
+FdageLights.prototype.getLightPos = function(a) {
+    return this.positionBuffer.subarray(4 * a, 4 * a + 4)
+};
+
+FdageLights.prototype.setLightDistance = function(a, c) {
+    0 >= c && (c = 1E-5);
+    this.parameters[3 * a + 2] = 1 / c
+};
+
+FdageLights.prototype.setLightSpotAngle = function(a, c) {
+    0 >= c && (c = 1E-6);
+    this.spot[3 * a] = c;
+    var b = Math.sin(3.1415926 / 180 * c / 2);
+    this.spot[3 * a + 2] = 1 / (b * b) * this.spot[3 * a + 1]
+};
+
+FdageLights.prototype.setLightSpotSharpness = function(a, c) {
+    this.spot[3 * a + 1] = c;
+    this.setLightSpotAngle(this.spot[3 * a])
+}
+;
+FdageLights.prototype.setLightPos = function(a, c) {
+    this.positions[4 * a + 0] = c[0];
+    this.positions[4 * a + 1] = c[1];
+    this.positions[4 * a + 2] = c[2];
+    var b = this.positions.subarray(4 * a, 4 * a + 4);
+    1 == this.matrixWeights[a] ? Matrix.mul4(b, this.defaultmatrix, c[0], c[1], c[2], b[3]) : 2 == this.matrixWeights[a] && Matrix.mul4(b, this.defaultviewmatrix, c[0], c[1], c[2], b[3])
+}
+;
+FdageLights.prototype.setLightDir = function(a, c) {
+    this.directions[3 * a + 0] = c[0];
+    this.directions[3 * a + 1] = c[1];
+    this.directions[3 * a + 2] = c[2];
+    var b = this.directions.subarray(3 * a, 3 * a + 3);
+    1 == this.matrixWeights[a] ? Matrix.mulVec(b, this.defaultmatrix, c[0], c[1], c[2]) : 2 == this.matrixWeights[a] && Matrix.mulVec(b, this.defaultviewmatrix, c[0], c[1], c[2])
+}
+;
+FdageLights.prototype.getLightColor = function(a) {
+    return this.colors.subarray(3 * a, 3 * a + 3)
+}
+;
+FdageLights.prototype.setLightColor = function(a, c) {
+    this.colors[3 * a + 0] = c[0];
+    this.colors[3 * a + 1] = c[1];
+    this.colors[3 * a + 2] = c[2]
+}
+;
+FdageLights.prototype.getLightDir = function(a) {
+    return this.directionBuffer.subarray(3 * a, 3 * a + 3)
+}
+;
+FdageLights.prototype.getColor = function(a) {
+    a *= 3;
+    return [this.colors[a], this.colors[a + 1], this.colors[a + 2]]
+}
+;
+FdageLights.prototype.update = function(a, c) {
+    var b = new Matrix.type(this.matrix);
+    Matrix.rotation(this.matrix, this.rotation, 1);
+    Matrix.transpose(this.invMatrix, this.matrix);
+    for (var d = 0; d < this.count; ++d) {
+        var e = this.positions.subarray(4 * d, 4 * d + 4)
+          , f = this.directions.subarray(3 * d, 3 * d + 3)
+          , g = this.getLightPos(d)
+          , h = this.getLightDir(d);
+        1 == this.matrixWeights[d] ? (g[0] = e[0],
+        g[1] = e[1],
+        g[2] = e[2],
+        g[3] = e[3],
+        h[0] = f[0],
+        h[1] = f[1],
+        h[2] = f[2]) : 2 == this.matrixWeights[d] ? (Matrix.mul4(g, a.transform, e[0], e[1], e[2], e[3]),
+        Matrix.mulVec(h, a.transform, f[0], f[1], f[2]),
+        Matrix.mul4(g, this.matrix, g[0], g[1], g[2], g[3]),
+        Matrix.mulVec(h, this.matrix, h[0], h[1], h[2])) : (Matrix.mul4(g, this.matrix, e[0], e[1], e[2], e[3]),
+        Matrix.mulVec(h, this.matrix, f[0], f[1], f[2]));
+        Vect.normalize(h, h)
+    }
+    for (var f = new Float32Array(this.finalTransformBuffer), g = Matrix.empty(), h = Matrix.empty(), k = Matrix.empty(), n = Vect.empty(), m = Vect.empty(), l = Vect.empty(), p = Vect.empty(), e = Vect.empty(), r = [], s = [], u = Matrix.create(0.5, 0, 0, 0.5, 0, 0.5, 0, 0.5, 0, 0, 0.5, 0.5, 0, 0, 0, 1), d = 0; d < this.count; ++d) {
+        n = this.getLightPos(d);
+        m = this.getLightDir(d);
+        0.99 < Math.abs(m[1]) ? Vect.set(l, 1, 0, 0) : Vect.set(l, 0, 1, 0);
+        Vect.cross(p, l, m);
+        Vect.normalize(p, p);
+        Vect.cross(l, m, p);
+        Vect.normalize(l, l);
+        Matrix.set(g, p[0], p[1], p[2], -Vect.dot(p, n), l[0], l[1], l[2], -Vect.dot(l, n), m[0], m[1], m[2], -Vect.dot(m, n), 0, 0, 0, 1);
+        for (n = 0; 8 > n; ++n)
+            e[0] = n & 1 ? c.max[0] : c.min[0],
+            e[1] = n & 2 ? c.max[1] : c.min[1],
+            e[2] = n & 4 ? c.max[2] : c.min[2],
+            Matrix.mulPoint(e, this.matrix, 1.005 * e[0], 1.005 * e[1], 1.005 * e[2]),
+            Matrix.mulPoint(e, g, e[0], e[1], e[2]),
+            0 == n ? (r[0] = s[0] = e[0],
+            r[1] = s[1] = e[1],
+            r[2] = s[2] = e[2]) : (r[0] = Math.min(r[0], e[0]),
+            r[1] = Math.min(r[1], e[1]),
+            r[2] = Math.min(r[2], e[2]),
+            s[0] = Math.max(s[0], e[0]),
+            s[1] = Math.max(s[1], e[1]),
+            s[2] = Math.max(s[2], e[2]));
+        var n = -r[2]
+          , m = -s[2]
+          , q = this.spot[3 * d];
+        0 < q ? (n = Math.min(n, 1 / this.parameters[3 * d + 2]),
+        m = Math.max(0.04 * n, m),
+        Matrix.perspective(h, q, 1, m, n),
+        d < this.shadowCount && (n = 2 * -Math.tan(0.00872664625 * q),
+        this.shadowTexelPadProjections[4 * d + 0] = this.modelViewBuffer[16 * d + 2] * n,
+        this.shadowTexelPadProjections[4 * d + 1] = this.modelViewBuffer[16 * d + 6] * n,
+        this.shadowTexelPadProjections[4 * d + 2] = this.modelViewBuffer[16 * d + 10] * n,
+        this.shadowTexelPadProjections[4 * d + 3] = this.modelViewBuffer[16 * d + 14] * n)) : (Matrix.ortho(h, r[0], s[0], r[1], s[1], m, n),
+        d < this.shadowCount && (this.shadowTexelPadProjections[4 * d + 0] = this.shadowTexelPadProjections[4 * d + 1] = this.shadowTexelPadProjections[4 * d + 2] = 0,
+        this.shadowTexelPadProjections[4 * d + 3] = Math.max(s[0] - r[0], s[1] - r[1])));
+        Matrix.mul(k, h, g);
+        Matrix.mul(k, u, k);
+        Matrix.copyToBuffer(this.modelViewBuffer, 16 * d, g);
+        Matrix.copyToBuffer(this.projectionBuffer, 16 * d, h);
+        Matrix.copyToBuffer(this.finalTransformBuffer, 16 * d, k);
+        Matrix.invert(k, k);
+        Matrix.copyToBuffer(this.inverseTransformBuffer, 16 * d, k)
+    }
+    e = !1;
+    for (d = 0; d < b.length; ++d)
+        if (b[d] != this.matrix[d]) {
+            e = !0;
+            break
+        }
+    for (d = 0; d < this.shadowCount; d++)
+        if (e && 1 == this.matrixWeights[d])
+            this.shadowsNeedUpdate[d] = 1;
+        else
+            for (b = 16 * d; b < 16 * d + 16; ++b)
+                if (f[b] != this.finalTransformBuffer[b]) {
+                    this.shadowsNeedUpdate[d] = 1;
+                    break
+                }
+}
+;
+FdageLights.prototype.flagUpdateAnimatedLighting = function() {
+    for (var a = 0; a < this.shadowCount; a++)
+        this.shadowsNeedUpdate[a] = 1
+}
+;
+
+
+export { FdageLights };

+ 275 - 0
src/materials/FdageMaterial.js

@@ -0,0 +1,275 @@
+/**
+ * 
+ * @param {webgl上下文:gl} gl 
+ * @param {json数据,里面包括了所有的模型文件} directory 
+ * @param {*} mat 
+ */
+function FdageMaterial(gl, directory, mat) {
+    this.gl = gl;
+    this.name = mat.name;
+    var d = {
+        mipmap: !0,
+        aniso: gl.hints.mobile ? 0 : 4,
+        clamp: !!mat.textureWrapClamp,
+        mirror: !!mat.textureWrapMirror
+    }
+      , e = {
+        mipmap: d.mipmap,
+        clamp: d.clamp,
+        mirror: d.mirror,
+        nofilter: mat.textureFilterNearest || !1
+    };
+    e.nofilter || (e.aniso = gl.hints.mobile ? 2 : 4);
+    this.textures = {
+        albedo: gl.textureCache.fromFilesMergeAlpha(directory.get(mat.albedoTex), directory.get(mat.alphaTex), e),
+        reflectivity: gl.textureCache.fromFilesMergeAlpha(directory.get(mat.reflectivityTex), directory.get(mat.glossTex), d),
+        normal: gl.textureCache.fromFile(directory.get(mat.normalTex), d),
+        extras: gl.textureCache.fromFilesMergeAlpha(directory.get(mat.extrasTex), directory.get(mat.extrasTexA), d)
+    };
+    this.extrasTexCoordRanges = {};
+    if (mat.extrasTexCoordRanges)
+        for (var f in mat.extrasTexCoordRanges)
+            this.extrasTexCoordRanges[f] = new Float32Array(mat.extrasTexCoordRanges[f].scaleBias);
+    this.textures.extras || (directory = new Texture(gl,{
+        width: 1,
+        height: 1
+    }),
+    directory.loadArray(new Uint8Array([255, 255, 255, 255])),
+    this.textures.extras = directory);
+    var g = mat.blendTint || [1, 1, 1];
+    var c = {
+        none: function() {
+            gl.disable(gl.BLEND)
+        },
+        alpha: function() {
+            gl.enable(gl.BLEND);
+            gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE_MINUS_DST_ALPHA, gl.ONE)
+        },
+        add: function() {
+            gl.enable(gl.BLEND);
+            gl.blendColor(g[0], g[1], g[2], 1);
+            gl.blendFunc(gl.ONE, gl.CONSTANT_COLOR)
+        }
+    };
+    this.blend = c[mat.blend] || c.none;
+    this.alphaTest = mat.alphaTest || 0;
+    this.usesBlending = this.blend !== c.none;
+    this.usesRefraction = !!mat.refraction;
+    this.shadowAlphaTest = this.alphaTest;
+    0 >= this.shadowAlphaTest && this.blend === c.alpha && (this.shadowAlphaTest = 0.5);
+    this.castShadows = this.blend !== c.add;
+    this.horizonOcclude = mat.horizonOcclude || 0;
+    this.fresnel = new Float32Array(mat.fresnel ? mat.fresnel : [1, 1, 1]);
+    this.emissiveIntensity = mat.emissiveIntensity || 1;
+    d = [];
+    e = !1;
+    0 < mat.lightCount && d.push("#define LIGHT_COUNT " + mat.lightCount);
+    0 < mat.shadowCount && (f = Math.min(mat.lightCount, mat.shadowCount),
+    this.usesRefraction && 8 >= gl.limits.textureCount && (f = 2 < f ? 2 : f),
+    d.push("#define SHADOW_COUNT " + f));
+    0 < mat.alphaTest && d.push("#define ALPHA_TEST");
+    this.blend === c.alpha ? d.push("#define TRANSPARENCY_DITHER") : this.blend === c.none && d.push("#define NOBLEND");
+    gl.hints.mobile && d.push("#define MOBILE");
+    gl.ext.textureDepth && d.push("#define SHADOW_NATIVE_DEPTH");
+    f = function(a) {
+        return 1 / (2 / 3 * 3.1415962 * (a * a + a + 1))
+    }
+    ;
+    mat.useSkin && (d.push("#define SKIN"),
+    this.skinParams = mat.skinParams || {
+        subdermisColor: [1, 1, 1],
+        transColor: [1, 0, 0, 1],
+        fresnelColor: [0.2, 0.2, 0.2, 0.5],
+        fresnelOcc: 1,
+        fresnelGlossMask: 1,
+        transSky: 0.5,
+        shadowBlur: 0.5,
+        normalSmooth: 0.5,
+        transScatter: 0,
+        transDepth: 0,
+        millimeterScale: 1
+    },
+    this.extrasTexCoordRanges.subdermisTex || d.push("#define SKIN_NO_SUBDERMIS_TEX"),
+    this.extrasTexCoordRanges.translucencyTex || d.push("#define SKIN_NO_TRANSLUCENCY_TEX"),
+    this.extrasTexCoordRanges.fuzzTex || d.push("#define SKIN_NO_FUZZ_TEX"),
+    void 0 === this.skinParams.version && (this.skinParams.version = 1),
+    2 == this.skinParams.version ? (d.push("#define SKIN_VERSION_2"),
+    this.skinParams.shadowBlur *= 4,
+    this.skinParams.shadowBlur = Math.min(this.skinParams.shadowBlur, 40),
+    this.skinParams.transIntegral = f(0.5 * this.skinParams.transScatter),
+    this.skinParams.fresnelIntegral = 1 / 3.14159 * (1 - 0.5 * this.skinParams.fresnelColor[3]),
+    this.skinParams.transSky = 0) : (d.push("#define SKIN_VERSION_1"),
+    this.skinParams.shadowBlur = 8 * Math.min(this.skinParams.shadowBlur, 1),
+    this.skinParams.transDepth = 0,
+    this.skinParams.transScatter = this.skinParams.transColor[3],
+    this.skinParams.transIntegral = 1 / 3.14159 * (1 - 0.5 * this.skinParams.transScatter),
+    this.skinParams.fresnelIntegral = 1 / 3.14159 * (1 - 0.5 * this.skinParams.fresnelColor[3]),
+    this.skinParams.transSky *= 1.25,
+    this.skinParams.transIntegral *= 1.25));
+    mat.aniso && (d.push("#define ANISO"),
+    this.anisoParams = mat.anisoParams || {
+        strength: 1,
+        tangent: [1, 0, 0],
+        integral: 0.5
+    },
+    this.extrasTexCoordRanges.anisoTex || d.push("#define ANISO_NO_DIR_TEX"));
+    mat.microfiber && (d.push("#define MICROFIBER"),
+    this.microfiberParams = mat.microfiberParams || {
+        fresnelColor: [0.2, 0.2, 0.2, 0.5],
+        fresnelOcc: 1,
+        fresnelGlossMask: 1
+    },
+    this.microfiberParams.fresnelIntegral = 1 / 3.14159 * (1 - 0.5 * this.microfiberParams.fresnelColor[3]),
+    this.extrasTexCoordRanges.fuzzTex || d.push("#define MICROFIBER_NO_FUZZ_TEX"));
+    mat.refraction && (d.push("#define REFRACTION"),
+    this.refractionParams = mat.refractionParams || {
+        distantBackground: !1,
+        tint: [1, 1, 1],
+        useAlbedoTint: !1,
+        IOR: 1.5
+    },
+    this.extrasTexCoordRanges.refractionMaskTex || d.push("#define REFRACTION_NO_MASK_TEX"));
+    mat.vertexColor && (d.push("#define VERTEX_COLOR"),
+    mat.vertexColorsRGB && d.push("#define VERTEX_COLOR_SRGB"),
+    mat.vertexColorAlpha && d.push("#define VERTEX_COLOR_ALPHA"));
+    this.horizonSmoothing = mat.horizonSmoothing || 0;
+    0 < this.horizonSmoothing && d.push("#define HORIZON_SMOOTHING");
+    mat.unlitDiffuse && d.push("#define DIFFUSE_UNLIT");
+    this.extrasTexCoordRanges.emissiveTex && (d.push("#define EMISSIVE"),
+    mat.emissiveSecondaryUV && (d.push("#define EMISSIVE_SECONDARY_UV"),
+    e = !0));
+    this.extrasTexCoordRanges.aoTex && (d.push("#define AMBIENT_OCCLUSION"),
+    mat.aoSecondaryUV && (d.push("#define AMBIENT_OCCLUSION_SECONDARY_UV"),
+    e = !0));
+    mat.tangentOrthogonalize && d.push("#define TSPACE_ORTHOGONALIZE");
+    mat.tangentNormalize && d.push("#define TSPACE_RENORMALIZE");
+    mat.tangentGenerateBitangent && d.push("#define TSPACE_COMPUTE_BITANGENT");
+    e && d.push("#define TEXCOORD_SECONDARY");
+    this.vOffset = this.uOffset = 0;
+    d.push("#define UV_OFFSET ");
+    this.shader = gl.shaderCache.fromURLs("matvert.glsl", "matfrag.glsl", d);
+    d.push("#define STRIPVIEW");
+    this.stripShader = gl.shaderCache.fromURLs("matvert.glsl", "matfrag.glsl", d);
+    this.wireShader = gl.shaderCache.fromURLs("wirevert.glsl", "wirefrag.glsl");
+    this.blend === c.alpha && (this.prepassShader = gl.shaderCache.fromURLs("alphaprepassvert.glsl", "alphaprepassfrag.glsl"))
+}
+
+FdageMaterial.prototype.bind = function(a, c) {
+    if (!this.complete())
+        return !1;
+    var b = a.view, d = a.lights, e = a.sky, f = a.shadow, g = a.stripData.active() ? this.stripShader : this.shader, h = this.skinParams, k = this.anisoParams, n = this.microfiberParams, m, l = this.gl, p = g.params, r = this.textures, s = g.samplers;
+    g.bind();
+    this.blend();
+    var u = c.mesh.displayMatrix
+      , q = Matrix.mul(Matrix.empty(), b.viewMatrix, u)
+      , x = Matrix.mul(Matrix.empty(), b.projectionMatrix, b.viewMatrix)
+      , q = Matrix.mul(Matrix.empty(), b.projectionMatrix, q)
+      , u = Matrix.mul(Matrix.empty(), d.matrix, u);
+    l.uniformMatrix4fv(p.uModelViewProjectionMatrix, !1, q);
+    l.uniformMatrix4fv(p.uSkyMatrix, !1, u);
+    u = Matrix.mulPoint(Vect.empty(), d.matrix, b.transform[12], b.transform[13], b.transform[14]);
+    l.uniform3f(p.uCameraPosition, u[0], u[1], u[2]);
+    l.uniform3fv(p.uFresnel, this.fresnel);
+    l.uniform1f(p.uAlphaTest, this.alphaTest);
+    l.uniform1f(p.uHorizonOcclude, this.horizonOcclude);
+    l.uniform1f(p.uHorizonSmoothing, this.horizonSmoothing);
+    l.uniform4fv(p.uDiffuseCoefficients, e.diffuseCoefficients);
+    0 < d.count && (l.uniform4fv(p.uLightPositions, d.positionBuffer),
+    l.uniform3fv(p.uLightDirections, d.directionBuffer),
+    l.uniform3fv(p.uLightColors, d.colors),
+    l.uniform3fv(p.uLightParams, d.parameters),
+    l.uniform3fv(p.uLightSpot, d.spot),
+    u = 0.392699 * a.postRender.currentSample(),
+    l.uniform2f(p.uShadowKernelRotation, 0.5 * Math.cos(u), 0.5 * Math.sin(u)),
+    0 < d.shadowCount && (u = f.depthTextures[0].desc.width,
+    l.uniform2f(p.uShadowMapSize, u, 1 / u),
+    l.uniformMatrix4fv(p.uShadowMatrices, !1, d.finalTransformBuffer),
+    l.uniformMatrix4fv(p.uInvShadowMatrices, !1, d.inverseTransformBuffer),
+    l.uniform4fv(p.uShadowTexelPadProjections, d.shadowTexelPadProjections),
+    f.bindDepthTexture(s.tDepth0, 0),
+    f.bindDepthTexture(s.tDepth1, 1),
+    f.bindDepthTexture(s.tDepth2, 2)));
+    h && (l.uniform3fv(p.uSubdermisColor, h.subdermisColor),
+    l.uniform4fv(p.uTransColor, h.transColor),
+    l.uniform1f(p.uTransScatter, h.transScatter),
+    l.uniform4fv(p.uFresnelColor, h.fresnelColor),
+    l.uniform1f(p.uFresnelOcc, h.fresnelOcc),
+    l.uniform1f(p.uFresnelGlossMask, h.fresnelGlossMask),
+    l.uniform1f(p.uFresnelIntegral, h.fresnelIntegral),
+    l.uniform1f(p.uTransIntegral, h.transIntegral),
+    l.uniform1f(p.uSkinTransDepth, h.transDepth),
+    l.uniform1f(p.uTransSky, h.transSky),
+    l.uniform1f(p.uSkinShadowBlur, h.shadowBlur),
+    l.uniform1f(p.uNormalSmooth, h.normalSmooth),
+    (m = this.extrasTexCoordRanges.subdermisTex) && l.uniform4fv(p.uTexRangeSubdermis, m),
+    (m = this.extrasTexCoordRanges.translucencyTex) && l.uniform4fv(p.uTexRangeTranslucency, m),
+    (m = this.extrasTexCoordRanges.fuzzTex) && l.uniform4fv(p.uTexRangeFuzz, m));
+    n && (l.uniform4fv(p.uFresnelColor, n.fresnelColor),
+    l.uniform1f(p.uFresnelOcc, n.fresnelOcc),
+    l.uniform1f(p.uFresnelGlossMask, n.fresnelGlossMask),
+    l.uniform1f(p.uFresnelIntegral, n.fresnelIntegral),
+    (m = this.extrasTexCoordRanges.fuzzTex) && l.uniform4fv(p.uTexRangeFuzz, m));
+    k && (l.uniform3fv(p.uAnisoTangent, k.tangent),
+    l.uniform1f(p.uAnisoStrength, k.strength),
+    l.uniform1f(p.uAnisoIntegral, k.integral),
+    (m = this.extrasTexCoordRanges.anisoTex) && l.uniform4fv(p.uTexRangeAniso, m));
+    this.usesRefraction && (a.refractionSurface && a.refractionSurface.bind(s.tRefraction),
+    d = Matrix.mul(Matrix.empty(), x, d.invMatrix),
+    l.uniformMatrix4fv(p.uRefractionViewProjection, !1, d),
+    l.uniform1f(p.uRefractionRayDistance, this.refractionParams.distantBackground ? 1E10 : 4 * c.mesh.bounds.maxExtent),
+    l.uniform3fv(p.uRefractionTint, this.refractionParams.tint),
+    l.uniform1f(p.uRefractionAlbedoTint, this.refractionParams.useAlbedoTint ? 1 : 0),
+    l.uniform1f(p.uRefractionIOREntry, 1 / this.refractionParams.IOR),
+    (m = this.extrasTexCoordRanges.refractionMaskTex) && l.uniform4fv(p.uTexRangeRefraction, m));
+    if (m = this.extrasTexCoordRanges.emissiveTex)
+        l.uniform4fv(p.uTexRangeEmissive, m),
+        l.uniform1f(p.uEmissiveScale, this.emissiveIntensity);
+    (m = this.extrasTexCoordRanges.aoTex) && l.uniform4fv(p.uTexRangeAO, m);
+    r.albedo.bind(s.tAlbedo);
+    r.reflectivity.bind(s.tReflectivity);
+    r.normal.bind(s.tNormal);
+    r.extras.bind(s.tExtras);
+    e.specularTexture.bind(s.tSkySpecular);
+    g === this.stripShader && (l.uniform1fv(p.uStrips, a.stripData.strips),
+    l.uniform2f(p.uStripRes, 2 / b.size[0], 2 / b.size[1]));
+    l.uniform2f(p.uUVOffset, this.uOffset, this.vOffset);
+    return !0
+};
+
+FdageMaterial.prototype.bindAlphaPrepass = function(a, c) {
+    if (!this.complete() || !this.prepassShader)
+        return !1;
+    var b = this.gl
+      , d = this.prepassShader.params
+      , e = this.prepassShader.samplers;
+    this.prepassShader.bind();
+    var f = Matrix.mul(Matrix.empty(), a.view.viewMatrix, c.mesh.displayMatrix)
+      , f = Matrix.mul(Matrix.empty(), a.view.projectionMatrix, f);
+    b.uniformMatrix4fv(d.uModelViewProjectionMatrix, !1, f);
+    b.uniform2f(d.uUVOffset, this.uOffset, this.vOffset);
+    this.textures.albedo.bind(e.tAlbedo);
+    return !0
+};
+
+FdageMaterial.prototype.bindWire = function(a, c) {
+    if (!this.complete())
+        return !1;
+    var b = this.gl
+      , d = this.wireShader.params
+      , e = a.view;
+    b.enable(b.BLEND);
+    b.blendFunc(b.SRC_ALPHA, b.ONE_MINUS_SRC_ALPHA);
+    b.depthMask(!1);
+    this.wireShader.bind();
+    var f = Matrix.mul(Matrix.empty(), a.view.viewMatrix, c.mesh.displayMatrix)
+      , f = Matrix.mul(Matrix.empty(), a.view.projectionMatrix, f);
+    b.uniformMatrix4fv(d.uModelViewProjectionMatrix, !1, f);
+    b.uniform4f(d.uStripParams, 2 / e.size[0], 2 / e.size[1], a.stripData.strips[3], a.stripData.strips[4]);
+    return !0
+};
+
+FdageMaterial.prototype.complete = function() {
+    return this.wireShader.complete() && this.shader.complete() && this.stripShader.complete() && (!this.prepassShader || this.prepassShader.complete()) && (!this.refractionShader || this.refractionShader.complete()) && this.textures.albedo.complete() && this.textures.reflectivity.complete() && this.textures.normal.complete()
+};
+
+export { FdageMaterial };

+ 103 - 0
src/scenes/FdageFog.js

@@ -0,0 +1,103 @@
+//gl,
+//{"opacity":0.9847131371498108,"distance":177.83547973632812,"dispersion":0.32692307233810425,"type":2,"skyIllum":0.7551020383834839,"lightIllum":1,"color":[1,1,1]}
+/**
+ * 
+ * @param {webgl自带的上下文变量类型} gl 
+ * @param {*} fogInfo
+ */
+function FdageFog(gl, fogInfo) {
+    this.desc = fogInfo;
+    this.gl = gl;
+    this.iblShader = gl.shaderCache.fromURLs("fogvert.glsl", "fogfrag.glsl", ["#define FOG_IBL"]);
+    var b = ["#define FOG_DIR"];
+    this.dirShader = gl.shaderCache.fromURLs("fogvert.glsl", "fogfrag.glsl", b);
+    b.push("#define FOG_SHADOWS");
+    this.dirShaderShadow = gl.shaderCache.fromURLs("fogvert.glsl", "fogfrag.glsl", b);
+    b = ["#define FOG_SPOT"];
+    this.spotShader = gl.shaderCache.fromURLs("fogvert.glsl", "fogfrag.glsl", b);
+    b.push("#define FOG_SHADOWS");
+    this.spotShaderShadow = gl.shaderCache.fromURLs("fogvert.glsl", "fogfrag.glsl", b);
+    b = ["#define FOG_OMNI"];
+    this.omniShaderShadow = this.omniShader = gl.shaderCache.fromURLs("fogvert.glsl", "fogfrag.glsl", b);
+    this.fullscreenTriangle = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, this.fullscreenTriangle);
+    b = new Float32Array([0, 0, 2, 0, 0, 2]);
+    gl.bufferData(gl.ARRAY_BUFFER, b, gl.STATIC_DRAW);
+    gl.bindBuffer(gl.ARRAY_BUFFER, null)
+}
+
+FdageFog.prototype.draw = function(scene, texture) {
+    var b = this.gl
+        , d = scene.view
+        , e = d.projectionMatrix
+        , f = Matrix.empty();
+    Matrix.mul(f, d.viewMatrix, d.projectionMatrix);
+    Matrix.invert(f, d.viewProjectionMatrix);
+    f = [e[10] + e[11], -e[14], -2 * e[11]];
+    e = [-2 / e[0], -2 / e[5], (1 - e[8]) / e[0], (1 - e[9]) / e[5]];
+    b.enable(b.BLEND);
+    b.blendFunc(b.ONE, b.ONE_MINUS_SRC_ALPHA);
+    for (var g = 0; g < scene.lights.count + 1; ++g) {
+        var h = g - 1, k = h < scene.lights.shadowCount, n;
+        n = 0 == g ? this.iblShader : 0 < scene.lights.spot[3 * h] ? k ? this.spotShaderShadow : this.spotShader : 0 < scene.lights.getLightPos(h)[3] ? this.omniShader : k ? this.dirShaderShadow : this.dirShader;
+        n.bind();
+        var m = n.params;
+        b.uniform3fv(m.uDepthToZ, f);
+        b.uniform4fv(m.uUnproject, e);
+        b.uniformMatrix4fv(m.uInvViewMatrix, !1, d.transform);
+        b.uniform1f(m.uFogInvDistance, 1 / this.desc.distance);
+        b.uniform1f(m.uFogOpacity, this.desc.opacity * (1 - scene.stripData.activeFade()));
+        b.uniform1f(m.uFogDispersion, 1 - this.desc.dispersion);
+        var l = [0, 0, 0];
+        l[this.desc.type] = 1;
+        b.uniform3fv(m.uFogType, l);
+        b.uniform3fv(m.uFogColor, this.desc.color);
+        b.uniform1f(m.uFogIllum, 0 == g ? this.desc.skyIllum : this.desc.lightIllum);
+        b.uniformMatrix4fv(m.uLightMatrix, !1, scene.lights.invMatrix);
+        if (0 == g) {
+            h = new Float32Array(scene.sky.diffuseCoefficients);
+            for (k = 4; 16 > k; ++k)
+                h[k] *= 1 - this.desc.dispersion;
+            for (k = 16; 36 > k; ++k)
+                h[k] *= 1 - this.desc.dispersion * this.desc.dispersion;
+            b.uniform4fv(m.uFogLightSphere, h)
+        } else {
+            var p = scene.lights.getLightPos(h)
+                , p = Matrix.mul4(Vect.empty(), scene.lights.invMatrix, p[0], p[1], p[2], p[3])
+                , l = scene.lights.getLightDir(h)
+                , l = Matrix.mulVec(Vect.empty(), scene.lights.invMatrix, l[0], l[1], l[2]);
+            b.uniform4fv(m.uLightPosition, p);
+            b.uniform3fv(m.uLightColor, scene.lights.getColor(h));
+            var p = 0.01745329251 * scene.lights.spot[3 * h]
+                , r = Math.cos(0.5 * p);
+            b.uniform4fv(m.uSpotParams, [-l[0], -l[1], -l[2], 0 < p ? r * r : 0]);
+            b.uniform4fv(m.uLightAttenuation, [scene.lights.parameters[3 * h + 0], scene.lights.parameters[3 * h + 1], scene.lights.parameters[3 * h + 2], r]);
+            k && (k = Matrix.mul(Matrix.empty(), scene.lights.finalTransformBuffer.subarray(16 * h), scene.lights.matrix),
+            b.uniformMatrix4fv(m.uShadowProj, !1, k),
+            scene.shadow.depthTextures[h].bind(n.samplers.uShadowMap),
+            h = 0,
+            1 < scene.postRender.sampleCount && (h = scene.postRender.currentSample() / scene.postRender.sampleCount),
+            b.uniform1f(m.uDitherOffset, h),
+            b.uniform3fv(m.uAABBMin, scene.bounds.min),
+            b.uniform3fv(m.uAABBMax, scene.bounds.max),
+            h = Vect.lerp(Vect.empty(), scene.bounds.min, scene.bounds.max, 0.5),
+            k = Vect.distance(h, scene.bounds.min),
+            b.uniform4f(m.uCylinder, h[0], h[1], h[2], k * k))
+        }
+        texture.bind(n.samplers.tDepth);
+        n = n.attribs.vCoord;
+        b.bindBuffer(b.ARRAY_BUFFER, this.fullscreenTriangle);
+        b.enableVertexAttribArray(n);
+        b.vertexAttribPointer(n, 2, b.FLOAT, !1, 0, 0);
+        b.drawArrays(b.TRIANGLES, 0, 3);
+        b.disableVertexAttribArray(n);
+        b.bindBuffer(b.ARRAY_BUFFER, null);
+    }
+    b.disable(b.BLEND)
+};
+
+FdageFog.prototype.complete = function() {
+    return this.iblShader.complete() && this.dirShader.complete() && this.dirShaderShadow.complete() && this.spotShader.complete() && this.spotShaderShadow.complete() && this.omniShader.complete() && this.omniShaderShadow.complete()
+};
+
+export { FdageFog };

+ 94 - 0
src/textures/FdageTexture.js

@@ -0,0 +1,94 @@
+//import { Texture } from './Texture.js';
+
+//images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding
+function FdageTexture(a, c) {
+    this.gl = a;
+    this.id = null;
+    this.type = a.TEXTURE_2D;
+    this.format = a.RGBA;
+    this.componentType = a.UNSIGNED_BYTE;
+    c = c || {};
+    this.desc = {
+        width: c.width || 1,
+        height: c.height || 1,
+        mipmap: c.mipmap,
+        clamp: c.clamp,
+        mirror: c.mirror,
+        aniso: c.aniso,
+        nofilter: c.nofilter
+    }
+}
+
+FdageTexture.prototype.loadImage = function(a, c) {
+    var b = this.gl;
+    a && a.width && a.height && (this.desc.width = a.width,
+    this.desc.height = a.height);
+    this.id = b.createTexture();
+    b.bindTexture(this.type, this.id);
+    this.format = c || b.RGBA;
+    this.componentType = b.UNSIGNED_BYTE;
+    b.pixelStorei(b.UNPACK_FLIP_Y_WEBGL, !0);
+    b.texImage2D(this.type, 0, this.format, this.format, this.componentType, a);
+    this.setParams();
+    b.bindTexture(this.type, null)
+};
+
+FdageTexture.prototype.loadArray = function(a, c, b) {
+    var d = this.gl;
+    this.id = d.createTexture();
+    d.bindTexture(this.type, this.id);
+    this.format = c || d.RGBA;
+    this.componentType = b || d.UNSIGNED_BYTE;
+    d.pixelStorei(d.UNPACK_FLIP_Y_WEBGL, !0);
+    d.texImage2D(this.type, 0, this.format, this.desc.width, this.desc.height, 0, this.format, this.componentType, a || null);
+    this.setParams();
+    d.bindTexture(this.type, null)
+};
+
+FdageTexture.prototype.setParams = function() {
+    var a = this.gl
+      , c = function(a) {
+        return 0 < a && 0 == (a & a - 1)
+    };
+    c(this.desc.width) && c(this.desc.height) || (this.desc.clamp = !0,
+    this.desc.mipmap = !1);
+    c = !this.desc.nofilter;
+    this.desc.mipmap ? (a.generateMipmap(this.type),
+    a.texParameteri(this.type, a.TEXTURE_MIN_FILTER, c ? a.LINEAR_MIPMAP_LINEAR : a.NEAREST_MIPMAP_NEAREST)) : a.texParameteri(this.type, a.TEXTURE_MIN_FILTER, c ? a.LINEAR : a.NEAREST);
+    a.texParameteri(this.type, a.TEXTURE_MAG_FILTER, c ? a.LINEAR : a.NEAREST);
+    if (this.desc.clamp || this.desc.mirror)
+        c = this.desc.clamp ? a.CLAMP_TO_EDGE : a.MIRRORED_REPEAT,
+        a.texParameteri(this.type, a.TEXTURE_WRAP_S, c),
+        a.texParameteri(this.type, a.TEXTURE_WRAP_T, c);
+    this.desc.aniso && a.ext.textureAniso && a.texParameteri(this.type, a.ext.textureAniso.TEXTURE_MAX_ANISOTROPY_EXT, this.desc.aniso)
+};
+
+FdageTexture.prototype.rebuildMips = function() {
+    this.desc.mipmap && (this.gl.bindTexture(this.type, this.id),
+    this.gl.generateMipmap(this.type))
+};
+
+FdageTexture.prototype.copyColorBuffer = function() {
+    this.gl.bindTexture(this.type, this.id);
+    this.gl.copyTexSubImage2D(this.type, 0, 0, 0, 0, 0, this.desc.width, this.desc.height)
+};
+
+FdageTexture.prototype.bind = function(a) {
+    if (a) {
+        var c = this.gl;
+        c.uniform1i(a.location, a.unit);
+        c.activeTexture(c.TEXTURE0 + a.unit);
+        c.bindTexture(this.type, this.id)
+    }
+};
+
+FdageTexture.prototype.destroy = function() {
+    this.gl.deleteTexture(this.id);
+    this.id = null
+};
+
+FdageTexture.prototype.complete = function() {
+    return !!this.id
+};
+
+export { FdageTexture };