function _generateLinkAttributes(portal, resonator, color, resonatorPercent) {
  resonatorPercent = resonatorPercent === undefined ? 1 : Math.max(Math.min(resonatorPercent, 1), 0);
  var values = new Float32Array(_size * _chunkSize);
  var dist = Math.sqrt(
    (resonator[0] - portal[0]) * (resonator[0] - portal[0]) +
    (resonator[1] - portal[1]) * (resonator[1] - portal[1])
  );
  var f4 = (2 / 30) * dist,
    f5 = 0.9 + 0.1 * resonatorPercent,
    f6 = 0.65 + 0.35 * resonatorPercent,
    f8 = 0.1 + 0.3 * resonatorPercent;
  var cl = vec4.lerp(vec4.create(), baseColor, color, 0.1 + resonatorPercent * 0.85);
  cl[3] = 0.75 + 0.25 * resonatorPercent * cl[3];
  var vec = vec3.fromValues(resonator[0], 0, resonator[1]);
  vec3.subtract(vec, vec, vec3.fromValues(portal[0], 0, portal[1]));
  var right = vec3.cross(vec3.create(), vec, up);
  vec3.normalize(right, right);
  var step = _len * 2;
  var f10 = 5.0 * ((portal[0] + portal[1]) - Math.floor(portal[0] + portal[1]));
  for(var i = 0; i < _len; i++)
  {
    var f11 = j[i],
      f12 = portal[0] + f11 * vec[0],
      f13 = portal[1] + f11 * vec[2],
      f14 = portalBaseOffset + f11 * (resonatorMidOffset - portalBaseOffset) + f5 * k[i],
      f15 = f6 * l[i],
      f16 = f11 * f4;
    fillChunk(values, (i * 2) + 0, f12 + f15 * right[0], f14, f13 + f15 * right[2], 0.0, f16 + f10, up, f8, cl);
    fillChunk(values, (i * 2) + 1, f12 - f15 * right[0], f14, f13 - f15 * right[2], 1.0, f16 + f10, up, f8, cl);
    fillChunk(values, step + (i * 2) + 0, f12, f14 + f15, f13, 0.0, f16 + f10, right, f8, cl);
    fillChunk(values, step + (i * 2) + 1, f12, f14 - f15, f13, 1.0, f16 + f10, right, f8, cl);
  }
  return values;
}
Ejemplo n.º 2
0
    return function unProject(out, a, invViewProj, viewport)
    {
        if (!vec4_0) vec4_0 = vec4.create();

        let x = a[0],
            y = a[1],
            z = a[2];

        vec4_0[0] = (x - viewport[0]) * 2.0 / viewport[2] - 1.0;
        vec4_0[1] = (y - viewport[1]) * 2.0 / viewport[3] - 1.0;
        vec4_0[2] = 2.0 * z - 1.0;
        vec4_0[3] = 1.0;

        vec4.transformMat4(vec4_0, vec4_0, invViewProj);

        if (vec4_0[3] === 0.0)
        {
            out[0] = 0;
            out[1] = 0;
            out[2] = 0;
            throw new Error('Perspective divide error');
        }

        out[0] = vec4_0[0] / vec4_0[3];
        out[1] = vec4_0[1] / vec4_0[3];
        out[2] = vec4_0[2] / vec4_0[3];
        return out;
    };
Ejemplo n.º 3
0
    interpolateValues (currentTime, interpolType, time1, time2, value1, value2, valueType){
        //Support and use only linear interpolation for now
        if (interpolType == 0) {
            return value1;
        } else if (interpolType >= 1) {

            if (valueType == 1 || valueType == 3) {
                var result = vec4.create();
                quat.slerp(result, value1, value2, (currentTime - time1)/(time2 - time1));
            } else {
                var diff = vec4.create();
                vec4.subtract(diff, value2, value1);
                vec4.scale(diff, diff, (currentTime - time1)/(time2 - time1));
                var result = vec4.create();
                vec4.add(result, value1, diff);
            }

            return result;
        }
    }
Ejemplo n.º 4
0
    update (deltaTime, cameraPos, invPlacementMat) {
        if (!this.m2Geom) return;
        //if (!this.materialArray) return;

        var animation = this.currentAnimation;
        animation = this.checkCurrentAnimation(animation, this.currentTime + deltaTime);
        var animationTime = this.currentTime + deltaTime - this.currentAnimationStart;

        var subMeshColors = this.getSubMeshColor(animation, animationTime);
        this.subMeshColors = subMeshColors;

        var transperencies = this.getTransperencies(animation, animationTime);
        this.transperencies = transperencies;

        this.calcBones(animation, animationTime, cameraPos, invPlacementMat);
        this.calcAnimMatrixes(animation, animationTime);

        var skinData = this.skinGeom.skinFile.header;

        var cameraInlocalPos = vec4.create();
        vec4.copy(cameraInlocalPos, cameraPos);
        vec4.transformMat4(cameraInlocalPos, cameraInlocalPos, invPlacementMat);

        this.materialArray.sort(function(a, b) {
            var result = a.layer - b.layer;
            if (result == 0) {
                var mesh1Pos = skinData.subMeshes[a.meshIndex].pos;
                var mesh2Pos = skinData.subMeshes[b.meshIndex].pos;

                var mesh1Vec = vec3.create();
                vec3.subtract(mesh1Vec, [mesh1Pos.x, mesh1Pos.y, mesh1Pos.z], cameraInlocalPos);

                var mesh2Vec = vec3.create();
                vec3.subtract(mesh2Vec, [mesh2Pos.x, mesh2Pos.y, mesh2Pos.z], cameraInlocalPos);

                var distMesh1 = vec3.length(mesh1Vec)
                var distMesh2 = vec3.length(mesh2Vec);

                result = distMesh2 - distMesh1;
            }

            return result;
        });

        this.currentTime += deltaTime;
    }
Ejemplo n.º 5
0
  /**
   *
   */
  constructor() {
    // Rendered viewport.
    this.rect = vec4.create();

    // Perspective values.
    this.isPerspective = true;
    this.fov = 0;
    this.aspect = 0;

    // Orthogonal values.
    this.isOrtho = false;
    this.leftClipPlane = 0;
    this.rightClipPlane = 0;
    this.bottomClipPlane = 0;
    this.topClipPlane = 0;

    // Shared values.
    this.nearClipPlane = 0;
    this.farClipPlane = 0;

    // World values.
    this.location = vec3.create();
    this.rotation = quat.create();

    // Derived values.
    this.inverseRotation = quat.create();
    this.worldMatrix = mat4.create();
    this.projectionMatrix = mat4.create();
    this.worldProjectionMatrix = mat4.create();
    this.inverseWorldMatrix = mat4.create();
    this.inverseRotationMatrix = mat4.create();
    this.inverseWorldProjectionMatrix = mat4.create();
    this.directionX = vec3.create();
    this.directionY = vec3.create();
    this.directionZ = vec3.create();

    // First four vectors are the corners of a 2x2 rectangle, the last three vectors are the unit axes
    this.vectors = [vec3.fromValues(-1, -1, 0), vec3.fromValues(-1, 1, 0), vec3.fromValues(1, 1, 0), vec3.fromValues(1, -1, 0), vec3.fromValues(1, 0, 0), vec3.fromValues(0, 1, 0), vec3.fromValues(0, 0, 1)];

    // First four vectors are the corners of a 2x2 rectangle billboarded to the camera, the last three vectors are the unit axes billboarded
    this.billboardedVectors = [vec3.create(), vec3.create(), vec3.create(), vec3.create(), vec3.create(), vec3.create(), vec3.create()];

    // Left, right, top, bottom, near, far
    this.planes = [vec4.create(), vec4.create(), vec4.create(), vec4.create(), vec4.create(), vec4.create()];

    this.dirty = true;
  }
Ejemplo n.º 6
0
/**
 * @class CubeGeometry
 * @implements Geometry
 * @classdesc
 *
 * A {@link Geometry} implementation suitable for tiled cube images with
 * multiple resolution levels.
 *
 * The following restrictions apply:
 *   - All tiles in a level must be square and form a rectangular grid;
 *   - The size of a level must be a multiple of the tile size;
 *   - The size of a level must be a multiple of the parent level size;
 *   - The number of tiles in a level must be a multiple of the number of tiles
 *     in the parent level.
 *
 * @param {Object[]} levelPropertiesList Level description
 * @param {number} levelPropertiesList[].size Cube face size in pixels
 * @param {number} levelPropertiesList[].tileSize Tile size in pixels
 */
function CubeGeometry(levelPropertiesList) {
  if (type(levelPropertiesList) !== 'array') {
    throw new Error('Level list must be an array');
  }

  this.levelList = makeLevelList(levelPropertiesList, CubeLevel);
  this.selectableLevelList = makeSelectableLevelList(this.levelList);

  for (var i = 1; i < this.levelList.length; i++) {
    this.levelList[i]._validateWithParentLevel(this.levelList[i-1]);
  }

  this._tileSearcher = new TileSearcher(this);

  this._neighborsCache = new LruMap(neighborsCacheSize);

  this._vec = vec4.create();

  this._viewSize = {};
}
Ejemplo n.º 7
0
/**
 * Helper functions for color transformation {@link Effects}.
 *
 * References:
 *
 *   - [ColorMatrix Guide](http://docs.rainmeter.net/tips/colormatrix-guide)
 *   - [Matrix Operations for Image Processing](http://www.graficaobscura.com/matrix/index.html)
 *   - [WebGLImageFilter](https://github.com/phoboslab/WebGLImageFilter)
 *   - [glfx.js](https://github.com/evanw/glfx.js)
 *
 * @namespace colorEffects
 */

/**
 * A vector and matrix corresponding to an identity transformation.
 *
 * @param {Object} result Object to store result
 * @param {vec4} result.colorOffset Array with zeroes.
 * @param {mat4} result.colorMatrix Identity matrix.
 *
 * @memberof colorEffects
 */
function identity(resultArg) {
  var result = resultArg || {};
  result.colorOffset = result.colorOffset || vec4.create();
  result.colorMatrix = result.colorMatrix || mat4.create();
  return result;
}
Ejemplo n.º 8
0
  out[2] = m[8] * x + m[9] * y + m[10] * z + m[11] * w;
  out[3] = m[12] * x + m[13] * y + m[14] * z + m[15] * w;
  return out;
}

/**
 * Apply color effects to an ImageData
 *
 * @param {ImageData} imageData This object will be mutated
 * @param {Object} effect
 * @param {vec4} effect.colorOffset
 * @param {mat4} effect.colorMatrix
 *
 * @memberof colorEffects
 */
var tmpPixel = vec4.create();
function applyToImageData(imageData, effect) {
  var width = imageData.width;
  var height = imageData.height;
  var data = imageData.data;

  for(var i = 0; i < width * height; i++) {
    vec4.set(tmpPixel, data[i*4+0]/255, data[i*4+1]/255, data[i*4+2]/255, data[i*4+3]/255);
    applyToPixel(tmpPixel, effect, tmpPixel);
    data[i*4+0] = tmpPixel[0]*255;
    data[i*4+1] = tmpPixel[1]*255;
    data[i*4+2] = tmpPixel[2]*255;
    data[i*4+3] = tmpPixel[3]*255;
  }
}
Ejemplo n.º 9
0
export default function mousePick(renderer) {
  const gl = renderer.gl;
  // Generate box data we need
  // We're literally spamming drawing calls - but it doesn't matter because
  // that's not in the scope of this example.
  let meshList = [];
  for (let i = 0; i < 100; ++i) {
    let transform = new MeshTransform();
    transform.translate([
      Math.random() * 30 - 15,
      Math.random() * 30 - 15,
      Math.random() * 30 - 15
    ]);
    meshList.push({
      transform: transform,
      color: packColor(i)
    });
  }
  let box = renderer.geometries.create(calcNormals(boxGeom()));
  let texture = renderer.textures.create(require('../texture/2.png'));
  let borderShader = renderer.shaders.create(
    require('../shader/minimalBias.vert'),
    require('../shader/monoColor.frag')
  );
  let pickShader = renderer.shaders.create(
    require('../shader/minimal.vert'),
    require('../shader/monoColor.frag')
  );
  let shader = renderer.shaders.create(
    require('../shader/phong.vert'),
    require('../shader/phong.frag')
  );

  let pickTexture = renderer.textures.create(null, {
    format: gl.RGBA
  });
  let pickFramebuffer = renderer.framebuffers.create({
    color: pickTexture,
    depth: gl.DEPTH_COMPONENT16 // Automatically use renderbuffer
  });

  let align = true;
  let alignColor = '#ff0000';
  let alignDir = [1, 0, 0];

  let alignGeom = renderer.geometries.create({
    attributes: {
      aPosition: [[-1, 0, 0], [1, 0, 0]]
    },
    mode: gl.LINES
  });

  let selectedId = 0;
  let contextCache;
  let mouseDown = false;
  let mousePosX = 0;
  let mousePosY = 0;
  let relativeOffset = vec2.create();
  return {
    update(delta, context) {
      contextCache = context;
      renderer.render({
        options: {
          clearColor: new Float32Array([0, 0, 0, 1]),
          clearDepth: 1,
          cull: gl.BACK,
          depth: gl.LEQUAL
        },
        uniforms: Object.assign({}, context.camera, {
          uPointLight: [],
          uDirectionalLight: {
            direction: [0, 0.7 / 1.22, 1 / 1.22],
            color: '#aaaaaa',
            intensity: [0.3, 1.0, 1.0]
          }
        }),
        passes: [meshList.map((data, id) => ({
          shader: shader,
          geometry: box,
          uniforms: {
            uMaterial: {
              ambient: '#ffffff',
              diffuse: '#ffffff',
              specular: '#555555',
              shininess: 30
            },
            uDiffuseMap: texture,
            uModel: data.transform.get,
            uNormal: data.transform.getNormal
          },
          passes: id === selectedId ? [{
            options: {
              // depthMask: true,
              cull: gl.FRONT
            },
            uniforms: {
              uBias: [0.1, 0],
              uColor: '#ffffff'
            },
            shader: borderShader
          }, {}] : [{}]
        })), align && meshList[selectedId] != null && {
          shader: pickShader,
          geometry: alignGeom,
          uniforms: {
            uColor: alignColor,
            uModel: [
              alignDir[0] * 1000, alignDir[1] * 1000, alignDir[2] * 1000, 0,
              0, 0, 0, 0,
              0, 0, 0, 0,
              meshList[selectedId].transform.position[0],
              meshList[selectedId].transform.position[1],
              meshList[selectedId].transform.position[2],
              1
            ]
          }
        }]
      });
    },
    mousedown(e, ndc) {
      if (e.button !== 0) return;
      // Render mouse pick data
      renderer.render({
        options: {
          clearColor: new Float32Array([1, 1, 1, 1]),
          clearDepth: 1,
          cull: gl.BACK,
          depth: gl.LEQUAL
        },
        uniforms: contextCache.camera,
        passes: meshList.map(data => ({
          shader: pickShader,
          geometry: box,
          uniforms: {
            uColor: data.color,
            uModel: data.transform.get,
            uNormal: data.transform.getNormal
          }
        })),
        framebuffer: pickFramebuffer
      });
      // Get mouse pixel
      let pixel = new Uint8Array(4);
      pickFramebuffer.readPixelsRGBA(e.clientX,
        gl.drawingBufferHeight - e.clientY, 1, 1, pixel);
      selectedId = unpackColor(pixel);
      mousePosX = ndc[0];
      mousePosY = ndc[1];
      mouseDown = true;
      if (meshList[selectedId] == null) return;
      if (align) {
        // We're aligning to axis - Get relative offset from origin to clicked
        // point
        let transform = meshList[selectedId].transform;
        // Project current model position to projection space
        // (to get Z value)
        let perspPos = vec4.fromValues(0, 0, 0, 1);
        vec4.transformMat4(perspPos, perspPos, transform.get());
        vec4.transformMat4(perspPos, perspPos, contextCache.cameraObj.getPV());
        vec4.scale(perspPos, perspPos, 1 / perspPos[3]);
        // Last, store relative offset for future use
        vec2.subtract(relativeOffset, ndc, perspPos);
      }
    },
    keydown(e) {
      if (e.keyCode === 67) {
        align = false;
      } else if (e.keyCode === 88) {
        align = true;
        alignColor = '#ff0000';
        alignDir = [1, 0, 0];
      } else if (e.keyCode === 89) {
        align = true;
        alignColor = '#00ff00';
        alignDir = [0, 1, 0];
      } else if (e.keyCode === 90) {
        align = true;
        alignColor = '#0000ff';
        alignDir = [0, 0, 1];
      }
    },
    mouseup() {
      mouseDown = false;
    },
    mousemove(e, ndc) {
      if (!mouseDown) return;
      let deltaX = ndc[0] - mousePosX;
      let deltaY = ndc[1] - mousePosY;
      mousePosX = ndc[0];
      mousePosY = ndc[1];
      if (meshList[selectedId] == null) return;
      if (!align) {
        // Freestyle translation
        let transform = meshList[selectedId].transform;
        // Project current model position to projection space
        let perspPos = vec4.fromValues(0, 0, 0, 1);
        vec4.transformMat4(perspPos, perspPos, transform.get());
        vec4.transformMat4(perspPos, perspPos, contextCache.cameraObj.getPV());
        // Then move using delta value
        perspPos[0] += deltaX * perspPos[3];
        perspPos[1] += deltaY * perspPos[3];
        // Inverse-project to world space
        vec4.transformMat4(perspPos, perspPos, contextCache.cameraObj.
          getInverseProjection());
        vec4.transformMat4(perspPos, perspPos, contextCache.cameraObj.
          transform.get());
        // Last, write the pos to transform
        vec3.copy(transform.position, perspPos);
        transform.invalidate();
      } else {
        // How much should it move in viewport space in order to move (1, 0, 0)?
        let transform = meshList[selectedId].transform;
        // Project current model position to projection space
        let perspPos = vec4.fromValues(0, 0, 0, 1);
        vec4.transformMat4(perspPos, perspPos, transform.get());
        let addedPos = vec4.create();
        addedPos[3] = 1;
        vec3.add(addedPos, perspPos, alignDir);
        vec4.transformMat4(perspPos, perspPos, contextCache.cameraObj.getPV());
        vec4.transformMat4(addedPos, addedPos, contextCache.cameraObj.getPV());
        let centerPos = vec2.create();
        vec2.copy(centerPos, perspPos);
        vec2.scale(centerPos, centerPos, 1 / perspPos[3]);
        let dirPos = vec2.create();
        vec2.copy(dirPos, addedPos);
        vec2.scale(dirPos, dirPos, 1 / addedPos[3]);
        vec2.subtract(dirPos, dirPos, centerPos);
        let dirNorm = vec2.create();
        vec2.normalize(dirNorm, dirPos);
        // Now we've got everything, calculated required transform length
        // and translate to it
        let projected = vec2.create();
        vec2.subtract(projected, ndc, centerPos);
        vec2.subtract(projected, projected, relativeOffset);
        let dist = vec2.dot(projected, dirNorm);
        let transSize = dist / vec2.length(dirPos);
        let translation = vec3.create();
        vec3.copy(translation, alignDir);
        vec3.scale(translation, translation, transSize);
        vec3.add(transform.position, transform.position, translation);
        transform.invalidate();
      }
    }
  };
}
Ejemplo n.º 10
0
    calcBoneMatrix (index, bone, animation, time, cameraPos, invPlacementMat){
        if (bone.isCalculated) return;
        var boneDefinition = this.m2Geom.m2File.bones[index];
        var parentBone = boneDefinition.parent_bone;
        var animationRecord = this.m2Geom.m2File.animations[animation];

        //2. Calc current transformation matrix

        var tranformMat = mat4.create();
        tranformMat = mat4.identity(tranformMat);

        if (parentBone>=0) {
            this.calcBoneMatrix(parentBone, this.bones[parentBone], animation, time, cameraPos, invPlacementMat);
            mat4.multiply(tranformMat, tranformMat, this.bones[parentBone].tranformMat);
        }

        mat4.translate(tranformMat, tranformMat, [
            boneDefinition.pivot.x,
            boneDefinition.pivot.y,
            boneDefinition.pivot.z,
            0
        ]);

        if (boneDefinition.translation.valuesPerAnimation.length > 0) {
            var transVec = this.getTimedValue(
                0,
                time,
                animationRecord.length,
                animation,
                boneDefinition.translation);

            if (transVec) {
                transVec = mat4.translate(tranformMat, tranformMat, [
                    transVec[0],
                    transVec[1],
                    transVec[2],
                    0
                ]);
                this.isAnimated = true;
            }
        }

        if (((boneDefinition.flags & 0x8) > 0) || ((boneDefinition.flags & 0x40) > 0)) {
            //From http://gamedev.stackexchange.com/questions/112270/calculating-rotation-matrix-for-an-object-relative-to-a-planets-surface-in-monog
            var modelForward = vec3.create();
            var cameraInlocalPos = vec4.create();

            vec4.copy(cameraInlocalPos, cameraPos);
            vec4.transformMat4(cameraInlocalPos, cameraInlocalPos, invPlacementMat);

            if (parentBone>=0) {
                vec4.transformMat4(cameraInlocalPos, cameraInlocalPos, this.bones[parentBone].inverTransforMat);
            }
            vec4.subtract(cameraInlocalPos, cameraInlocalPos, [
                boneDefinition.pivot.x,
                boneDefinition.pivot.y,
                boneDefinition.pivot.z,
                0
            ]);

            vec3.normalize(modelForward, cameraInlocalPos);

            if ((boneDefinition.flags & 0x40) > 0) {
                //Cylindrical billboard

                var modelUp = vec3.fromValues(0,0,1);

                var modelRight = vec3.create();
                vec3.cross(modelRight, modelUp, modelForward);
                vec3.normalize(modelRight, modelRight);

                vec3.cross(modelForward, modelRight, modelUp);
                vec3.normalize(modelForward, modelForward);

                vec3.cross(modelRight, modelUp, modelForward);
                vec3.normalize(modelRight, modelRight);

            } else {
                //Spherical billboard
                var modelRight = vec3.create();
                vec3.cross(modelRight, [0, 0, 1], modelForward);
                vec3.normalize(modelRight, modelRight);

                var modelUp = vec3.create();
                vec3.cross(modelUp, modelForward, modelRight);
                vec3.normalize(modelUp, modelUp);
            }


            mat4.multiply(tranformMat, tranformMat,
                [
                    modelForward[0],modelForward[1],modelForward[2],0,
                    modelRight[0],modelRight[1],modelRight[2],0,
                    modelUp[0],modelUp[1],modelUp[2],0,
                    0,0,0,1
                ]);
            this.isAnimated = true;
        } else if (boneDefinition.rotation.valuesPerAnimation.length > 0) {

            var quaternionVec4 = this.getTimedValue(
                1,
                time,
                animationRecord.length,
                animation,
                boneDefinition.rotation);

            if (quaternionVec4) {
                var orientMatrix = mat4.create();
                mat4.fromQuat(orientMatrix, quaternionVec4 );
                mat4.multiply(tranformMat, tranformMat, orientMatrix);
                this.isAnimated = true;
            }
        }

        if (boneDefinition.scale.valuesPerAnimation.length > 0) {

            var scaleVec3 = this.getTimedValue(
                0,
                time,
                animationRecord.length,
                animation,
                boneDefinition.scale);

            if (scaleVec3) {
                mat4.scale(tranformMat, tranformMat, [
                        scaleVec3[0],
                        scaleVec3[1],
                        scaleVec3[2]
                    ]
                );
            }
            this.isAnimated = true;
        }

        mat4.translate(tranformMat, tranformMat, [
            -boneDefinition.pivot.x,
            -boneDefinition.pivot.y,
            -boneDefinition.pivot.z,
            0
        ]);

        var invertTransformMat = mat4.create();
        mat4.invert(invertTransformMat, tranformMat);
        bone.tranformMat = tranformMat;
        bone.inverTransforMat = invertTransformMat;
    }
Ejemplo n.º 11
0
function setTexture(gl, shaderProgram, texture) {
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, texture._texture);
  gl.uniform1i(shaderProgram.uSampler, 0);
}


function setDepth(gl, shaderProgram, layerZ, tileZ) {
  var depth = (((layerZ + 1) * MAX_LEVELS) - tileZ) / (MAX_LEVELS * MAX_LAYERS);
  gl.uniform1f(shaderProgram.uDepth, depth);
}


var defaultOpacity = 1.0;
var defaultColorOffset = vec4.create();
var defaultColorMatrix = mat4.create();
mat4.identity(defaultColorMatrix);

function setupPixelEffectUniforms(gl, effects, uniforms) {
  var opacity = defaultOpacity;
  if (effects && effects.opacity != null) {
    opacity = effects.opacity;
  }
  gl.uniform1f(uniforms.opacity, opacity);

  var colorOffset = defaultColorOffset;
  if (effects && effects.colorOffset) {
    colorOffset = effects.colorOffset;
  }
  gl.uniform4fv(uniforms.colorOffset, colorOffset);