目录
- 1. math
- shader attribute属性 的一些预定义的名字
- VertexFormat
- IndexBuffer
- VertexBuffer
- Program
- Texture
- Texture2D
- TextureCube
- RenderBuffer
- FrameBuffer
- State
- _type2uniformCommit、_type2uniformArrayCommit
一组方便传递 uniform 变量值的函数. - _commitBlendStates、_commitDepthStates、_commitStencilStates、_commitCullMode
如果上一帧的渲染管线状态和当前即将渲染的管线状态不一致, 则需要更新. - _commitVertexBuffers
提交顶点 buffer 给 vertex shader - _commitTextures
激活绑定纹理单元. 可能会绑定多个. - _attach(gl, location, attachment, face)
- Device
- gfx
- InputAssembler
- Pass
- stage 的名字和id 的记录.
- Technique (这里不讨论3d)
- Effect (这里不讨论3d)
- createIA
- View
- Light
- Camera
- Model 略
- TimSort
- FixedArray
- Pool
- LinkedArray
- RecyclePool
- Scene
- ProgramLib
- Base
- renderer
- 创建 ForwardRenderer 的shader 模板
- BaseRenderData
- RenderData
- IARenderData
- Asset Texture Material
- SpriteMaterial
- GraySpriteMaterial
- StencilMaterial
- Device$2 Texture2D$2
- renderEngine
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)
- 可以绑定 texture2d 到 framebuffer
- 可以绑定 textureCube 到 framebuffer
- 可以把 renderbuffer 挂到 framebuffer上.
Device
webgl context的封装.
- 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;
};
- 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的最大数
- 记录渲染的情况
this._stats = {
texture: 0,
vb: 0,
ib: 0,
drawcalls: 0,
};
- 创建了两个 State.
用来记录当前的状态(即上一帧的渲染状态),和当前帧的渲染状态(未渲染).
this._current = new State(this);
this._next = new State(this);
- 设置渲染的状态.
一堆 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 方法
- 提交数据给 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);
}
- 使用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;
}
- 提交纹理
// commit texture/sampler
_commitTextures(gl, cur, next);
- 提交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);
}
- 开始绘制
// 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
);
}
- 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
图元装配
- 包含的 vertexbuffer
- 包含的 indexbuffer
- 怎么绘制? 直线/三角形/三角形带 等.
- 绘制时的开始位置和数量
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.
如:
- gray_sprite // GraySpriteMaterial
- 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 略
- cullingMask 决定摄像机会渲染场景的哪一部分。
- targetTexture 摄像机渲染的目标 RenderTexture.
用来做渲染到纹理.
TimSort
排序算法
FixedArray
就是个 数组
Pool
池,通过构造函数的 fn去创建对象.
LinkedArray
就是个链表
RecyclePool
和 FixedArray 有点像. 也是对数组的封装.
Scene
和 cc.director.getScene() 这个返回的scene不一样.
这个 Scene 3d场景, 暂时不管.
ProgramLib
- 主要关注,创建 ProgramLib 的 templates 和 chunks格式.
- define方法中, defines 的作用.
会将此方法提供的参数,构造成一个 template 存起来. 用来生成 shader program.
programLib.define('foobar', vertTmpl, fragTmpl, [
{ name: 'shadow' },
{ name: 'lightCount', min: 1, max: 4 }
]);
- 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
一个渲染基类
- _registerStage 方法
this._stage2fn[name] = fn;
在渲染的某个stage,会调用这个 fn.
2d 的 transparent stage,就调用了这个方法注册. 后面会有介绍.
Base.prototype._render = function _render (view, scene) 方法
此方法 只是渲染在 view 的位置 渲染scene.
- 设置 framebuffer
device.setFrameBuffer(view._framebuffer);
setup viewport、setup clear
- 根据模型和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);
}
}
- 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;
}
- 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
- 获取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));
}
set technique uniforms.
就是更新 item上 technique 的 _parameters. 都是 uniform 类型.- 执行 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的流程:
- 创建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
);
- 创建technique
var mainTech = new renderer.Technique(
['transparent'],
[
// 表示shader里面使用到的 uniform 变量
{ name: 'texture', type: renderer.PARAM_TEXTURE_2D },
{ name: 'color', type: renderer.PARAM_COLOR4 } ],
[
pass
]
);
- 创建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 来进行组织数据和渲染的.