目录

1. math

var math = Object.freeze({
  bits: bits,
  vec2: vec2,
  vec3: vec3,
  vec4: vec4,
  quat: quat,
  mat2: mat2,
  mat23: mat23,
  mat3: mat3,
  mat4: mat4,
  color3: color3,
  color4: color4,
  EPSILON: EPSILON,
  equals: equals,
  approx: approx,
  clamp: clamp,
  clamp01: clamp01,
  lerp: lerp,
  toRadian: toRadian,
  toDegree: toDegree,
  random: random,
  randomRange: randomRange,
  randomRangeInt: randomRangeInt,
  nextPow2: nextPow2
});

shader attribute属性 的一些预定义的名字

ATTR_POSITION: 'a_position',
ATTR_NORMAL: 'a_normal',
ATTR_TANGENT: 'a_tangent',
ATTR_BITANGENT: 'a_bitangent',
ATTR_WEIGHTS: 'a_weights',
ATTR_JOINTS: 'a_joints',
ATTR_COLOR: 'a_color',
ATTR_COLOR0: 'a_color0',
ATTR_COLOR1: 'a_color1',
ATTR_UV: 'a_uv',
ATTR_UV0: 'a_uv0',
ATTR_UV1: 'a_uv1',
ATTR_UV2: 'a_uv2',
ATTR_UV3: 'a_uv3',
ATTR_UV4: 'a_uv4',
ATTR_UV5: 'a_uv5',
ATTR_UV6: 'a_uv6',
ATTR_UV7: 'a_uv7',

VertexFormat

attribute属性的布局. 主要看构造的时候,参数infos的构造形式.
每个 element的 stream(-1) 属性作用是什么??
就是 vertexbuffer 自己的索引,最大为3. 个数为4.

//在 Device::_initCaps 方法里 声明.
this._caps.maxVertexStreams = 4;

就是一次提交的数据中,最多包含4个 vertexbuffer.

IndexBuffer

根据数据创建并且更新 indexbuffer

VertexBuffer

根据数据创建并且更新 vertexBuffer

Program

shader program对象.
主要存储了:

this._attributes = [];
this._uniforms = [];
this._samplers = [];

//对于 attribute:
this$1._attributes.push({
  name: info.name,
  location: location,
  type: info.type,
});

// 对于 uniform
this$1._uniforms.push({
  name: name,
  location: location$1,
  type: info$1.type,
  size: isArray ? info$1.size : undefined, // used when uniform is an array
});
  

Texture

只是纹理参数等配置. 被2d纹理 cube纹理继承

Texture2D

单个2d纹理. 在update中,会绑定到纹理单元0.

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, this._glID);

TextureCube

和 Texture2D 作用类似,在update中绑定纹理单元0.

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, this._glID);

RenderBuffer

创建renderbuffer,然后分配了内存. 其余啥事没干.

FrameBuffer

创建了 framebuffer. 啥事没干.

State

1.包含一组 webgl 渲染管线的状态.
2.还存储了顶点buffer、纹理单元

this.vertexBuffers = new Array(device._caps.maxVertexStreams);
this.vertexBufferOffsets = new Array(device._caps.maxVertexStreams);
this.textureUnits = new Array(device._caps.maxTextureUnits);

_type2uniformCommit、_type2uniformArrayCommit
一组方便传递 uniform 变量值的函数.

_commitBlendStates、_commitDepthStates、_commitStencilStates、_commitCullMode
如果上一帧的渲染管线状态和当前即将渲染的管线状态不一致, 则需要更新.

_commitVertexBuffers
提交顶点 buffer 给 vertex shader

_commitTextures
激活绑定纹理单元. 可能会绑定多个.

_attach(gl, location, attachment, face)

  1. 可以绑定 texture2d 到 framebuffer
  2. 可以绑定 textureCube 到 framebuffer
  3. 可以把 renderbuffer 挂到 framebuffer上.

Device

webgl context的封装.

  1. context attribute
// https://www.khronos.org/registry/webgl/specs/1.0.3/#WEBGLCONTEXTATTRIBUTES
dictionary WebGLContextAttributes {
    GLboolean alpha = true;
    GLboolean depth = true;
    GLboolean stencil = false;
    GLboolean antialias = true;
    GLboolean premultipliedAlpha = true;
    GLboolean preserveDrawingBuffer = false;
    GLboolean preferLowPowerToHighPerformance = false;
    GLboolean failIfMajorPerformanceCaveat = false;
};
  1. webgl 扩展
  this._initExtensions([
    'EXT_texture_filter_anisotropic',
    'EXT_shader_texture_lod',
    'OES_standard_derivatives',
    'OES_texture_float',
    'OES_texture_float_linear',
    'OES_texture_half_float',
    'OES_texture_half_float_linear',
    'OES_vertex_array_object',
    'WEBGL_compressed_texture_atc',
    'WEBGL_compressed_texture_etc1',
    'WEBGL_compressed_texture_pvrtc',
    'WEBGL_compressed_texture_s3tc',
    'WEBGL_depth_texture',
    'WEBGL_draw_buffers' ]);

    // _initCaps()下
    // this._caps.maxVertexStreams = 4;  vertexbuffer的最大数
  1. 记录渲染的情况
 this._stats = {
    texture: 0,
    vb: 0,
    ib: 0,
    drawcalls: 0,
  };
  1. 创建了两个 State.
    用来记录当前的状态(即上一帧的渲染状态),和当前帧的渲染状态(未渲染).
  this._current = new State(this);
  this._next = new State(this);
  1. 设置渲染的状态.
    一堆 webgl 函数的封装,都是对 next state的设置.
    setFrameBuffer
    setViewport
    setScissor
    clear
    enableBlend
    enableDepthTest
    enableDepthWrite
    enableStencilTest
    setStencilFunc
    setStencilFuncFront
    setStencilFuncBack
    setStencilOp
    setStencilOpFront
    setStencilOpBack
    setDepthFunc
    setBlendColor32
    setBlendColor
    setBlendFunc
    setBlendFuncSep
    setBlendEq
    setBlendEqSep
    setCullMode
  • setVertexBuffer/setIndexBuffer/setTexture/setTextureArray. 关注参数怎么传数据.

setProgram

  • setUniform
    不是提交 uniform 变量,而是更新 this._uniforms 对象里面的数据.

setPrimitiveType

devide draw 方法

  1. 提交数据给 device里面的 next state.
// commit blend
_commitBlendStates(gl, cur, next);

// commit depth
_commitDepthStates(gl, cur, next);

// commit stencil
_commitStencilStates(gl, cur, next);

// commit cull
_commitCullMode(gl, cur, next);

// commit vertex-buffer
_commitVertexBuffers(this, gl, cur, next);

// commit index-buffer
if (cur.indexBuffer !== next.indexBuffer) {
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, next.indexBuffer ? next.indexBuffer._glID : null);
}
  1. 使用shader program
  // commit program
  var programDirty = false;
  if (cur.program !== next.program) {
    if (next.program._linked) {
      gl.useProgram(next.program._glID);
    } else {
      console.warn('Failed to use program: has not linked yet.');
    }
    programDirty = true;
  }
  1. 提交纹理
// commit texture/sampler
_commitTextures(gl, cur, next);
  1. 提交uniform 变量
  // commit uniforms
  for (var i = 0; i < next.program._uniforms.length; ++i) {
    var uniformInfo = next.program._uniforms[i];
    var uniform = this$1._uniforms[uniformInfo.name];
    if (!uniform) {
      // console.warn(`Can not find uniform ${uniformInfo.name}`);
      continue;
    }

    if (!programDirty && !uniform.dirty) {
      continue;
    }

    uniform.dirty = false;

    // TODO: please consider array uniform: uniformInfo.size > 0

    var commitFunc = (uniformInfo.size === undefined) ? _type2uniformCommit[uniformInfo.type] : _type2uniformArrayCommit[uniformInfo.type];
    if (!commitFunc) {
      console.warn(("Can not find commit function for uniform " + (uniformInfo.name)));
      continue;
    }

    commitFunc(gl, uniformInfo.location, uniform.value);
  }
  1. 开始绘制
  // drawPrimitives
  if (next.indexBuffer) {
    gl.drawElements(
      this._next.primitiveType,
      count,
      next.indexBuffer._format,
      base * next.indexBuffer._bytesPerIndex
    );
  } else {
    gl.drawArrays(
      this._next.primitiveType,
      base,
      count
    );
  }
  1. drawcall + 1,更新 state
  // update stats
  this._stats.drawcalls += 1;

  // reset states
  cur.set(next);
  next.reset();

gfx

内容上面都有

var gfx = {
  // classes
  VertexFormat: VertexFormat,
  IndexBuffer: IndexBuffer,
  VertexBuffer: VertexBuffer,
  Program: Program,
  Texture: Texture,
  Texture2D: Texture2D,
  TextureCube: TextureCube,
  RenderBuffer: RenderBuffer,
  FrameBuffer: FrameBuffer,
  Device: Device,

  // functions
  attrTypeBytes: attrTypeBytes,
  glFilter: glFilter,
  glTextureFmt: glTextureFmt,
};
Object.assign(gfx, enums$1);

InputAssembler

图元装配

  1. 包含的 vertexbuffer
  2. 包含的 indexbuffer
  3. 怎么绘制? 直线/三角形/三角形带 等.
  4. 绘制时的开始位置和数量
  this._vertexBuffer = vb;
  this._indexBuffer = ib;
  this._primitiveType = pt;
  this._start = 0;
  this._count = -1;

Pass

一次绘制的管线状态.

stage 的名字和id 的记录.

var _stageOffset = 0;
var _name2stageID = {};

var config = {
  addStage: function (name) {
    // already added
    if (_name2stageID[name] !== undefined) {
      return;
    }

    var stageID = 1 << _stageOffset;
    _name2stageID[name] = stageID;

    _stageOffset += 1;
  },

  stageID: function (name) {
    var id = _name2stageID[name];
    if (id === undefined) {
      return -1;
    }
    return id;
  },

  stageIDs: function (nameList) {
    var key = 0;
    for (var i = 0; i < nameList.length; ++i) {
      var id = _name2stageID[nameList[i]];
      if (id !== undefined) {
        key |= id;
      }
    }
    return key;
  }
};

Technique (这里不讨论3d)

在 creator 里, 2d的绘制,
Technique 里面都只一个 pass. 并且都处于 transparent 这个 stage.
如:

  1. gray_sprite // GraySpriteMaterial
  2. sprite // SpriteMaterial/StencilMaterial

Effect (这里不讨论3d)

在 creator 里, 2d的绘制,
就包含一个 technique,
创建 Effect,参见 GraySpriteMaterial/SpriteMaterial/StencilMaterial

createIA

根据参数,创建一个 InputAssembler. 需要注意 参数data 的格式.
data:{
positions:[v0x,v0y,v0z,v1x,v1y,v1z,...],
normals:
uv:
}
里面包含了创建 VertexBuffer IndexBuffer 所需要的数据类型和格式.

function createIA(device, data) {
  if (!data.positions) {
    console.error('The data must have positions field');
    return null;
  }

  var verts = [];
  var vcount = data.positions.length / 3;

  for (var i = 0; i < vcount; ++i) {
    verts.push(data.positions[3 * i], data.positions[3 * i + 1], data.positions[3 * i + 2]);

    if (data.normals) {
      verts.push(data.normals[3 * i], data.normals[3 * i + 1], data.normals[3 * i + 2]);
    }

    if (data.uvs) {
      verts.push(data.uvs[2 * i], data.uvs[2 * i + 1]);
    }
  }

  var vfmt = [];
  vfmt.push({ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 3 });
  if (data.normals) {
    vfmt.push({ name: gfx.ATTR_NORMAL, type: gfx.ATTR_TYPE_FLOAT32, num: 3 });
  }
  if (data.uvs) {
    vfmt.push({ name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 });
  }

  var vb = new gfx.VertexBuffer(
    device,
    new gfx.VertexFormat(vfmt),
    gfx.USAGE_STATIC,
    new Float32Array(verts),
    vcount
  );

  var ib = null;
  if (data.indices) {
    ib = new gfx.IndexBuffer(
      device,
      gfx.INDEX_FMT_UINT16,
      gfx.USAGE_STATIC,
      new Uint16Array(data.indices),
      data.indices.length
    );
  }

  return new InputAssembler(vb, ib);
}

View

和Camera有点像,主要包含了几个矩阵:

this._matView = mat4.create();
this._matProj = mat4.create();
this._matViewProj = mat4.create();
this._matInvViewProj = mat4.create();

2d下基本用不到

Light

灯光的封装,2d下基本用不到

Camera

制作卷轴类游戏使用.

Model 略

  1. cullingMask 决定摄像机会渲染场景的哪一部分。
  2. targetTexture 摄像机渲染的目标 RenderTexture.
    用来做渲染到纹理.

TimSort

排序算法

FixedArray

就是个 数组

Pool

池,通过构造函数的 fn去创建对象.

LinkedArray

就是个链表

RecyclePool

和 FixedArray 有点像. 也是对数组的封装.

Scene

和 cc.director.getScene() 这个返回的scene不一样.
这个 Scene 3d场景, 暂时不管.

ProgramLib

  1. 主要关注,创建 ProgramLib 的 templates 和 chunks格式.
  2. define方法中, defines 的作用.
    会将此方法提供的参数,构造成一个 template 存起来. 用来生成 shader program.
  programLib.define('foobar', vertTmpl, fragTmpl, [
    { name: 'shadow' },
    { name: 'lightCount', min: 1, max: 4 }
  ]);
  1. getProgram方法中,包含了 shader 代码的组成, 创建 gfx.Program.
ProgramLib.prototype.getProgram = function getProgram (name, defines) {
  var key = this.getKey(name, defines);
  var program = this._cache[key];
  if (program) {
    return program;
  }

  // get template
  var tmpl = this._templates[name];
  var customDef = _generateDefines(defines) + '\n';
  var vert = _replaceMacroNums(tmpl.vert, defines);
  vert = customDef + _unrollLoops(vert);
  var frag = _replaceMacroNums(tmpl.frag, defines);
  frag = customDef + _unrollLoops(frag);

  program = new gfx.Program(this._device, {
    vert: vert,
    frag: frag
  });
  program.link();
  this._cache[key] = program;

  return program;
};

可以在里面打印出 shader 代码,看看是什么样的. TODO

Base

一个渲染基类

  1. _registerStage 方法
this._stage2fn[name] = fn;

在渲染的某个stage,会调用这个 fn.
2d 的 transparent stage,就调用了这个方法注册. 后面会有介绍.

Base.prototype._render = function _render (view, scene) 方法
此方法 只是渲染在 view 的位置 渲染scene.

  1. 设置 framebuffer
device.setFrameBuffer(view._framebuffer);
  1. setup viewport、setup clear

  2. 根据模型和view的_cullingMask, 提取模型的 drawItem,存在 _drawItemsPools里
for (var i = 0; i < scene._models.length; ++i) {
    var model = scene._models.data[i];

    // filter model by view
    if ((model._cullingMask & view._cullingMask) === 0) {
      continue;
    }

    for (var m = 0; m < model.drawItemCount; ++m) {
      var drawItem = this$1._drawItemsPools.add();
      model.extractDrawItem(drawItem, m);
    }
  }
  1. dispatch draw items to different stage
for (var i$1 = 0; i$1 < view._stages.length; ++i$1) {
    var stage = view._stages[i$1];
    var stageItems = this$1._stageItemsPools.add();
    stageItems.reset();

    for (var j = 0; j < this._drawItemsPools.length; ++j) {
      var drawItem$1 = this$1._drawItemsPools.data[j];
      var tech = drawItem$1.effect.getTechnique(stage);

      if (tech) {
        var stageItem = stageItems.add();
        stageItem.model = drawItem$1.model;
        stageItem.node = drawItem$1.node;
        stageItem.ia = drawItem$1.ia;
        stageItem.effect = drawItem$1.effect;
        stageItem.defines = drawItem$1.defines;
        stageItem.technique = tech;
        stageItem.sortKey = -1;
      }
    }

    var stageInfo = _stageInfos.add();
    stageInfo.stage = stage;
    stageInfo.items = stageItems;
  }
  1. render stages
for (var i$2 = 0; i$2 < _stageInfos.length; ++i$2) {
    var info = _stageInfos.data[i$2];
    var fn = this$1._stage2fn[info.stage];

    fn(view, info.items);
  }

Base.prototype._draw = function _draw (item)方法
绘制 item

  1. 获取item的节点node的 模型矩阵,并给device.
    如果存在法线矩阵,顺便也计算出来,传给device
  node.getWorldMatrix(_m4_tmp$2);
  device.setUniform('model', mat4.array(_float16_pool.add(), _m4_tmp$2));

  var inverse = mat3.invert(_m3_tmp$1, mat3.fromMat4(_m3_tmp$1, _m4_tmp$2));
  if (inverse) {
    mat3.transpose(_m3_tmp$1, inverse);
    device.setUniform('normalMatrix', mat3.array(_float9_pool.add(), _m3_tmp$1));
  }
  1. set technique uniforms.
    就是更新 item上 technique 的 _parameters. 都是 uniform 类型.

  2. 执行 item 上 technique的 pass.
    执行一个pass的流程:

a. 设置 vertexbuffer,indexbuffer,primitivetype

    // set vertex buffer
    device.setVertexBuffer(0, ia._vertexBuffer);

    // set index buffer
    if (ia._indexBuffer) {
      device.setIndexBuffer(ia._indexBuffer);
    }

    // set primitive type
    device.setPrimitiveType(ia._primitiveType);

b. 设置 shader program.

    // set program
    var program = programLib.getProgram(pass._programName, defines);
    device.setProgram(program);

c. 设置当前pass里 管线的状态
cullmode, blend ,depthtest, stenciltest.

d. 绘制

    // draw pass
    device.draw(ia._start, count);

renderer

上面都有介绍

var renderer = {
  // config
  addStage: config.addStage,

  // utils
  createIA: createIA,

  // classes
  Pass: Pass,
  Technique: Technique,
  Effect: Effect,
  InputAssembler: InputAssembler,
  View: View,

  Light: Light,
  Camera: Camera,
  Model: Model,
  Scene: Scene,

  Base: Base,
  ProgramLib: ProgramLib,
};
Object.assign(renderer, enums);

注意,在 14589 行, 有:

renderer.addStage('transparent');

直接添加了 transparent 这个stage,目前2d功能也就使用了这一个 stage.

ForwardRenderer

前向渲染. 继承自 Base. 只注册了一个 transparent stage.
这个 stage 的渲染方法: _transparentStage:

ForwardRenderer.prototype._transparentStage = function _transparentStage (view, items) {
    var this$1 = this;

    // update uniforms
    this._device.setUniform('view', mat4.array(_a16_view, view._matView));
    this._device.setUniform('proj', mat4.array(_a16_proj, view._matProj));
    this._device.setUniform('viewProj', mat4.array(_a16_viewProj, view._matViewProj));

    // draw it
    for (var i = 0; i < items.length; ++i) {
      var item = items.data[i];
      this$1._draw(item);
    }
  };

就是给 device 设置了当前的 view,proj,viewProj 矩阵,然后绘制每一个item.

创建 ForwardRenderer 的shader 模板

var templates = [
  {
    name: 'gray_sprite',
    vert: '\n \nuniform mat4 viewProj;\nattribute vec3 a_position;\nattribute mediump vec2 a_uv0;\nvarying mediump vec2 uv0;\nvoid main () {\n  vec4 pos = viewProj * vec4(a_position, 1);\n  gl_Position = pos;\n  uv0 = a_uv0;\n}',
    frag: '\n \nuniform sampler2D texture;\nvarying mediump vec2 uv0;\nuniform lowp vec4 color;\nvoid main () {\n  vec4 c = color * texture2D(texture, uv0);\n  float gray = 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;\n  gl_FragColor = vec4(gray, gray, gray, c.a);\n}',
    defines: [
    ],
  },
  {
    name: 'sprite',
    vert: '\n \nuniform mat4 viewProj;\n#ifdef use2DPos\nattribute vec2 a_position;\n#else\nattribute vec3 a_position;\n#endif\nattribute lowp vec4 a_color;\n#ifdef useModel\n  uniform mat4 model;\n#endif\n#ifdef useTexture\n  attribute mediump vec2 a_uv0;\n  varying mediump vec2 uv0;\n#endif\n#ifndef useColor\nvarying lowp vec4 v_fragmentColor;\n#endif\nvoid main () {\n  mat4 mvp;\n  #ifdef useModel\n    mvp = viewProj * model;\n  #else\n    mvp = viewProj;\n  #endif\n  #ifdef use2DPos\n  vec4 pos = mvp * vec4(a_position, 0, 1);\n  #else\n  vec4 pos = mvp * vec4(a_position, 1);\n  #endif\n  #ifndef useColor\n  v_fragmentColor = a_color;\n  #endif\n  #ifdef useTexture\n    uv0 = a_uv0;\n  #endif\n  gl_Position = pos;\n}',
    frag: '\n \n#ifdef useTexture\n  uniform sampler2D texture;\n  varying mediump vec2 uv0;\n#endif\n#ifdef alphaTest\n  uniform lowp float alphaThreshold;\n#endif\n#ifdef useColor\n  uniform lowp vec4 color;\n#else\n  varying lowp vec4 v_fragmentColor;\n#endif\nvoid main () {\n  #ifdef useColor\n    vec4 o = color;\n  #else\n    vec4 o = v_fragmentColor;\n  #endif\n  #ifdef useTexture\n    o *= texture2D(texture, uv0);\n  #endif\n  #ifdef alphaTest\n    if (o.a <= alphaThreshold)\n      discard;\n  #endif\n  gl_FragColor = o;\n}',
    defines: [
      { name: 'useTexture', },
      { name: 'useModel', },
      { name: 'alphaTest', },
      { name: 'use2DPos', },
      { name: 'useColor', } ],
  } ];

BaseRenderData

/**
 * BaseRenderData is a core data abstraction for renderer, this is a abstract class.
 * An inherited render data type should define raw vertex datas.
 * User should also define the effect, vertex count and index count.
 */
var BaseRenderData = function BaseRenderData () {
    this.material = null;
    this.vertexCount = 0;
    this.indiceCount = 0;
};

自定义渲染的时候,还需要自己定义 effect.
是基础渲染数据的基类.

RenderData

使用最多的 渲染数据,按照 x,y,u,v,color 布局.

IARenderData

/**

  • IARenderData is user customized render data type, user should provide the entier input assembler.
  • IARenderData just defines a property ia for accessing the input assembler.
  • It doesn't manage memory so users should manage the memory of input assembler by themselves.
    */

设置好数据好,指定其 ia 属性就可以进行自定义绘制了.
参见 CustomeIA 的例子.

Asset Texture Material

Asset 材质类的基类
Texture 继承自 Asset, 单一纹理材质. 不包含 Effect.
Material 继承自 Asset, 包含一个 Effect, 自定义材质的时候,继承此类.

SpriteMaterial

用的最多的材质,继承自Material.
里面创建Effect的流程:

  1. 创建pass
var pass = new renderer.Pass('sprite');
    pass.setDepth(false, false);
    pass.setCullMode(gfx.CULL_NONE);
    pass.setBlend(
      gfx.BLEND_FUNC_ADD,
      gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA,
      gfx.BLEND_FUNC_ADD,
      gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA
    );
  1. 创建technique
var mainTech = new renderer.Technique(
      ['transparent'],
      [
        // 表示shader里面使用到的 uniform 变量
        { name: 'texture', type: renderer.PARAM_TEXTURE_2D },
        { name: 'color', type: renderer.PARAM_COLOR4 } ],
      [
        pass
      ]
    );
  1. 创建effect
this._color = {r: 1, g: 1, b: 1, a: 1};
    this._effect = new renderer.Effect(
      [
        mainTech ],
      {
        // 传递上面 声明的 uniform 变量
        'color': this._color
      },
      [
        { name: 'useTexture', value: true },  // shader里面的 #define 的定义
        { name: 'useModel', value: false },
        { name: 'alphaTest', value: false },
        { name: 'use2DPos', value: true },
        { name: 'useColor', value: true } ]
    );

为了清晰,对比下 sprite 的 shader.
sprite vert

uniform mat4 viewProj;

#ifdef use2DPos
attribute vec2 a_position;
#else
attribute vec3 a_position;
#endif

attribute lowp vec4 a_color;

#ifdef useModel
uniform mat4 model;
#endif

#ifdef useTexture
attribute mediump vec2 a_uv0;
varying mediump vec2 uv0;
#endif


#ifndef useColor
varying lowp vec4 v_fragmentColor;
#endif
void main ()
{
    mat4 mvp;
    #ifdef useModel
        mvp = viewProj * model;
    #else
        mvp = viewProj;
    #endif

    #ifdef use2DPos
        vec4 pos = mvp * vec4(a_position, 0, 1);
    #else
        vec4 pos = mvp * vec4(a_position, 1);
    #endif

    #ifndef useColor
         v_fragmentColor = a_color;
    #endif

    #ifdef useTexture
        uv0 = a_uv0;
    #endif

     gl_Position = pos;
}   

sprite frag

#ifdef useTexture
uniform sampler2D texture;
varying mediump vec2 uv0;
#endif

#ifdef alphaTest
uniform lowp float alphaThreshold;
#endif


#ifdef useColor
uniform lowp vec4 color;
#else
varying lowp vec4 v_fragmentColor;
#endif

void main () {

    #ifdef useColor
        vec4 o = color;
    #else
        vec4 o = v_fragmentColor;
    #endif

    #ifdef useTexture
        o *= texture2D(texture, uv0);
    #endif

    #ifdef alphaTest
        if (o.a <= alphaThreshold)
            discard;
    #endif

    gl_FragColor = o;
}   

对比下,变量就很清晰了.
注意:其中精度声明 会在加载编译 shader source之前,加上去.
在 ProgramLib::getProgram 方法里.

GraySpriteMaterial

和 SpriteMaterial 类似. 使用的是 gray_sprite 这个模板.
查看其 shader 代码:

gray_sprite vert:

uniform mat4 viewProj;
attribute vec3 a_position;
attribute mediump vec2 a_uv0;
varying mediump vec2 uv0;
void main () {
  vec4 pos = viewProj * vec4(a_position, 1);
  gl_Position = pos;
  uv0 = a_uv0;
}

gray_sprite frag:

uniform sampler2D texture;
varying mediump vec2 uv0;
uniform lowp vec4 color;
void main () {
  vec4 c = color * texture2D(texture, uv0);
  float gray = 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;
  gl_FragColor = vec4(gray, gray, gray, c.a);
}

自定义 shader 的时候,最好参见 gray_sprite 的代码实现.
自定义材质 参照 GraySpriteMaterial 来实现.

StencilMaterial

和 SpriteMaterial 非常类似.
但是在渲染的时候,有些不同. 说到 Mask 的时候再细说. (TODO)

Device$2 Texture2D$2

Device$2 是 canvas 的 context. 现在好像不使用了.
Texture2D$2 canvas 下图片的简单封装, 略.

renderEngine

最终的声明,导出:

var renderEngine = {
  // core classes
  Device: Device$4,
  ForwardRenderer: ForwardRenderer,
  Texture2D: Texture2D$4,

  // Canvas render support
  canvas: canvas,

  // render scene
  Scene: Scene$2,
  Camera: Camera$2,
  View: View$2,
  Model: Model$2,
  RenderData: RenderData,
  IARenderData: IARenderData,
  InputAssembler: InputAssembler$2,

  // assets
  Asset: Asset,
  TextureAsset: Texture$2,
  Material: Material,

  // materials
  SpriteMaterial: SpriteMaterial,
  GraySpriteMaterial: GraySpriteMaterial,
  StencilMaterial: StencilMaterial,

  // shaders
  shaders: shaders,

  // memop
  RecyclePool: RecyclePool,
  Pool: Pool,

  // modules
  math: math,
  renderer: renderer,
  gfx: gfx,
};

上面基本都有介绍.
有机会再写 creator 里, 是如何使用 renderEngine 来进行组织数据和渲染的.

02-28 12:51