From 14ca74392ccb28a7300a2994178be6a323d285c4 Mon Sep 17 00:00:00 2001 From: zxg <247274249@qq.com> Date: Mon, 16 Dec 2019 18:21:39 +0800 Subject: [PATCH 01/13] refactor material instance --- .../batched-skinning-model-component.ts | 4 +- cocos/core/3d/framework/model-component.ts | 8 +- .../core/3d/framework/renderable-component.ts | 122 +++-- cocos/core/assets/material.ts | 121 ++--- .../components/ui-base/ui-render-component.ts | 33 +- cocos/core/pipeline/render-pipeline.ts | 2 +- cocos/core/renderer/core/material-instance.ts | 162 ++++++ cocos/core/renderer/core/pass-instance.ts | 489 ++++++++++++++++++ cocos/core/renderer/core/pass.ts | 135 ++--- cocos/core/renderer/index.ts | 2 + cocos/core/renderer/models/skinning-model.ts | 12 +- cocos/core/renderer/scene/model.ts | 58 ++- cocos/core/renderer/scene/planar-shadows.ts | 6 +- cocos/core/renderer/scene/render-scene.ts | 8 +- cocos/core/renderer/scene/skybox.ts | 2 +- cocos/core/renderer/scene/submodel.ts | 14 +- cocos/core/renderer/ui/render-data.ts | 3 +- cocos/core/renderer/ui/stencil-manager.ts | 8 +- cocos/core/renderer/ui/ui-batch-model.ts | 5 +- cocos/core/renderer/ui/ui-draw-batch.ts | 16 +- cocos/core/renderer/ui/ui-material.ts | 7 +- cocos/core/renderer/ui/ui.ts | 7 +- cocos/core/utils/material-interface.ts | 135 +++++ cocos/core/utils/pass-interface.ts | 238 +++++++++ cocos/core/utils/profiler/profiler.ts | 9 +- cocos/particle/models/particle-batch-model.ts | 4 +- .../renderer/particle-system-renderer.ts | 24 +- cocos/terrain/terrain.ts | 28 +- cocos/ui/components/graphics-component.ts | 20 +- 29 files changed, 1325 insertions(+), 357 deletions(-) create mode 100644 cocos/core/renderer/core/material-instance.ts create mode 100644 cocos/core/renderer/core/pass-instance.ts create mode 100644 cocos/core/utils/material-interface.ts create mode 100644 cocos/core/utils/pass-interface.ts diff --git a/cocos/core/3d/framework/batched-skinning-model-component.ts b/cocos/core/3d/framework/batched-skinning-model-component.ts index c9d750528ad..7cadd972e1a 100644 --- a/cocos/core/3d/framework/batched-skinning-model-component.ts +++ b/cocos/core/3d/framework/batched-skinning-model-component.ts @@ -81,7 +81,7 @@ export class SkinningModelUnit { if (!comp) { return; } this.mesh = comp.mesh; this.skeleton = comp.skeleton; - this.material = comp.getSharedMaterial(0); + this.material = comp.getMaterial(0); } get copyFrom () { return null; @@ -164,7 +164,7 @@ export class BatchedSkinningModelComponent extends SkinningModelComponent { public cookMaterials () { if (!this._batchMaterial) { - this._batchMaterial = this.getSharedMaterial(0); + this._batchMaterial = this.getMaterial(0); } const mat = this.getMaterial(0); if (!mat || !this._batchMaterial || !this._batchMaterial.effectAsset) { diff --git a/cocos/core/3d/framework/model-component.ts b/cocos/core/3d/framework/model-component.ts index d9b4cb8b860..2293d52f9e3 100644 --- a/cocos/core/3d/framework/model-component.ts +++ b/cocos/core/3d/framework/model-component.ts @@ -133,7 +133,7 @@ export class ModelComponent extends RenderableComponent { } if (this._model) { this._model.isDynamicBatching = enable; - this._model.onPipelineChange(); // update material + this._model.onGlobalPipelineStateChanged(); // update material for (let i = 0; i < this._model.subModels.length; ++i) { const subModel = this._model.subModels[i]; for (let p = 0; p < subModel.passes.length; ++p) { @@ -268,7 +268,7 @@ export class ModelComponent extends RenderableComponent { this._model.isDynamicBatching = this._enableDynamicBatching; // should pass this in before create PSO const meshCount = this._mesh ? this._mesh.subMeshCount : 0; for (let i = 0; i < meshCount; ++i) { - const material = this.getSharedMaterial(i); + const material = this.getRenderMaterial(i); const renderingMesh = this._mesh.renderingMesh; if (renderingMesh) { const subMeshData = renderingMesh.getSubmesh(i); @@ -280,7 +280,7 @@ export class ModelComponent extends RenderableComponent { } protected _onMaterialModified (idx: number, material: Material | null) { - if (this._model == null) { + if (this._model == null || !this._model.inited) { return; } this._onRebuildPSO(idx, material || this._getBuiltinMaterial()); @@ -298,7 +298,7 @@ export class ModelComponent extends RenderableComponent { } protected _onRebuildPSO (idx: number, material: Material) { - if (this._model) { + if (this._model && this._model.inited) { this._model.setSubModelMaterial(idx, material); } } diff --git a/cocos/core/3d/framework/renderable-component.ts b/cocos/core/3d/framework/renderable-component.ts index 1eb5b3f8c8c..09447ce10c5 100644 --- a/cocos/core/3d/framework/renderable-component.ts +++ b/cocos/core/3d/framework/renderable-component.ts @@ -6,8 +6,10 @@ import { Material } from '../../assets/material'; import { Component } from '../../components/component'; import { _decorator } from '../../data/index'; +import { MaterialInstance } from '../../renderer/core/material-instance'; import { Model } from '../../renderer/scene/model'; import { Layers } from '../../scene-graph/layers'; +import { IMaterial } from '../../utils/material-interface'; const { ccclass, property } = _decorator; @ccclass('cc.RenderableComponent') @@ -18,6 +20,8 @@ export class RenderableComponent extends Component { }) protected _materials: Array = []; + protected _materialInstances: Array = []; + @property protected _visFlags = Layers.Enum.NONE; @@ -41,17 +45,49 @@ export class RenderableComponent extends Component { set sharedMaterials (val) { for (let i = 0; i < val.length; i++) { if (val[i] !== this._materials[i]) { - this.setMaterial(val[i], i); + this.setMaterial(i, val[i]); } } if (val.length < this._materials.length) { for (let i = val.length; i < this._materials.length; i++) { - this.setMaterial(null, i); + this.setMaterial(i, null); } this._materials.splice(val.length); } } + get sharedMaterial () { + return this.getMaterial(0); + } + + /** + * 获取指定的sharedMaterial + * @param idx 材质序号 + */ + public getMaterial (idx: number): Material | null { + if (idx < 0 || idx >= this._materials.length) { + return null; + } + return this._materials[idx]; + } + + /** + * 设置指定的sharedMaterial,如果对应位置有材质实例则会创建一个对应的材质实例 + * @param index 材质序号 + * @param material 材质对象 + */ + public setMaterial (index: number, material: Material | null) { + this._materials[index] = material; + if (this._materialInstances[index]) { + if (this._materialInstances[index]!.parent !== material) { + this.getMaterialInstance(index); + this._onMaterialModified(index, material); + } + } else { + this._onMaterialModified(index, material); + } + } + /** * @en The material of the model * @zh 模型材质。 @@ -64,7 +100,7 @@ export class RenderableComponent extends Component { }) get materials () { for (let i = 0; i < this._materials.length; i++) { - this._materials[i] = this.getMaterial(i)!; + this._materialInstances[i] = this.getMaterialInstance(i) as MaterialInstance; } return this._materials; } @@ -75,47 +111,64 @@ export class RenderableComponent extends Component { this._materials = this._materials.concat(new Array(dLen).fill(null)); } else if (dLen < 0) { for (let i = -dLen; i < this._materials.length; ++i) { - this.setMaterial(null, i); + this.setMaterialInstance(i, null); } this._materials = this._materials.splice(-dLen); } } + get material () { + return this.getMaterialInstance(0); + } + + set material (val) { + if (this._materials.length === 1 && this._materials[0] === val) { + return; + } + this.setMaterialInstance(0, val); + } + /** - * @en Returns the material corresponding to the sequence number - * @zh 返回相对应序号的材质。 + * @en Returns the material instance corresponding to the sequence number + * @zh 获取相对应序号的材质实例。 * @param {Number} idx - Look for the material list number */ - public getMaterial (idx: number, inEditor: boolean = CC_EDITOR, autoUpdate: boolean = false): Material | null { + public getMaterialInstance (idx: number): IMaterial | null { const mat = this._materials[idx]; - if (!mat) { return null; } - const instantiated = Material.getInstantiatedMaterial(mat, this, inEditor); - if (instantiated !== this._materials[idx]) { - this.setMaterial(instantiated, idx, autoUpdate || !inEditor); - } - return this._materials[idx]; - } - - public getSharedMaterial (idx: number): Material | null { - if (idx < 0 || idx >= this._materials.length) { + if (!mat) { return null; } - return this._materials[idx]; - } - - get material () { - return this.getMaterial(0); + if (this._materialInstances[idx] == null) { + const instantiated = new MaterialInstance(this._materials[idx]!, this); + this.setMaterialInstance(idx, instantiated); + } + return this._materialInstances[idx]; } - set material (val) { - if (this._materials.length === 1 && this._materials[0] === val) { - return; + /** + * 设置对应序号的材质实例 + * @param index 材质序号 + * @param matInst 材质实例 + */ + public setMaterialInstance (index: number, matInst: IMaterial | null) { + if (matInst && matInst.parent) { + if (matInst !== this._materialInstances[index]) { + this._materialInstances[index] = matInst as MaterialInstance; + this._onMaterialModified(index, matInst); + } + } else { + if (matInst !== this._materials[index]) { + this.setMaterial(index, matInst as Material); + } } - this.setMaterial(val, 0); } - get sharedMaterial () { - return this.getSharedMaterial(0); + /** + * 获取指定位置可供渲染的材质,如果有材质实例则使用材质实例,如果没有则使用材质资源 + * @param index 材质序号 + */ + public getRenderMaterial (index: number): IMaterial | null { + return this._materialInstances[index] || this._materials[index]; } @property({ visible: false }) @@ -128,24 +181,17 @@ export class RenderableComponent extends Component { this._onVisiblityChange(val); } - public setMaterial (material: Material | null, index: number, notify: boolean = true) { - this._materials[index] = material; - if (notify) { - this._onMaterialModified(index, material); - } - } - public _collectModels (): Model[] { return this._models; } - protected _attachToScene() { + protected _attachToScene () { } - protected _detachFromScene() { + protected _detachFromScene () { } - protected _onMaterialModified (index: number, material: Material | null) { + protected _onMaterialModified (index: number, material: IMaterial | null) { } diff --git a/cocos/core/assets/material.ts b/cocos/core/assets/material.ts index e1dc304ebf8..1df1ffb50bc 100644 --- a/cocos/core/assets/material.ts +++ b/cocos/core/assets/material.ts @@ -29,17 +29,12 @@ */ import { ccclass, property } from '../../core/data/class-decorator'; -import { murmurhash2_32_gc } from '../../core/utils/murmurhash2_gc'; import { builtinResMgr } from '../3d/builtin/init'; import { RenderableComponent } from '../3d/framework/renderable-component'; -import { GFXBindingType } from '../gfx/define'; -import { GFXTextureView } from '../gfx/texture-view'; import { IDefineMap, Pass, PassOverrides } from '../renderer/core/pass'; -import { samplerLib } from '../renderer/core/sampler-lib'; +import { _uploadProperty, generateMaterailHash, IMaterial } from '../utils/material-interface'; import { Asset } from './asset'; import { EffectAsset } from './effect-asset'; -import { SpriteFrame } from './sprite-frame'; -import { TextureBase } from './texture-base'; /** * @zh @@ -79,40 +74,7 @@ interface IMaterialInfo { * 材质资源类,负责指定每个模型的材质信息。 */ @ccclass('cc.Material') -export class Material extends Asset { - /** - * @zh - * 获取材质资源的实例,应当不会需要手动调用这个函数。 - */ - public static getInstantiatedMaterial (mat: Material, rndCom: RenderableComponent, inEditor: boolean) { - if (mat._owner === rndCom) { - return mat; - } else { - const instance = new Material(); - instance.copy(mat); - instance._native = mat._native + ' (Instance)'; - instance._owner = rndCom; - if (inEditor) { - instance._uuid = mat._uuid; - } - return instance; - } - } - - @property(EffectAsset) - protected _effectAsset: EffectAsset | null = null; - @property - protected _techIdx = 0; - @property - protected _defines: IDefineMap[] = []; - @property - protected _states: PassOverrides[] = []; - @property - protected _props: Array> = []; - - protected _passes: Pass[] = []; - protected _owner: RenderableComponent | null = null; - protected _hash = 0; +export class Material extends Asset implements IMaterial { /** * @zh @@ -154,6 +116,28 @@ export class Material extends Asset { return this._hash; } + get parent (): IMaterial | null { + return null; + } + + get owner (): RenderableComponent | null { + return null; + } + + @property(EffectAsset) + protected _effectAsset: EffectAsset | null = null; + @property + protected _techIdx = 0; + @property + protected _defines: IDefineMap[] = []; + @property + protected _states: PassOverrides[] = []; + @property + protected _props: Array> = []; + + protected _passes: Pass[] = []; + protected _hash = 0; + constructor () { super(); this.loaded = false; @@ -229,7 +213,6 @@ export class Material extends Asset { } else { this._passes[passIdx].tryCompile(overrides); } - this._onPassesChange(); } /** @@ -251,7 +234,6 @@ export class Material extends Asset { this._states[passIdx] = overrides; this._passes[passIdx].overridePipelineStates(passInfos[passIdx], overrides); } - this._onPassesChange(); } /** @@ -283,7 +265,7 @@ export class Material extends Asset { const len = passes.length; for (let i = 0; i < len; i++) { const pass = passes[i]; - if (this._uploadProperty(pass, name, val)) { + if (_uploadProperty(pass, name, val)) { this._props[i][name] = val; success = true; } @@ -291,7 +273,7 @@ export class Material extends Asset { } else { if (passIdx >= this._passes.length) { console.warn(`illegal pass index: ${passIdx}.`); return; } const pass = this._passes[passIdx]; - if (this._uploadProperty(pass, name, val)) { + if (_uploadProperty(pass, name, val)) { this._props[passIdx][name] = val; success = true; } @@ -351,6 +333,10 @@ export class Material extends Asset { this._update(); } + public _onPassStateChanged () { + this._hash = generateMaterailHash(this); + } + protected _prepareInfo (patch: object | object[], cur: object[]) { if (!Array.isArray(patch)) { // fill all the passes if not specified const len = this._effectAsset ? this._effectAsset.techniques[this._techIdx].passes.length : 1; @@ -381,7 +367,7 @@ export class Material extends Asset { let props = this._props[pass.idxInTech]; if (!props) { props = this._props[i] = {}; } for (const p in props) { - this._uploadProperty(pass, p, props[p]); + _uploadProperty(pass, p, props[p]); } }); } else { @@ -391,50 +377,7 @@ export class Material extends Asset { const missing = builtinResMgr.get('missing-effect-material'); if (missing) { this._passes = missing._passes.slice(); } } - this._onPassesChange(); - } - - protected _uploadProperty (pass: Pass, name: string, val: any) { - const handle = pass.getHandle(name); - if (handle === undefined) { return false; } - const bindingType = Pass.getBindingTypeFromHandle(handle); - if (bindingType === GFXBindingType.UNIFORM_BUFFER) { - if (Array.isArray(val)) { - pass.setUniformArray(handle, val); - } else { - pass.setUniform(handle, val); - } - } else if (bindingType === GFXBindingType.SAMPLER) { - const binding = Pass.getBindingFromHandle(handle); - if (val instanceof GFXTextureView) { - pass.bindTextureView(binding, val); - } else if (val instanceof TextureBase || val instanceof SpriteFrame) { - const textureView: GFXTextureView | null = val.getGFXTextureView(); - if (!textureView || !textureView.texture.width || !textureView.texture.height) { - // console.warn(`material '${this._uuid}' received incomplete texture asset '${val._uuid}'`); - return false; - } - pass.bindTextureView(binding, textureView); - if (val instanceof TextureBase) { - pass.bindSampler(binding, samplerLib.getSampler(cc.game._gfxDevice, val.getSamplerHash())); - } - } - } - return true; - } - - protected _onPassesChange () { - let str = ''; - for (const pass of this._passes) { - str += Pass.getPSOHash(pass); - } - this._hash = murmurhash2_32_gc(str, 666); - if (this._owner) { - const comp = this._owner; - const index = comp.sharedMaterials.findIndex((m) => m === this); - // @ts-ignore - if (index >= 0) { comp._onRebuildPSO(index, this); } - } + this._hash = generateMaterailHash(this); } } diff --git a/cocos/core/components/ui-base/ui-render-component.ts b/cocos/core/components/ui-base/ui-render-component.ts index 963ba6ee8d3..4a6b558fa15 100644 --- a/cocos/core/components/ui-base/ui-render-component.ts +++ b/cocos/core/components/ui-base/ui-render-component.ts @@ -27,22 +27,21 @@ * @category ui */ -import { - ccclass, - property, -} from '../../../core/data/class-decorator'; -import { SystemEventType } from '../../../core/platform/event-manager/event-enum'; +import { RenderableComponent } from '../../../core/3d/framework/renderable-component'; +import { ccclass, property } from '../../../core/data/class-decorator'; import { Color } from '../../../core/math'; +import { SystemEventType } from '../../../core/platform/event-manager/event-enum'; import { ccenum } from '../../../core/value-types/enum'; +import { Material } from '../../assets'; import { GFXBlendFactor } from '../../gfx/define'; +import { MaterialInstance } from '../../renderer'; +import { IAssembler, IAssemblerManager } from '../../renderer/ui/base'; import { RenderData } from '../../renderer/ui/render-data'; import { UI } from '../../renderer/ui/ui'; -import { Material } from '../../assets'; -import { RenderableComponent } from '../../../core/3d/framework/renderable-component'; -import { IAssembler, IAssemblerManager } from '../../renderer/ui/base'; -import { UIComponent } from './ui-component'; -import { TransformBit } from '../../scene-graph/node-enum'; import { Node } from '../../scene-graph'; +import { TransformBit } from '../../scene-graph/node-enum'; +import { IMaterial } from '../../utils/material-interface'; +import { UIComponent } from './ui-component'; // hack ccenum(GFXBlendFactor); @@ -226,7 +225,7 @@ export class UIRenderComponent extends UIComponent { protected _renderFlag = true; // 特殊渲染节点,给一些不在节点树上的组件做依赖渲染(例如 mask 组件内置两个 graphics 来渲染) protected _delegateSrc: Node | null = null; - protected _material: Material | null = null; + protected _material: IMaterial | null = null; protected _instanceMaterialType = InstanceMaterialType.ADDCOLORANDTEXTURE; protected _blendTemplate = { blendState: { @@ -360,7 +359,7 @@ export class UIRenderComponent extends UIComponent { } } - protected _updateMaterial (material: Material | null) { + protected _updateMaterial (material: IMaterial | null) { this._material = material; this._updateBlendFunc(); @@ -396,19 +395,19 @@ export class UIRenderComponent extends UIComponent { } protected _instanceMaterial () { - let mat: Material | null = null; + let mat: IMaterial | null = null; if (this._sharedMaterial) { - mat = Material.getInstantiatedMaterial(this._sharedMaterial, new RenderableComponent(), CC_EDITOR ? true : false); + mat = new MaterialInstance(this._sharedMaterial, new RenderableComponent()); } else { switch (this._instanceMaterialType){ case InstanceMaterialType.ADDCOLOR: - mat = Material.getInstantiatedMaterial(cc.builtinResMgr.get('ui-base-material'), new RenderableComponent(), CC_EDITOR ? true : false); + mat = new MaterialInstance(cc.builtinResMgr.get('ui-base-material'), new RenderableComponent()); break; case InstanceMaterialType.ADDCOLORANDTEXTURE: - mat = Material.getInstantiatedMaterial(cc.builtinResMgr.get('ui-sprite-material'), new RenderableComponent(), CC_EDITOR ? true : false); + mat = new MaterialInstance(cc.builtinResMgr.get('ui-sprite-material'), new RenderableComponent()); break; case InstanceMaterialType.GRAYSCALE: - mat = Material.getInstantiatedMaterial(cc.builtinResMgr.get('ui-sprite-gray-material'), new RenderableComponent(), CC_EDITOR ? true : false); + mat = new MaterialInstance(cc.builtinResMgr.get('ui-sprite-gray-material'), new RenderableComponent()); break; } } diff --git a/cocos/core/pipeline/render-pipeline.ts b/cocos/core/pipeline/render-pipeline.ts index 2b360d0eebe..eb3559e40a0 100644 --- a/cocos/core/pipeline/render-pipeline.ts +++ b/cocos/core/pipeline/render-pipeline.ts @@ -495,7 +495,7 @@ export abstract class RenderPipeline { programLib.destroyShaderByDefines(this._macros); this._macros.CC_USE_HDR = (this._isHDR); for (let i = 0; i < this._root.scenes.length; i++) { - this._root.scenes[i].onPipelineChange(); + this._root.scenes[i].onGlobalPipelineStateChanged(); } } diff --git a/cocos/core/renderer/core/material-instance.ts b/cocos/core/renderer/core/material-instance.ts new file mode 100644 index 00000000000..187d2744265 --- /dev/null +++ b/cocos/core/renderer/core/material-instance.ts @@ -0,0 +1,162 @@ +import { RenderableComponent } from '../../3d'; +import { EffectAsset, Material } from '../../assets'; +import { _uploadProperty, IMaterial } from '../../utils/material-interface'; +import { murmurhash2_32_gc } from '../../utils/murmurhash2_gc'; +import { IPass } from '../../utils/pass-interface'; +import { IDefineMap, PassOverrides } from './pass'; +import { PassInstance } from './pass-instance'; + +export class MaterialInstance implements IMaterial { + + get effectAsset (): EffectAsset | null { + return this._parent.effectAsset; + } + + get effectName (): string { + return this._parent.effectName; + } + + get technique (): number { + return this._parent.technique; + } + + get passes (): IPass[] { + return this._passes; + } + + get hash (): number { + return this._hash; + } + + get parent (): IMaterial { + return this._parent; + } + + get owner (): RenderableComponent { + return this._owner; + } + + private _parent: IMaterial; + private _owner: RenderableComponent; + // data overwritten in material instance + private _passes: IPass[] = []; + private _hash: number = -1; + private _props: Array> = []; + private _states: PassOverrides[] = []; + + constructor (parent: Material, owner: RenderableComponent) { + this._parent = parent; + this._owner = owner; + // @ts-ignore + const parentProps = parent._props; + for (let i = 0; i < parentProps.length; i++) { + const passProp = {}; + Object.assign(passProp, parentProps[i]); + this._props[i] = passProp; + } + + for (let i = 0; i < parent.passes.length; i++) { + this._passes[i] = new PassInstance(parent.passes[i], this, i); + } + } + + public resetUniforms (clearPasses?: boolean): void { + this._props.length = this._passes.length; + for (let i = 0; i < this._props.length; i++) { this._props[i] = {}; } + if (!clearPasses) { return; } + for (const pass of this._passes) { + pass.resetUBOs(); + pass.resetTextures(); + } + } + + public recompileShaders (overrides: IDefineMap, passIdx?: number): void { + if (!this._passes || !this.effectAsset) { + return; + } + if (passIdx === undefined) { + for (const pass of this._passes) { + pass.tryCompile(overrides); + } + } else { + this._passes[passIdx].tryCompile(overrides); + } + } + + public overridePipelineStates (overrides: any, passIdx?: number): void { + if (!this._passes || !this.effectAsset) { return; } + const passInfos = this.effectAsset.techniques[this.technique].passes; + if (passIdx === undefined) { + for (let i = 0; i < this._passes.length; i++) { + const pass = this._passes[i]; + this._states[i] = overrides; + pass.overridePipelineStates(passInfos[pass.idxInTech], overrides); + } + } else { + this._states[passIdx] = overrides; + this._passes[passIdx].overridePipelineStates(passInfos[passIdx], overrides); + } + } + + public setProperty (name: string, val: any, passIdx?: number): void { + let success = false; + if (passIdx === undefined) { // try set property for all applicable passes + const passes = this._passes; + const len = passes.length; + for (let i = 0; i < len; i++) { + const pass = passes[i]; + if (_uploadProperty(pass, name, val)) { + this._props[i][name] = val; + success = true; + } + } + } else { + if (passIdx >= this._passes.length) { console.warn(`illegal pass index: ${passIdx}.`); return; } + const pass = this._passes[passIdx]; + if (_uploadProperty(pass, name, val)) { + this._props[passIdx][name] = val; + success = true; + } + } + if (!success) { + console.warn(`illegal property name: ${name}.`); + return; + } + } + + public getProperty (name: string, passIdx?: number) { + if (passIdx === undefined) { // try get property in all possible passes + const propsArray = this._props; + const len = propsArray.length; + for (let i = 0; i < len; i++) { + const props = propsArray[i]; + for (const p in props) { + if (p === name) { return props[p]; } + } + } + } else { + if (passIdx >= this._props.length) { console.warn(`illegal pass index: ${passIdx}.`); return null; } + const props = this._props[passIdx]; + for (const p in props) { + if (p === name) { return props[p]; } + } + } + return null; + } + + public destroy (): void { + for (let i = 0; i < this._passes.length; i++) { + this._passes[i].destroy(); + } + this._passes.length = 0; + this._props.length = 0; + } + + public _onPassStateChanged (idx: number) { + let str = ''; + for (const pass of this._passes) { + str += pass.psoHash; + } + this._hash = murmurhash2_32_gc(str, 666); + } +} diff --git a/cocos/core/renderer/core/pass-instance.ts b/cocos/core/renderer/core/pass-instance.ts new file mode 100644 index 00000000000..606254f4404 --- /dev/null +++ b/cocos/core/renderer/core/pass-instance.ts @@ -0,0 +1,489 @@ +import { builtinResMgr } from '../../3d/builtin/init'; +import { IPassInfo, IPassStates, IPropertyInfo } from '../../assets/effect-asset'; +import { TextureBase } from '../../assets/texture-base'; +// tslint:disable-next-line: max-line-length +import { GFXBindingType, GFXBuffer, GFXBufferUsageBit, GFXDevice, GFXDynamicState, GFXGetTypeSize, GFXMemoryUsageBit, GFXPrimitiveMode, GFXRenderPass, GFXSampler, GFXShader, GFXTextureView, GFXType, IGFXBufferInfo } from '../../gfx'; +import { GFXBindingLayout, IGFXBinding, IGFXBindingLayoutInfo } from '../../gfx/binding-layout'; +import { GFXPipelineLayout, IGFXPipelineLayoutInfo } from '../../gfx/pipeline-layout'; +import { GFXBlendState, GFXDepthStencilState, GFXPipelineState, GFXRasterizerState, IGFXPipelineStateInfo } from '../../gfx/pipeline-state'; +import { BatchedBuffer } from '../../pipeline/batched-buffer'; +import { isBuiltinBinding, RenderPassStage, RenderPriority } from '../../pipeline/define'; +import { getPhaseID } from '../../pipeline/pass-phase'; +import { IMaterial } from '../../utils/material-interface'; +import { generatePassPSOHash, IBlock, IPass, IPassDynamics, IPSOHashInfo } from '../../utils/pass-interface'; +import { IDefineMap, Pass } from './pass'; +import { getBindingFromHandle, getOffsetFromHandle, getTypeFromHandle, type2default, type2reader, type2writer } from './pass-utils'; +import { IProgramInfo, programLib } from './program-lib'; +import { samplerLib } from './sampler-lib'; + +const _bfInfo: IGFXBufferInfo = { + memUsage: GFXMemoryUsageBit.HOST | GFXMemoryUsageBit.DEVICE, + size: 0, + usage: GFXBufferUsageBit.UNIFORM | GFXBufferUsageBit.TRANSFER_DST, +}; + +const _blInfo: IGFXBindingLayoutInfo = {} as IGFXBindingLayoutInfo; + +const _plInfo: IGFXPipelineLayoutInfo = {} as IGFXPipelineLayoutInfo; + +const _psoInfo: IGFXPipelineStateInfo & IPSOHashInfo = {} as IGFXPipelineStateInfo & IPSOHashInfo; + +export class PassInstance implements IPass { + get batchedBuffer (): BatchedBuffer | null { + return null; + } + + get parent (): IPass { + return this._parent; + } + + get priority (): RenderPriority { + return this._priority; + } + + get primitive (): GFXPrimitiveMode { + return this._primitive; + } + + get stage (): RenderPassStage { + return this._stage; + } + + get rasterizerState (): GFXRasterizerState { + return this._rs; + } + + get depthStencilState (): GFXDepthStencilState { + return this._dss; + } + + get blendState (): GFXBlendState { + return this._bs; + } + + get dynamicStates (): GFXDynamicState[] { + return this._dynamicStates; + } + + get customizations (): string[] { + return this._customizations; + } + + get phase (): number { + return this._phase; + } + + get shaderInfo (): IProgramInfo { + return this._parent.shaderInfo; + } + + get program (): string { + return this._parent.program; + } + + get properties (): Record { + return this._parent.properties; + } + + get defines (): IDefineMap { + return this._defines; + } + + get idxInTech (): number { + return this._parent.idxInTech; + } + + get device (): GFXDevice { + return this._parent.device; + } + + get bindings (): IGFXBinding[] { + return this._bindings; + } + + get shader (): GFXShader { + return this._shader!; + } + + get renderPass (): GFXRenderPass { + return this._renderPass!; + } + + get dynamics (): IPassDynamics { + return this._dynamics; + } + + get blocks (): IBlock[] { + return this._blocks; + } + + get psoHash (): number { + return this._hash; + } + + private _parent: Pass; + private _owner: IMaterial; + private _idx: number; + private _dontNotify: boolean = false; + // instance resources + private _hash: number; + private _blocks: IBlock[] = []; + private _buffers: Record = {}; + private _samplers: Record = {}; + private _textureViews: Record = {}; + private _bindingLayout: GFXBindingLayout | null = null; + private _pipelineLayout: GFXPipelineLayout | null = null; + private _pipelineState: GFXPipelineState | null = null; + + // states could be overwritten + private _phase = getPhaseID('default'); + private _priority: RenderPriority = RenderPriority.DEFAULT; + private _primitive: GFXPrimitiveMode = GFXPrimitiveMode.TRIANGLE_LIST; + private _stage: RenderPassStage = RenderPassStage.DEFAULT; + private _renderPass: GFXRenderPass | null = null; + private _bindings: IGFXBinding[] = []; + private _bs: GFXBlendState = new GFXBlendState(); + private _dss: GFXDepthStencilState = new GFXDepthStencilState(); + private _rs: GFXRasterizerState = new GFXRasterizerState(); + private _dynamicStates: GFXDynamicState[] = []; + private _dynamics: IPassDynamics = {}; + private _customizations: string[] = []; + private _defines: IDefineMap = {}; + private _shader: GFXShader | null = null; + + constructor (parent: Pass, mat: IMaterial, idx: number) { + this._parent = parent; + this._owner = mat; + this._idx = idx; + this._hash = parent.psoHash; + this._shader = parent.shader; + this._bindings = parent.bindings; + + const blocks = this.shaderInfo.blocks; + for (let i = 0; i < blocks.length; i++) { + const { size, binding } = blocks[i]; + if (isBuiltinBinding(binding)) { + continue; + } + // create gfx buffer resource + _bfInfo.size = Math.ceil(size / 16) * 16; // https://bugs.chromium.org/p/chromium/issues/detail?id=988988 + this._buffers[binding] = this.device.createBuffer(_bfInfo); + // non-builtin UBO data pools, note that the effect compiler + // guarantees these bindings to be consecutive, starting from 0 + const buffer = new ArrayBuffer(size); + this._blocks[binding] = { + buffer, + dirty: true, + view: new Float32Array(buffer), + }; + const source = parent.blocks[binding].view; + const dest = this._blocks[binding].view; + for (let j = 0; j < source.length; j++) { + dest[j] = source[j]; + } + } + for (let i = 0; i < this.shaderInfo.samplers.length; i++) { + const binding = this.shaderInfo.samplers[i].binding; + if (isBuiltinBinding(binding)) { + continue; + } + // @ts-ignore + this._textureViews[binding] = parent._textureViews[binding]; + // @ts-ignore + this._samplers[binding] = parent._samplers[binding]; + } + Pass.fillinPipelineInfo(this as unknown as Pass, this._parent); + } + + public getHandle (name: string, offset?: number, targetType?: GFXType): number | undefined { + return this._parent.getHandle(name, offset, targetType); + } + + public getBinding (name: string): number | undefined { + return this._parent.getBinding(name); + } + + public setUniform (handle: number, value: any): void { + const binding = getBindingFromHandle(handle); + const type = getTypeFromHandle(handle); + const ofs = getOffsetFromHandle(handle); + const block = this._blocks[binding]; + type2writer[type](block.view, value, ofs); + block.dirty = true; + } + + public getUniform (handle: number, out: any) { + const binding = getBindingFromHandle(handle); + const type = getTypeFromHandle(handle); + const ofs = getOffsetFromHandle(handle); + const block = this._blocks[binding]; + return type2reader[type](block.view, out, ofs); + } + + public setUniformArray (handle: number, value: any[]): void { + const binding = getBindingFromHandle(handle); + const type = getTypeFromHandle(handle); + const stride = GFXGetTypeSize(type) >> 2; + const block = this._blocks[binding]; + let ofs = getOffsetFromHandle(handle); + for (let i = 0; i < value.length; i++ , ofs += stride) { + if (value[i] === null) { continue; } + type2writer[type](block.view, value[i], ofs); + } + block.dirty = true; + } + + public bindBuffer (binding: number, value: GFXBuffer): void { + if (this._buffers[binding] === value) { + return; + } + this._buffers[binding] = value; + if (!this._bindingLayout) { + return; + } + this._bindingLayout.bindBuffer(binding, value); + } + + public bindTextureView (binding: number, value: GFXTextureView): void { + if (this._textureViews[binding] === value) { + return; + } + this._textureViews[binding] = value; + if (!this._bindingLayout) { + return; + } + this._bindingLayout.bindTextureView(binding, value); + } + + public bindSampler (binding: number, value: GFXSampler): void { + if (!this._bindingLayout || this._samplers[binding] === value) { + return; + } + this._samplers[binding] = value; + this._bindingLayout.bindSampler(binding, value); + } + + public setDynamicState (state: GFXDynamicState, value: any): void { + const ds = this._dynamics[state]; + if (ds && ds.value === value) { + return; + } + ds.value = value; + ds.dirty = true; + } + + public overridePipelineStates (original: IPassInfo, overrides: any): void { + this._bs = new GFXBlendState(); + this._dss = new GFXDepthStencilState(); + this._rs = new GFXRasterizerState(); + Pass.fillinPipelineInfo(this as unknown as Pass, original); + Pass.fillinPipelineInfo(this as unknown as Pass, overrides); + this._hash = generatePassPSOHash(this); + this._onPipelineStateChanged(); + } + + public update (): void { + const len = this._blocks.length; + for (let i = 0; i < len; i++) { + const block = this._blocks[i]; + if (block.dirty) { + this._buffers[i].update(block.buffer); + block.dirty = false; + } + } + const source = cc.director.root.pipeline.globalBindings; + const target = this.shaderInfo.builtins.globals; + const samplerLen = target.samplers.length; + for (let i = 0; i < samplerLen; i++) { + const s = target.samplers[i]; + const info = source.get(s.name)!; + if (info.sampler) { + this.bindSampler(info.samplerInfo!.binding, info.sampler); + } + this.bindTextureView(info.samplerInfo!.binding, info.textureView!); + } + } + + public destroy (): void { + for (const u of this.shaderInfo.blocks) { + if (isBuiltinBinding(u.binding)) { continue; } + this._buffers[u.binding].destroy(); + } + this._buffers = {}; + // textures are reused + this._samplers = {}; + this._textureViews = {}; + } + + public resetUBOs (): void { + for (const u of this.shaderInfo.blocks) { + if (isBuiltinBinding(u.binding)) { + continue; + } + const block: IBlock = this._blocks[u.binding]; + let ofs = 0; + for (let i = 0; i < u.members.length; i++) { + const cur = u.members[i]; + const inf = this.properties[cur.name]; + const givenDefault = inf && inf.value; + const value = givenDefault ? givenDefault : type2default[cur.type]; + const stride = GFXGetTypeSize(cur.type) >> 2; + for (let j = 0; j < cur.count; j++) { + block.view.set(value, ofs + j * stride); + } + ofs += stride * cur.count; + } + block.dirty = true; + } + } + + public resetTextures (): void { + if (!this._bindingLayout) { + return; + } + for (const u of this.shaderInfo.samplers) { + if (isBuiltinBinding(u.binding)) { + continue; + } + const inf = this.properties[u.name]; + const texName = inf && inf.value ? inf.value + '-texture' : type2default[u.type]; + const texture = builtinResMgr.get(texName); + const textureView = texture && texture.getGFXTextureView(); + if (!textureView) { + console.warn('illegal texture default value: ' + texName); continue; + } + this._textureViews[u.binding] = textureView; + const samplerHash = inf && (inf.samplerHash !== undefined) ? inf.samplerHash : texture.getSamplerHash(); + const sampler = this._samplers[u.binding] = samplerLib.getSampler(this.device, samplerHash); + this._bindingLayout.bindSampler(u.binding, sampler); + this._bindingLayout.bindTextureView(u.binding, textureView); + } + } + + public tryCompile (defineOverrides?: IDefineMap, saveOverrides?: boolean): any { + const pipeline = cc.director.root.pipeline; + if (!pipeline) { + return null; + } + this._renderPass = pipeline.getRenderPass(this._stage); + if (!this._renderPass) { + console.warn(`illegal pass stage.`); return null; + } + let defines = this._defines; + if (defineOverrides) { + if (saveOverrides) { + Object.assign(this._defines, defineOverrides); + } + else { + Object.assign(defineOverrides, this._defines); + defines = defineOverrides; + } + } + const res = programLib.getGFXShader(this.device, this.program, defines, pipeline); + if (!res.shader) { + console.warn(`create shader ${this.program} failed`); + return null; + } + if (saveOverrides) { + this._shader = res.shader; + this._bindings = res.bindings; + } + this._hash = generatePassPSOHash(this); + this._onPipelineStateChanged(); + return res; + } + + public createPipelineState (): GFXPipelineState | null { + if ((!this._renderPass || !this._shader || !this._bindings.length) && !this.tryCompile()) { + console.warn(`pass resources not complete, create PSO failed`); + return null; + } + _blInfo.bindings = this._bindings; + // bind resources + this._bindingLayout = this.device.createBindingLayout(_blInfo); + for (const b in this._buffers) { + this._bindingLayout.bindBuffer(parseInt(b), this._buffers[b]); + } + for (const s in this._samplers) { + this._bindingLayout.bindSampler(parseInt(s), this._samplers[s]); + } + for (const t in this._textureViews) { + this._bindingLayout.bindTextureView(parseInt(t), this._textureViews[t]); + } + // bind pipeline builtins + const source = cc.director.root.pipeline.globalBindings; + const target = this.shaderInfo.builtins.globals; + for (const b of target.blocks) { + const info = source.get(b.name); + if (!info || info.type !== GFXBindingType.UNIFORM_BUFFER) { + console.warn(`builtin UBO '${b.name}' not available!`); continue; + } + this._bindingLayout.bindBuffer(info.blockInfo!.binding, info.buffer!); + } + for (const s of target.samplers) { + const info = source.get(s.name); + if (!info || info.type !== GFXBindingType.SAMPLER) { + console.warn(`builtin texture '${s.name}' not available!`); continue; + } + if (info.sampler) { + this._bindingLayout.bindSampler(info.samplerInfo!.binding, info.sampler); + } + this._bindingLayout.bindTextureView(info.samplerInfo!.binding, info.textureView!); + } + _plInfo.layouts = [this._bindingLayout]; + this._pipelineLayout = this.device.createPipelineLayout(_plInfo); + // create pipeline state + _psoInfo.primitive = this._primitive; + _psoInfo.shader = this._shader!; + _psoInfo.rasterizerState = this._rs; + _psoInfo.depthStencilState = this._dss; + _psoInfo.blendState = this._bs; + _psoInfo.dynamicStates = this._dynamicStates; + _psoInfo.layout = this._pipelineLayout; + _psoInfo.renderPass = this._renderPass!; + _psoInfo.program = this.program; + _psoInfo.defines = this._defines; + _psoInfo.stage = this._stage; + _psoInfo.hash = this._hash; + this._pipelineState = this.device.createPipelineState(_psoInfo); + return this._pipelineState; + } + + public destroyPipelineState (pipelineStates?: GFXPipelineState): void { + if (this._pipelineState) { + if (this._pipelineState !== pipelineStates) { + console.warn('Node(' + this._owner.owner!.node.name + ')\s pso doesn\'t equal to pass instance\'s pso,please check the destroy logic.(pass info:' + this.shaderInfo.name + ')'); + } + this._pipelineState.destroy(); + this._pipelineLayout!.destroy(); + this._bindingLayout!.destroy(); + this._pipelineState = null; + this._pipelineLayout = null; + this._bindingLayout = null; + } + } + + public createBatchedBuffer (): void { + throw new Error('Pass instance don\'t have batched buffer.'); + } + + public clearBatchedBuffer (): void { + throw new Error('Pass instance don\'t have batched buffer.'); + } + + public beginChangeStatesSilently (): void { + this._dontNotify = true; + } + + public endChangeStatesSilently (): void { + this._dontNotify = false; + } + + protected _onPipelineStateChanged () { + this._owner._onPassStateChanged(this._idx); + if (!this._dontNotify) { + // @ts-ignore + this._owner.owner._onRebuildPSO(this._idx, this._owner); + } + } +} diff --git a/cocos/core/renderer/core/pass.ts b/cocos/core/renderer/core/pass.ts index aededf42402..a9215a7862f 100644 --- a/cocos/core/renderer/core/pass.ts +++ b/cocos/core/renderer/core/pass.ts @@ -32,12 +32,10 @@ import { EffectAsset, IPassInfo, IPassStates, IPropertyInfo } from '../../assets import { TextureBase } from '../../assets/texture-base'; import { GFXBindingLayout, IGFXBinding, IGFXBindingLayoutInfo } from '../../gfx/binding-layout'; import { GFXBuffer, IGFXBufferInfo } from '../../gfx/buffer'; -import { GFXBindingType, GFXBufferUsageBit, GFXDynamicState, - GFXGetTypeSize, GFXMemoryUsageBit, GFXPrimitiveMode, GFXType } from '../../gfx/define'; +import { GFXBindingType, GFXBufferUsageBit, GFXDynamicState, GFXGetTypeSize, GFXMemoryUsageBit, GFXPrimitiveMode, GFXType } from '../../gfx/define'; import { GFXDevice } from '../../gfx/device'; import { GFXPipelineLayout, IGFXPipelineLayoutInfo } from '../../gfx/pipeline-layout'; -import { GFXBlendState, GFXBlendTarget, GFXDepthStencilState, - GFXInputState, GFXPipelineState, GFXRasterizerState, IGFXPipelineStateInfo } from '../../gfx/pipeline-state'; +import { GFXBlendState, GFXBlendTarget, GFXDepthStencilState, GFXInputState, GFXPipelineState, GFXRasterizerState, IGFXPipelineStateInfo } from '../../gfx/pipeline-state'; import { GFXRenderPass } from '../../gfx/render-pass'; import { GFXSampler } from '../../gfx/sampler'; import { GFXShader } from '../../gfx/shader'; @@ -46,9 +44,8 @@ import { BatchedBuffer } from '../../pipeline/batched-buffer'; import { isBuiltinBinding, RenderPassStage, RenderPriority } from '../../pipeline/define'; import { getPhaseID } from '../../pipeline/pass-phase'; import { Root } from '../../root'; -import { murmurhash2_32_gc } from '../../utils/murmurhash2_gc'; -import { customizeType, getBindingFromHandle, getBindingTypeFromHandle, - getOffsetFromHandle, getTypeFromHandle, type2default, type2reader, type2writer } from './pass-utils'; +import { generatePassPSOHash, IBlock, IPass, IPassDynamics, IPSOHashInfo } from '../../utils/pass-interface'; +import { customizeType, getBindingFromHandle, getBindingTypeFromHandle, getOffsetFromHandle, getTypeFromHandle, type2default, type2reader, type2writer } from './pass-utils'; import { IProgramInfo, IShaderResources, programLib } from './program-lib'; import { samplerLib } from './sampler-lib'; @@ -61,42 +58,18 @@ export interface IPassInfoFull extends IPassInfo { } export type PassOverrides = RecursivePartial; -export interface IBlock { - buffer: ArrayBuffer; - view: Float32Array; - dirty: boolean; -} - interface IPassResources { bindingLayout: GFXBindingLayout; pipelineLayout: GFXPipelineLayout; pipelineState: GFXPipelineState; } -interface IPassDynamics { - [type: number]: { - dirty: boolean, - value: number[], - }; -} - interface IEffectInfo { techIdx: number; defines: IDefineMap[]; states: PassOverrides[]; } -interface IPSOHashInfo { - program: string; - defines: IDefineMap; - stage: RenderPassStage; - primitive: GFXPrimitiveMode; - rasterizerState: GFXRasterizerState; - depthStencilState: GFXDepthStencilState; - blendState: GFXBlendState; - dynamicStates: GFXDynamicState[]; -} - const _bfInfo: IGFXBufferInfo = { memUsage: GFXMemoryUsageBit.HOST | GFXMemoryUsageBit.DEVICE, size: 0, @@ -132,7 +105,7 @@ const _psoInfo: IGFXPipelineStateInfo & IPSOHashInfo = { * @zh * 渲染 pass,储存实际描述绘制过程的各项资源。 */ -export class Pass { +export class Pass implements IPass { /** * @zh * 根据 handle 获取 unform 的绑定类型(UBO 或贴图等)。 @@ -181,7 +154,7 @@ export class Pass { const bsInfo = Object.assign({}, info.blendState); if (bsInfo.targets) { bsInfo.targets.forEach((t, i) => Object.assign( - bs.targets[i] || (bs.targets[i] = new GFXBlendTarget()), t)); + bs.targets[i] || (bs.targets[i] = new GFXBlendTarget()), t)); } delete bsInfo.targets; Object.assign(bs, bsInfo); @@ -190,20 +163,6 @@ export class Pass { Object.assign(target._dss, info.depthStencilState); } - /** - * @zh - * 根据指定 PSO 信息计算 hash - * @param psoInfo 用于计算 PSO hash 的最小必要信息 - */ - public static getPSOHash (psoInfo: IPSOHashInfo) { - const shaderKey = programLib.getKey(psoInfo.program, psoInfo.defines); - let res = `${shaderKey},${psoInfo.stage},${psoInfo.primitive}`; - res += serializeBlendState(psoInfo.blendState); - res += serializeDepthStencilState(psoInfo.depthStencilState); - res += serializeRasterizerState(psoInfo.rasterizerState); - return murmurhash2_32_gc(res, 666); - } - protected static getOffsetFromHandle = getOffsetFromHandle; // internal resources protected _buffers: Record = {}; @@ -229,6 +188,7 @@ export class Pass { protected _shaderInfo: IProgramInfo = null!; protected _defines: IDefineMap = {}; protected _properties: Record = {}; + protected _hash: number = -1; // external references protected _device: GFXDevice; protected _renderPass: GFXRenderPass | null = null; @@ -236,6 +196,14 @@ export class Pass { // for dynamic batching protected _batchedBuffer: BatchedBuffer | null = null; + get parent (): IPass | null { + return null; + } + + get psoHash (): number { + return this._hash; + } + public constructor (device: GFXDevice) { this._device = device; } @@ -280,6 +248,8 @@ export class Pass { this.resetUBOs(); this.resetTextures(); this.tryCompile(); + + this._hash = generatePassPSOHash(this); } /** @@ -358,7 +328,7 @@ export class Pass { const stride = GFXGetTypeSize(type) >> 2; const block = this._blocks[binding]; let ofs = Pass.getOffsetFromHandle(handle); - for (let i = 0; i < value.length; i++, ofs += stride) { + for (let i = 0; i < value.length; i++ , ofs += stride) { if (value[i] === null) { continue; } type2writer[type](block.view, value[i], ofs); } @@ -432,11 +402,7 @@ export class Pass { * @param value 管线状态重载值。 */ public overridePipelineStates (original: IPassInfo, overrides: PassOverrides) { - this._bs = new GFXBlendState(); - this._dss = new GFXDepthStencilState(); - this._rs = new GFXRasterizerState(); - Pass.fillinPipelineInfo(this, original); - Pass.fillinPipelineInfo(this, overrides); + console.error('Pass:' + this._programName + ' cann\'t be overwritten.Please use pass instance to do so.'); } /** @@ -540,14 +506,10 @@ export class Pass { if (!pipeline) { return null; } this._renderPass = pipeline.getRenderPass(this._stage); if (!this._renderPass) { console.warn(`illegal pass stage.`); return null; } - let defines = this._defines; - if (defineOverrides) { - if (saveOverrides) { Object.assign(this._defines, defineOverrides); } - else { Object.assign(defineOverrides, this._defines); defines = defineOverrides; } - } - const res = programLib.getGFXShader(this._device, this._programName, defines, pipeline); + const res = programLib.getGFXShader(this._device, this._programName, this._defines, pipeline); if (!res.shader) { console.warn(`create shader ${this._programName} failed`); return null; } if (saveOverrides) { this._shader = res.shader; this._bindings = res.bindings; } + this._hash = generatePassPSOHash(this); return res; } @@ -555,16 +517,12 @@ export class Pass { * @zh * 根据当前 pass 持有的信息创建 [[GFXPipelineState]]。 */ - public createPipelineState (defineOverrides?: IDefineMap, stateOverrides?: IPassStates): GFXPipelineState | null { + public createPipelineState (): GFXPipelineState | null { if ((!this._renderPass || !this._shader || !this._bindings.length) && !this.tryCompile()) { console.warn(`pass resources not complete, create PSO failed`); return null; } - let shader = this._shader!; _blInfo.bindings = this._bindings; - if (defineOverrides) { - const res = this.tryCompile(defineOverrides, false); - if (res) { shader = res.shader; _blInfo.bindings = res.bindings; } - } + _blInfo.bindings = this._bindings; // bind resources const bindingLayout = this._device.createBindingLayout(_blInfo); for (const b in this._buffers) { @@ -593,23 +551,31 @@ export class Pass { _plInfo.layouts = [bindingLayout]; const pipelineLayout = this._device.createPipelineLayout(_plInfo); // create pipeline state - _psoInfo.primitive = stateOverrides && stateOverrides.primitive || this._primitive; - _psoInfo.shader = shader; - _psoInfo.rasterizerState = stateOverrides && stateOverrides.rasterizerState || this._rs; - _psoInfo.depthStencilState = stateOverrides && stateOverrides.depthStencilState || this._dss; - _psoInfo.blendState = stateOverrides && stateOverrides.blendState || this._bs; - _psoInfo.dynamicStates = stateOverrides && stateOverrides.dynamicStates || this._dynamicStates; + _psoInfo.primitive = this._primitive; + _psoInfo.shader = this._shader!; + _psoInfo.rasterizerState = this._rs; + _psoInfo.depthStencilState = this._dss; + _psoInfo.blendState = this._bs; + _psoInfo.dynamicStates = this._dynamicStates; _psoInfo.layout = pipelineLayout; _psoInfo.renderPass = this._renderPass!; _psoInfo.program = this._programName; - _psoInfo.defines = defineOverrides || this._defines; + _psoInfo.defines = this._defines; _psoInfo.stage = this._stage; - _psoInfo.hash = Pass.getPSOHash(_psoInfo); + _psoInfo.hash = this._hash; const pipelineState = this._device.createPipelineState(_psoInfo); this._resources.push({ bindingLayout, pipelineLayout, pipelineState }); return pipelineState; } + public beginChangeStatesSilently (): void { + + } + + public endChangeStatesSilently (): void { + + } + /** * @zh * 销毁指定的 [[GFXPipelineState]],如果它是这个 pass 创建的。 @@ -668,26 +634,3 @@ export class Pass { get batchedBuffer () { return this._batchedBuffer; } get blocks () { return this._blocks; } } - -function serializeBlendState (bs: GFXBlendState) { - let res = `,bs,${bs.isA2C},${bs.blendColor}`; - for (const t of bs.targets) { - res += `,bt,${t.blend},${t.blendEq},${t.blendAlphaEq},${t.blendColorMask}`; - res += `,${t.blendSrc},${t.blendDst},${t.blendSrcAlpha},${t.blendDstAlpha}`; - } - return res; -} - -function serializeRasterizerState (rs: GFXRasterizerState) { - const res = `,rs,${rs.cullMode},${rs.depthBias},${rs.isFrontFaceCCW}`; - return res; -} - -function serializeDepthStencilState (dss: GFXDepthStencilState) { - let res = `,dss,${dss.depthTest},${dss.depthWrite},${dss.depthFunc}`; - res += `,${dss.stencilTestFront},${dss.stencilFuncFront},${dss.stencilRefFront},${dss.stencilReadMaskFront}`; - res += `,${dss.stencilFailOpFront},${dss.stencilZFailOpFront},${dss.stencilPassOpFront},${dss.stencilWriteMaskFront}`; - res += `,${dss.stencilTestBack},${dss.stencilFuncBack},${dss.stencilRefBack},${dss.stencilReadMaskBack}`; - res += `,${dss.stencilFailOpBack},${dss.stencilZFailOpBack},${dss.stencilPassOpBack},${dss.stencilWriteMaskBack}`; - return res; -} diff --git a/cocos/core/renderer/index.ts b/cocos/core/renderer/index.ts index b455e528baa..2a3d9df9acd 100644 --- a/cocos/core/renderer/index.ts +++ b/cocos/core/renderer/index.ts @@ -10,6 +10,8 @@ export * from './core/pass'; export * from './core/program-lib'; export * from './core/sampler-lib'; export * from './core/texture-buffer-pool'; +export { MaterialInstance } from './core/material-instance'; +export { PassInstance } from './core/pass-instance'; export * from './models/skeletal-animation-utils'; export * from './models/skinning-model'; diff --git a/cocos/core/renderer/models/skinning-model.ts b/cocos/core/renderer/models/skinning-model.ts index e1def86c39f..e11ad7391ab 100644 --- a/cocos/core/renderer/models/skinning-model.ts +++ b/cocos/core/renderer/models/skinning-model.ts @@ -35,12 +35,12 @@ import { GFXBuffer } from '../../gfx/buffer'; import { GFXBufferUsageBit, GFXMemoryUsageBit } from '../../gfx/define'; import { Vec3 } from '../../math'; import { UBOSkinningAnimation, UBOSkinningTexture, UniformJointsTexture } from '../../pipeline/define'; -import { Pass } from '../core/pass'; +import { Node } from '../../scene-graph'; +import { IPass } from '../../utils/pass-interface'; import { samplerLib } from '../core/sampler-lib'; import { DataPoolManager } from '../data-pool-manager'; import { Model } from '../scene/model'; import { IAnimInfo, IJointsTextureHandle, jointsTextureSamplerHash, selectJointsMediumType } from './skeletal-animation-utils'; -import { Node } from '../../scene-graph'; interface IJointsInfo { buffer: GFXBuffer | null; @@ -158,8 +158,12 @@ export class SkinningModel extends Model { } } - protected _doCreatePSO (pass: Pass) { - const pso = super._doCreatePSO(pass, { CC_USE_SKINNING: selectJointsMediumType(this._device) }); + protected createPipelineState (pass: IPass) { + pass.beginChangeStatesSilently(); + // warning:this behavior is now forbidden. + pass.tryCompile({ CC_USE_SKINNING: selectJointsMediumType(this._device) }); + pass.endChangeStatesSilently(); + const pso = super.createPipelineState(pass); const { buffer, texture, animInfo } = this._jointsMedium; const bindingLayout = pso.pipelineLayout.layouts[0]; bindingLayout.bindBuffer(UBOSkinningTexture.BLOCK.binding, buffer!); diff --git a/cocos/core/renderer/scene/model.ts b/cocos/core/renderer/scene/model.ts index cc64b4b3d88..171205dec5e 100644 --- a/cocos/core/renderer/scene/model.ts +++ b/cocos/core/renderer/scene/model.ts @@ -1,6 +1,5 @@ // Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. import { IPassStates } from '../../assets/effect-asset'; -import { Material } from '../../assets/material'; import { IRenderingSubmesh } from '../../assets/mesh'; import { aabb } from '../../geom-utils'; import { GFXBuffer } from '../../gfx/buffer'; @@ -11,12 +10,14 @@ import { GFXUniformBlock } from '../../gfx/shader'; import { Mat4, Vec3 } from '../../math'; import { Pool } from '../../memop'; import { IInternalBindingInst, UBOForwardLight, UBOLocal } from '../../pipeline/define'; +import { Node } from '../../scene-graph'; import { Layers } from '../../scene-graph/layers'; -import { IDefineMap, Pass } from '../core/pass'; +import { IMaterial } from '../../utils/material-interface'; +import { IPass } from '../../utils/pass-interface'; +import { IDefineMap } from '../core/pass'; import { customizationManager } from './customization-manager'; import { RenderScene } from './render-scene'; import { SubModel } from './submodel'; -import { Node } from '../../scene-graph'; const m4_1 = new Mat4(); @@ -156,8 +157,8 @@ export class Model { protected _modelBounds: aabb | null = null; protected _subModels: SubModel[] = []; protected _implantPSOs: GFXPipelineState[] = []; - protected _matPSORecord = new Map(); - protected _matRefCount = new Map(); + protected _matPSORecord = new Map(); + protected _matRefCount = new Map(); protected _uboLocal = new UBOLocal(); protected _localUBO: GFXBuffer | null = null; protected _localBindings = new Map(); @@ -272,7 +273,7 @@ export class Model { this._modelBounds.transform(this._transform._mat, this._transform._pos, this._transform._rot, this._transform._scale, this._worldBounds); } - public initSubModel (idx: number, subMeshData: IRenderingSubmesh, mat: Material) { + public initSubModel (idx: number, subMeshData: IRenderingSubmesh, mat: IMaterial) { this.initLocalBindings(mat); if (this._subModels[idx] == null) { this._subModels[idx] = _subMeshPool.alloc(); @@ -293,15 +294,15 @@ export class Model { this._subModels[idx].subMeshData = subMeshData; } - public setSubModelMaterial (idx: number, mat: Material | null) { + public setSubModelMaterial (idx: number, mat: IMaterial | null) { if (this._subModels[idx] == null) { return; } this.initLocalBindings(mat); if (this._subModels[idx].material === mat) { if (mat) { - this.destroyPipelineState(mat, this._matPSORecord.get(mat)!); - this._matPSORecord.set(mat, this.createPipelineState(mat)); + this.destroyPipelineStates(mat, this._matPSORecord.get(mat)!); + this._matPSORecord.set(mat, this.createPipelineStates(mat)); } } else { if (this._subModels[idx].material) { @@ -315,15 +316,17 @@ export class Model { this._subModels[idx].material = mat; } - public onPipelineChange () { + public onGlobalPipelineStateChanged () { for (const m of this._subModels) { const mat = m.material!; const psos = this._matPSORecord.get(mat)!; for (let i = 0; i < mat.passes.length; i++) { const pass = mat.passes[i]; + pass.beginChangeStatesSilently(); pass.tryCompile(); // force update shaders + pass.endChangeStatesSilently(); pass.destroyPipelineState(psos[i]); - psos[i] = this._doCreatePSO(pass); + psos[i] = this.createPipelineState(pass); psos[i].pipelineLayout.layouts[0].update(); } m.updateCommandBuffer(); @@ -339,17 +342,17 @@ export class Model { if (idx >= 0) { this._implantPSOs.splice(idx, 1); } } - protected createPipelineState (mat: Material): GFXPipelineState[] { + protected createPipelineStates (mat: IMaterial): GFXPipelineState[] { const ret = new Array(mat.passes.length); for (let i = 0; i < ret.length; i++) { const pass = mat.passes[i]; for (const cus of pass.customizations) { customizationManager.attach(cus, this); } - ret[i] = this._doCreatePSO(pass); + ret[i] = this.createPipelineState(pass); } return ret; } - protected destroyPipelineState (mat: Material, pso: GFXPipelineState[]) { + protected destroyPipelineStates (mat: IMaterial, pso: GFXPipelineState[]) { for (let i = 0; i < mat.passes.length; i++) { const pass = mat.passes[i]; pass.destroyPipelineState(pso[i]); @@ -357,11 +360,16 @@ export class Model { } } - protected _doCreatePSO (pass: Pass, defineOverrides?: IDefineMap, stateOverrides?: IPassStates) { + protected createPipelineState (pass: IPass, defineOverrides?: IDefineMap, stateOverrides?: IPassStates) { defineOverrides = defineOverrides || {}; - if (pass.blendState.targets[0].blend) { this._isDynamicBatching = false; } - defineOverrides.CC_USE_BATCHING = this._isDynamicBatching; - const pso = pass.createPipelineState(defineOverrides, stateOverrides)!; + if (pass.blendState.targets[0].blend) { + this._isDynamicBatching = false; + } + pass.beginChangeStatesSilently(); + // warning:this behavior is now forbidden. + pass.tryCompile({ CC_USE_BATCHING: this._isDynamicBatching }); + pass.endChangeStatesSilently(); + const pso = pass.createPipelineState()!; pso.pipelineLayout.layouts[0].bindBuffer(UBOLocal.BLOCK.binding, this._localBindings.get(UBOLocal.BLOCK.name)!.buffer!); if (this._localBindings.has(UBOForwardLight.BLOCK.name)) { pso.pipelineLayout.layouts[0].bindBuffer(UBOForwardLight.BLOCK.binding, this._localBindings.get(UBOForwardLight.BLOCK.name)!.buffer!); @@ -369,7 +377,7 @@ export class Model { return pso; } - protected onSetLocalBindings (mat: Material) { + protected onSetLocalBindings (mat: IMaterial) { if (!this._localBindings.has(UBOLocal.BLOCK.name)) { this._localBindings.set(UBOLocal.BLOCK.name, { type: GFXBindingType.UNIFORM_BUFFER, @@ -393,7 +401,7 @@ export class Model { } } - protected initLocalBindings (mat: Material | null) { + protected initLocalBindings (mat: IMaterial | null) { if (mat) { this.onSetLocalBindings(mat); const lbIter = this._localBindings.values(); @@ -412,7 +420,7 @@ export class Model { } } - private _updatePass (psos: GFXPipelineState[], mat: Material) { + private _updatePass (psos: GFXPipelineState[], mat: IMaterial) { for (let i = 0; i < mat.passes.length; i++) { mat.passes[i].update(); } @@ -421,19 +429,19 @@ export class Model { } } - private allocatePSO (mat: Material) { + private allocatePSO (mat: IMaterial) { if (this._matRefCount.get(mat) == null) { this._matRefCount.set(mat, 1); - this._matPSORecord.set(mat, this.createPipelineState(mat)); + this._matPSORecord.set(mat, this.createPipelineStates(mat)); } else { this._matRefCount.set(mat, this._matRefCount.get(mat)! + 1); } } - private releasePSO (mat: Material) { + private releasePSO (mat: IMaterial) { this._matRefCount.set(mat, this._matRefCount.get(mat)! - 1); if (this._matRefCount.get(mat) === 0) { - this.destroyPipelineState(mat, this._matPSORecord.get(mat)!); + this.destroyPipelineStates(mat, this._matPSORecord.get(mat)!); this._matPSORecord.delete(mat); this._matRefCount.delete(mat); } diff --git a/cocos/core/renderer/scene/planar-shadows.ts b/cocos/core/renderer/scene/planar-shadows.ts index 2b6992de3d2..e07f93d73c4 100644 --- a/cocos/core/renderer/scene/planar-shadows.ts +++ b/cocos/core/renderer/scene/planar-shadows.ts @@ -198,7 +198,7 @@ export class PlanarShadows { } } - public onPipelineChange () { + public onGlobalPipelineStateChanged () { const cbs = this._cbRecord.values(); let cbRes = cbs.next(); while (!cbRes.done) { @@ -216,7 +216,7 @@ export class PlanarShadows { } public destroy () { - this.onPipelineChange(); + this.onGlobalPipelineStateChanged(); this._passNormal.destroy(); this._passSkinning.destroy(); } @@ -224,7 +224,7 @@ export class PlanarShadows { protected _createPSO (model: Model) { const pass = model instanceof SkinningModel ? this._passSkinning : this._passNormal; // @ts-ignore TS2445 - const pso = model._doCreatePSO(pass); + const pso = model.createPipelineState(pass); model.insertImplantPSO(pso); // add back to model to sync binding layouts pso.pipelineLayout.layouts[0].update(); return pso; diff --git a/cocos/core/renderer/scene/render-scene.ts b/cocos/core/renderer/scene/render-scene.ts index 54e4025be52..e8075eb40f5 100644 --- a/cocos/core/renderer/scene/render-scene.ts +++ b/cocos/core/renderer/scene/render-scene.ts @@ -241,12 +241,12 @@ export class RenderScene { this._models.length = 0; } - public onPipelineChange () { + public onGlobalPipelineStateChanged () { for (const m of this._models) { - m.onPipelineChange(); + m.onGlobalPipelineStateChanged(); } - this._skybox.onPipelineChange(); - this._planarShadows.onPipelineChange(); + this._skybox.onGlobalPipelineStateChanged(); + this._planarShadows.onGlobalPipelineStateChanged(); } public generateModelId (): number { diff --git a/cocos/core/renderer/scene/skybox.ts b/cocos/core/renderer/scene/skybox.ts index 1e6dab554ec..1c427467b74 100644 --- a/cocos/core/renderer/scene/skybox.ts +++ b/cocos/core/renderer/scene/skybox.ts @@ -67,7 +67,7 @@ export class Skybox extends Model { const pipeline = this._scene!.root.pipeline; if (pipeline.macros.CC_USE_IBL === value) { return; } pipeline.macros.CC_USE_IBL = value; - this._scene!.onPipelineChange(); + this._scene!.onGlobalPipelineStateChanged(); } protected _updateGlobalBinding () { diff --git a/cocos/core/renderer/scene/submodel.ts b/cocos/core/renderer/scene/submodel.ts index 7e63c705c28..c2dcfa0cf05 100644 --- a/cocos/core/renderer/scene/submodel.ts +++ b/cocos/core/renderer/scene/submodel.ts @@ -1,4 +1,3 @@ -import { Material } from '../../assets/material'; import { IRenderingSubmesh } from '../../assets/mesh'; import { GFXCommandBuffer } from '../../gfx/command-buffer'; import { GFXCommandBufferType, GFXStatus } from '../../gfx/define'; @@ -6,12 +5,13 @@ import { GFXDevice } from '../../gfx/device'; import { GFXInputAssembler, IGFXInputAssemblerInfo } from '../../gfx/input-assembler'; import { GFXPipelineState } from '../../gfx/pipeline-state'; import { RenderPriority } from '../../pipeline/define'; -import { Pass } from '../core/pass'; +import { IMaterial } from '../../utils/material-interface'; +import { IPass } from '../../utils/pass-interface'; export class SubModel { protected _subMeshObject: IRenderingSubmesh | null; protected _inputAssembler: GFXInputAssembler | null; - private _material: Material | null; + private _material: IMaterial | null; private _cmdBuffers: GFXCommandBuffer[]; private _psos: GFXPipelineState[] | null; private _priority: RenderPriority; @@ -25,7 +25,7 @@ export class SubModel { this._priority = RenderPriority.DEFAULT; } - public initialize (subMesh: IRenderingSubmesh, mat: Material, psos: GFXPipelineState[]) { + public initialize (subMesh: IRenderingSubmesh, mat: IMaterial, psos: GFXPipelineState[]) { this._psos = psos; this.subMeshData = subMesh; @@ -87,7 +87,7 @@ export class SubModel { this._psos = val; } - set material (material: Material | null) { + set material (material: IMaterial | null) { this._material = material; if (material == null) { return; @@ -95,7 +95,7 @@ export class SubModel { this.updateCommandBuffer(); } - get material (): Material | null { + get material (): IMaterial | null { return this._material; } @@ -147,7 +147,7 @@ export class SubModel { cmdBuff.end(); } - get passes (): Pass[] { + get passes (): IPass[] { return this._material!.passes; } diff --git a/cocos/core/renderer/ui/render-data.ts b/cocos/core/renderer/ui/render-data.ts index dabdfe84ffd..88c01230efd 100644 --- a/cocos/core/renderer/ui/render-data.ts +++ b/cocos/core/renderer/ui/render-data.ts @@ -30,6 +30,7 @@ import { Material } from '../../assets'; import { Color } from '../../math'; import { Pool, RecyclePool } from '../../memop'; +import { IMaterial } from '../../utils/material-interface'; export interface IRenderData { x: number; @@ -41,7 +42,7 @@ export interface IRenderData { } export class BaseRenderData { - public material: Material | null = null; + public material: IMaterial | null = null; public vertexCount: number = 0; public indiceCount: number = 0; } diff --git a/cocos/core/renderer/ui/stencil-manager.ts b/cocos/core/renderer/ui/stencil-manager.ts index 259e363732f..6b57fec5cb1 100644 --- a/cocos/core/renderer/ui/stencil-manager.ts +++ b/cocos/core/renderer/ui/stencil-manager.ts @@ -26,9 +26,11 @@ * @hidden */ +import { Material } from '../../assets/material'; import { GFXComparisonFunc, GFXStencilOp } from '../../gfx/define'; +import { IMaterial } from '../../utils/material-interface'; +import { IPass } from '../../utils/pass-interface'; import { Pass } from '../core/pass'; -import { Material } from '../../assets/material'; // import { GFXStencilOp } from '../../gfx/define'; @@ -118,7 +120,7 @@ export class StencilManager { } } - public handleMaterial (mat: Material){ + public handleMaterial (mat: IMaterial){ const pattern = this._stencilPattern; if (this.stage === Stage.DISABLED) { pattern.stencilTest = false; @@ -204,7 +206,7 @@ export class StencilManager { this.stage = Stage.DISABLED; } - private _changed (pass: Pass) { + private _changed (pass: IPass) { const stencilState = pass.depthStencilState; const pattern = this._stencilPattern; if (pattern.stencilTest !== stencilState.stencilTestFront || diff --git a/cocos/core/renderer/ui/ui-batch-model.ts b/cocos/core/renderer/ui/ui-batch-model.ts index 7bbf3723641..5875331b217 100644 --- a/cocos/core/renderer/ui/ui-batch-model.ts +++ b/cocos/core/renderer/ui/ui-batch-model.ts @@ -26,11 +26,10 @@ * @hidden */ -import { Material } from '../../assets/material'; import { GFXInputAssembler } from '../../gfx/input-assembler'; import { GFXPipelineState } from '../../gfx/pipeline-state'; +import { IMaterial } from '../../utils/material-interface'; import { Model } from '../scene/model'; -import { RenderScene } from '../scene/render-scene'; import { SubModel } from '../scene/submodel'; import { UIDrawBatch } from './ui-draw-batch'; @@ -66,7 +65,7 @@ class UISubModel extends SubModel { this.psos = []; } - public directInitialize (ia: GFXInputAssembler, mat: Material, pso: GFXPipelineState) { + public directInitialize (ia: GFXInputAssembler, mat: IMaterial, pso: GFXPipelineState) { this._inputAssembler = ia; this.psos![0] = pso; this.material = mat; diff --git a/cocos/core/renderer/ui/ui-draw-batch.ts b/cocos/core/renderer/ui/ui-draw-batch.ts index 379a7a93630..6190c37c6ea 100644 --- a/cocos/core/renderer/ui/ui-draw-batch.ts +++ b/cocos/core/renderer/ui/ui-draw-batch.ts @@ -2,20 +2,20 @@ * @hidden */ -import { UI } from "./ui"; -import { Camera } from "../scene/camera"; -import { MeshBuffer } from "../../../ui"; -import { Model } from "../scene/model"; -import { Material } from "../../assets"; -import { GFXTextureView, GFXPipelineState } from "../../gfx"; -import { GFXBindingLayout } from "../../gfx/binding-layout"; +import { MeshBuffer } from '../../../ui'; +import { GFXPipelineState, GFXTextureView } from '../../gfx'; +import { GFXBindingLayout } from '../../gfx/binding-layout'; import { Node } from '../../scene-graph'; +import { IMaterial } from '../../utils/material-interface'; +import { Camera } from '../scene/camera'; +import { Model } from '../scene/model'; +import { UI } from './ui'; export class UIDrawBatch { public camera: Camera | null = null; public bufferBatch: MeshBuffer | null = null; public model: Model | null = null; - public material: Material | null = null; + public material: IMaterial | null = null; public texView: GFXTextureView | null = null; public firstIdx: number = 0; public idxCount: number = 0; diff --git a/cocos/core/renderer/ui/ui-material.ts b/cocos/core/renderer/ui/ui-material.ts index e7755efae81..7a4c636a89d 100644 --- a/cocos/core/renderer/ui/ui-material.ts +++ b/cocos/core/renderer/ui/ui-material.ts @@ -30,14 +30,15 @@ import { Material } from '../../assets/material'; import { GFXPipelineState } from '../../gfx/pipeline-state'; import { Pool } from '../../memop'; import { Pass } from '../../renderer/core/pass'; +import { IMaterial } from '../../utils/material-interface'; export interface IUIMaterialInfo { - material: Material; + material: IMaterial; } export class UIMaterial { - public get material (): Material { + public get material (): IMaterial { return this._material!; } @@ -62,7 +63,7 @@ export class UIMaterial { this._material = new Material(); - this._material.copy(info.material); + this._material.copy(info.material instanceof Material ? info.material : info.material.parent as Material); this._pass = this._material.passes[0]; this._pass.update(); diff --git a/cocos/core/renderer/ui/ui.ts b/cocos/core/renderer/ui/ui.ts index 72b8d1edac7..f428dc895f6 100644 --- a/cocos/core/renderer/ui/ui.ts +++ b/cocos/core/renderer/ui/ui.ts @@ -42,6 +42,7 @@ import { Model } from '../../renderer/scene/model'; import { RenderScene } from '../../renderer/scene/render-scene'; import { Root } from '../../root'; import { Layers, Node } from '../../scene-graph'; +import { IMaterial } from '../../utils/material-interface'; import { MeshBuffer } from './mesh-buffer'; import { StencilManager } from './stencil-manager'; import { UIBatchModel } from './ui-batch-model'; @@ -95,7 +96,7 @@ export class UI { private _modelInUse: CachedArray; // batcher private _emptyMaterial = new Material(); - private _currMaterial: Material = this._emptyMaterial; + private _currMaterial: IMaterial = this._emptyMaterial; private _currTexView: GFXTextureView | null = null; private _currCanvas: CanvasComponent | null = null; private _currMeshBuffer: MeshBuffer | null = null; @@ -163,7 +164,7 @@ export class UI { return Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this), 'renderScene')!.get!.bind(this); } - public _getUIMaterial (mat: Material): UIMaterial { + public _getUIMaterial (mat: IMaterial): UIMaterial { if (this._uiMaterials.has(mat.hash)) { return this._uiMaterials.get(mat.hash)!; } else { @@ -363,7 +364,7 @@ export class UI { * @param model - 提交渲染的 model 数据。 * @param mat - 提交渲染的材质。 */ - public commitModel (comp: UIComponent, model: Model | null, mat: Material | null) { + public commitModel (comp: UIComponent, model: Model | null, mat: IMaterial | null) { // if the last comp is spriteComp, previous comps should be batched. if (this._currMaterial !== this._emptyMaterial) { this.autoMergeBatches(); diff --git a/cocos/core/utils/material-interface.ts b/cocos/core/utils/material-interface.ts new file mode 100644 index 00000000000..a0dfcbc5430 --- /dev/null +++ b/cocos/core/utils/material-interface.ts @@ -0,0 +1,135 @@ +import { RenderableComponent } from '../3d/framework/renderable-component'; +import { EffectAsset } from '../assets/effect-asset'; +import { SpriteFrame } from '../assets/sprite-frame'; +import { TextureBase } from '../assets/texture-base'; +import { GFXBindingType, GFXTextureView } from '../gfx'; +import { IDefineMap, PassOverrides } from '../renderer/core/pass'; +import { getBindingFromHandle, getBindingTypeFromHandle } from '../renderer/core/pass-utils'; +import { samplerLib } from '../renderer/core/sampler-lib'; +import { murmurhash2_32_gc } from './murmurhash2_gc'; +import { IPass } from './pass-interface'; + +export function _uploadProperty (pass: IPass, name: string, val: any) { + const handle = pass.getHandle(name); + if (handle === undefined) { return false; } + const bindingType = getBindingTypeFromHandle(handle); + if (bindingType === GFXBindingType.UNIFORM_BUFFER) { + if (Array.isArray(val)) { + pass.setUniformArray(handle, val); + } else { + pass.setUniform(handle, val); + } + } else if (bindingType === GFXBindingType.SAMPLER) { + const binding = getBindingFromHandle(handle); + if (val instanceof GFXTextureView) { + pass.bindTextureView(binding, val); + } else if (val instanceof TextureBase || val instanceof SpriteFrame) { + const textureView: GFXTextureView | null = val.getGFXTextureView(); + if (!textureView || !textureView.texture.width || !textureView.texture.height) { + // console.warn(`material '${this._uuid}' received incomplete texture asset '${val._uuid}'`); + return false; + } + pass.bindTextureView(binding, textureView); + if (val instanceof TextureBase) { + pass.bindSampler(binding, samplerLib.getSampler(cc.game._gfxDevice, val.getSamplerHash())); + } + } + } + return true; +} + +export function generateMaterailHash (mat: IMaterial) { + let str = ''; + for (const pass of mat.passes) { + str += pass.psoHash; + } + return murmurhash2_32_gc(str, 666); +} + +export interface IMaterial { + /** + * @zh + * 当前使用的 EffectAsset 资源。 + */ + readonly effectAsset: EffectAsset | null; + + /** + * @zh + * 当前使用的 EffectAsset 资源名。 + */ + readonly effectName: string; + + /** + * @zh + * 当前的 technique 索引。 + */ + readonly technique: number; + + /** + * @zh + * 当前正在使用的 pass 数组。 + */ + readonly passes: IPass[]; + + /** + * @zh + * 材质的 hash。 + */ + readonly hash: number; + + readonly parent: IMaterial | null; + readonly owner: RenderableComponent | null; + + /** + * @zh + * 重置材质的所有 uniform 参数数据为 effect 默认初始值。 + * @param clearPasses 是否同时重置当前正在用于渲染的 pass 数组内的信息 + */ + resetUniforms (clearPasses?: boolean): void; + + /** + * @zh + * 使用指定预处理宏重新编译当前 pass(数组)中的 shader。 + * @param overrides 新增的预处理宏列表,会覆盖进当前列表。 + * @param passIdx 要编译的 pass 索引,默认编译所有 pass。 + */ + recompileShaders (overrides: IDefineMap, passIdx?: number): void; + + /** + * @zh + * 使用指定管线状态重载当前的 pass(数组)。 + * @param overrides 新增的管线状态列表,会覆盖进当前列表。 + * @param passIdx 要重载的 pass 索引,默认重载所有 pass。 + */ + overridePipelineStates (overrides: PassOverrides, passIdx?: number): void; + + /** + * @en + * Convenient property setter provided for quick material setup.
+ * [[Pass.setUniform]] should be used instead
+ * if you need to do per-frame property update. + * @zh + * 设置材质 uniform 参数的统一入口。
+ * 注意如果需要每帧更新 uniform,建议使用 [[Pass.setUniform]] 以获得更好的性能。 + * @param name 要设置的 uniform 名字。 + * @param val 要设置的 uniform 值。 + * @param passIdx 要设置的 pass 索引,默认设置所有 pass。 + */ + setProperty (name: string, val: any, passIdx?: number): void; + + /** + * @zh + * 获取当前材质的指定 uniform 值。 + * @param name 要获取的 uniform 名字。 + * @param passIdx 要获取的源 pass 索引,默认遍历所有 pass,返回第一个找到指定名字的 uniform。 + */ + getProperty (name: string, passIdx?: number): any; + + /** + * @zh + * 销毁材质实例 + */ + destroy (): void; + + _onPassStateChanged (idx: number); +} diff --git a/cocos/core/utils/pass-interface.ts b/cocos/core/utils/pass-interface.ts new file mode 100644 index 00000000000..7a3fee6ba79 --- /dev/null +++ b/cocos/core/utils/pass-interface.ts @@ -0,0 +1,238 @@ +import { IProgramInfo, programLib } from '../../core/renderer/core/program-lib'; +import { IPassInfo, IPropertyInfo } from '../assets/effect-asset'; +import { GFXBuffer, GFXDevice, GFXDynamicState, GFXPipelineState, GFXPrimitiveMode, GFXRenderPass, GFXSampler, GFXShader, GFXTextureView, GFXType } from '../gfx'; +import { IGFXBinding } from '../gfx/binding-layout'; +import { GFXBlendState, GFXDepthStencilState, GFXRasterizerState } from '../gfx/pipeline-state'; +import { BatchedBuffer } from '../pipeline/batched-buffer'; +import { RenderPassStage, RenderPriority } from '../pipeline/define'; +import { IDefineMap, PassOverrides } from '../renderer/core/pass'; +import { murmurhash2_32_gc } from './murmurhash2_gc'; + +export interface IBlock { + buffer: ArrayBuffer; + view: Float32Array; + dirty: boolean; +} + +export interface IPassDynamics { + [type: number]: { + dirty: boolean, + value: number[], + }; +} + +export interface IPSOHashInfo { + program: string; + defines: IDefineMap; + stage: RenderPassStage; + primitive: GFXPrimitiveMode; + rasterizerState: GFXRasterizerState; + depthStencilState: GFXDepthStencilState; + blendState: GFXBlendState; + dynamicStates: GFXDynamicState[]; +} + +function serializeBlendState (bs: GFXBlendState) { + let res = `,bs,${bs.isA2C},${bs.blendColor}`; + for (const t of bs.targets) { + res += `,bt,${t.blend},${t.blendEq},${t.blendAlphaEq},${t.blendColorMask}`; + res += `,${t.blendSrc},${t.blendDst},${t.blendSrcAlpha},${t.blendDstAlpha}`; + } + return res; +} + +function serializeRasterizerState (rs: GFXRasterizerState) { + const res = `,rs,${rs.cullMode},${rs.depthBias},${rs.isFrontFaceCCW}`; + return res; +} + +function serializeDepthStencilState (dss: GFXDepthStencilState) { + let res = `,dss,${dss.depthTest},${dss.depthWrite},${dss.depthFunc}`; + res += `,${dss.stencilTestFront},${dss.stencilFuncFront},${dss.stencilRefFront},${dss.stencilReadMaskFront}`; + res += `,${dss.stencilFailOpFront},${dss.stencilZFailOpFront},${dss.stencilPassOpFront},${dss.stencilWriteMaskFront}`; + res += `,${dss.stencilTestBack},${dss.stencilFuncBack},${dss.stencilRefBack},${dss.stencilReadMaskBack}`; + res += `,${dss.stencilFailOpBack},${dss.stencilZFailOpBack},${dss.stencilPassOpBack},${dss.stencilWriteMaskBack}`; + return res; +} + +export function generatePassPSOHash (pass: IPass) { + const shaderKey = programLib.getKey(pass.program, pass.defines); + let res = `${shaderKey},${pass.stage},${pass.primitive}`; + res += serializeBlendState(pass.blendState); + res += serializeDepthStencilState(pass.depthStencilState); + res += serializeRasterizerState(pass.rasterizerState); + return murmurhash2_32_gc(res, 666); +} + +export interface IPass { + + readonly parent: IPass | null; + readonly psoHash: number; + readonly batchedBuffer: BatchedBuffer | null; + // states + readonly priority: RenderPriority; + readonly primitive: GFXPrimitiveMode; + readonly stage: RenderPassStage; + readonly rasterizerState: GFXRasterizerState; + readonly depthStencilState: GFXDepthStencilState; + readonly blendState: GFXBlendState; + readonly dynamicStates: GFXDynamicState[]; + readonly customizations: string[]; + readonly phase: number; + // infos + readonly shaderInfo: IProgramInfo; + readonly program: string; + readonly properties: Record; + readonly defines: IDefineMap; + readonly idxInTech: number; + // resources + readonly device: GFXDevice; + readonly bindings: IGFXBinding[]; + readonly shader: GFXShader; + readonly renderPass: GFXRenderPass; + readonly dynamics: IPassDynamics; + readonly blocks: IBlock[]; + /** + * @zh + * 获取指定 UBO 成员,或其更具体分量的读写句柄。默认以成员自身的类型为目标读写类型(即读写时必须传入与成员类型相同的变量)。 + * @param name 目标 UBO 成员名 + * @param offset 目标分量在成员内的偏移量 + * @param targetType 目标读写类型,用于定制化在使用此句柄时,将以什么类型进行读写操作 + * @example + * ``` + * // say 'pbrParams' is a uniform vec4 + * const hParams = pass.getHandle('pbrParams'); // get the default handle + * pass.setUniform(hAlbedo, cc.v3(1, 0, 0)); // wrong! pbrParams.w is NaN now + * + * // say 'albedoScale' is a uniform vec4, and we only want to modify the w component in the form of a single float + * const hThreshold = pass.getHandle('albedoScale', 3, cc.GFXType.FLOAT); + * pass.setUniform(hThreshold, 0.5); // now, albedoScale.w = 0.5 + * ``` + */ + getHandle (name: string, offset?: number, targetType?: GFXType): number | undefined; + + /** + * @zh + * 获取指定 uniform 的 binding。 + * @param name 目标 uniform 名。 + */ + getBinding (name: string): number | undefined; + + /** + * @zh + * 设置指定普通向量类 uniform 的值,如果需要频繁更新请尽量使用此接口。 + * @param handle 目标 uniform 的 handle。 + * @param value 目标值。 + */ + setUniform (handle: number, value: any): void; + + /** + * @zh + * 获取指定普通向量类 uniform 的值。 + * @param handle 目标 uniform 的 handle。 + * @param out 输出向量。 + */ + getUniform (handle: number, out: any): any; + + /** + * @zh + * 设置指定数组类 uniform 的值,如果需要频繁更新请尽量使用此接口。 + * @param handle 目标 uniform 的 handle。 + * @param value 目标值。 + */ + setUniformArray (handle: number, value: any[]): void; + + /** + * @zh + * 绑定实际 [[GFXBuffer]] 到指定 binding。 + * @param binding 目标 UBO 的 binding。 + * @param value 目标 buffer。 + */ + bindBuffer (binding: number, value: GFXBuffer): void; + + /** + * @zh + * 绑定实际 [[GFXTextureView]] 到指定 binding。 + * @param binding 目标贴图类 uniform 的 binding。 + * @param value 目标 texture view。 + */ + bindTextureView (binding: number, value: GFXTextureView): void; + + /** + * @zh + * 绑定实际 [[GFXSampler]] 到指定 binding。 + * @param binding 目标贴图类 uniform 的 binding。 + * @param value 目标 sampler。 + */ + bindSampler (binding: number, value: GFXSampler): void; + + /** + * @zh + * 设置运行时 pass 内可动态更新的管线状态属性。 + * @param state 目标管线状态。 + * @param value 目标值。 + */ + setDynamicState (state: GFXDynamicState, value: any): void; + + /** + * @zh + * 重载当前所有管线状态。 + * @param original 原始管线状态。 + * @param value 管线状态重载值。 + */ + overridePipelineStates (original: IPassInfo, overrides: PassOverrides): void; + + /** + * @zh + * 更新当前 Uniform 数据。 + */ + update (): void; + + /** + * @zh + * 销毁当前 pass。 + */ + destroy (): void; + + /** + * @zh + * 重置所有 UBO 为初始默认值。 + */ + resetUBOs (): void; + + /** + * @zh + * 重置所有 texture 和 sampler 为初始默认值。 + */ + resetTextures (): void; + + /** + * @zh + * 尝试编译 shader 并获取相关资源引用。 + * @param defineOverrides shader 预处理宏定义重载 + */ + tryCompile (defineOverrides?: IDefineMap, saveOverrides?: boolean): any; + + /** + * @zh + * 根据当前 pass 持有的信息创建 [[GFXPipelineState]]。 + */ + createPipelineState (): GFXPipelineState | null; + + /** + * @zh + * 销毁指定的 [[GFXPipelineState]],如果它是这个 pass 创建的。 + */ + destroyPipelineState (pipelineStates?: GFXPipelineState): void; + + createBatchedBuffer (): void; + + clearBatchedBuffer (): void; + + /** + * @zh + * 用于在component的pso变化的回调中调用以取消pso变化的通知,一般情况下不应该调用该函数,如果必须调用,请先检查上层逻辑是否合理。 + */ + beginChangeStatesSilently (): void; + endChangeStatesSilently (): void; +} diff --git a/cocos/core/utils/profiler/profiler.ts b/cocos/core/utils/profiler/profiler.ts index b12f429d214..7f0faadfa11 100644 --- a/cocos/core/utils/profiler/profiler.ts +++ b/cocos/core/utils/profiler/profiler.ts @@ -32,9 +32,9 @@ import { GFXDevice } from '../../gfx/device'; import { GFXTexture } from '../../gfx/texture'; import { GFXTextureView } from '../../gfx/texture-view'; import { Vec4 } from '../../math'; -import { IBlock } from '../../renderer/core/pass'; import { Layers } from '../../scene-graph'; import { Node } from '../../scene-graph/node'; +import { IBlock } from '../pass-interface'; import { ICounterOption } from './counter'; import { PerfCounter } from './perf-counter'; @@ -339,10 +339,11 @@ export class Profiler { const handle = pass.getBinding('mainTexture'); pass.bindTextureView(handle!, this._textureView!); - const binding = pass.getBinding('digits')!; - this.digitsData = pass.blocks[binding]; - modelCom.material = _material; + const passInstance = modelCom.material.passes[0]; + const binding = passInstance.getBinding('digits')!; + this.digitsData = passInstance.blocks[binding]; + modelCom.node.layer = Layers.Enum.PROFILER; } diff --git a/cocos/particle/models/particle-batch-model.ts b/cocos/particle/models/particle-batch-model.ts index 3b108a55b9e..8c74cb31b38 100644 --- a/cocos/particle/models/particle-batch-model.ts +++ b/cocos/particle/models/particle-batch-model.ts @@ -27,7 +27,6 @@ * @hidden */ -import { Material } from '../../core/assets/material'; import { IRenderingSubmesh, Mesh } from '../../core/assets/mesh'; import { GFX_DRAW_INFO_SIZE, GFXBuffer, IGFXIndirectBuffer } from '../../core/gfx/buffer'; import { GFXAttributeName, GFXBufferUsageBit, GFXFormatInfos, @@ -35,6 +34,7 @@ import { GFXAttributeName, GFXBufferUsageBit, GFXFormatInfos, import { IGFXAttribute } from '../../core/gfx/input-assembler'; import { Color } from '../../core/math/color'; import { Model } from '../../core/renderer/scene/model'; +import { IMaterial } from '../../core/utils/material-interface'; export default class ParticleBatchModel extends Model { @@ -204,7 +204,7 @@ export default class ParticleBatchModel extends Model { return vBuffer; } - public setSubModelMaterial (idx: number, mat: Material | null) { + public setSubModelMaterial (idx: number, mat: IMaterial | null) { this.initLocalBindings(mat); super.setSubModelMaterial(idx, mat); } diff --git a/cocos/particle/renderer/particle-system-renderer.ts b/cocos/particle/renderer/particle-system-renderer.ts index c1c248d04a7..40c1fe633f5 100644 --- a/cocos/particle/renderer/particle-system-renderer.ts +++ b/cocos/particle/renderer/particle-system-renderer.ts @@ -6,7 +6,9 @@ import { GFXAttributeName, GFXFormat } from '../../core/gfx/define'; import { IGFXAttribute } from '../../core/gfx/input-assembler'; import { Mat4, Vec2, Vec3, Vec4 } from '../../core/math'; import { RecyclePool } from '../../core/memop'; +import { MaterialInstance } from '../../core/renderer'; import { IDefineMap } from '../../core/renderer/core/pass'; +import { IMaterial } from '../../core/utils/material-interface'; import { RenderMode, Space } from '../enum'; import ParticleBatchModel from '../models/particle-batch-model'; import Particle from '../particle'; @@ -177,7 +179,7 @@ export default class ParticleSystemRenderer { } public set particleMaterial (val) { - this._particleSystem.setMaterial(val, 0); + this._particleSystem.setMaterial(0, val); } /** @@ -196,7 +198,7 @@ export default class ParticleSystemRenderer { } public set trailMaterial (val) { - this._particleSystem.setMaterial(val, 1); + this._particleSystem.setMaterial(1, val); } private _defines: IDefineMap; @@ -207,8 +209,8 @@ export default class ParticleSystemRenderer { private attrs: any[]; private _vertAttrs: IGFXAttribute[] = []; private _particles: RecyclePool | null = null; - private _defaultMat: Material | null = null; - private _defaultTrailMat: Material | null = null; + private _defaultMat: IMaterial | null = null; + private _defaultTrailMat: IMaterial | null = null; constructor () { this._model = null; @@ -301,7 +303,7 @@ export default class ParticleSystemRenderer { this._particleSystem.node.getWorldScale(this._node_scale); break; } - const mat: Material | null = this._particleSystem.sharedMaterial ? this.particleMaterial : this._defaultMat; + const mat: Material | null = this._particleSystem.getMaterialInstance(0) || this._defaultMat; mat!.setProperty('scale', this._node_scale); if (this._particleSystem.velocityOvertimeModule.enable) { this._particleSystem.velocityOvertimeModule.update(this._particleSystem._simulationSpace, _tempWorldTrans); @@ -455,12 +457,12 @@ export default class ParticleSystemRenderer { return; } if (this._particleSystem.sharedMaterial != null && this._particleSystem.sharedMaterial._effectAsset._name.indexOf('particle') === -1) { - this._particleSystem.setMaterial(null, 0, false); + this._particleSystem.setMaterial(0, null); } if (this._particleSystem.sharedMaterial == null && this._defaultMat == null) { - this._defaultMat = Material.getInstantiatedMaterial(builtinResMgr.get('default-particle-material'), this._particleSystem, true); + this._defaultMat = new MaterialInstance(builtinResMgr.get('default-particle-material'), this._particleSystem); } - const mat: Material | null = this._particleSystem.sharedMaterial ? this.particleMaterial : this._defaultMat; + const mat: IMaterial | null = this._particleSystem.getMaterialInstance(0) || this._defaultMat; if (this._particleSystem._simulationSpace === Space.World) { this._defines[CC_USE_WORLD_SPACE] = true; } else { @@ -491,7 +493,7 @@ export default class ParticleSystemRenderer { } mat!.recompileShaders(this._defines); if (this._model) { - this._model.setSubModelMaterial(0, this._particleSystem.sharedMaterial || this._defaultMat); + this._model.setSubModelMaterial(0, mat); } } @@ -502,9 +504,9 @@ export default class ParticleSystemRenderer { } else { this._trailDefines[CC_USE_WORLD_SPACE] = false; } - let mat = this.trailMaterial; + let mat = this._particleSystem.getMaterialInstance(1); if (mat === null && this._defaultTrailMat === null) { - this._defaultTrailMat = Material.getInstantiatedMaterial(builtinResMgr.get('default-trail-material'), this._particleSystem, true); + this._defaultTrailMat = new MaterialInstance(builtinResMgr.get('default-trail-material'), this._particleSystem); } if (mat === null) { mat = this._defaultTrailMat; diff --git a/cocos/terrain/terrain.ts b/cocos/terrain/terrain.ts index 11ec8ca7ec4..0ff1719b336 100644 --- a/cocos/terrain/terrain.ts +++ b/cocos/terrain/terrain.ts @@ -1,32 +1,26 @@ /** * @category terrain */ + import { builtinResMgr } from '../core/3d/builtin'; -import { Component } from '../core/components'; -import { director } from '../core/director'; -// tslint:disable-next-line: ordered-imports -import { Material } from '../core/assets/material'; -import { IRenderingSubmesh } from '../core/assets/mesh'; -// tslint:disable-next-line: ordered-imports import { RenderableComponent } from '../core/3d/framework/renderable-component'; -import { Root } from '../core/root'; -// tslint:disable-next-line: ordered-imports +import { Texture2D } from '../core/assets'; import { Filter, PixelFormat, WrapMode } from '../core/assets/asset-enum'; -// tslint:disable-next-line: ordered-imports -import { ccclass, executeInEditMode, menu, property, disallowMultiple } from '../core/data/class-decorator'; -import { clamp, Rect, Size, Vec2, Vec3, Vec4 } from '../core/math'; -// tslint:disable-next-line: ordered-imports +import { Material } from '../core/assets/material'; +import { IRenderingSubmesh } from '../core/assets/mesh'; +import { Component } from '../core/components'; +import { ccclass, disallowMultiple, executeInEditMode, menu, property } from '../core/data/class-decorator'; +import { director } from '../core/director'; import { GFXBuffer } from '../core/gfx/buffer'; import { GFXAttributeName, GFXBufferUsageBit, GFXFormat, GFXMemoryUsageBit, GFXPrimitiveMode } from '../core/gfx/define'; import { GFXDevice } from '../core/gfx/device'; import { IGFXAttribute } from '../core/gfx/input-assembler'; +import { clamp, Rect, Size, Vec2, Vec3, Vec4 } from '../core/math'; +import { IDefineMap } from '../core/renderer/core/pass'; import { Model } from '../core/renderer/scene/model'; +import { Root } from '../core/root'; import { PrivateNode } from '../core/scene-graph/private-node'; -// tslint:disable-next-line: ordered-imports -import { IDefineMap } from '../core/renderer/core/pass'; import { HeightField } from './height-field'; -// tslint:disable-next-line: ordered-imports -import { Texture2D } from '../core/assets'; import { TerrainAsset, TerrainLayerInfo } from './terrain-asset'; export const TERRAIN_MAX_LEVELS = 4; @@ -156,7 +150,7 @@ export class TerrainRenderable extends RenderableComponent { this._model.initSubModel(0, this._meshData, this._currentMaterial); } - this.setMaterial(this._currentMaterial, 0); + this.setMaterial(0, this._currentMaterial); this._currentMaterialLayers = nlayers; this._model.enabled = true; } diff --git a/cocos/ui/components/graphics-component.ts b/cocos/ui/components/graphics-component.ts index e0c53fa27c5..5a34b82e4f3 100644 --- a/cocos/ui/components/graphics-component.ts +++ b/cocos/ui/components/graphics-component.ts @@ -28,18 +28,17 @@ * @category ui */ +import { builtinResMgr } from '../../core/3d/builtin'; +import { RenderableComponent } from '../../core/3d/framework/renderable-component'; +import { InstanceMaterialType, UIRenderComponent } from '../../core/components/ui-base/ui-render-component'; import { ccclass, executionOrder, menu, property } from '../../core/data/class-decorator'; +import { director } from '../../core/director'; import { Color } from '../../core/math'; -import { Model } from '../../core/renderer'; -import { UI } from '../../core/renderer/ui/ui'; -import { Material } from '../../core/assets/material'; -import { RenderableComponent } from '../../core/3d/framework/renderable-component'; +import { MaterialInstance, Model } from '../../core/renderer'; import { IAssembler } from '../../core/renderer/ui/base'; +import { UI } from '../../core/renderer/ui/ui'; import { LineCap, LineJoin } from '../assembler/graphics/types'; import { Impl } from '../assembler/graphics/webgl/impl'; -import { InstanceMaterialType, UIRenderComponent } from '../../core/components/ui-base/ui-render-component'; -import { director } from '../../core/director'; -import { builtinResMgr } from '../../core/3d/builtin'; /** * @zh @@ -474,13 +473,12 @@ export class GraphicsComponent extends UIRenderComponent { * 辅助材质实例化。可用于只取数据而无实体情况下渲染使用。特殊情况可参考:[[instanceMaterial]] */ public helpInstanceMaterial () { - let mat: Material | null = null; + let mat: MaterialInstance | null = null; if (this._sharedMaterial) { - mat = Material.getInstantiatedMaterial(this._sharedMaterial, new RenderableComponent(), CC_EDITOR ? true : false); + mat = new MaterialInstance(this._sharedMaterial, new RenderableComponent()); } else { - mat = Material.getInstantiatedMaterial(builtinResMgr.get('ui-base-material'), new RenderableComponent(), CC_EDITOR ? true : false); + mat = new MaterialInstance(builtinResMgr.get('ui-base-material'), new RenderableComponent()); mat.recompileShaders({ USE_LOCAL: true }); - mat.onLoaded(); } this._updateMaterial(mat); From 6fc6ddf59b058c50355dff259ae9ced889710bcd Mon Sep 17 00:00:00 2001 From: zxg <247274249@qq.com> Date: Mon, 23 Dec 2019 10:30:24 +0800 Subject: [PATCH 02/13] revert setMaterial signature --- cocos/core/3d/framework/renderable-component.ts | 8 ++++---- cocos/particle/renderer/particle-system-renderer.ts | 6 +++--- cocos/terrain/terrain.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cocos/core/3d/framework/renderable-component.ts b/cocos/core/3d/framework/renderable-component.ts index 09447ce10c5..ae451f30828 100644 --- a/cocos/core/3d/framework/renderable-component.ts +++ b/cocos/core/3d/framework/renderable-component.ts @@ -45,12 +45,12 @@ export class RenderableComponent extends Component { set sharedMaterials (val) { for (let i = 0; i < val.length; i++) { if (val[i] !== this._materials[i]) { - this.setMaterial(i, val[i]); + this.setMaterial(val[i], i); } } if (val.length < this._materials.length) { for (let i = val.length; i < this._materials.length; i++) { - this.setMaterial(i, null); + this.setMaterial(null, i); } this._materials.splice(val.length); } @@ -76,7 +76,7 @@ export class RenderableComponent extends Component { * @param index 材质序号 * @param material 材质对象 */ - public setMaterial (index: number, material: Material | null) { + public setMaterial (material: Material | null, index: number) { this._materials[index] = material; if (this._materialInstances[index]) { if (this._materialInstances[index]!.parent !== material) { @@ -158,7 +158,7 @@ export class RenderableComponent extends Component { } } else { if (matInst !== this._materials[index]) { - this.setMaterial(index, matInst as Material); + this.setMaterial(matInst as Material, index); } } } diff --git a/cocos/particle/renderer/particle-system-renderer.ts b/cocos/particle/renderer/particle-system-renderer.ts index 40c1fe633f5..0ddbec55bcd 100644 --- a/cocos/particle/renderer/particle-system-renderer.ts +++ b/cocos/particle/renderer/particle-system-renderer.ts @@ -179,7 +179,7 @@ export default class ParticleSystemRenderer { } public set particleMaterial (val) { - this._particleSystem.setMaterial(0, val); + this._particleSystem.setMaterial(val, 0); } /** @@ -198,7 +198,7 @@ export default class ParticleSystemRenderer { } public set trailMaterial (val) { - this._particleSystem.setMaterial(1, val); + this._particleSystem.setMaterial(val, 1); } private _defines: IDefineMap; @@ -457,7 +457,7 @@ export default class ParticleSystemRenderer { return; } if (this._particleSystem.sharedMaterial != null && this._particleSystem.sharedMaterial._effectAsset._name.indexOf('particle') === -1) { - this._particleSystem.setMaterial(0, null); + this._particleSystem.setMaterial(null, 0); } if (this._particleSystem.sharedMaterial == null && this._defaultMat == null) { this._defaultMat = new MaterialInstance(builtinResMgr.get('default-particle-material'), this._particleSystem); diff --git a/cocos/terrain/terrain.ts b/cocos/terrain/terrain.ts index 0ff1719b336..d5d4069e0fe 100644 --- a/cocos/terrain/terrain.ts +++ b/cocos/terrain/terrain.ts @@ -150,7 +150,7 @@ export class TerrainRenderable extends RenderableComponent { this._model.initSubModel(0, this._meshData, this._currentMaterial); } - this.setMaterial(0, this._currentMaterial); + this.setMaterial(this._currentMaterial, 0); this._currentMaterialLayers = nlayers; this._model.enabled = true; } From 5f970781063e150745d4e14620b05e695a336fe7 Mon Sep 17 00:00:00 2001 From: zxg <247274249@qq.com> Date: Mon, 23 Dec 2019 17:30:30 +0800 Subject: [PATCH 03/13] fix some defects --- cocos/core/3d/framework/model-component.ts | 4 ++- cocos/core/assets/effect-asset.ts | 2 +- cocos/core/assets/material.ts | 16 +++-------- cocos/core/pipeline/render-pipeline.ts | 2 +- cocos/core/renderer/core/material-instance.ts | 3 ++- cocos/core/renderer/core/pass-instance.ts | 27 +++++++------------ cocos/core/renderer/core/pass-utils.ts | 14 ++++++++++ cocos/core/renderer/core/pass.ts | 11 +++++--- cocos/core/renderer/core/program-lib.ts | 3 +-- cocos/core/renderer/scene/model.ts | 4 +-- cocos/core/utils/material-interface.ts | 4 +-- cocos/core/utils/pass-interface.ts | 5 ++-- .../renderer/particle-system-renderer.ts | 4 +-- cocos/terrain/terrain.ts | 2 +- 14 files changed, 51 insertions(+), 50 deletions(-) diff --git a/cocos/core/3d/framework/model-component.ts b/cocos/core/3d/framework/model-component.ts index 2293d52f9e3..8234c579b5c 100644 --- a/cocos/core/3d/framework/model-component.ts +++ b/cocos/core/3d/framework/model-component.ts @@ -268,7 +268,9 @@ export class ModelComponent extends RenderableComponent { this._model.isDynamicBatching = this._enableDynamicBatching; // should pass this in before create PSO const meshCount = this._mesh ? this._mesh.subMeshCount : 0; for (let i = 0; i < meshCount; ++i) { - const material = this.getRenderMaterial(i); + // warning:这里先改成model总是使用材质实例,等model中的createPipelineState修改完后再替换成getRenderMaterial + const material = this.getMaterialInstance(i); + // const material = this.getRenderMaterial(i); const renderingMesh = this._mesh.renderingMesh; if (renderingMesh) { const subMeshData = renderingMesh.getSubmesh(i); diff --git a/cocos/core/assets/effect-asset.ts b/cocos/core/assets/effect-asset.ts index 4b7a4c445cc..5bfec5f4783 100644 --- a/cocos/core/assets/effect-asset.ts +++ b/cocos/core/assets/effect-asset.ts @@ -33,7 +33,7 @@ import { GFXDynamicState, GFXPrimitiveMode } from '../gfx/define'; import { GFXBlendState, GFXDepthStencilState, GFXRasterizerState } from '../gfx/pipeline-state'; import { GFXUniformBlock, GFXUniformSampler } from '../gfx/shader'; import { RenderPassStage } from '../pipeline/define'; -import { IDefineMap } from '../renderer/core/pass'; +import { IDefineMap } from '../renderer/core/pass-utils'; import { programLib } from '../renderer/core/program-lib'; import { Asset } from './asset'; diff --git a/cocos/core/assets/material.ts b/cocos/core/assets/material.ts index 1df1ffb50bc..00316e19acf 100644 --- a/cocos/core/assets/material.ts +++ b/cocos/core/assets/material.ts @@ -31,7 +31,8 @@ import { ccclass, property } from '../../core/data/class-decorator'; import { builtinResMgr } from '../3d/builtin/init'; import { RenderableComponent } from '../3d/framework/renderable-component'; -import { IDefineMap, Pass, PassOverrides } from '../renderer/core/pass'; +import { Pass, PassOverrides } from '../renderer/core/pass'; +import { IDefineMap } from '../renderer/core/pass-utils'; import { _uploadProperty, generateMaterailHash, IMaterial } from '../utils/material-interface'; import { Asset } from './asset'; import { EffectAsset } from './effect-asset'; @@ -222,18 +223,7 @@ export class Material extends Asset implements IMaterial { * @param passIdx 要重载的 pass 索引,默认重载所有 pass。 */ public overridePipelineStates (overrides: PassOverrides, passIdx?: number) { - if (!this._passes || !this._effectAsset) { return; } - const passInfos = this._effectAsset.techniques[this._techIdx].passes; - if (passIdx === undefined) { - for (let i = 0; i < this._passes.length; i++) { - const pass = this._passes[i]; - this._states[i] = overrides; - pass.overridePipelineStates(passInfos[pass.idxInTech], overrides); - } - } else { - this._states[passIdx] = overrides; - this._passes[passIdx].overridePipelineStates(passInfos[passIdx], overrides); - } + console.error('Material:' + this.effectName + ' cann\'t be overwritten.Please use pass instance to do so.'); } /** diff --git a/cocos/core/pipeline/render-pipeline.ts b/cocos/core/pipeline/render-pipeline.ts index eb3559e40a0..0b44f5c84de 100644 --- a/cocos/core/pipeline/render-pipeline.ts +++ b/cocos/core/pipeline/render-pipeline.ts @@ -20,7 +20,7 @@ import { GFXTexture } from '../gfx/texture'; import { GFXTextureView } from '../gfx/texture-view'; import { Mat4, Vec3, Vec4 } from '../math'; import { Camera, Model } from '../renderer'; -import { IDefineMap } from '../renderer/core/pass'; +import { IDefineMap } from '../renderer/core/pass-utils'; import { programLib } from '../renderer/core/program-lib'; import { SKYBOX_FLAG } from '../renderer/scene/camera'; import { Root } from '../root'; diff --git a/cocos/core/renderer/core/material-instance.ts b/cocos/core/renderer/core/material-instance.ts index 187d2744265..e321f3d6753 100644 --- a/cocos/core/renderer/core/material-instance.ts +++ b/cocos/core/renderer/core/material-instance.ts @@ -3,8 +3,9 @@ import { EffectAsset, Material } from '../../assets'; import { _uploadProperty, IMaterial } from '../../utils/material-interface'; import { murmurhash2_32_gc } from '../../utils/murmurhash2_gc'; import { IPass } from '../../utils/pass-interface'; -import { IDefineMap, PassOverrides } from './pass'; +import { PassOverrides } from './pass'; import { PassInstance } from './pass-instance'; +import { IDefineMap } from './pass-utils'; export class MaterialInstance implements IMaterial { diff --git a/cocos/core/renderer/core/pass-instance.ts b/cocos/core/renderer/core/pass-instance.ts index 606254f4404..67cacd757ef 100644 --- a/cocos/core/renderer/core/pass-instance.ts +++ b/cocos/core/renderer/core/pass-instance.ts @@ -11,8 +11,8 @@ import { isBuiltinBinding, RenderPassStage, RenderPriority } from '../../pipelin import { getPhaseID } from '../../pipeline/pass-phase'; import { IMaterial } from '../../utils/material-interface'; import { generatePassPSOHash, IBlock, IPass, IPassDynamics, IPSOHashInfo } from '../../utils/pass-interface'; -import { IDefineMap, Pass } from './pass'; -import { getBindingFromHandle, getOffsetFromHandle, getTypeFromHandle, type2default, type2reader, type2writer } from './pass-utils'; +import { Pass } from './pass'; +import { assignDefines, getBindingFromHandle, getOffsetFromHandle, getTypeFromHandle, IDefineMap, type2default, type2reader, type2writer } from './pass-utils'; import { IProgramInfo, programLib } from './program-lib'; import { samplerLib } from './sampler-lib'; @@ -360,7 +360,10 @@ export class PassInstance implements IPass { } } - public tryCompile (defineOverrides?: IDefineMap, saveOverrides?: boolean): any { + public tryCompile (defineOverrides?: IDefineMap): any { + if (defineOverrides && !assignDefines(this._defines, defineOverrides)) { + return null; + } const pipeline = cc.director.root.pipeline; if (!pipeline) { return null; @@ -369,25 +372,13 @@ export class PassInstance implements IPass { if (!this._renderPass) { console.warn(`illegal pass stage.`); return null; } - let defines = this._defines; - if (defineOverrides) { - if (saveOverrides) { - Object.assign(this._defines, defineOverrides); - } - else { - Object.assign(defineOverrides, this._defines); - defines = defineOverrides; - } - } - const res = programLib.getGFXShader(this.device, this.program, defines, pipeline); + const res = programLib.getGFXShader(this.device, this.program, this._defines, pipeline); if (!res.shader) { console.warn(`create shader ${this.program} failed`); return null; } - if (saveOverrides) { - this._shader = res.shader; - this._bindings = res.bindings; - } + this._shader = res.shader; + this._bindings = res.bindings; this._hash = generatePassPSOHash(this); this._onPipelineStateChanged(); return res; diff --git a/cocos/core/renderer/core/pass-utils.ts b/cocos/core/renderer/core/pass-utils.ts index aa4ca44004c..85ff97f7cf0 100644 --- a/cocos/core/renderer/core/pass-utils.ts +++ b/cocos/core/renderer/core/pass-utils.ts @@ -85,3 +85,17 @@ export const type2default = { [GFXType.SAMPLER2D]: 'default-texture', [GFXType.SAMPLER_CUBE]: 'default-cube-texture', }; + +export interface IDefineMap { [name: string]: number | boolean | string; } + +export function assignDefines (target: IDefineMap, source: IDefineMap): boolean { + const entries = Object.entries(source); + let isDifferent: boolean = false; + for (let i = 0; i < entries.length; i++) { + if (target[entries[i][0]] !== entries[i][1]) { + target[entries[i][0]] = entries[i][1]; + isDifferent = true; + } + } + return isDifferent; +} diff --git a/cocos/core/renderer/core/pass.ts b/cocos/core/renderer/core/pass.ts index a9215a7862f..10b0882a1cc 100644 --- a/cocos/core/renderer/core/pass.ts +++ b/cocos/core/renderer/core/pass.ts @@ -45,11 +45,11 @@ import { isBuiltinBinding, RenderPassStage, RenderPriority } from '../../pipelin import { getPhaseID } from '../../pipeline/pass-phase'; import { Root } from '../../root'; import { generatePassPSOHash, IBlock, IPass, IPassDynamics, IPSOHashInfo } from '../../utils/pass-interface'; -import { customizeType, getBindingFromHandle, getBindingTypeFromHandle, getOffsetFromHandle, getTypeFromHandle, type2default, type2reader, type2writer } from './pass-utils'; +// tslint:disable-next-line: max-line-length +import { assignDefines, customizeType, getBindingFromHandle, getBindingTypeFromHandle, getOffsetFromHandle, getTypeFromHandle, IDefineMap, type2default, type2reader, type2writer } from './pass-utils'; import { IProgramInfo, IShaderResources, programLib } from './program-lib'; import { samplerLib } from './sampler-lib'; -export interface IDefineMap { [name: string]: number | boolean | string; } export interface IPassInfoFull extends IPassInfo { // generated part idxInTech: number; @@ -500,15 +500,18 @@ export class Pass implements IPass { */ public tryCompile ( defineOverrides?: IDefineMap, - saveOverrides = true, ): IShaderResources | null /* TODO: Explicit since TS4053 bug , changes required once the issue is fixed. */ { + if (defineOverrides && !assignDefines(this._defines, defineOverrides)) { + return null; + } const pipeline = (cc.director.root as Root).pipeline; if (!pipeline) { return null; } this._renderPass = pipeline.getRenderPass(this._stage); if (!this._renderPass) { console.warn(`illegal pass stage.`); return null; } const res = programLib.getGFXShader(this._device, this._programName, this._defines, pipeline); if (!res.shader) { console.warn(`create shader ${this._programName} failed`); return null; } - if (saveOverrides) { this._shader = res.shader; this._bindings = res.bindings; } + this._shader = res.shader; + this._bindings = res.bindings; this._hash = generatePassPSOHash(this); return res; } diff --git a/cocos/core/renderer/core/program-lib.ts b/cocos/core/renderer/core/program-lib.ts index 99983bc995b..17f4c3605bf 100644 --- a/cocos/core/renderer/core/program-lib.ts +++ b/cocos/core/renderer/core/program-lib.ts @@ -34,8 +34,7 @@ import { GFXAPI, GFXDevice } from '../../gfx/device'; import { GFXShader, GFXUniformBlock } from '../../gfx/shader'; import { IInternalBindingDesc, localBindingsDesc } from '../../pipeline/define'; import { RenderPipeline } from '../../pipeline/render-pipeline'; -import { IDefineMap } from './pass'; -import { genHandle } from './pass-utils'; +import { genHandle, IDefineMap } from './pass-utils'; interface IDefineRecord extends IDefineInfo { _map: (value: any) => number; diff --git a/cocos/core/renderer/scene/model.ts b/cocos/core/renderer/scene/model.ts index 171205dec5e..a2594ad93e8 100644 --- a/cocos/core/renderer/scene/model.ts +++ b/cocos/core/renderer/scene/model.ts @@ -14,10 +14,10 @@ import { Node } from '../../scene-graph'; import { Layers } from '../../scene-graph/layers'; import { IMaterial } from '../../utils/material-interface'; import { IPass } from '../../utils/pass-interface'; -import { IDefineMap } from '../core/pass'; import { customizationManager } from './customization-manager'; import { RenderScene } from './render-scene'; import { SubModel } from './submodel'; +import { IDefineMap } from '../core/pass-utils'; const m4_1 = new Mat4(); @@ -360,7 +360,7 @@ export class Model { } } - protected createPipelineState (pass: IPass, defineOverrides?: IDefineMap, stateOverrides?: IPassStates) { + protected createPipelineState (pass: IPass, defineOverrides?: IDefineMap) { defineOverrides = defineOverrides || {}; if (pass.blendState.targets[0].blend) { this._isDynamicBatching = false; diff --git a/cocos/core/utils/material-interface.ts b/cocos/core/utils/material-interface.ts index a0dfcbc5430..430f1840faf 100644 --- a/cocos/core/utils/material-interface.ts +++ b/cocos/core/utils/material-interface.ts @@ -3,8 +3,8 @@ import { EffectAsset } from '../assets/effect-asset'; import { SpriteFrame } from '../assets/sprite-frame'; import { TextureBase } from '../assets/texture-base'; import { GFXBindingType, GFXTextureView } from '../gfx'; -import { IDefineMap, PassOverrides } from '../renderer/core/pass'; -import { getBindingFromHandle, getBindingTypeFromHandle } from '../renderer/core/pass-utils'; +import { PassOverrides } from '../renderer/core/pass'; +import { getBindingFromHandle, getBindingTypeFromHandle, IDefineMap } from '../renderer/core/pass-utils'; import { samplerLib } from '../renderer/core/sampler-lib'; import { murmurhash2_32_gc } from './murmurhash2_gc'; import { IPass } from './pass-interface'; diff --git a/cocos/core/utils/pass-interface.ts b/cocos/core/utils/pass-interface.ts index 7a3fee6ba79..e6963101b54 100644 --- a/cocos/core/utils/pass-interface.ts +++ b/cocos/core/utils/pass-interface.ts @@ -5,7 +5,8 @@ import { IGFXBinding } from '../gfx/binding-layout'; import { GFXBlendState, GFXDepthStencilState, GFXRasterizerState } from '../gfx/pipeline-state'; import { BatchedBuffer } from '../pipeline/batched-buffer'; import { RenderPassStage, RenderPriority } from '../pipeline/define'; -import { IDefineMap, PassOverrides } from '../renderer/core/pass'; +import { PassOverrides } from '../renderer/core/pass'; +import { IDefineMap } from '../renderer/core/pass-utils'; import { murmurhash2_32_gc } from './murmurhash2_gc'; export interface IBlock { @@ -211,7 +212,7 @@ export interface IPass { * 尝试编译 shader 并获取相关资源引用。 * @param defineOverrides shader 预处理宏定义重载 */ - tryCompile (defineOverrides?: IDefineMap, saveOverrides?: boolean): any; + tryCompile (defineOverrides?: IDefineMap): any; /** * @zh diff --git a/cocos/particle/renderer/particle-system-renderer.ts b/cocos/particle/renderer/particle-system-renderer.ts index 0ddbec55bcd..aadc3b6bdca 100644 --- a/cocos/particle/renderer/particle-system-renderer.ts +++ b/cocos/particle/renderer/particle-system-renderer.ts @@ -6,8 +6,8 @@ import { GFXAttributeName, GFXFormat } from '../../core/gfx/define'; import { IGFXAttribute } from '../../core/gfx/input-assembler'; import { Mat4, Vec2, Vec3, Vec4 } from '../../core/math'; import { RecyclePool } from '../../core/memop'; -import { MaterialInstance } from '../../core/renderer'; -import { IDefineMap } from '../../core/renderer/core/pass'; +import { MaterialInstance } from '../../core/renderer/core/material-instance'; +import { IDefineMap } from '../../core/renderer/core/pass-utils'; import { IMaterial } from '../../core/utils/material-interface'; import { RenderMode, Space } from '../enum'; import ParticleBatchModel from '../models/particle-batch-model'; diff --git a/cocos/terrain/terrain.ts b/cocos/terrain/terrain.ts index d5d4069e0fe..9d4018bab13 100644 --- a/cocos/terrain/terrain.ts +++ b/cocos/terrain/terrain.ts @@ -16,7 +16,7 @@ import { GFXAttributeName, GFXBufferUsageBit, GFXFormat, GFXMemoryUsageBit, GFXP import { GFXDevice } from '../core/gfx/device'; import { IGFXAttribute } from '../core/gfx/input-assembler'; import { clamp, Rect, Size, Vec2, Vec3, Vec4 } from '../core/math'; -import { IDefineMap } from '../core/renderer/core/pass'; +import { IDefineMap } from '../core/renderer/core/pass-utils'; import { Model } from '../core/renderer/scene/model'; import { Root } from '../core/root'; import { PrivateNode } from '../core/scene-graph/private-node'; From e50c04e8c8130b020a5774de53abc5056f0f1549 Mon Sep 17 00:00:00 2001 From: Yun Hsiao Wu Date: Tue, 24 Dec 2019 11:01:57 +0800 Subject: [PATCH 04/13] material instance using inheritance (#5) * material instance using inheritance * renderable component --- .../core/3d/framework/renderable-component.ts | 114 ++-- cocos/core/assets/material.ts | 195 ++++--- cocos/core/renderer/core/material-instance.ts | 186 +++---- cocos/core/renderer/core/pass-instance.ts | 495 ++---------------- cocos/core/renderer/core/pass.ts | 163 +++--- cocos/core/utils/material-interface.ts | 135 ----- cocos/core/utils/pass-interface.ts | 239 --------- 7 files changed, 386 insertions(+), 1141 deletions(-) delete mode 100644 cocos/core/utils/material-interface.ts delete mode 100644 cocos/core/utils/pass-interface.ts diff --git a/cocos/core/3d/framework/renderable-component.ts b/cocos/core/3d/framework/renderable-component.ts index ae451f30828..eb7819753a1 100644 --- a/cocos/core/3d/framework/renderable-component.ts +++ b/cocos/core/3d/framework/renderable-component.ts @@ -5,12 +5,16 @@ // @ts-check import { Material } from '../../assets/material'; import { Component } from '../../components/component'; -import { _decorator } from '../../data/index'; -import { MaterialInstance } from '../../renderer/core/material-instance'; +import { ccclass, property } from '../../data/class-decorator'; +import { IMaterialInstanceInfo, MaterialInstance } from '../../renderer/core/material-instance'; import { Model } from '../../renderer/scene/model'; import { Layers } from '../../scene-graph/layers'; -import { IMaterial } from '../../utils/material-interface'; -const { ccclass, property } = _decorator; + +const _matInsInfo: IMaterialInstanceInfo = { + parent: null!, + owner: null!, + subModelIdx: 0, +}; @ccclass('cc.RenderableComponent') export class RenderableComponent extends Component { @@ -20,15 +24,17 @@ export class RenderableComponent extends Component { }) protected _materials: Array = []; - protected _materialInstances: Array = []; - @property protected _visFlags = Layers.Enum.NONE; - protected _models: Model[] = []; + @property({ visible: false }) + get visibility () { + return this._visFlags; + } - constructor () { - super(); + set visibility (val) { + this._visFlags = val; + this._onVisiblityChange(val); } @property({ @@ -56,6 +62,37 @@ export class RenderableComponent extends Component { } } + /** + * @en The material of the model + * @zh 模型材质。 + */ + @property({ + type: Material, + visible: false, + animatable: true, + }) + get materials () { + for (let i = 0; i < this._materials.length; i++) { + this._materialInstances[i] = this.getMaterialInstance(i) as MaterialInstance; + } + return this._materials; + } + + set materials (val) { + const dLen = val.length - this._materials.length; + if (dLen > 0) { + this._materials = this._materials.concat(new Array(dLen).fill(null)); + } else if (dLen < 0) { + for (let i = -dLen; i < this._materials.length; ++i) { + this.setMaterialInstance(i, null); + } + this._materials = this._materials.splice(-dLen); + } + } + + protected _materialInstances: Array = []; + protected _models: Model[] = []; + get sharedMaterial () { return this.getMaterial(0); } @@ -72,7 +109,7 @@ export class RenderableComponent extends Component { } /** - * 设置指定的sharedMaterial,如果对应位置有材质实例则会创建一个对应的材质实例 + * 设置指定的 sharedMaterial,如果对应位置有材质实例则会创建一个对应的材质实例 * @param index 材质序号 * @param material 材质对象 */ @@ -88,35 +125,6 @@ export class RenderableComponent extends Component { } } - /** - * @en The material of the model - * @zh 模型材质。 - * @type {Material[]} - */ - @property({ - type: Material, - visible: false, - animatable: true, - }) - get materials () { - for (let i = 0; i < this._materials.length; i++) { - this._materialInstances[i] = this.getMaterialInstance(i) as MaterialInstance; - } - return this._materials; - } - - set materials (val) { - const dLen = val.length - this._materials.length; - if (dLen > 0) { - this._materials = this._materials.concat(new Array(dLen).fill(null)); - } else if (dLen < 0) { - for (let i = -dLen; i < this._materials.length; ++i) { - this.setMaterialInstance(i, null); - } - this._materials = this._materials.splice(-dLen); - } - } - get material () { return this.getMaterialInstance(0); } @@ -131,15 +139,18 @@ export class RenderableComponent extends Component { /** * @en Returns the material instance corresponding to the sequence number * @zh 获取相对应序号的材质实例。 - * @param {Number} idx - Look for the material list number + * @param idx Look for the material list number */ - public getMaterialInstance (idx: number): IMaterial | null { + public getMaterialInstance (idx: number): MaterialInstance | null { const mat = this._materials[idx]; if (!mat) { return null; } if (this._materialInstances[idx] == null) { - const instantiated = new MaterialInstance(this._materials[idx]!, this); + _matInsInfo.parent = this._materials[idx]!; + _matInsInfo.owner = this; + _matInsInfo.subModelIdx = idx; + const instantiated = new MaterialInstance(_matInsInfo); this.setMaterialInstance(idx, instantiated); } return this._materialInstances[idx]; @@ -150,7 +161,7 @@ export class RenderableComponent extends Component { * @param index 材质序号 * @param matInst 材质实例 */ - public setMaterialInstance (index: number, matInst: IMaterial | null) { + public setMaterialInstance (index: number, matInst: MaterialInstance | null) { if (matInst && matInst.parent) { if (matInst !== this._materialInstances[index]) { this._materialInstances[index] = matInst as MaterialInstance; @@ -167,20 +178,10 @@ export class RenderableComponent extends Component { * 获取指定位置可供渲染的材质,如果有材质实例则使用材质实例,如果没有则使用材质资源 * @param index 材质序号 */ - public getRenderMaterial (index: number): IMaterial | null { + public getRenderMaterial (index: number): Material | null { return this._materialInstances[index] || this._materials[index]; } - @property({ visible: false }) - get visibility () { - return this._visFlags; - } - - set visibility (val) { - this._visFlags = val; - this._onVisiblityChange(val); - } - public _collectModels (): Model[] { return this._models; } @@ -191,18 +192,15 @@ export class RenderableComponent extends Component { protected _detachFromScene () { } - protected _onMaterialModified (index: number, material: IMaterial | null) { - + protected _onMaterialModified (index: number, material: Material | null) { } protected _onRebuildPSO (index: number, material: Material | null) { } protected _clearMaterials () { - } protected _onVisiblityChange (val) { - } } diff --git a/cocos/core/assets/material.ts b/cocos/core/assets/material.ts index 00316e19acf..3109e6053d0 100644 --- a/cocos/core/assets/material.ts +++ b/cocos/core/assets/material.ts @@ -29,13 +29,17 @@ */ import { ccclass, property } from '../../core/data/class-decorator'; +import { murmurhash2_32_gc } from '../../core/utils/murmurhash2_gc'; import { builtinResMgr } from '../3d/builtin/init'; -import { RenderableComponent } from '../3d/framework/renderable-component'; -import { Pass, PassOverrides } from '../renderer/core/pass'; -import { IDefineMap } from '../renderer/core/pass-utils'; -import { _uploadProperty, generateMaterailHash, IMaterial } from '../utils/material-interface'; +import { GFXBindingType } from '../gfx/define'; +import { GFXTextureView } from '../gfx/texture-view'; +import { IDefineMap } from '../renderer'; +import { IPassInfoFull, Pass, PassOverrides } from '../renderer/core/pass'; +import { samplerLib } from '../renderer/core/sampler-lib'; import { Asset } from './asset'; import { EffectAsset } from './effect-asset'; +import { SpriteFrame } from './sprite-frame'; +import { TextureBase } from './texture-base'; /** * @zh @@ -75,7 +79,29 @@ interface IMaterialInfo { * 材质资源类,负责指定每个模型的材质信息。 */ @ccclass('cc.Material') -export class Material extends Asset implements IMaterial { +export class Material extends Asset { + + public static getHash (material: Material) { + let str = ''; + for (const pass of material.passes) { + str += pass.hash; + } + return murmurhash2_32_gc(str, 666); + } + + @property(EffectAsset) + protected _effectAsset: EffectAsset | null = null; + @property + protected _techIdx = 0; + @property + protected _defines: IDefineMap[] = []; + @property + protected _states: PassOverrides[] = []; + @property + protected _props: Array> = []; + + protected _passes: Pass[] = []; + protected _hash = 0; /** * @zh @@ -117,28 +143,6 @@ export class Material extends Asset implements IMaterial { return this._hash; } - get parent (): IMaterial | null { - return null; - } - - get owner (): RenderableComponent | null { - return null; - } - - @property(EffectAsset) - protected _effectAsset: EffectAsset | null = null; - @property - protected _techIdx = 0; - @property - protected _defines: IDefineMap[] = []; - @property - protected _states: PassOverrides[] = []; - @property - protected _props: Array> = []; - - protected _passes: Pass[] = []; - protected _hash = 0; - constructor () { super(); this.loaded = false; @@ -149,7 +153,7 @@ export class Material extends Asset implements IMaterial { * 根据所给信息初始化这个材质,初始化正常结束后材质即可立即用于渲染。 * @param info 初始化材质需要的基本信息。 */ - public reset (info: IMaterialInfo) { + public initialize (info: IMaterialInfo) { if (!this._defines) { this._defines = []; } if (!this._states) { this._states = []; } if (!this._props) { this._props = []; } @@ -160,8 +164,8 @@ export class Material extends Asset implements IMaterial { if (info.states) { this._prepareInfo(info.states, this._states); } this._update(); } - public initialize (info: IMaterialInfo) { - this.reset(info); + public reset (info: IMaterialInfo) { // consistency with other assets + this.initialize(info); } /** @@ -170,35 +174,10 @@ export class Material extends Asset implements IMaterial { * 如需重新初始化材质,不必先调用 destroy。 */ public destroy () { - if (this._passes && this._passes.length) { - for (const pass of this._passes) { - pass.destroy(); - } - } - this._passes = []; - this._effectAsset = null; - - this._props = []; - this._defines = []; - this._states = []; + this._doDestroy(); return super.destroy(); } - /** - * @zh - * 重置材质的所有 uniform 参数数据为 effect 默认初始值。 - * @param clearPasses 是否同时重置当前正在用于渲染的 pass 数组内的信息 - */ - public resetUniforms (clearPasses = true) { - this._props.length = this._passes.length; - for (let i = 0; i < this._props.length; i++) { this._props[i] = {}; } - if (!clearPasses) { return; } - for (const pass of this._passes) { - pass.resetUBOs(); - pass.resetTextures(); - } - } - /** * @zh * 使用指定预处理宏重新编译当前 pass(数组)中的 shader。 @@ -206,14 +185,7 @@ export class Material extends Asset implements IMaterial { * @param passIdx 要编译的 pass 索引,默认编译所有 pass。 */ public recompileShaders (overrides: IDefineMap, passIdx?: number) { - if (!this._passes || !this._effectAsset) { return; } - if (passIdx === undefined) { - for (const pass of this._passes) { - pass.tryCompile(overrides); - } - } else { - this._passes[passIdx].tryCompile(overrides); - } + console.warn('shaders in material asset cannot be modified at runtime, please instantiate the material first'); } /** @@ -223,7 +195,7 @@ export class Material extends Asset implements IMaterial { * @param passIdx 要重载的 pass 索引,默认重载所有 pass。 */ public overridePipelineStates (overrides: PassOverrides, passIdx?: number) { - console.error('Material:' + this.effectName + ' cann\'t be overwritten.Please use pass instance to do so.'); + console.warn('pipeline states in material asset cannot be modified at runtime, please instantiate the material first'); } /** @@ -236,6 +208,21 @@ export class Material extends Asset implements IMaterial { this.emit('load'); } + /** + * @zh + * 重置材质的所有 uniform 参数数据为 effect 默认初始值。 + * @param clearPasses 是否同时重置当前正在用于渲染的 pass 数组内的信息 + */ + public resetUniforms (clearPasses = true) { + this._props.length = this._passes.length; + for (let i = 0; i < this._props.length; i++) { this._props[i] = {}; } + if (!clearPasses) { return; } + for (const pass of this._passes) { + pass.resetUBOs(); + pass.resetTextures(); + } + } + /** * @en * Convenient property setter provided for quick material setup.
@@ -255,7 +242,7 @@ export class Material extends Asset implements IMaterial { const len = passes.length; for (let i = 0; i < len; i++) { const pass = passes[i]; - if (_uploadProperty(pass, name, val)) { + if (this._uploadProperty(pass, name, val)) { this._props[i][name] = val; success = true; } @@ -263,7 +250,7 @@ export class Material extends Asset implements IMaterial { } else { if (passIdx >= this._passes.length) { console.warn(`illegal pass index: ${passIdx}.`); return; } const pass = this._passes[passIdx]; - if (_uploadProperty(pass, name, val)) { + if (this._uploadProperty(pass, name, val)) { this._props[passIdx][name] = val; success = true; } @@ -323,10 +310,6 @@ export class Material extends Asset implements IMaterial { this._update(); } - public _onPassStateChanged () { - this._hash = generateMaterailHash(this); - } - protected _prepareInfo (patch: object | object[], cur: object[]) { if (!Array.isArray(patch)) { // fill all the passes if not specified const len = this._effectAsset ? this._effectAsset.techniques[this._techIdx].passes.length : 1; @@ -337,6 +320,24 @@ export class Material extends Asset implements IMaterial { } } + protected _createPasses () { + const tech = this._effectAsset!.techniques[this._techIdx || 0]; + if (!tech) { return []; } + const passNum = tech.passes.length; + const passes: Pass[] = []; + for (let k = 0; k < passNum; ++k) { + const passInfo = tech.passes[k] as IPassInfoFull; + const defs = passInfo.defines = this._defines.length > k ? this._defines[k] : {}; + if (passInfo.switch && !defs[passInfo.switch]) { continue; } + passInfo.stateOverrides = this._states.length > k ? this._states[k] : {}; + passInfo.idxInTech = k; + const pass = new Pass(cc.director.root.device); + pass.initialize(passInfo); + passes.push(pass); + } + return passes; + } + protected _update (keepProps: boolean = true) { if (this._effectAsset) { if (this._passes && this._passes.length) { @@ -344,11 +345,7 @@ export class Material extends Asset implements IMaterial { pass.destroy(); } } - this._passes = Pass.createPasses(this._effectAsset, { - techIdx: this._techIdx, - defines: this._defines, - states: this._states, - }); + this._passes = this._createPasses(); // handle property values const totalPasses = this._effectAsset.techniques[this._techIdx].passes.length; this._props.length = totalPasses; @@ -357,7 +354,7 @@ export class Material extends Asset implements IMaterial { let props = this._props[pass.idxInTech]; if (!props) { props = this._props[i] = {}; } for (const p in props) { - _uploadProperty(pass, p, props[p]); + this._uploadProperty(pass, p, props[p]); } }); } else { @@ -367,7 +364,49 @@ export class Material extends Asset implements IMaterial { const missing = builtinResMgr.get('missing-effect-material'); if (missing) { this._passes = missing._passes.slice(); } } - this._hash = generateMaterailHash(this); + this._hash = Material.getHash(this); + } + + protected _uploadProperty (pass: Pass, name: string, val: any) { + const handle = pass.getHandle(name); + if (handle === undefined) { return false; } + const bindingType = Pass.getBindingTypeFromHandle(handle); + if (bindingType === GFXBindingType.UNIFORM_BUFFER) { + if (Array.isArray(val)) { + pass.setUniformArray(handle, val); + } else { + pass.setUniform(handle, val); + } + } else if (bindingType === GFXBindingType.SAMPLER) { + const binding = Pass.getBindingFromHandle(handle); + if (val instanceof GFXTextureView) { + pass.bindTextureView(binding, val); + } else if (val instanceof TextureBase || val instanceof SpriteFrame) { + const textureView: GFXTextureView | null = val.getGFXTextureView(); + if (!textureView || !textureView.texture.width || !textureView.texture.height) { + // console.warn(`material '${this._uuid}' received incomplete texture asset '${val._uuid}'`); + return false; + } + pass.bindTextureView(binding, textureView); + if (val instanceof TextureBase) { + pass.bindSampler(binding, samplerLib.getSampler(cc.director.root.device, val.getSamplerHash())); + } + } + } + return true; + } + + protected _doDestroy () { + if (this._passes && this._passes.length) { + for (const pass of this._passes) { + pass.destroy(); + } + } + this._effectAsset = null; + this._passes.length = 0; + this._props.length = 0; + this._defines.length = 0; + this._states.length = 0; } } diff --git a/cocos/core/renderer/core/material-instance.ts b/cocos/core/renderer/core/material-instance.ts index e321f3d6753..33633ee3200 100644 --- a/cocos/core/renderer/core/material-instance.ts +++ b/cocos/core/renderer/core/material-instance.ts @@ -1,80 +1,73 @@ -import { RenderableComponent } from '../../3d'; -import { EffectAsset, Material } from '../../assets'; -import { _uploadProperty, IMaterial } from '../../utils/material-interface'; -import { murmurhash2_32_gc } from '../../utils/murmurhash2_gc'; -import { IPass } from '../../utils/pass-interface'; -import { PassOverrides } from './pass'; +/* + Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + + http://www.cocos.com + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated engine source code (the "Software"), a limited, + worldwide, royalty-free, non-assignable, revocable and non-exclusive license + to use Cocos Creator solely to develop games on your target platforms. You shall + not use Cocos Creator software for developing other software or tools that's + used for developing games. You are not granted to publish, distribute, + sublicense, and/or sell copies of Cocos Creator. + + The software or tools in this License Agreement are licensed, not sold. + Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/** + * @category material + */ + +import { RenderableComponent } from '../../3d/framework/renderable-component'; +import { Material } from '../../assets/material'; import { PassInstance } from './pass-instance'; import { IDefineMap } from './pass-utils'; -export class MaterialInstance implements IMaterial { - - get effectAsset (): EffectAsset | null { - return this._parent.effectAsset; - } - - get effectName (): string { - return this._parent.effectName; - } - - get technique (): number { - return this._parent.technique; - } - - get passes (): IPass[] { - return this._passes; - } +export interface IMaterialInstanceInfo { + parent: Material; + owner: RenderableComponent; + subModelIdx: number; +} - get hash (): number { - return this._hash; - } +/** + * @zh + * 材质实例,当有材质修改需求时,根据材质资源创建的,可任意定制的实例。 + */ +export class MaterialInstance extends Material { - get parent (): IMaterial { + get parent () { return this._parent; } - get owner (): RenderableComponent { + get owner () { return this._owner; } - private _parent: IMaterial; - private _owner: RenderableComponent; - // data overwritten in material instance - private _passes: IPass[] = []; - private _hash: number = -1; - private _props: Array> = []; - private _states: PassOverrides[] = []; - - constructor (parent: Material, owner: RenderableComponent) { - this._parent = parent; - this._owner = owner; - // @ts-ignore - const parentProps = parent._props; - for (let i = 0; i < parentProps.length; i++) { - const passProp = {}; - Object.assign(passProp, parentProps[i]); - this._props[i] = passProp; - } - - for (let i = 0; i < parent.passes.length; i++) { - this._passes[i] = new PassInstance(parent.passes[i], this, i); - } - } + protected _passes: PassInstance[] = []; - public resetUniforms (clearPasses?: boolean): void { - this._props.length = this._passes.length; - for (let i = 0; i < this._props.length; i++) { this._props[i] = {}; } - if (!clearPasses) { return; } - for (const pass of this._passes) { - pass.resetUBOs(); - pass.resetTextures(); - } + private _parent: Material; + private _owner: RenderableComponent; + private _subModelIdx = 0; + + constructor (info: IMaterialInstanceInfo) { + super(); + this._parent = info.parent; + this._owner = info.owner; + this._subModelIdx = info.subModelIdx; + this.copy(this._parent); } public recompileShaders (overrides: IDefineMap, passIdx?: number): void { - if (!this._passes || !this.effectAsset) { - return; - } + if (!this._passes || !this.effectAsset) { return; } if (passIdx === undefined) { for (const pass of this._passes) { pass.tryCompile(overrides); @@ -99,65 +92,26 @@ export class MaterialInstance implements IMaterial { } } - public setProperty (name: string, val: any, passIdx?: number): void { - let success = false; - if (passIdx === undefined) { // try set property for all applicable passes - const passes = this._passes; - const len = passes.length; - for (let i = 0; i < len; i++) { - const pass = passes[i]; - if (_uploadProperty(pass, name, val)) { - this._props[i][name] = val; - success = true; - } - } - } else { - if (passIdx >= this._passes.length) { console.warn(`illegal pass index: ${passIdx}.`); return; } - const pass = this._passes[passIdx]; - if (_uploadProperty(pass, name, val)) { - this._props[passIdx][name] = val; - success = true; - } - } - if (!success) { - console.warn(`illegal property name: ${name}.`); - return; - } - } - - public getProperty (name: string, passIdx?: number) { - if (passIdx === undefined) { // try get property in all possible passes - const propsArray = this._props; - const len = propsArray.length; - for (let i = 0; i < len; i++) { - const props = propsArray[i]; - for (const p in props) { - if (p === name) { return props[p]; } - } - } - } else { - if (passIdx >= this._props.length) { console.warn(`illegal pass index: ${passIdx}.`); return null; } - const props = this._props[passIdx]; - for (const p in props) { - if (p === name) { return props[p]; } - } - } - return null; + public destroy () { + this._doDestroy(); + return true; } - public destroy (): void { - for (let i = 0; i < this._passes.length; i++) { - this._passes[i].destroy(); + public onPassStateChange (dontNotify: boolean) { + this._hash = Material.getHash(this); + if (!dontNotify) { + // @ts-ignore + this.owner._onRebuildPSO(this._subModelIdx, this); } - this._passes.length = 0; - this._props.length = 0; } - public _onPassStateChanged (idx: number) { - let str = ''; - for (const pass of this._passes) { - str += pass.psoHash; + protected _createPasses () { + const passes: PassInstance[] = []; + const parentPasses = this._parent.passes; + if (!parentPasses) { return passes; } + for (let k = 0; k < parentPasses.length; ++k) { + passes.push(new PassInstance(parentPasses[k], this)); } - this._hash = murmurhash2_32_gc(str, 666); + return passes; } } diff --git a/cocos/core/renderer/core/pass-instance.ts b/cocos/core/renderer/core/pass-instance.ts index 67cacd757ef..09a7a8c1255 100644 --- a/cocos/core/renderer/core/pass-instance.ts +++ b/cocos/core/renderer/core/pass-instance.ts @@ -1,480 +1,89 @@ -import { builtinResMgr } from '../../3d/builtin/init'; -import { IPassInfo, IPassStates, IPropertyInfo } from '../../assets/effect-asset'; -import { TextureBase } from '../../assets/texture-base'; -// tslint:disable-next-line: max-line-length -import { GFXBindingType, GFXBuffer, GFXBufferUsageBit, GFXDevice, GFXDynamicState, GFXGetTypeSize, GFXMemoryUsageBit, GFXPrimitiveMode, GFXRenderPass, GFXSampler, GFXShader, GFXTextureView, GFXType, IGFXBufferInfo } from '../../gfx'; -import { GFXBindingLayout, IGFXBinding, IGFXBindingLayoutInfo } from '../../gfx/binding-layout'; -import { GFXPipelineLayout, IGFXPipelineLayoutInfo } from '../../gfx/pipeline-layout'; -import { GFXBlendState, GFXDepthStencilState, GFXPipelineState, GFXRasterizerState, IGFXPipelineStateInfo } from '../../gfx/pipeline-state'; -import { BatchedBuffer } from '../../pipeline/batched-buffer'; -import { isBuiltinBinding, RenderPassStage, RenderPriority } from '../../pipeline/define'; -import { getPhaseID } from '../../pipeline/pass-phase'; -import { IMaterial } from '../../utils/material-interface'; -import { generatePassPSOHash, IBlock, IPass, IPassDynamics, IPSOHashInfo } from '../../utils/pass-interface'; -import { Pass } from './pass'; -import { assignDefines, getBindingFromHandle, getOffsetFromHandle, getTypeFromHandle, IDefineMap, type2default, type2reader, type2writer } from './pass-utils'; -import { IProgramInfo, programLib } from './program-lib'; -import { samplerLib } from './sampler-lib'; +/* + Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. -const _bfInfo: IGFXBufferInfo = { - memUsage: GFXMemoryUsageBit.HOST | GFXMemoryUsageBit.DEVICE, - size: 0, - usage: GFXBufferUsageBit.UNIFORM | GFXBufferUsageBit.TRANSFER_DST, -}; + http://www.cocos.com -const _blInfo: IGFXBindingLayoutInfo = {} as IGFXBindingLayoutInfo; + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated engine source code (the "Software"), a limited, + worldwide, royalty-free, non-assignable, revocable and non-exclusive license + to use Cocos Creator solely to develop games on your target platforms. You shall + not use Cocos Creator software for developing other software or tools that's + used for developing games. You are not granted to publish, distribute, + sublicense, and/or sell copies of Cocos Creator. -const _plInfo: IGFXPipelineLayoutInfo = {} as IGFXPipelineLayoutInfo; + The software or tools in this License Agreement are licensed, not sold. + Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. -const _psoInfo: IGFXPipelineStateInfo & IPSOHashInfo = {} as IGFXPipelineStateInfo & IPSOHashInfo; + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ -export class PassInstance implements IPass { - get batchedBuffer (): BatchedBuffer | null { - return null; - } - - get parent (): IPass { - return this._parent; - } - - get priority (): RenderPriority { - return this._priority; - } - - get primitive (): GFXPrimitiveMode { - return this._primitive; - } - - get stage (): RenderPassStage { - return this._stage; - } - - get rasterizerState (): GFXRasterizerState { - return this._rs; - } - - get depthStencilState (): GFXDepthStencilState { - return this._dss; - } - - get blendState (): GFXBlendState { - return this._bs; - } - - get dynamicStates (): GFXDynamicState[] { - return this._dynamicStates; - } - - get customizations (): string[] { - return this._customizations; - } - - get phase (): number { - return this._phase; - } - - get shaderInfo (): IProgramInfo { - return this._parent.shaderInfo; - } - - get program (): string { - return this._parent.program; - } +/** + * @category material + */ - get properties (): Record { - return this._parent.properties; - } - - get defines (): IDefineMap { - return this._defines; - } +import { IPassInfo } from '../../assets/effect-asset'; +import { GFXBlendState, GFXDepthStencilState, GFXRasterizerState } from '../../gfx/pipeline-state'; +import { MaterialInstance } from './material-instance'; +import { Pass, PassOverrides } from './pass'; +import { IDefineMap } from './pass-utils'; - get idxInTech (): number { - return this._parent.idxInTech; - } +export class PassInstance extends Pass { - get device (): GFXDevice { - return this._parent.device; - } - - get bindings (): IGFXBinding[] { - return this._bindings; - } - - get shader (): GFXShader { - return this._shader!; - } - - get renderPass (): GFXRenderPass { - return this._renderPass!; - } - - get dynamics (): IPassDynamics { - return this._dynamics; - } - - get blocks (): IBlock[] { - return this._blocks; - } - - get psoHash (): number { - return this._hash; - } + get parent () { return this._parent; } private _parent: Pass; - private _owner: IMaterial; - private _idx: number; - private _dontNotify: boolean = false; - // instance resources - private _hash: number; - private _blocks: IBlock[] = []; - private _buffers: Record = {}; - private _samplers: Record = {}; - private _textureViews: Record = {}; - private _bindingLayout: GFXBindingLayout | null = null; - private _pipelineLayout: GFXPipelineLayout | null = null; - private _pipelineState: GFXPipelineState | null = null; - - // states could be overwritten - private _phase = getPhaseID('default'); - private _priority: RenderPriority = RenderPriority.DEFAULT; - private _primitive: GFXPrimitiveMode = GFXPrimitiveMode.TRIANGLE_LIST; - private _stage: RenderPassStage = RenderPassStage.DEFAULT; - private _renderPass: GFXRenderPass | null = null; - private _bindings: IGFXBinding[] = []; - private _bs: GFXBlendState = new GFXBlendState(); - private _dss: GFXDepthStencilState = new GFXDepthStencilState(); - private _rs: GFXRasterizerState = new GFXRasterizerState(); - private _dynamicStates: GFXDynamicState[] = []; - private _dynamics: IPassDynamics = {}; - private _customizations: string[] = []; - private _defines: IDefineMap = {}; - private _shader: GFXShader | null = null; + private _owner: MaterialInstance; + private _dontNotify = false; - constructor (parent: Pass, mat: IMaterial, idx: number) { + constructor (parent: Pass, owner: MaterialInstance) { + super(parent.device); this._parent = parent; - this._owner = mat; - this._idx = idx; - this._hash = parent.psoHash; - this._shader = parent.shader; - this._bindings = parent.bindings; - - const blocks = this.shaderInfo.blocks; - for (let i = 0; i < blocks.length; i++) { - const { size, binding } = blocks[i]; - if (isBuiltinBinding(binding)) { - continue; - } - // create gfx buffer resource - _bfInfo.size = Math.ceil(size / 16) * 16; // https://bugs.chromium.org/p/chromium/issues/detail?id=988988 - this._buffers[binding] = this.device.createBuffer(_bfInfo); - // non-builtin UBO data pools, note that the effect compiler - // guarantees these bindings to be consecutive, starting from 0 - const buffer = new ArrayBuffer(size); - this._blocks[binding] = { - buffer, - dirty: true, - view: new Float32Array(buffer), - }; - const source = parent.blocks[binding].view; - const dest = this._blocks[binding].view; - for (let j = 0; j < source.length; j++) { - dest[j] = source[j]; - } - } - for (let i = 0; i < this.shaderInfo.samplers.length; i++) { - const binding = this.shaderInfo.samplers[i].binding; - if (isBuiltinBinding(binding)) { - continue; - } - // @ts-ignore - this._textureViews[binding] = parent._textureViews[binding]; - // @ts-ignore - this._samplers[binding] = parent._samplers[binding]; - } - Pass.fillinPipelineInfo(this as unknown as Pass, this._parent); - } - - public getHandle (name: string, offset?: number, targetType?: GFXType): number | undefined { - return this._parent.getHandle(name, offset, targetType); - } - - public getBinding (name: string): number | undefined { - return this._parent.getBinding(name); + this._owner = owner; + this.initialize(this._parent); } - public setUniform (handle: number, value: any): void { - const binding = getBindingFromHandle(handle); - const type = getTypeFromHandle(handle); - const ofs = getOffsetFromHandle(handle); - const block = this._blocks[binding]; - type2writer[type](block.view, value, ofs); - block.dirty = true; - } - - public getUniform (handle: number, out: any) { - const binding = getBindingFromHandle(handle); - const type = getTypeFromHandle(handle); - const ofs = getOffsetFromHandle(handle); - const block = this._blocks[binding]; - return type2reader[type](block.view, out, ofs); - } - - public setUniformArray (handle: number, value: any[]): void { - const binding = getBindingFromHandle(handle); - const type = getTypeFromHandle(handle); - const stride = GFXGetTypeSize(type) >> 2; - const block = this._blocks[binding]; - let ofs = getOffsetFromHandle(handle); - for (let i = 0; i < value.length; i++ , ofs += stride) { - if (value[i] === null) { continue; } - type2writer[type](block.view, value[i], ofs); - } - block.dirty = true; - } - - public bindBuffer (binding: number, value: GFXBuffer): void { - if (this._buffers[binding] === value) { - return; - } - this._buffers[binding] = value; - if (!this._bindingLayout) { - return; - } - this._bindingLayout.bindBuffer(binding, value); - } - - public bindTextureView (binding: number, value: GFXTextureView): void { - if (this._textureViews[binding] === value) { - return; - } - this._textureViews[binding] = value; - if (!this._bindingLayout) { - return; - } - this._bindingLayout.bindTextureView(binding, value); - } - - public bindSampler (binding: number, value: GFXSampler): void { - if (!this._bindingLayout || this._samplers[binding] === value) { - return; - } - this._samplers[binding] = value; - this._bindingLayout.bindSampler(binding, value); - } - - public setDynamicState (state: GFXDynamicState, value: any): void { - const ds = this._dynamics[state]; - if (ds && ds.value === value) { - return; - } - ds.value = value; - ds.dirty = true; - } - - public overridePipelineStates (original: IPassInfo, overrides: any): void { + public overridePipelineStates (original: IPassInfo, overrides: PassOverrides): void { this._bs = new GFXBlendState(); this._dss = new GFXDepthStencilState(); this._rs = new GFXRasterizerState(); Pass.fillinPipelineInfo(this as unknown as Pass, original); Pass.fillinPipelineInfo(this as unknown as Pass, overrides); - this._hash = generatePassPSOHash(this); - this._onPipelineStateChanged(); - } - - public update (): void { - const len = this._blocks.length; - for (let i = 0; i < len; i++) { - const block = this._blocks[i]; - if (block.dirty) { - this._buffers[i].update(block.buffer); - block.dirty = false; - } - } - const source = cc.director.root.pipeline.globalBindings; - const target = this.shaderInfo.builtins.globals; - const samplerLen = target.samplers.length; - for (let i = 0; i < samplerLen; i++) { - const s = target.samplers[i]; - const info = source.get(s.name)!; - if (info.sampler) { - this.bindSampler(info.samplerInfo!.binding, info.sampler); - } - this.bindTextureView(info.samplerInfo!.binding, info.textureView!); - } + this._onStateChange(); } - public destroy (): void { - for (const u of this.shaderInfo.blocks) { - if (isBuiltinBinding(u.binding)) { continue; } - this._buffers[u.binding].destroy(); + public tryCompile (defineOverrides?: IDefineMap) { + if (defineOverrides) { + this._defines = Object.assign({}, this._defines, defineOverrides); } - this._buffers = {}; - // textures are reused - this._samplers = {}; - this._textureViews = {}; - } - - public resetUBOs (): void { - for (const u of this.shaderInfo.blocks) { - if (isBuiltinBinding(u.binding)) { - continue; - } - const block: IBlock = this._blocks[u.binding]; - let ofs = 0; - for (let i = 0; i < u.members.length; i++) { - const cur = u.members[i]; - const inf = this.properties[cur.name]; - const givenDefault = inf && inf.value; - const value = givenDefault ? givenDefault : type2default[cur.type]; - const stride = GFXGetTypeSize(cur.type) >> 2; - for (let j = 0; j < cur.count; j++) { - block.view.set(value, ofs + j * stride); - } - ofs += stride * cur.count; - } - block.dirty = true; - } - } - - public resetTextures (): void { - if (!this._bindingLayout) { - return; - } - for (const u of this.shaderInfo.samplers) { - if (isBuiltinBinding(u.binding)) { - continue; - } - const inf = this.properties[u.name]; - const texName = inf && inf.value ? inf.value + '-texture' : type2default[u.type]; - const texture = builtinResMgr.get(texName); - const textureView = texture && texture.getGFXTextureView(); - if (!textureView) { - console.warn('illegal texture default value: ' + texName); continue; - } - this._textureViews[u.binding] = textureView; - const samplerHash = inf && (inf.samplerHash !== undefined) ? inf.samplerHash : texture.getSamplerHash(); - const sampler = this._samplers[u.binding] = samplerLib.getSampler(this.device, samplerHash); - this._bindingLayout.bindSampler(u.binding, sampler); - this._bindingLayout.bindTextureView(u.binding, textureView); - } - } - - public tryCompile (defineOverrides?: IDefineMap): any { - if (defineOverrides && !assignDefines(this._defines, defineOverrides)) { - return null; - } - const pipeline = cc.director.root.pipeline; - if (!pipeline) { - return null; - } - this._renderPass = pipeline.getRenderPass(this._stage); - if (!this._renderPass) { - console.warn(`illegal pass stage.`); return null; - } - const res = programLib.getGFXShader(this.device, this.program, this._defines, pipeline); - if (!res.shader) { - console.warn(`create shader ${this.program} failed`); - return null; - } - this._shader = res.shader; - this._bindings = res.bindings; - this._hash = generatePassPSOHash(this); - this._onPipelineStateChanged(); + const res = super.tryCompile(); + this._onStateChange(); return res; } - public createPipelineState (): GFXPipelineState | null { - if ((!this._renderPass || !this._shader || !this._bindings.length) && !this.tryCompile()) { - console.warn(`pass resources not complete, create PSO failed`); - return null; - } - _blInfo.bindings = this._bindings; - // bind resources - this._bindingLayout = this.device.createBindingLayout(_blInfo); - for (const b in this._buffers) { - this._bindingLayout.bindBuffer(parseInt(b), this._buffers[b]); - } - for (const s in this._samplers) { - this._bindingLayout.bindSampler(parseInt(s), this._samplers[s]); - } - for (const t in this._textureViews) { - this._bindingLayout.bindTextureView(parseInt(t), this._textureViews[t]); - } - // bind pipeline builtins - const source = cc.director.root.pipeline.globalBindings; - const target = this.shaderInfo.builtins.globals; - for (const b of target.blocks) { - const info = source.get(b.name); - if (!info || info.type !== GFXBindingType.UNIFORM_BUFFER) { - console.warn(`builtin UBO '${b.name}' not available!`); continue; - } - this._bindingLayout.bindBuffer(info.blockInfo!.binding, info.buffer!); - } - for (const s of target.samplers) { - const info = source.get(s.name); - if (!info || info.type !== GFXBindingType.SAMPLER) { - console.warn(`builtin texture '${s.name}' not available!`); continue; - } - if (info.sampler) { - this._bindingLayout.bindSampler(info.samplerInfo!.binding, info.sampler); - } - this._bindingLayout.bindTextureView(info.samplerInfo!.binding, info.textureView!); - } - _plInfo.layouts = [this._bindingLayout]; - this._pipelineLayout = this.device.createPipelineLayout(_plInfo); - // create pipeline state - _psoInfo.primitive = this._primitive; - _psoInfo.shader = this._shader!; - _psoInfo.rasterizerState = this._rs; - _psoInfo.depthStencilState = this._dss; - _psoInfo.blendState = this._bs; - _psoInfo.dynamicStates = this._dynamicStates; - _psoInfo.layout = this._pipelineLayout; - _psoInfo.renderPass = this._renderPass!; - _psoInfo.program = this.program; - _psoInfo.defines = this._defines; - _psoInfo.stage = this._stage; - _psoInfo.hash = this._hash; - this._pipelineState = this.device.createPipelineState(_psoInfo); - return this._pipelineState; + public createBatchedBuffer () { + console.warn('pass instance have no batched buffer.'); } - public destroyPipelineState (pipelineStates?: GFXPipelineState): void { - if (this._pipelineState) { - if (this._pipelineState !== pipelineStates) { - console.warn('Node(' + this._owner.owner!.node.name + ')\s pso doesn\'t equal to pass instance\'s pso,please check the destroy logic.(pass info:' + this.shaderInfo.name + ')'); - } - this._pipelineState.destroy(); - this._pipelineLayout!.destroy(); - this._bindingLayout!.destroy(); - this._pipelineState = null; - this._pipelineLayout = null; - this._bindingLayout = null; - } - } - - public createBatchedBuffer (): void { - throw new Error('Pass instance don\'t have batched buffer.'); + public clearBatchedBuffer () { + console.warn('pass instance have no batched buffer.'); } - public clearBatchedBuffer (): void { - throw new Error('Pass instance don\'t have batched buffer.'); - } - - public beginChangeStatesSilently (): void { + public beginChangeStatesSilently () { this._dontNotify = true; } - public endChangeStatesSilently (): void { + public endChangeStatesSilently () { this._dontNotify = false; } - protected _onPipelineStateChanged () { - this._owner._onPassStateChanged(this._idx); - if (!this._dontNotify) { - // @ts-ignore - this._owner.owner._onRebuildPSO(this._idx, this._owner); - } + protected _onStateChange () { + this._hash = Pass.getPSOHash(this); + this._owner.onPassStateChange(this._dontNotify); } } diff --git a/cocos/core/renderer/core/pass.ts b/cocos/core/renderer/core/pass.ts index 10b0882a1cc..c41f7115125 100644 --- a/cocos/core/renderer/core/pass.ts +++ b/cocos/core/renderer/core/pass.ts @@ -28,14 +28,16 @@ */ import { builtinResMgr } from '../../3d/builtin/init'; -import { EffectAsset, IPassInfo, IPassStates, IPropertyInfo } from '../../assets/effect-asset'; +import { IPassInfo, IPassStates, IPropertyInfo } from '../../assets/effect-asset'; import { TextureBase } from '../../assets/texture-base'; import { GFXBindingLayout, IGFXBinding, IGFXBindingLayoutInfo } from '../../gfx/binding-layout'; import { GFXBuffer, IGFXBufferInfo } from '../../gfx/buffer'; -import { GFXBindingType, GFXBufferUsageBit, GFXDynamicState, GFXGetTypeSize, GFXMemoryUsageBit, GFXPrimitiveMode, GFXType } from '../../gfx/define'; +import { GFXBindingType, GFXBufferUsageBit, GFXDynamicState, + GFXGetTypeSize, GFXMemoryUsageBit, GFXPrimitiveMode, GFXType } from '../../gfx/define'; import { GFXDevice } from '../../gfx/device'; import { GFXPipelineLayout, IGFXPipelineLayoutInfo } from '../../gfx/pipeline-layout'; -import { GFXBlendState, GFXBlendTarget, GFXDepthStencilState, GFXInputState, GFXPipelineState, GFXRasterizerState, IGFXPipelineStateInfo } from '../../gfx/pipeline-state'; +import { GFXBlendState, GFXBlendTarget, GFXDepthStencilState, + GFXInputState, GFXPipelineState, GFXRasterizerState, IGFXPipelineStateInfo } from '../../gfx/pipeline-state'; import { GFXRenderPass } from '../../gfx/render-pass'; import { GFXSampler } from '../../gfx/sampler'; import { GFXShader } from '../../gfx/shader'; @@ -44,30 +46,48 @@ import { BatchedBuffer } from '../../pipeline/batched-buffer'; import { isBuiltinBinding, RenderPassStage, RenderPriority } from '../../pipeline/define'; import { getPhaseID } from '../../pipeline/pass-phase'; import { Root } from '../../root'; -import { generatePassPSOHash, IBlock, IPass, IPassDynamics, IPSOHashInfo } from '../../utils/pass-interface'; -// tslint:disable-next-line: max-line-length -import { assignDefines, customizeType, getBindingFromHandle, getBindingTypeFromHandle, getOffsetFromHandle, getTypeFromHandle, IDefineMap, type2default, type2reader, type2writer } from './pass-utils'; -import { IProgramInfo, IShaderResources, programLib } from './program-lib'; +import { murmurhash2_32_gc } from '../../utils/murmurhash2_gc'; +import { customizeType, getBindingFromHandle, getBindingTypeFromHandle, + getOffsetFromHandle, getTypeFromHandle, IDefineMap, type2default, type2reader, type2writer } from './pass-utils'; +import { IProgramInfo, programLib } from './program-lib'; import { samplerLib } from './sampler-lib'; export interface IPassInfoFull extends IPassInfo { // generated part idxInTech: number; - curDefs: IDefineMap; - states: PassOverrides; + defines: IDefineMap; + stateOverrides?: PassOverrides; } export type PassOverrides = RecursivePartial; +export interface IBlock { + buffer: ArrayBuffer; + view: Float32Array; + dirty: boolean; +} + interface IPassResources { bindingLayout: GFXBindingLayout; pipelineLayout: GFXPipelineLayout; pipelineState: GFXPipelineState; } -interface IEffectInfo { - techIdx: number; - defines: IDefineMap[]; - states: PassOverrides[]; +interface IPassDynamics { + [type: number]: { + dirty: boolean, + value: number[], + }; +} + +interface IPSOHashInfo { + program: string; + defines: IDefineMap; + stage: RenderPassStage; + primitive: GFXPrimitiveMode; + rasterizerState: GFXRasterizerState; + depthStencilState: GFXDepthStencilState; + blendState: GFXBlendState; + dynamicStates: GFXDynamicState[]; } const _bfInfo: IGFXBufferInfo = { @@ -105,7 +125,7 @@ const _psoInfo: IGFXPipelineStateInfo & IPSOHashInfo = { * @zh * 渲染 pass,储存实际描述绘制过程的各项资源。 */ -export class Pass implements IPass { +export class Pass { /** * @zh * 根据 handle 获取 unform 的绑定类型(UBO 或贴图等)。 @@ -122,25 +142,6 @@ export class Pass implements IPass { */ public static getBindingFromHandle = getBindingFromHandle; - public static createPasses (effect: EffectAsset, info: IEffectInfo) { - const { techIdx, defines, states } = info; - const tech = effect.techniques[techIdx || 0]; - if (!tech) { return []; } - const passNum = tech.passes.length; - const passes: Pass[] = []; - for (let k = 0; k < passNum; ++k) { - const passInfo = tech.passes[k] as IPassInfoFull; - const defs = passInfo.curDefs = defines.length > k ? defines[k] : {}; - if (passInfo.switch && !defs[passInfo.switch]) { continue; } - passInfo.states = states.length > k ? states[k] : {}; - passInfo.idxInTech = k; - const pass = new Pass(cc.game._gfxDevice); - pass.initialize(passInfo); - passes.push(pass); - } - return passes; - } - public static fillinPipelineInfo (target: Pass, info: PassOverrides) { if (info.priority !== undefined) { target._priority = info.priority; } if (info.primitive !== undefined) { target._primitive = info.primitive; } @@ -154,7 +155,7 @@ export class Pass implements IPass { const bsInfo = Object.assign({}, info.blendState); if (bsInfo.targets) { bsInfo.targets.forEach((t, i) => Object.assign( - bs.targets[i] || (bs.targets[i] = new GFXBlendTarget()), t)); + bs.targets[i] || (bs.targets[i] = new GFXBlendTarget()), t)); } delete bsInfo.targets; Object.assign(bs, bsInfo); @@ -163,6 +164,20 @@ export class Pass implements IPass { Object.assign(target._dss, info.depthStencilState); } + /** + * @zh + * 根据指定 PSO 信息计算 hash + * @param psoInfo 用于计算 PSO hash 的最小必要信息 + */ + public static getPSOHash (psoInfo: IPSOHashInfo) { + const shaderKey = programLib.getKey(psoInfo.program, psoInfo.defines); + let res = `${shaderKey},${psoInfo.stage},${psoInfo.primitive}`; + res += serializeBlendState(psoInfo.blendState); + res += serializeDepthStencilState(psoInfo.depthStencilState); + res += serializeRasterizerState(psoInfo.rasterizerState); + return murmurhash2_32_gc(res, 666); + } + protected static getOffsetFromHandle = getOffsetFromHandle; // internal resources protected _buffers: Record = {}; @@ -188,7 +203,7 @@ export class Pass implements IPass { protected _shaderInfo: IProgramInfo = null!; protected _defines: IDefineMap = {}; protected _properties: Record = {}; - protected _hash: number = -1; + protected _hash = 0; // external references protected _device: GFXDevice; protected _renderPass: GFXRenderPass | null = null; @@ -196,14 +211,6 @@ export class Pass implements IPass { // for dynamic batching protected _batchedBuffer: BatchedBuffer | null = null; - get parent (): IPass | null { - return null; - } - - get psoHash (): number { - return this._hash; - } - public constructor (device: GFXDevice) { this._device = device; } @@ -215,13 +222,14 @@ export class Pass implements IPass { public initialize (info: IPassInfoFull) { this._idxInTech = info.idxInTech; this._programName = info.program; - this._defines = info.curDefs; + this._defines = info.defines; this._shaderInfo = programLib.getTemplate(info.program); this._properties = info.properties || this._properties; // pipeline state const device = this._device; Pass.fillinPipelineInfo(this, info); - Pass.fillinPipelineInfo(this, info.states); + if (info.stateOverrides) { Pass.fillinPipelineInfo(this, info.stateOverrides); } + this._hash = Pass.getPSOHash(this); const blocks = this._shaderInfo.blocks; for (let i = 0; i < blocks.length; i++) { @@ -248,8 +256,6 @@ export class Pass implements IPass { this.resetUBOs(); this.resetTextures(); this.tryCompile(); - - this._hash = generatePassPSOHash(this); } /** @@ -328,7 +334,7 @@ export class Pass implements IPass { const stride = GFXGetTypeSize(type) >> 2; const block = this._blocks[binding]; let ofs = Pass.getOffsetFromHandle(handle); - for (let i = 0; i < value.length; i++ , ofs += stride) { + for (let i = 0; i < value.length; i++, ofs += stride) { if (value[i] === null) { continue; } type2writer[type](block.view, value[i], ofs); } @@ -402,7 +408,7 @@ export class Pass implements IPass { * @param value 管线状态重载值。 */ public overridePipelineStates (original: IPassInfo, overrides: PassOverrides) { - console.error('Pass:' + this._programName + ' cann\'t be overwritten.Please use pass instance to do so.'); + console.warn('base pass cannot override states, please use pass instance instead.'); } /** @@ -498,22 +504,15 @@ export class Pass implements IPass { * 尝试编译 shader 并获取相关资源引用。 * @param defineOverrides shader 预处理宏定义重载 */ - public tryCompile ( - defineOverrides?: IDefineMap, - ): IShaderResources | null /* TODO: Explicit since TS4053 bug , changes required once the issue is fixed. */ { - if (defineOverrides && !assignDefines(this._defines, defineOverrides)) { - return null; - } + public tryCompile () { const pipeline = (cc.director.root as Root).pipeline; if (!pipeline) { return null; } this._renderPass = pipeline.getRenderPass(this._stage); - if (!this._renderPass) { console.warn(`illegal pass stage.`); return null; } + if (!this._renderPass) { console.warn(`illegal pass stage.`); return false; } const res = programLib.getGFXShader(this._device, this._programName, this._defines, pipeline); - if (!res.shader) { console.warn(`create shader ${this._programName} failed`); return null; } - this._shader = res.shader; - this._bindings = res.bindings; - this._hash = generatePassPSOHash(this); - return res; + if (!res.shader) { console.warn(`create shader ${this._programName} failed`); return false; } + this._shader = res.shader; this._bindings = res.bindings; + return true; } /** @@ -525,7 +524,7 @@ export class Pass implements IPass { console.warn(`pass resources not complete, create PSO failed`); return null; } - _blInfo.bindings = this._bindings; + const shader = this._shader!; _blInfo.bindings = this._bindings; // bind resources const bindingLayout = this._device.createBindingLayout(_blInfo); for (const b in this._buffers) { @@ -555,7 +554,7 @@ export class Pass implements IPass { const pipelineLayout = this._device.createPipelineLayout(_plInfo); // create pipeline state _psoInfo.primitive = this._primitive; - _psoInfo.shader = this._shader!; + _psoInfo.shader = shader; _psoInfo.rasterizerState = this._rs; _psoInfo.depthStencilState = this._dss; _psoInfo.blendState = this._bs; @@ -571,14 +570,6 @@ export class Pass implements IPass { return pipelineState; } - public beginChangeStatesSilently (): void { - - } - - public endChangeStatesSilently (): void { - - } - /** * @zh * 销毁指定的 [[GFXPipelineState]],如果它是这个 pass 创建的。 @@ -612,6 +603,10 @@ export class Pass implements IPass { } } + // internal use + public beginChangeStatesSilently () {} + public endChangeStatesSilently () {} + // states get priority () { return this._priority; } get primitive () { return this._primitive; } @@ -623,17 +618,41 @@ export class Pass implements IPass { get customizations () { return this._customizations; } get phase () { return this._phase; } // infos + get device () { return this._device; } get shaderInfo () { return this._shaderInfo; } get program () { return this._programName; } get properties () { return this._properties; } get defines () { return this._defines; } get idxInTech () { return this._idxInTech; } // resources - get device () { return this._device; } get bindings () { return this._bindings; } get shader () { return this._shader!; } get renderPass () { return this._renderPass!; } get dynamics () { return this._dynamics; } get batchedBuffer () { return this._batchedBuffer; } get blocks () { return this._blocks; } + get hash () { return this._hash; } +} + +function serializeBlendState (bs: GFXBlendState) { + let res = `,bs,${bs.isA2C},${bs.blendColor}`; + for (const t of bs.targets) { + res += `,bt,${t.blend},${t.blendEq},${t.blendAlphaEq},${t.blendColorMask}`; + res += `,${t.blendSrc},${t.blendDst},${t.blendSrcAlpha},${t.blendDstAlpha}`; + } + return res; +} + +function serializeRasterizerState (rs: GFXRasterizerState) { + const res = `,rs,${rs.cullMode},${rs.depthBias},${rs.isFrontFaceCCW}`; + return res; +} + +function serializeDepthStencilState (dss: GFXDepthStencilState) { + let res = `,dss,${dss.depthTest},${dss.depthWrite},${dss.depthFunc}`; + res += `,${dss.stencilTestFront},${dss.stencilFuncFront},${dss.stencilRefFront},${dss.stencilReadMaskFront}`; + res += `,${dss.stencilFailOpFront},${dss.stencilZFailOpFront},${dss.stencilPassOpFront},${dss.stencilWriteMaskFront}`; + res += `,${dss.stencilTestBack},${dss.stencilFuncBack},${dss.stencilRefBack},${dss.stencilReadMaskBack}`; + res += `,${dss.stencilFailOpBack},${dss.stencilZFailOpBack},${dss.stencilPassOpBack},${dss.stencilWriteMaskBack}`; + return res; } diff --git a/cocos/core/utils/material-interface.ts b/cocos/core/utils/material-interface.ts deleted file mode 100644 index 430f1840faf..00000000000 --- a/cocos/core/utils/material-interface.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { RenderableComponent } from '../3d/framework/renderable-component'; -import { EffectAsset } from '../assets/effect-asset'; -import { SpriteFrame } from '../assets/sprite-frame'; -import { TextureBase } from '../assets/texture-base'; -import { GFXBindingType, GFXTextureView } from '../gfx'; -import { PassOverrides } from '../renderer/core/pass'; -import { getBindingFromHandle, getBindingTypeFromHandle, IDefineMap } from '../renderer/core/pass-utils'; -import { samplerLib } from '../renderer/core/sampler-lib'; -import { murmurhash2_32_gc } from './murmurhash2_gc'; -import { IPass } from './pass-interface'; - -export function _uploadProperty (pass: IPass, name: string, val: any) { - const handle = pass.getHandle(name); - if (handle === undefined) { return false; } - const bindingType = getBindingTypeFromHandle(handle); - if (bindingType === GFXBindingType.UNIFORM_BUFFER) { - if (Array.isArray(val)) { - pass.setUniformArray(handle, val); - } else { - pass.setUniform(handle, val); - } - } else if (bindingType === GFXBindingType.SAMPLER) { - const binding = getBindingFromHandle(handle); - if (val instanceof GFXTextureView) { - pass.bindTextureView(binding, val); - } else if (val instanceof TextureBase || val instanceof SpriteFrame) { - const textureView: GFXTextureView | null = val.getGFXTextureView(); - if (!textureView || !textureView.texture.width || !textureView.texture.height) { - // console.warn(`material '${this._uuid}' received incomplete texture asset '${val._uuid}'`); - return false; - } - pass.bindTextureView(binding, textureView); - if (val instanceof TextureBase) { - pass.bindSampler(binding, samplerLib.getSampler(cc.game._gfxDevice, val.getSamplerHash())); - } - } - } - return true; -} - -export function generateMaterailHash (mat: IMaterial) { - let str = ''; - for (const pass of mat.passes) { - str += pass.psoHash; - } - return murmurhash2_32_gc(str, 666); -} - -export interface IMaterial { - /** - * @zh - * 当前使用的 EffectAsset 资源。 - */ - readonly effectAsset: EffectAsset | null; - - /** - * @zh - * 当前使用的 EffectAsset 资源名。 - */ - readonly effectName: string; - - /** - * @zh - * 当前的 technique 索引。 - */ - readonly technique: number; - - /** - * @zh - * 当前正在使用的 pass 数组。 - */ - readonly passes: IPass[]; - - /** - * @zh - * 材质的 hash。 - */ - readonly hash: number; - - readonly parent: IMaterial | null; - readonly owner: RenderableComponent | null; - - /** - * @zh - * 重置材质的所有 uniform 参数数据为 effect 默认初始值。 - * @param clearPasses 是否同时重置当前正在用于渲染的 pass 数组内的信息 - */ - resetUniforms (clearPasses?: boolean): void; - - /** - * @zh - * 使用指定预处理宏重新编译当前 pass(数组)中的 shader。 - * @param overrides 新增的预处理宏列表,会覆盖进当前列表。 - * @param passIdx 要编译的 pass 索引,默认编译所有 pass。 - */ - recompileShaders (overrides: IDefineMap, passIdx?: number): void; - - /** - * @zh - * 使用指定管线状态重载当前的 pass(数组)。 - * @param overrides 新增的管线状态列表,会覆盖进当前列表。 - * @param passIdx 要重载的 pass 索引,默认重载所有 pass。 - */ - overridePipelineStates (overrides: PassOverrides, passIdx?: number): void; - - /** - * @en - * Convenient property setter provided for quick material setup.
- * [[Pass.setUniform]] should be used instead
- * if you need to do per-frame property update. - * @zh - * 设置材质 uniform 参数的统一入口。
- * 注意如果需要每帧更新 uniform,建议使用 [[Pass.setUniform]] 以获得更好的性能。 - * @param name 要设置的 uniform 名字。 - * @param val 要设置的 uniform 值。 - * @param passIdx 要设置的 pass 索引,默认设置所有 pass。 - */ - setProperty (name: string, val: any, passIdx?: number): void; - - /** - * @zh - * 获取当前材质的指定 uniform 值。 - * @param name 要获取的 uniform 名字。 - * @param passIdx 要获取的源 pass 索引,默认遍历所有 pass,返回第一个找到指定名字的 uniform。 - */ - getProperty (name: string, passIdx?: number): any; - - /** - * @zh - * 销毁材质实例 - */ - destroy (): void; - - _onPassStateChanged (idx: number); -} diff --git a/cocos/core/utils/pass-interface.ts b/cocos/core/utils/pass-interface.ts deleted file mode 100644 index e6963101b54..00000000000 --- a/cocos/core/utils/pass-interface.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { IProgramInfo, programLib } from '../../core/renderer/core/program-lib'; -import { IPassInfo, IPropertyInfo } from '../assets/effect-asset'; -import { GFXBuffer, GFXDevice, GFXDynamicState, GFXPipelineState, GFXPrimitiveMode, GFXRenderPass, GFXSampler, GFXShader, GFXTextureView, GFXType } from '../gfx'; -import { IGFXBinding } from '../gfx/binding-layout'; -import { GFXBlendState, GFXDepthStencilState, GFXRasterizerState } from '../gfx/pipeline-state'; -import { BatchedBuffer } from '../pipeline/batched-buffer'; -import { RenderPassStage, RenderPriority } from '../pipeline/define'; -import { PassOverrides } from '../renderer/core/pass'; -import { IDefineMap } from '../renderer/core/pass-utils'; -import { murmurhash2_32_gc } from './murmurhash2_gc'; - -export interface IBlock { - buffer: ArrayBuffer; - view: Float32Array; - dirty: boolean; -} - -export interface IPassDynamics { - [type: number]: { - dirty: boolean, - value: number[], - }; -} - -export interface IPSOHashInfo { - program: string; - defines: IDefineMap; - stage: RenderPassStage; - primitive: GFXPrimitiveMode; - rasterizerState: GFXRasterizerState; - depthStencilState: GFXDepthStencilState; - blendState: GFXBlendState; - dynamicStates: GFXDynamicState[]; -} - -function serializeBlendState (bs: GFXBlendState) { - let res = `,bs,${bs.isA2C},${bs.blendColor}`; - for (const t of bs.targets) { - res += `,bt,${t.blend},${t.blendEq},${t.blendAlphaEq},${t.blendColorMask}`; - res += `,${t.blendSrc},${t.blendDst},${t.blendSrcAlpha},${t.blendDstAlpha}`; - } - return res; -} - -function serializeRasterizerState (rs: GFXRasterizerState) { - const res = `,rs,${rs.cullMode},${rs.depthBias},${rs.isFrontFaceCCW}`; - return res; -} - -function serializeDepthStencilState (dss: GFXDepthStencilState) { - let res = `,dss,${dss.depthTest},${dss.depthWrite},${dss.depthFunc}`; - res += `,${dss.stencilTestFront},${dss.stencilFuncFront},${dss.stencilRefFront},${dss.stencilReadMaskFront}`; - res += `,${dss.stencilFailOpFront},${dss.stencilZFailOpFront},${dss.stencilPassOpFront},${dss.stencilWriteMaskFront}`; - res += `,${dss.stencilTestBack},${dss.stencilFuncBack},${dss.stencilRefBack},${dss.stencilReadMaskBack}`; - res += `,${dss.stencilFailOpBack},${dss.stencilZFailOpBack},${dss.stencilPassOpBack},${dss.stencilWriteMaskBack}`; - return res; -} - -export function generatePassPSOHash (pass: IPass) { - const shaderKey = programLib.getKey(pass.program, pass.defines); - let res = `${shaderKey},${pass.stage},${pass.primitive}`; - res += serializeBlendState(pass.blendState); - res += serializeDepthStencilState(pass.depthStencilState); - res += serializeRasterizerState(pass.rasterizerState); - return murmurhash2_32_gc(res, 666); -} - -export interface IPass { - - readonly parent: IPass | null; - readonly psoHash: number; - readonly batchedBuffer: BatchedBuffer | null; - // states - readonly priority: RenderPriority; - readonly primitive: GFXPrimitiveMode; - readonly stage: RenderPassStage; - readonly rasterizerState: GFXRasterizerState; - readonly depthStencilState: GFXDepthStencilState; - readonly blendState: GFXBlendState; - readonly dynamicStates: GFXDynamicState[]; - readonly customizations: string[]; - readonly phase: number; - // infos - readonly shaderInfo: IProgramInfo; - readonly program: string; - readonly properties: Record; - readonly defines: IDefineMap; - readonly idxInTech: number; - // resources - readonly device: GFXDevice; - readonly bindings: IGFXBinding[]; - readonly shader: GFXShader; - readonly renderPass: GFXRenderPass; - readonly dynamics: IPassDynamics; - readonly blocks: IBlock[]; - /** - * @zh - * 获取指定 UBO 成员,或其更具体分量的读写句柄。默认以成员自身的类型为目标读写类型(即读写时必须传入与成员类型相同的变量)。 - * @param name 目标 UBO 成员名 - * @param offset 目标分量在成员内的偏移量 - * @param targetType 目标读写类型,用于定制化在使用此句柄时,将以什么类型进行读写操作 - * @example - * ``` - * // say 'pbrParams' is a uniform vec4 - * const hParams = pass.getHandle('pbrParams'); // get the default handle - * pass.setUniform(hAlbedo, cc.v3(1, 0, 0)); // wrong! pbrParams.w is NaN now - * - * // say 'albedoScale' is a uniform vec4, and we only want to modify the w component in the form of a single float - * const hThreshold = pass.getHandle('albedoScale', 3, cc.GFXType.FLOAT); - * pass.setUniform(hThreshold, 0.5); // now, albedoScale.w = 0.5 - * ``` - */ - getHandle (name: string, offset?: number, targetType?: GFXType): number | undefined; - - /** - * @zh - * 获取指定 uniform 的 binding。 - * @param name 目标 uniform 名。 - */ - getBinding (name: string): number | undefined; - - /** - * @zh - * 设置指定普通向量类 uniform 的值,如果需要频繁更新请尽量使用此接口。 - * @param handle 目标 uniform 的 handle。 - * @param value 目标值。 - */ - setUniform (handle: number, value: any): void; - - /** - * @zh - * 获取指定普通向量类 uniform 的值。 - * @param handle 目标 uniform 的 handle。 - * @param out 输出向量。 - */ - getUniform (handle: number, out: any): any; - - /** - * @zh - * 设置指定数组类 uniform 的值,如果需要频繁更新请尽量使用此接口。 - * @param handle 目标 uniform 的 handle。 - * @param value 目标值。 - */ - setUniformArray (handle: number, value: any[]): void; - - /** - * @zh - * 绑定实际 [[GFXBuffer]] 到指定 binding。 - * @param binding 目标 UBO 的 binding。 - * @param value 目标 buffer。 - */ - bindBuffer (binding: number, value: GFXBuffer): void; - - /** - * @zh - * 绑定实际 [[GFXTextureView]] 到指定 binding。 - * @param binding 目标贴图类 uniform 的 binding。 - * @param value 目标 texture view。 - */ - bindTextureView (binding: number, value: GFXTextureView): void; - - /** - * @zh - * 绑定实际 [[GFXSampler]] 到指定 binding。 - * @param binding 目标贴图类 uniform 的 binding。 - * @param value 目标 sampler。 - */ - bindSampler (binding: number, value: GFXSampler): void; - - /** - * @zh - * 设置运行时 pass 内可动态更新的管线状态属性。 - * @param state 目标管线状态。 - * @param value 目标值。 - */ - setDynamicState (state: GFXDynamicState, value: any): void; - - /** - * @zh - * 重载当前所有管线状态。 - * @param original 原始管线状态。 - * @param value 管线状态重载值。 - */ - overridePipelineStates (original: IPassInfo, overrides: PassOverrides): void; - - /** - * @zh - * 更新当前 Uniform 数据。 - */ - update (): void; - - /** - * @zh - * 销毁当前 pass。 - */ - destroy (): void; - - /** - * @zh - * 重置所有 UBO 为初始默认值。 - */ - resetUBOs (): void; - - /** - * @zh - * 重置所有 texture 和 sampler 为初始默认值。 - */ - resetTextures (): void; - - /** - * @zh - * 尝试编译 shader 并获取相关资源引用。 - * @param defineOverrides shader 预处理宏定义重载 - */ - tryCompile (defineOverrides?: IDefineMap): any; - - /** - * @zh - * 根据当前 pass 持有的信息创建 [[GFXPipelineState]]。 - */ - createPipelineState (): GFXPipelineState | null; - - /** - * @zh - * 销毁指定的 [[GFXPipelineState]],如果它是这个 pass 创建的。 - */ - destroyPipelineState (pipelineStates?: GFXPipelineState): void; - - createBatchedBuffer (): void; - - clearBatchedBuffer (): void; - - /** - * @zh - * 用于在component的pso变化的回调中调用以取消pso变化的通知,一般情况下不应该调用该函数,如果必须调用,请先检查上层逻辑是否合理。 - */ - beginChangeStatesSilently (): void; - endChangeStatesSilently (): void; -} From cf9cfdaf4b4dd86067fda9bc967d3d5680f11987 Mon Sep 17 00:00:00 2001 From: Yun Hsiao Wu Date: Tue, 24 Dec 2019 15:49:07 +0800 Subject: [PATCH 05/13] more fixes (#6) * more fixes * minor --- cocos/core/3d/builtin/effects.ts | 91 ++++++++++--------- cocos/core/3d/builtin/init.ts | 2 +- .../core/3d/framework/renderable-component.ts | 4 +- cocos/core/assets/material.ts | 4 + .../components/ui-base/ui-render-component.ts | 42 ++++++--- cocos/core/renderer/core/program-lib.ts | 2 + cocos/core/renderer/index.ts | 4 +- cocos/core/renderer/models/skinning-model.ts | 10 +- cocos/core/renderer/scene/model.ts | 40 +++----- cocos/core/renderer/scene/planar-shadows.ts | 28 +++--- cocos/core/renderer/scene/submodel.ts | 14 +-- cocos/core/renderer/ui/render-data.ts | 5 +- cocos/core/renderer/ui/stencil-manager.ts | 6 +- cocos/core/renderer/ui/ui-batch-model.ts | 4 +- cocos/core/renderer/ui/ui-draw-batch.ts | 4 +- cocos/core/renderer/ui/ui-material.ts | 8 +- cocos/core/renderer/ui/ui.ts | 35 ++++--- cocos/core/utils/profiler/profiler.ts | 2 +- cocos/particle/models/particle-batch-model.ts | 4 +- .../renderer/particle-system-renderer.ts | 25 +++-- cocos/ui/components/graphics-component.ts | 35 ++++--- 21 files changed, 195 insertions(+), 174 deletions(-) diff --git a/cocos/core/3d/builtin/effects.ts b/cocos/core/3d/builtin/effects.ts index 7e3afa643fa..c2b50159565 100644 --- a/cocos/core/3d/builtin/effects.ts +++ b/cocos/core/3d/builtin/effects.ts @@ -10,13 +10,13 @@ export default [ "shaders": [ { "name": "builtin-billboard|vert:vs_main|tinted-fs:add", - "hash": 4131745192, + "hash": 916813039, "glsl3": { - "vert": `\nprecision mediump float;\nuniform Constants {\n vec4 mainTiling_Offset;\n vec4 frameTile_velLenScale;\n vec4 scale;\n};\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\nvec4 quaternionFromAxis (vec3 xAxis,vec3 yAxis,vec3 zAxis){\n mat3 m = mat3(xAxis,yAxis,zAxis);\n float trace = m[0][0] + m[1][1] + m[2][2];\n vec4 quat;\n if (trace > 0.) {\n float s = 0.5 / sqrt(trace + 1.0);\n quat.w = 0.25 / s;\n quat.x = (m[2][1] - m[1][2]) * s;\n quat.y = (m[0][2] - m[2][0]) * s;\n quat.z = (m[1][0] - m[0][1]) * s;\n } else if ((m[0][0] > m[1][1]) && (m[0][0] > m[2][2])) {\n float s = 2.0 * sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]);\n quat.w = (m[2][1] - m[1][2]) / s;\n quat.x = 0.25 * s;\n quat.y = (m[0][1] + m[1][0]) / s;\n quat.z = (m[0][2] + m[2][0]) / s;\n } else if (m[1][1] > m[2][2]) {\n float s = 2.0 * sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]);\n quat.w = (m[0][2] - m[2][0]) / s;\n quat.x = (m[0][1] + m[1][0]) / s;\n quat.y = 0.25 * s;\n quat.z = (m[1][2] + m[2][1]) / s;\n } else {\n float s = 2.0 * sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]);\n quat.w = (m[1][0] - m[0][1]) / s;\n quat.x = (m[0][2] + m[2][0]) / s;\n quat.y = (m[1][2] + m[2][1]) / s;\n quat.z = 0.25 * s;\n }\n float len = quat.x * quat.x + quat.y * quat.y + quat.z * quat.z + quat.w * quat.w;\n if (len > 0.) {\n len = 1. / sqrt(len);\n quat.x = quat.x * len;\n quat.y = quat.y * len;\n quat.z = quat.z * len;\n quat.w = quat.w * len;\n }\n return quat;\n}\nvec4 quaternionFromEuler (vec3 angle){\n float x = angle.x / 2.;\n float y = angle.y / 2.;\n float z = angle.z / 2.;\n float sx = sin(x);\n float cx = cos(x);\n float sy = sin(y);\n float cy = cos(y);\n float sz = sin(z);\n float cz = cos(z);\n vec4 quat = vec4(0);\n quat.x = sx * cy * cz + cx * sy * sz;\n quat.y = cx * sy * cz + sx * cy * sz;\n quat.z = cx * cy * sz - sx * sy * cz;\n quat.w = cx * cy * cz - sx * sy * sz;\n return quat;\n}\nvec4 quatMultiply (vec4 a, vec4 b){\n vec4 quat;\n quat.x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;\n quat.y = a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z;\n quat.z = a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x;\n quat.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;\n return quat;\n}\nvoid rotateVecFromQuat (inout vec3 v, vec4 q){\n float ix = q.w * v.x + q.y * v.z - q.z * v.y;\n float iy = q.w * v.y + q.z * v.x - q.x * v.z;\n float iz = q.w * v.z + q.x * v.y - q.y * v.x;\n float iw = -q.x * v.x - q.y * v.y - q.z * v.z;\n v.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;\n v.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;\n v.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;\n}\nvec3 rotateInLocalSpace (vec3 pos, vec3 xAxis, vec3 yAxis, vec3 zAxis, vec4 q){\n vec4 viewQuat = quaternionFromAxis(xAxis, yAxis, zAxis);\n vec4 rotQuat = quatMultiply(viewQuat, q);\n rotateVecFromQuat(pos, rotQuat);\n return pos;\n}\nvoid rotateCorner (inout vec2 corner, float angle){\n float xOS = cos(angle) * corner.x - sin(angle) * corner.y;\n float yOS = sin(angle) * corner.x + cos(angle) * corner.y;\n corner.x = xOS;\n corner.y = yOS;\n}\nout vec2 uv;\nout vec4 color;\nvoid computeVertPos (inout vec4 pos, vec2 vertOffset, vec4 q, vec3 s\n , mat4 viewInv\n) {\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = normalize(vec3(viewInv[0][0], viewInv[1][0], viewInv[2][0]));\n vec3 camY = normalize(vec3(viewInv[0][1], viewInv[1][1], viewInv[2][1]));\n vec3 camZ = normalize(vec3(viewInv[0][2], viewInv[1][2], viewInv[2][2]));\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, camZ, q);\n}\nin vec3 a_position;\nin vec2 a_texCoord;\nin vec4 a_color;\nuniform builtin {\n vec4 cc_size_rotation;\n};\nvec4 vs_main() {\n vec4 pos = vec4(a_position, 1);\n pos = cc_matWorld * pos;\n vec2 vertOffset = a_texCoord.xy - 0.5;\n computeVertPos(pos, vertOffset, quaternionFromEuler(vec3(0., 0., cc_size_rotation.z)), vec3(cc_size_rotation.xy, 0.), cc_matViewInv);\n pos = cc_matViewProj * pos;\n uv = a_texCoord.xy;\n color = a_color;\n return pos;\n}\nvoid main() { gl_Position = vs_main(); }`, - "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nin vec2 uv;\nin vec4 color;\nuniform sampler2D mainTexture;\nuniform FragConstants {\n vec4 tintColor;\n};\nvec4 add () {\n vec4 col = 2.0 * color * tintColor * texture(mainTexture, uv);\n return CCFragOutput(col);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = add(); }` + "vert": `\nprecision mediump float;\nuniform Constants {\n vec4 mainTiling_Offset;\n vec4 frameTile_velLenScale;\n vec4 scale;\n};\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\nvec4 quaternionFromAxis (vec3 xAxis,vec3 yAxis,vec3 zAxis){\n mat3 m = mat3(xAxis,yAxis,zAxis);\n float trace = m[0][0] + m[1][1] + m[2][2];\n vec4 quat;\n if (trace > 0.) {\n float s = 0.5 / sqrt(trace + 1.0);\n quat.w = 0.25 / s;\n quat.x = (m[2][1] - m[1][2]) * s;\n quat.y = (m[0][2] - m[2][0]) * s;\n quat.z = (m[1][0] - m[0][1]) * s;\n } else if ((m[0][0] > m[1][1]) && (m[0][0] > m[2][2])) {\n float s = 2.0 * sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]);\n quat.w = (m[2][1] - m[1][2]) / s;\n quat.x = 0.25 * s;\n quat.y = (m[0][1] + m[1][0]) / s;\n quat.z = (m[0][2] + m[2][0]) / s;\n } else if (m[1][1] > m[2][2]) {\n float s = 2.0 * sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]);\n quat.w = (m[0][2] - m[2][0]) / s;\n quat.x = (m[0][1] + m[1][0]) / s;\n quat.y = 0.25 * s;\n quat.z = (m[1][2] + m[2][1]) / s;\n } else {\n float s = 2.0 * sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]);\n quat.w = (m[1][0] - m[0][1]) / s;\n quat.x = (m[0][2] + m[2][0]) / s;\n quat.y = (m[1][2] + m[2][1]) / s;\n quat.z = 0.25 * s;\n }\n float len = quat.x * quat.x + quat.y * quat.y + quat.z * quat.z + quat.w * quat.w;\n if (len > 0.) {\n len = 1. / sqrt(len);\n quat.x = quat.x * len;\n quat.y = quat.y * len;\n quat.z = quat.z * len;\n quat.w = quat.w * len;\n }\n return quat;\n}\nvec4 quaternionFromEuler (vec3 angle){\n float x = angle.x / 2.;\n float y = angle.y / 2.;\n float z = angle.z / 2.;\n float sx = sin(x);\n float cx = cos(x);\n float sy = sin(y);\n float cy = cos(y);\n float sz = sin(z);\n float cz = cos(z);\n vec4 quat = vec4(0);\n quat.x = sx * cy * cz + cx * sy * sz;\n quat.y = cx * sy * cz + sx * cy * sz;\n quat.z = cx * cy * sz - sx * sy * cz;\n quat.w = cx * cy * cz - sx * sy * sz;\n return quat;\n}\nvec4 quatMultiply (vec4 a, vec4 b){\n vec4 quat;\n quat.x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;\n quat.y = a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z;\n quat.z = a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x;\n quat.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;\n return quat;\n}\nvoid rotateVecFromQuat (inout vec3 v, vec4 q){\n float ix = q.w * v.x + q.y * v.z - q.z * v.y;\n float iy = q.w * v.y + q.z * v.x - q.x * v.z;\n float iz = q.w * v.z + q.x * v.y - q.y * v.x;\n float iw = -q.x * v.x - q.y * v.y - q.z * v.z;\n v.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;\n v.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;\n v.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;\n}\nvec3 rotateInLocalSpace (vec3 pos, vec3 xAxis, vec3 yAxis, vec3 zAxis, vec4 q){\n vec4 viewQuat = quaternionFromAxis(xAxis, yAxis, zAxis);\n vec4 rotQuat = quatMultiply(viewQuat, q);\n rotateVecFromQuat(pos, rotQuat);\n return pos;\n}\nvoid rotateCorner (inout vec2 corner, float angle){\n float xOS = cos(angle) * corner.x - sin(angle) * corner.y;\n float yOS = sin(angle) * corner.x + cos(angle) * corner.y;\n corner.x = xOS;\n corner.y = yOS;\n}\nout vec2 uv;\nout vec4 color;\nvoid computeVertPos (inout vec4 pos, vec2 vertOffset, vec4 q, vec3 s\n , mat4 viewInv\n) {\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = normalize(vec3(viewInv[0][0], viewInv[1][0], viewInv[2][0]));\n vec3 camY = normalize(vec3(viewInv[0][1], viewInv[1][1], viewInv[2][1]));\n vec3 camZ = normalize(vec3(viewInv[0][2], viewInv[1][2], viewInv[2][2]));\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, camZ, q);\n}\nin vec3 a_position;\nin vec2 a_texCoord;\nin vec4 a_color;\nuniform builtin {\n vec4 cc_size_rotation;\n};\nvec4 vs_main() {\n vec4 pos = vec4(a_position, 1);\n pos = cc_matWorld * pos;\n vec2 vertOffset = a_texCoord.xy - 0.5;\n computeVertPos(pos, vertOffset, quaternionFromEuler(vec3(0., 0., cc_size_rotation.z)), vec3(cc_size_rotation.xy, 0.), cc_matViewInv);\n pos = cc_matViewProj * pos;\n uv = a_texCoord.xy;\n color = a_color;\n return pos;\n}\nvoid main() { gl_Position = vs_main(); }`, + "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nin vec2 uv;\nin vec4 color;\nuniform sampler2D mainTexture;\nuniform FragConstants {\n vec4 tintColor;\n};\nvec4 add () {\n vec4 col = 2.0 * color * tintColor * texture(mainTexture, uv);\n return CCFragOutput(col);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = add(); }` }, "glsl1": { - "vert": `\nprecision mediump float;\nuniform highp mat4 cc_matView;\nuniform mediump mat4 cc_matViewInv;\nuniform mediump mat4 cc_matViewProj;\nuniform highp mat4 cc_matWorld;\nvec4 quaternionFromAxis (vec3 xAxis,vec3 yAxis,vec3 zAxis){\n mat3 m = mat3(xAxis,yAxis,zAxis);\n float trace = m[0][0] + m[1][1] + m[2][2];\n vec4 quat;\n if (trace > 0.) {\n float s = 0.5 / sqrt(trace + 1.0);\n quat.w = 0.25 / s;\n quat.x = (m[2][1] - m[1][2]) * s;\n quat.y = (m[0][2] - m[2][0]) * s;\n quat.z = (m[1][0] - m[0][1]) * s;\n } else if ((m[0][0] > m[1][1]) && (m[0][0] > m[2][2])) {\n float s = 2.0 * sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]);\n quat.w = (m[2][1] - m[1][2]) / s;\n quat.x = 0.25 * s;\n quat.y = (m[0][1] + m[1][0]) / s;\n quat.z = (m[0][2] + m[2][0]) / s;\n } else if (m[1][1] > m[2][2]) {\n float s = 2.0 * sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]);\n quat.w = (m[0][2] - m[2][0]) / s;\n quat.x = (m[0][1] + m[1][0]) / s;\n quat.y = 0.25 * s;\n quat.z = (m[1][2] + m[2][1]) / s;\n } else {\n float s = 2.0 * sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]);\n quat.w = (m[1][0] - m[0][1]) / s;\n quat.x = (m[0][2] + m[2][0]) / s;\n quat.y = (m[1][2] + m[2][1]) / s;\n quat.z = 0.25 * s;\n }\n float len = quat.x * quat.x + quat.y * quat.y + quat.z * quat.z + quat.w * quat.w;\n if (len > 0.) {\n len = 1. / sqrt(len);\n quat.x = quat.x * len;\n quat.y = quat.y * len;\n quat.z = quat.z * len;\n quat.w = quat.w * len;\n }\n return quat;\n}\nvec4 quaternionFromEuler (vec3 angle){\n float x = angle.x / 2.;\n float y = angle.y / 2.;\n float z = angle.z / 2.;\n float sx = sin(x);\n float cx = cos(x);\n float sy = sin(y);\n float cy = cos(y);\n float sz = sin(z);\n float cz = cos(z);\n vec4 quat = vec4(0);\n quat.x = sx * cy * cz + cx * sy * sz;\n quat.y = cx * sy * cz + sx * cy * sz;\n quat.z = cx * cy * sz - sx * sy * cz;\n quat.w = cx * cy * cz - sx * sy * sz;\n return quat;\n}\nvec4 quatMultiply (vec4 a, vec4 b){\n vec4 quat;\n quat.x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;\n quat.y = a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z;\n quat.z = a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x;\n quat.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;\n return quat;\n}\nvoid rotateVecFromQuat (inout vec3 v, vec4 q){\n float ix = q.w * v.x + q.y * v.z - q.z * v.y;\n float iy = q.w * v.y + q.z * v.x - q.x * v.z;\n float iz = q.w * v.z + q.x * v.y - q.y * v.x;\n float iw = -q.x * v.x - q.y * v.y - q.z * v.z;\n v.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;\n v.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;\n v.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;\n}\nvec3 rotateInLocalSpace (vec3 pos, vec3 xAxis, vec3 yAxis, vec3 zAxis, vec4 q){\n vec4 viewQuat = quaternionFromAxis(xAxis, yAxis, zAxis);\n vec4 rotQuat = quatMultiply(viewQuat, q);\n rotateVecFromQuat(pos, rotQuat);\n return pos;\n}\nvoid rotateCorner (inout vec2 corner, float angle){\n float xOS = cos(angle) * corner.x - sin(angle) * corner.y;\n float yOS = sin(angle) * corner.x + cos(angle) * corner.y;\n corner.x = xOS;\n corner.y = yOS;\n}\nvarying vec2 uv;\nvarying vec4 color;\nvoid computeVertPos (inout vec4 pos, vec2 vertOffset, vec4 q, vec3 s\n , mat4 viewInv\n) {\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = normalize(vec3(viewInv[0][0], viewInv[1][0], viewInv[2][0]));\n vec3 camY = normalize(vec3(viewInv[0][1], viewInv[1][1], viewInv[2][1]));\n vec3 camZ = normalize(vec3(viewInv[0][2], viewInv[1][2], viewInv[2][2]));\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, camZ, q);\n}\nattribute vec3 a_position;\nattribute vec2 a_texCoord;\nattribute vec4 a_color;\nuniform vec4 cc_size_rotation;\nvec4 vs_main() {\n vec4 pos = vec4(a_position, 1);\n pos = cc_matWorld * pos;\n vec2 vertOffset = a_texCoord.xy - 0.5;\n computeVertPos(pos, vertOffset, quaternionFromEuler(vec3(0., 0., cc_size_rotation.z)), vec3(cc_size_rotation.xy, 0.), cc_matViewInv);\n pos = cc_matViewProj * pos;\n uv = a_texCoord.xy;\n color = a_color;\n return pos;\n}\nvoid main() { gl_Position = vs_main(); }`, + "vert": `\nprecision mediump float;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matViewInv;\nuniform highp mat4 cc_matViewProj;\nuniform highp mat4 cc_matWorld;\nvec4 quaternionFromAxis (vec3 xAxis,vec3 yAxis,vec3 zAxis){\n mat3 m = mat3(xAxis,yAxis,zAxis);\n float trace = m[0][0] + m[1][1] + m[2][2];\n vec4 quat;\n if (trace > 0.) {\n float s = 0.5 / sqrt(trace + 1.0);\n quat.w = 0.25 / s;\n quat.x = (m[2][1] - m[1][2]) * s;\n quat.y = (m[0][2] - m[2][0]) * s;\n quat.z = (m[1][0] - m[0][1]) * s;\n } else if ((m[0][0] > m[1][1]) && (m[0][0] > m[2][2])) {\n float s = 2.0 * sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]);\n quat.w = (m[2][1] - m[1][2]) / s;\n quat.x = 0.25 * s;\n quat.y = (m[0][1] + m[1][0]) / s;\n quat.z = (m[0][2] + m[2][0]) / s;\n } else if (m[1][1] > m[2][2]) {\n float s = 2.0 * sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]);\n quat.w = (m[0][2] - m[2][0]) / s;\n quat.x = (m[0][1] + m[1][0]) / s;\n quat.y = 0.25 * s;\n quat.z = (m[1][2] + m[2][1]) / s;\n } else {\n float s = 2.0 * sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]);\n quat.w = (m[1][0] - m[0][1]) / s;\n quat.x = (m[0][2] + m[2][0]) / s;\n quat.y = (m[1][2] + m[2][1]) / s;\n quat.z = 0.25 * s;\n }\n float len = quat.x * quat.x + quat.y * quat.y + quat.z * quat.z + quat.w * quat.w;\n if (len > 0.) {\n len = 1. / sqrt(len);\n quat.x = quat.x * len;\n quat.y = quat.y * len;\n quat.z = quat.z * len;\n quat.w = quat.w * len;\n }\n return quat;\n}\nvec4 quaternionFromEuler (vec3 angle){\n float x = angle.x / 2.;\n float y = angle.y / 2.;\n float z = angle.z / 2.;\n float sx = sin(x);\n float cx = cos(x);\n float sy = sin(y);\n float cy = cos(y);\n float sz = sin(z);\n float cz = cos(z);\n vec4 quat = vec4(0);\n quat.x = sx * cy * cz + cx * sy * sz;\n quat.y = cx * sy * cz + sx * cy * sz;\n quat.z = cx * cy * sz - sx * sy * cz;\n quat.w = cx * cy * cz - sx * sy * sz;\n return quat;\n}\nvec4 quatMultiply (vec4 a, vec4 b){\n vec4 quat;\n quat.x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;\n quat.y = a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z;\n quat.z = a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x;\n quat.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;\n return quat;\n}\nvoid rotateVecFromQuat (inout vec3 v, vec4 q){\n float ix = q.w * v.x + q.y * v.z - q.z * v.y;\n float iy = q.w * v.y + q.z * v.x - q.x * v.z;\n float iz = q.w * v.z + q.x * v.y - q.y * v.x;\n float iw = -q.x * v.x - q.y * v.y - q.z * v.z;\n v.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;\n v.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;\n v.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;\n}\nvec3 rotateInLocalSpace (vec3 pos, vec3 xAxis, vec3 yAxis, vec3 zAxis, vec4 q){\n vec4 viewQuat = quaternionFromAxis(xAxis, yAxis, zAxis);\n vec4 rotQuat = quatMultiply(viewQuat, q);\n rotateVecFromQuat(pos, rotQuat);\n return pos;\n}\nvoid rotateCorner (inout vec2 corner, float angle){\n float xOS = cos(angle) * corner.x - sin(angle) * corner.y;\n float yOS = sin(angle) * corner.x + cos(angle) * corner.y;\n corner.x = xOS;\n corner.y = yOS;\n}\nvarying vec2 uv;\nvarying vec4 color;\nvoid computeVertPos (inout vec4 pos, vec2 vertOffset, vec4 q, vec3 s\n , mat4 viewInv\n) {\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = normalize(vec3(viewInv[0][0], viewInv[1][0], viewInv[2][0]));\n vec3 camY = normalize(vec3(viewInv[0][1], viewInv[1][1], viewInv[2][1]));\n vec3 camZ = normalize(vec3(viewInv[0][2], viewInv[1][2], viewInv[2][2]));\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, camZ, q);\n}\nattribute vec3 a_position;\nattribute vec2 a_texCoord;\nattribute vec4 a_color;\nuniform vec4 cc_size_rotation;\nvec4 vs_main() {\n vec4 pos = vec4(a_position, 1);\n pos = cc_matWorld * pos;\n vec2 vertOffset = a_texCoord.xy - 0.5;\n computeVertPos(pos, vertOffset, quaternionFromEuler(vec3(0., 0., cc_size_rotation.z)), vec3(cc_size_rotation.xy, 0.), cc_matViewInv);\n pos = cc_matViewProj * pos;\n uv = a_texCoord.xy;\n color = a_color;\n return pos;\n}\nvoid main() { gl_Position = vs_main(); }`, "frag": `\nprecision mediump float;\nuniform mediump vec4 cc_exposure;\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvarying vec2 uv;\nvarying vec4 color;\nuniform sampler2D mainTexture;\nuniform vec4 tintColor;\nvec4 add () {\n vec4 col = 2.0 * color * tintColor * texture2D(mainTexture, uv);\n return CCFragOutput(col);\n}\nvoid main() { gl_FragColor = add(); }` }, "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[]}, "locals":{"blocks":[{"name":"CCLocal", "defines":[]}], "samplers":[]}}, @@ -51,13 +51,13 @@ export default [ "shaders": [ { "name": "builtin-particle-trail|particle-trail:vs_main|tinted-fs:add", - "hash": 2513735112, + "hash": 516627142, "glsl3": { - "vert": `\nprecision mediump float;\nuniform Constants {\n vec4 mainTiling_Offset;\n vec4 frameTile_velLenScale;\n vec4 scale;\n};\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\nout vec2 uv;\nout vec4 color;\nin vec3 a_position;\nin vec4 a_texCoord;\nin vec3 a_texCoord1;\nin vec3 a_texCoord2;\nin vec4 a_color;\n#if CC_DRAW_WIRE_FRAME\n out vec3 vBarycentric;\n#endif\nvec4 vs_main() {\n highp vec4 pos = vec4(a_position, 1);\n vec4 velocity = vec4(a_texCoord1.xyz, 0);\n #if !CC_USE_WORLD_SPACE\n pos = cc_matWorld * pos;\n velocity = cc_matWorld * velocity;\n #endif\n float vertOffset = (a_texCoord.x - 0.5) * a_texCoord.y;\n vec3 camUp = normalize(cross(pos.xyz - cc_cameraPos.xyz, velocity.xyz));\n pos.xyz += camUp * vertOffset;\n pos = cc_matViewProj * pos;\n uv = a_texCoord.zw * mainTiling_Offset.xy + mainTiling_Offset.zw;;\n color = a_color;\n #if CC_DRAW_WIRE_FRAME\n vBarycentric = a_texCoord2;\n #endif\n return pos;\n}\nvoid main() { gl_Position = vs_main(); }`, - "frag": `\n precision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\n in vec2 uv;\n in vec4 color;\n #if CC_DRAW_WIRE_FRAME\n in vec3 vBarycentric;\n #endif\n uniform sampler2D mainTexture;\n uniform FragConstants {\n vec4 tintColor;\n };\n vec4 add () {\n vec4 col = 2.0 * color * tintColor * texture(mainTexture, uv);\n#if CC_DRAW_WIRE_FRAME\n if (any(lessThan(vBarycentric, vec3(0.02)))) {\n col = vec4(0., 1., 1., 1.);\n }\n#endif\n return CCFragOutput(col);\n }\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = add(); }` + "vert": `\nprecision mediump float;\nuniform Constants {\n vec4 mainTiling_Offset;\n vec4 frameTile_velLenScale;\n vec4 scale;\n};\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\nout vec2 uv;\nout vec4 color;\nin vec3 a_position;\nin vec4 a_texCoord;\nin vec3 a_texCoord1;\nin vec3 a_texCoord2;\nin vec4 a_color;\n#if CC_DRAW_WIRE_FRAME\n out vec3 vBarycentric;\n#endif\nvec4 vs_main() {\n highp vec4 pos = vec4(a_position, 1);\n vec4 velocity = vec4(a_texCoord1.xyz, 0);\n #if !CC_USE_WORLD_SPACE\n pos = cc_matWorld * pos;\n velocity = cc_matWorld * velocity;\n #endif\n float vertOffset = (a_texCoord.x - 0.5) * a_texCoord.y;\n vec3 camUp = normalize(cross(pos.xyz - cc_cameraPos.xyz, velocity.xyz));\n pos.xyz += camUp * vertOffset;\n pos = cc_matViewProj * pos;\n uv = a_texCoord.zw * mainTiling_Offset.xy + mainTiling_Offset.zw;;\n color = a_color;\n #if CC_DRAW_WIRE_FRAME\n vBarycentric = a_texCoord2;\n #endif\n return pos;\n}\nvoid main() { gl_Position = vs_main(); }`, + "frag": `\n precision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\n in vec2 uv;\n in vec4 color;\n #if CC_DRAW_WIRE_FRAME\n in vec3 vBarycentric;\n #endif\n uniform sampler2D mainTexture;\n uniform FragConstants {\n vec4 tintColor;\n };\n vec4 add () {\n vec4 col = 2.0 * color * tintColor * texture(mainTexture, uv);\n#if CC_DRAW_WIRE_FRAME\n if (any(lessThan(vBarycentric, vec3(0.02)))) {\n col = vec4(0., 1., 1., 1.);\n }\n#endif\n return CCFragOutput(col);\n }\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = add(); }` }, "glsl1": { - "vert": `\nprecision mediump float;\nuniform vec4 mainTiling_Offset;\nuniform mediump mat4 cc_matViewProj;\nuniform mediump vec4 cc_cameraPos;\nuniform highp mat4 cc_matWorld;\nvarying vec2 uv;\nvarying vec4 color;\nattribute vec3 a_position;\nattribute vec4 a_texCoord;\nattribute vec3 a_texCoord1;\nattribute vec3 a_texCoord2;\nattribute vec4 a_color;\n#if CC_DRAW_WIRE_FRAME\n varying vec3 vBarycentric;\n#endif\nvec4 vs_main() {\n highp vec4 pos = vec4(a_position, 1);\n vec4 velocity = vec4(a_texCoord1.xyz, 0);\n #if !CC_USE_WORLD_SPACE\n pos = cc_matWorld * pos;\n velocity = cc_matWorld * velocity;\n #endif\n float vertOffset = (a_texCoord.x - 0.5) * a_texCoord.y;\n vec3 camUp = normalize(cross(pos.xyz - cc_cameraPos.xyz, velocity.xyz));\n pos.xyz += camUp * vertOffset;\n pos = cc_matViewProj * pos;\n uv = a_texCoord.zw * mainTiling_Offset.xy + mainTiling_Offset.zw;;\n color = a_color;\n #if CC_DRAW_WIRE_FRAME\n vBarycentric = a_texCoord2;\n #endif\n return pos;\n}\nvoid main() { gl_Position = vs_main(); }`, + "vert": `\nprecision mediump float;\nuniform vec4 mainTiling_Offset;\nuniform highp mat4 cc_matViewProj;\nuniform highp vec4 cc_cameraPos;\nuniform highp mat4 cc_matWorld;\nvarying vec2 uv;\nvarying vec4 color;\nattribute vec3 a_position;\nattribute vec4 a_texCoord;\nattribute vec3 a_texCoord1;\nattribute vec3 a_texCoord2;\nattribute vec4 a_color;\n#if CC_DRAW_WIRE_FRAME\n varying vec3 vBarycentric;\n#endif\nvec4 vs_main() {\n highp vec4 pos = vec4(a_position, 1);\n vec4 velocity = vec4(a_texCoord1.xyz, 0);\n #if !CC_USE_WORLD_SPACE\n pos = cc_matWorld * pos;\n velocity = cc_matWorld * velocity;\n #endif\n float vertOffset = (a_texCoord.x - 0.5) * a_texCoord.y;\n vec3 camUp = normalize(cross(pos.xyz - cc_cameraPos.xyz, velocity.xyz));\n pos.xyz += camUp * vertOffset;\n pos = cc_matViewProj * pos;\n uv = a_texCoord.zw * mainTiling_Offset.xy + mainTiling_Offset.zw;;\n color = a_color;\n #if CC_DRAW_WIRE_FRAME\n vBarycentric = a_texCoord2;\n #endif\n return pos;\n}\nvoid main() { gl_Position = vs_main(); }`, "frag": `\n precision mediump float;\nuniform mediump vec4 cc_exposure;\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\n varying vec2 uv;\n varying vec4 color;\n #if CC_DRAW_WIRE_FRAME\n varying vec3 vBarycentric;\n #endif\n uniform sampler2D mainTexture;\n uniform vec4 tintColor;\n vec4 add () {\n vec4 col = 2.0 * color * tintColor * texture2D(mainTexture, uv);\n#if CC_DRAW_WIRE_FRAME\n if (any(lessThan(vBarycentric, vec3(0.02)))) {\n col = vec4(0., 1., 1., 1.);\n }\n#endif\n return CCFragOutput(col);\n }\nvoid main() { gl_FragColor = add(); }` }, "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[]}, "locals":{"blocks":[{"name":"CCLocal", "defines":[]}], "samplers":[]}}, @@ -92,13 +92,13 @@ export default [ "shaders": [ { "name": "builtin-particle|particle-vs-legacy:lpvs_main|tinted-fs:add", - "hash": 2667565674, + "hash": 317180679, "glsl3": { - "vert": `\nprecision highp float;\nvec4 quaternionFromAxis (vec3 xAxis,vec3 yAxis,vec3 zAxis){\n mat3 m = mat3(xAxis,yAxis,zAxis);\n float trace = m[0][0] + m[1][1] + m[2][2];\n vec4 quat;\n if (trace > 0.) {\n float s = 0.5 / sqrt(trace + 1.0);\n quat.w = 0.25 / s;\n quat.x = (m[2][1] - m[1][2]) * s;\n quat.y = (m[0][2] - m[2][0]) * s;\n quat.z = (m[1][0] - m[0][1]) * s;\n } else if ((m[0][0] > m[1][1]) && (m[0][0] > m[2][2])) {\n float s = 2.0 * sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]);\n quat.w = (m[2][1] - m[1][2]) / s;\n quat.x = 0.25 * s;\n quat.y = (m[0][1] + m[1][0]) / s;\n quat.z = (m[0][2] + m[2][0]) / s;\n } else if (m[1][1] > m[2][2]) {\n float s = 2.0 * sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]);\n quat.w = (m[0][2] - m[2][0]) / s;\n quat.x = (m[0][1] + m[1][0]) / s;\n quat.y = 0.25 * s;\n quat.z = (m[1][2] + m[2][1]) / s;\n } else {\n float s = 2.0 * sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]);\n quat.w = (m[1][0] - m[0][1]) / s;\n quat.x = (m[0][2] + m[2][0]) / s;\n quat.y = (m[1][2] + m[2][1]) / s;\n quat.z = 0.25 * s;\n }\n float len = quat.x * quat.x + quat.y * quat.y + quat.z * quat.z + quat.w * quat.w;\n if (len > 0.) {\n len = 1. / sqrt(len);\n quat.x = quat.x * len;\n quat.y = quat.y * len;\n quat.z = quat.z * len;\n quat.w = quat.w * len;\n }\n return quat;\n}\nvec4 quaternionFromEuler (vec3 angle){\n float x = angle.x / 2.;\n float y = angle.y / 2.;\n float z = angle.z / 2.;\n float sx = sin(x);\n float cx = cos(x);\n float sy = sin(y);\n float cy = cos(y);\n float sz = sin(z);\n float cz = cos(z);\n vec4 quat = vec4(0);\n quat.x = sx * cy * cz + cx * sy * sz;\n quat.y = cx * sy * cz + sx * cy * sz;\n quat.z = cx * cy * sz - sx * sy * cz;\n quat.w = cx * cy * cz - sx * sy * sz;\n return quat;\n}\nmat4 matrixFromRT (vec4 q, vec3 p){\n float x2 = q.x + q.x;\n float y2 = q.y + q.y;\n float z2 = q.z + q.z;\n float xx = q.x * x2;\n float xy = q.x * y2;\n float xz = q.x * z2;\n float yy = q.y * y2;\n float yz = q.y * z2;\n float zz = q.z * z2;\n float wx = q.w * x2;\n float wy = q.w * y2;\n float wz = q.w * z2;\n return mat4(\n 1. - (yy + zz), xy + wz, xz - wy, 0,\n xy - wz, 1. - (xx + zz), yz + wx, 0,\n xz + wy, yz - wx, 1. - (xx + yy), 0,\n p.x, p.y, p.z, 1\n );\n}\nmat4 matFromRTS (vec4 q, vec3 t, vec3 s){\n float x = q.x, y = q.y, z = q.z, w = q.w;\n float x2 = x + x;\n float y2 = y + y;\n float z2 = z + z;\n float xx = x * x2;\n float xy = x * y2;\n float xz = x * z2;\n float yy = y * y2;\n float yz = y * z2;\n float zz = z * z2;\n float wx = w * x2;\n float wy = w * y2;\n float wz = w * z2;\n float sx = s.x;\n float sy = s.y;\n float sz = s.z;\n return mat4((1. - (yy + zz)) * sx, (xy + wz) * sx, (xz - wy) * sx, 0,\n (xy - wz) * sy, (1. - (xx + zz)) * sy, (yz + wx) * sy, 0,\n (xz + wy) * sz, (yz - wx) * sz, (1. - (xx + yy)) * sz, 0,\n t.x, t.y, t.z, 1);\n}\nvec4 quatMultiply (vec4 a, vec4 b){\n vec4 quat;\n quat.x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;\n quat.y = a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z;\n quat.z = a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x;\n quat.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;\n return quat;\n}\nvoid rotateVecFromQuat (inout vec3 v, vec4 q){\n float ix = q.w * v.x + q.y * v.z - q.z * v.y;\n float iy = q.w * v.y + q.z * v.x - q.x * v.z;\n float iz = q.w * v.z + q.x * v.y - q.y * v.x;\n float iw = -q.x * v.x - q.y * v.y - q.z * v.z;\n v.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;\n v.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;\n v.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;\n}\nvec3 rotateInLocalSpace (vec3 pos, vec3 xAxis, vec3 yAxis, vec3 zAxis, vec4 q){\n vec4 viewQuat = quaternionFromAxis(xAxis, yAxis, zAxis);\n vec4 rotQuat = quatMultiply(viewQuat, q);\n rotateVecFromQuat(pos, rotQuat);\n return pos;\n}\nvoid rotateCorner (inout vec2 corner, float angle){\n float xOS = cos(angle) * corner.x - sin(angle) * corner.y;\n float yOS = sin(angle) * corner.x + cos(angle) * corner.y;\n corner.x = xOS;\n corner.y = yOS;\n}\nuniform Constants {\n vec4 mainTiling_Offset;\n vec4 frameTile_velLenScale;\n vec4 scale;\n};\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\nout vec2 uv;\nout vec4 color;\nvoid computeVertPos (inout vec4 pos, vec2 vertOffset, vec4 q, vec3 s\n#if CC_RENDER_MODE == 0 || CC_RENDER_MODE == 3\n , mat4 viewInv\n#endif\n#if CC_RENDER_MODE == 1\n , vec3 eye\n , vec4 velocity\n , float velocityScale\n , float lengthScale\n , float xIndex\n#endif\n) {\n#if CC_RENDER_MODE == 0\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = normalize(vec3(viewInv[0][0], viewInv[1][0], viewInv[2][0]));\n vec3 camY = normalize(vec3(viewInv[0][1], viewInv[1][1], viewInv[2][1]));\n vec3 camZ = normalize(vec3(viewInv[0][2], viewInv[1][2], viewInv[2][2]));\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, camZ, q);\n#elif CC_RENDER_MODE == 1\n vec3 camRight = normalize(cross(pos.xyz - eye, velocity.xyz)) * s.x;\n vec3 camUp = velocity.xyz * velocityScale + normalize(velocity.xyz) * lengthScale * s.y;\n pos.xyz += (camRight * abs(vertOffset.x) * sign(vertOffset.y)) - camUp * xIndex;\n#elif CC_RENDER_MODE == 2\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = vec3(1, 0, 0);\n vec3 camY = vec3(0, 0, -1);\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, cross(camX, camY), q);\n#elif CC_RENDER_MODE == 3\n vec2 viewSpaceVert = vec2(vertOffset.x * s.x, vertOffset.y * s.y);\n rotateCorner(viewSpaceVert, q.z);\n vec3 camX = normalize(vec3(cc_matView[0][0], cc_matView[1][0], cc_matView[2][0]));\n vec3 camY = vec3(0, 1, 0);\n vec3 offset = camX * viewSpaceVert.x + camY * viewSpaceVert.y;\n pos.xyz += offset;\n#else\n pos.x += vertOffset.x;\n pos.y += vertOffset.y;\n#endif\n}\nvec2 computeUV (float frameIndex, vec2 vertIndex, vec2 frameTile){\n vec2 aniUV = vec2(0, floor(frameIndex * frameTile.y));\n aniUV.x = floor(frameIndex * frameTile.x * frameTile.y - aniUV.y * frameTile.x);\n#if CC_RENDER_MODE != 4\n vertIndex.y = 1. - vertIndex.y;\n#endif\n return (aniUV.xy + vertIndex) / vec2(frameTile.x, frameTile.y);\n}\nin vec3 a_position;\nin vec3 a_texCoord;\nin vec3 a_texCoord1;\nin vec3 a_texCoord2;\nin vec4 a_color;\n#if CC_RENDER_MODE == 1\n in vec3 a_color1;\n#endif\n#if CC_RENDER_MODE == 4\n in vec3 a_texCoord3;\n in vec3 a_normal;\n in vec4 a_color1;\n#endif\nvec4 lpvs_main () {\n vec3 compScale = scale.xyz * a_texCoord1;\n vec4 pos = vec4(a_position, 1);\n #if CC_RENDER_MODE == 1\n vec4 velocity = vec4(a_color1.xyz, 0);\n #endif\n #if !CC_USE_WORLD_SPACE\n pos = cc_matWorld * pos;\n #if CC_RENDER_MODE == 1\n velocity = cc_matWorld * velocity;\n #endif\n #endif\n #if CC_RENDER_MODE != 4\n vec2 cornerOffset = vec2((a_texCoord.xy - 0.5));\n #if CC_RENDER_MODE == 0\n vec3 rotEuler = a_texCoord2;\n #elif CC_RENDER_MODE == 1\n vec3 rotEuler = vec3(0.);\n #else\n vec3 rotEuler = vec3(0., 0., a_texCoord2.z);\n #endif\n computeVertPos(pos, cornerOffset, quaternionFromEuler(rotEuler), compScale\n #if CC_RENDER_MODE == 0 || CC_RENDER_MODE == 3\n , cc_matViewInv\n #endif\n #if CC_RENDER_MODE == 1\n , cc_cameraPos.xyz\n , velocity\n , frameTile_velLenScale.z\n , frameTile_velLenScale.w\n , a_texCoord.x\n #endif\n );\n color = a_color;\n #else\n mat4 xformNoScale = matrixFromRT(quaternionFromEuler(a_texCoord2), pos.xyz);\n mat4 xform = matFromRTS(quaternionFromEuler(a_texCoord2), pos.xyz, compScale);\n pos = xform * vec4(a_texCoord3, 1);\n vec4 normal = xformNoScale * vec4(a_normal, 0);\n color = a_color * a_color1;\n #endif\n uv = computeUV(a_texCoord.z, a_texCoord.xy, frameTile_velLenScale.xy) * mainTiling_Offset.xy + mainTiling_Offset.zw;\n pos = cc_matViewProj * pos;\n return pos;\n}\nvoid main() { gl_Position = lpvs_main(); }`, - "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nin vec2 uv;\nin vec4 color;\nuniform sampler2D mainTexture;\nuniform FragConstants {\n vec4 tintColor;\n};\nvec4 add () {\n vec4 col = 2.0 * color * tintColor * texture(mainTexture, uv);\n return CCFragOutput(col);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = add(); }` + "vert": `\nprecision highp float;\nvec4 quaternionFromAxis (vec3 xAxis,vec3 yAxis,vec3 zAxis){\n mat3 m = mat3(xAxis,yAxis,zAxis);\n float trace = m[0][0] + m[1][1] + m[2][2];\n vec4 quat;\n if (trace > 0.) {\n float s = 0.5 / sqrt(trace + 1.0);\n quat.w = 0.25 / s;\n quat.x = (m[2][1] - m[1][2]) * s;\n quat.y = (m[0][2] - m[2][0]) * s;\n quat.z = (m[1][0] - m[0][1]) * s;\n } else if ((m[0][0] > m[1][1]) && (m[0][0] > m[2][2])) {\n float s = 2.0 * sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]);\n quat.w = (m[2][1] - m[1][2]) / s;\n quat.x = 0.25 * s;\n quat.y = (m[0][1] + m[1][0]) / s;\n quat.z = (m[0][2] + m[2][0]) / s;\n } else if (m[1][1] > m[2][2]) {\n float s = 2.0 * sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]);\n quat.w = (m[0][2] - m[2][0]) / s;\n quat.x = (m[0][1] + m[1][0]) / s;\n quat.y = 0.25 * s;\n quat.z = (m[1][2] + m[2][1]) / s;\n } else {\n float s = 2.0 * sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]);\n quat.w = (m[1][0] - m[0][1]) / s;\n quat.x = (m[0][2] + m[2][0]) / s;\n quat.y = (m[1][2] + m[2][1]) / s;\n quat.z = 0.25 * s;\n }\n float len = quat.x * quat.x + quat.y * quat.y + quat.z * quat.z + quat.w * quat.w;\n if (len > 0.) {\n len = 1. / sqrt(len);\n quat.x = quat.x * len;\n quat.y = quat.y * len;\n quat.z = quat.z * len;\n quat.w = quat.w * len;\n }\n return quat;\n}\nvec4 quaternionFromEuler (vec3 angle){\n float x = angle.x / 2.;\n float y = angle.y / 2.;\n float z = angle.z / 2.;\n float sx = sin(x);\n float cx = cos(x);\n float sy = sin(y);\n float cy = cos(y);\n float sz = sin(z);\n float cz = cos(z);\n vec4 quat = vec4(0);\n quat.x = sx * cy * cz + cx * sy * sz;\n quat.y = cx * sy * cz + sx * cy * sz;\n quat.z = cx * cy * sz - sx * sy * cz;\n quat.w = cx * cy * cz - sx * sy * sz;\n return quat;\n}\nmat4 matrixFromRT (vec4 q, vec3 p){\n float x2 = q.x + q.x;\n float y2 = q.y + q.y;\n float z2 = q.z + q.z;\n float xx = q.x * x2;\n float xy = q.x * y2;\n float xz = q.x * z2;\n float yy = q.y * y2;\n float yz = q.y * z2;\n float zz = q.z * z2;\n float wx = q.w * x2;\n float wy = q.w * y2;\n float wz = q.w * z2;\n return mat4(\n 1. - (yy + zz), xy + wz, xz - wy, 0,\n xy - wz, 1. - (xx + zz), yz + wx, 0,\n xz + wy, yz - wx, 1. - (xx + yy), 0,\n p.x, p.y, p.z, 1\n );\n}\nmat4 matFromRTS (vec4 q, vec3 t, vec3 s){\n float x = q.x, y = q.y, z = q.z, w = q.w;\n float x2 = x + x;\n float y2 = y + y;\n float z2 = z + z;\n float xx = x * x2;\n float xy = x * y2;\n float xz = x * z2;\n float yy = y * y2;\n float yz = y * z2;\n float zz = z * z2;\n float wx = w * x2;\n float wy = w * y2;\n float wz = w * z2;\n float sx = s.x;\n float sy = s.y;\n float sz = s.z;\n return mat4((1. - (yy + zz)) * sx, (xy + wz) * sx, (xz - wy) * sx, 0,\n (xy - wz) * sy, (1. - (xx + zz)) * sy, (yz + wx) * sy, 0,\n (xz + wy) * sz, (yz - wx) * sz, (1. - (xx + yy)) * sz, 0,\n t.x, t.y, t.z, 1);\n}\nvec4 quatMultiply (vec4 a, vec4 b){\n vec4 quat;\n quat.x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;\n quat.y = a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z;\n quat.z = a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x;\n quat.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;\n return quat;\n}\nvoid rotateVecFromQuat (inout vec3 v, vec4 q){\n float ix = q.w * v.x + q.y * v.z - q.z * v.y;\n float iy = q.w * v.y + q.z * v.x - q.x * v.z;\n float iz = q.w * v.z + q.x * v.y - q.y * v.x;\n float iw = -q.x * v.x - q.y * v.y - q.z * v.z;\n v.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;\n v.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;\n v.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;\n}\nvec3 rotateInLocalSpace (vec3 pos, vec3 xAxis, vec3 yAxis, vec3 zAxis, vec4 q){\n vec4 viewQuat = quaternionFromAxis(xAxis, yAxis, zAxis);\n vec4 rotQuat = quatMultiply(viewQuat, q);\n rotateVecFromQuat(pos, rotQuat);\n return pos;\n}\nvoid rotateCorner (inout vec2 corner, float angle){\n float xOS = cos(angle) * corner.x - sin(angle) * corner.y;\n float yOS = sin(angle) * corner.x + cos(angle) * corner.y;\n corner.x = xOS;\n corner.y = yOS;\n}\nuniform Constants {\n vec4 mainTiling_Offset;\n vec4 frameTile_velLenScale;\n vec4 scale;\n};\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\nout vec2 uv;\nout vec4 color;\nvoid computeVertPos (inout vec4 pos, vec2 vertOffset, vec4 q, vec3 s\n#if CC_RENDER_MODE == 0 || CC_RENDER_MODE == 3\n , mat4 viewInv\n#endif\n#if CC_RENDER_MODE == 1\n , vec3 eye\n , vec4 velocity\n , float velocityScale\n , float lengthScale\n , float xIndex\n#endif\n) {\n#if CC_RENDER_MODE == 0\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = normalize(vec3(viewInv[0][0], viewInv[1][0], viewInv[2][0]));\n vec3 camY = normalize(vec3(viewInv[0][1], viewInv[1][1], viewInv[2][1]));\n vec3 camZ = normalize(vec3(viewInv[0][2], viewInv[1][2], viewInv[2][2]));\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, camZ, q);\n#elif CC_RENDER_MODE == 1\n vec3 camRight = normalize(cross(pos.xyz - eye, velocity.xyz)) * s.x;\n vec3 camUp = velocity.xyz * velocityScale + normalize(velocity.xyz) * lengthScale * s.y;\n pos.xyz += (camRight * abs(vertOffset.x) * sign(vertOffset.y)) - camUp * xIndex;\n#elif CC_RENDER_MODE == 2\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = vec3(1, 0, 0);\n vec3 camY = vec3(0, 0, -1);\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, cross(camX, camY), q);\n#elif CC_RENDER_MODE == 3\n vec2 viewSpaceVert = vec2(vertOffset.x * s.x, vertOffset.y * s.y);\n rotateCorner(viewSpaceVert, q.z);\n vec3 camX = normalize(vec3(cc_matView[0][0], cc_matView[1][0], cc_matView[2][0]));\n vec3 camY = vec3(0, 1, 0);\n vec3 offset = camX * viewSpaceVert.x + camY * viewSpaceVert.y;\n pos.xyz += offset;\n#else\n pos.x += vertOffset.x;\n pos.y += vertOffset.y;\n#endif\n}\nvec2 computeUV (float frameIndex, vec2 vertIndex, vec2 frameTile){\n vec2 aniUV = vec2(0, floor(frameIndex * frameTile.y));\n aniUV.x = floor(frameIndex * frameTile.x * frameTile.y - aniUV.y * frameTile.x);\n#if CC_RENDER_MODE != 4\n vertIndex.y = 1. - vertIndex.y;\n#endif\n return (aniUV.xy + vertIndex) / vec2(frameTile.x, frameTile.y);\n}\nin vec3 a_position;\nin vec3 a_texCoord;\nin vec3 a_texCoord1;\nin vec3 a_texCoord2;\nin vec4 a_color;\n#if CC_RENDER_MODE == 1\n in vec3 a_color1;\n#endif\n#if CC_RENDER_MODE == 4\n in vec3 a_texCoord3;\n in vec3 a_normal;\n in vec4 a_color1;\n#endif\nvec4 lpvs_main () {\n vec3 compScale = scale.xyz * a_texCoord1;\n vec4 pos = vec4(a_position, 1);\n #if CC_RENDER_MODE == 1\n vec4 velocity = vec4(a_color1.xyz, 0);\n #endif\n #if !CC_USE_WORLD_SPACE\n pos = cc_matWorld * pos;\n #if CC_RENDER_MODE == 1\n velocity = cc_matWorld * velocity;\n #endif\n #endif\n #if CC_RENDER_MODE != 4\n vec2 cornerOffset = vec2((a_texCoord.xy - 0.5));\n #if CC_RENDER_MODE == 0\n vec3 rotEuler = a_texCoord2;\n #elif CC_RENDER_MODE == 1\n vec3 rotEuler = vec3(0.);\n #else\n vec3 rotEuler = vec3(0., 0., a_texCoord2.z);\n #endif\n computeVertPos(pos, cornerOffset, quaternionFromEuler(rotEuler), compScale\n #if CC_RENDER_MODE == 0 || CC_RENDER_MODE == 3\n , cc_matViewInv\n #endif\n #if CC_RENDER_MODE == 1\n , cc_cameraPos.xyz\n , velocity\n , frameTile_velLenScale.z\n , frameTile_velLenScale.w\n , a_texCoord.x\n #endif\n );\n color = a_color;\n #else\n mat4 xformNoScale = matrixFromRT(quaternionFromEuler(a_texCoord2), pos.xyz);\n mat4 xform = matFromRTS(quaternionFromEuler(a_texCoord2), pos.xyz, compScale);\n pos = xform * vec4(a_texCoord3, 1);\n vec4 normal = xformNoScale * vec4(a_normal, 0);\n color = a_color * a_color1;\n #endif\n uv = computeUV(a_texCoord.z, a_texCoord.xy, frameTile_velLenScale.xy) * mainTiling_Offset.xy + mainTiling_Offset.zw;\n pos = cc_matViewProj * pos;\n return pos;\n}\nvoid main() { gl_Position = lpvs_main(); }`, + "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nin vec2 uv;\nin vec4 color;\nuniform sampler2D mainTexture;\nuniform FragConstants {\n vec4 tintColor;\n};\nvec4 add () {\n vec4 col = 2.0 * color * tintColor * texture(mainTexture, uv);\n return CCFragOutput(col);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = add(); }` }, "glsl1": { - "vert": `\nprecision highp float;\nvec4 quaternionFromAxis (vec3 xAxis,vec3 yAxis,vec3 zAxis){\n mat3 m = mat3(xAxis,yAxis,zAxis);\n float trace = m[0][0] + m[1][1] + m[2][2];\n vec4 quat;\n if (trace > 0.) {\n float s = 0.5 / sqrt(trace + 1.0);\n quat.w = 0.25 / s;\n quat.x = (m[2][1] - m[1][2]) * s;\n quat.y = (m[0][2] - m[2][0]) * s;\n quat.z = (m[1][0] - m[0][1]) * s;\n } else if ((m[0][0] > m[1][1]) && (m[0][0] > m[2][2])) {\n float s = 2.0 * sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]);\n quat.w = (m[2][1] - m[1][2]) / s;\n quat.x = 0.25 * s;\n quat.y = (m[0][1] + m[1][0]) / s;\n quat.z = (m[0][2] + m[2][0]) / s;\n } else if (m[1][1] > m[2][2]) {\n float s = 2.0 * sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]);\n quat.w = (m[0][2] - m[2][0]) / s;\n quat.x = (m[0][1] + m[1][0]) / s;\n quat.y = 0.25 * s;\n quat.z = (m[1][2] + m[2][1]) / s;\n } else {\n float s = 2.0 * sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]);\n quat.w = (m[1][0] - m[0][1]) / s;\n quat.x = (m[0][2] + m[2][0]) / s;\n quat.y = (m[1][2] + m[2][1]) / s;\n quat.z = 0.25 * s;\n }\n float len = quat.x * quat.x + quat.y * quat.y + quat.z * quat.z + quat.w * quat.w;\n if (len > 0.) {\n len = 1. / sqrt(len);\n quat.x = quat.x * len;\n quat.y = quat.y * len;\n quat.z = quat.z * len;\n quat.w = quat.w * len;\n }\n return quat;\n}\nvec4 quaternionFromEuler (vec3 angle){\n float x = angle.x / 2.;\n float y = angle.y / 2.;\n float z = angle.z / 2.;\n float sx = sin(x);\n float cx = cos(x);\n float sy = sin(y);\n float cy = cos(y);\n float sz = sin(z);\n float cz = cos(z);\n vec4 quat = vec4(0);\n quat.x = sx * cy * cz + cx * sy * sz;\n quat.y = cx * sy * cz + sx * cy * sz;\n quat.z = cx * cy * sz - sx * sy * cz;\n quat.w = cx * cy * cz - sx * sy * sz;\n return quat;\n}\nmat4 matrixFromRT (vec4 q, vec3 p){\n float x2 = q.x + q.x;\n float y2 = q.y + q.y;\n float z2 = q.z + q.z;\n float xx = q.x * x2;\n float xy = q.x * y2;\n float xz = q.x * z2;\n float yy = q.y * y2;\n float yz = q.y * z2;\n float zz = q.z * z2;\n float wx = q.w * x2;\n float wy = q.w * y2;\n float wz = q.w * z2;\n return mat4(\n 1. - (yy + zz), xy + wz, xz - wy, 0,\n xy - wz, 1. - (xx + zz), yz + wx, 0,\n xz + wy, yz - wx, 1. - (xx + yy), 0,\n p.x, p.y, p.z, 1\n );\n}\nmat4 matFromRTS (vec4 q, vec3 t, vec3 s){\n float x = q.x, y = q.y, z = q.z, w = q.w;\n float x2 = x + x;\n float y2 = y + y;\n float z2 = z + z;\n float xx = x * x2;\n float xy = x * y2;\n float xz = x * z2;\n float yy = y * y2;\n float yz = y * z2;\n float zz = z * z2;\n float wx = w * x2;\n float wy = w * y2;\n float wz = w * z2;\n float sx = s.x;\n float sy = s.y;\n float sz = s.z;\n return mat4((1. - (yy + zz)) * sx, (xy + wz) * sx, (xz - wy) * sx, 0,\n (xy - wz) * sy, (1. - (xx + zz)) * sy, (yz + wx) * sy, 0,\n (xz + wy) * sz, (yz - wx) * sz, (1. - (xx + yy)) * sz, 0,\n t.x, t.y, t.z, 1);\n}\nvec4 quatMultiply (vec4 a, vec4 b){\n vec4 quat;\n quat.x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;\n quat.y = a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z;\n quat.z = a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x;\n quat.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;\n return quat;\n}\nvoid rotateVecFromQuat (inout vec3 v, vec4 q){\n float ix = q.w * v.x + q.y * v.z - q.z * v.y;\n float iy = q.w * v.y + q.z * v.x - q.x * v.z;\n float iz = q.w * v.z + q.x * v.y - q.y * v.x;\n float iw = -q.x * v.x - q.y * v.y - q.z * v.z;\n v.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;\n v.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;\n v.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;\n}\nvec3 rotateInLocalSpace (vec3 pos, vec3 xAxis, vec3 yAxis, vec3 zAxis, vec4 q){\n vec4 viewQuat = quaternionFromAxis(xAxis, yAxis, zAxis);\n vec4 rotQuat = quatMultiply(viewQuat, q);\n rotateVecFromQuat(pos, rotQuat);\n return pos;\n}\nvoid rotateCorner (inout vec2 corner, float angle){\n float xOS = cos(angle) * corner.x - sin(angle) * corner.y;\n float yOS = sin(angle) * corner.x + cos(angle) * corner.y;\n corner.x = xOS;\n corner.y = yOS;\n}\nuniform vec4 mainTiling_Offset;\nuniform vec4 frameTile_velLenScale;\nuniform vec4 scale;\nuniform highp mat4 cc_matView;\nuniform mediump mat4 cc_matViewInv;\nuniform mediump mat4 cc_matViewProj;\nuniform mediump vec4 cc_cameraPos;\nuniform highp mat4 cc_matWorld;\nvarying vec2 uv;\nvarying vec4 color;\nvoid computeVertPos (inout vec4 pos, vec2 vertOffset, vec4 q, vec3 s\n#if CC_RENDER_MODE == 0 || CC_RENDER_MODE == 3\n , mat4 viewInv\n#endif\n#if CC_RENDER_MODE == 1\n , vec3 eye\n , vec4 velocity\n , float velocityScale\n , float lengthScale\n , float xIndex\n#endif\n) {\n#if CC_RENDER_MODE == 0\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = normalize(vec3(viewInv[0][0], viewInv[1][0], viewInv[2][0]));\n vec3 camY = normalize(vec3(viewInv[0][1], viewInv[1][1], viewInv[2][1]));\n vec3 camZ = normalize(vec3(viewInv[0][2], viewInv[1][2], viewInv[2][2]));\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, camZ, q);\n#elif CC_RENDER_MODE == 1\n vec3 camRight = normalize(cross(pos.xyz - eye, velocity.xyz)) * s.x;\n vec3 camUp = velocity.xyz * velocityScale + normalize(velocity.xyz) * lengthScale * s.y;\n pos.xyz += (camRight * abs(vertOffset.x) * sign(vertOffset.y)) - camUp * xIndex;\n#elif CC_RENDER_MODE == 2\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = vec3(1, 0, 0);\n vec3 camY = vec3(0, 0, -1);\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, cross(camX, camY), q);\n#elif CC_RENDER_MODE == 3\n vec2 viewSpaceVert = vec2(vertOffset.x * s.x, vertOffset.y * s.y);\n rotateCorner(viewSpaceVert, q.z);\n vec3 camX = normalize(vec3(cc_matView[0][0], cc_matView[1][0], cc_matView[2][0]));\n vec3 camY = vec3(0, 1, 0);\n vec3 offset = camX * viewSpaceVert.x + camY * viewSpaceVert.y;\n pos.xyz += offset;\n#else\n pos.x += vertOffset.x;\n pos.y += vertOffset.y;\n#endif\n}\nvec2 computeUV (float frameIndex, vec2 vertIndex, vec2 frameTile){\n vec2 aniUV = vec2(0, floor(frameIndex * frameTile.y));\n aniUV.x = floor(frameIndex * frameTile.x * frameTile.y - aniUV.y * frameTile.x);\n#if CC_RENDER_MODE != 4\n vertIndex.y = 1. - vertIndex.y;\n#endif\n return (aniUV.xy + vertIndex) / vec2(frameTile.x, frameTile.y);\n}\nattribute vec3 a_position;\nattribute vec3 a_texCoord;\nattribute vec3 a_texCoord1;\nattribute vec3 a_texCoord2;\nattribute vec4 a_color;\n#if CC_RENDER_MODE == 1\n attribute vec3 a_color1;\n#endif\n#if CC_RENDER_MODE == 4\n attribute vec3 a_texCoord3;\n attribute vec3 a_normal;\n attribute vec4 a_color1;\n#endif\nvec4 lpvs_main () {\n vec3 compScale = scale.xyz * a_texCoord1;\n vec4 pos = vec4(a_position, 1);\n #if CC_RENDER_MODE == 1\n vec4 velocity = vec4(a_color1.xyz, 0);\n #endif\n #if !CC_USE_WORLD_SPACE\n pos = cc_matWorld * pos;\n #if CC_RENDER_MODE == 1\n velocity = cc_matWorld * velocity;\n #endif\n #endif\n #if CC_RENDER_MODE != 4\n vec2 cornerOffset = vec2((a_texCoord.xy - 0.5));\n #if CC_RENDER_MODE == 0\n vec3 rotEuler = a_texCoord2;\n #elif CC_RENDER_MODE == 1\n vec3 rotEuler = vec3(0.);\n #else\n vec3 rotEuler = vec3(0., 0., a_texCoord2.z);\n #endif\n computeVertPos(pos, cornerOffset, quaternionFromEuler(rotEuler), compScale\n #if CC_RENDER_MODE == 0 || CC_RENDER_MODE == 3\n , cc_matViewInv\n #endif\n #if CC_RENDER_MODE == 1\n , cc_cameraPos.xyz\n , velocity\n , frameTile_velLenScale.z\n , frameTile_velLenScale.w\n , a_texCoord.x\n #endif\n );\n color = a_color;\n #else\n mat4 xformNoScale = matrixFromRT(quaternionFromEuler(a_texCoord2), pos.xyz);\n mat4 xform = matFromRTS(quaternionFromEuler(a_texCoord2), pos.xyz, compScale);\n pos = xform * vec4(a_texCoord3, 1);\n vec4 normal = xformNoScale * vec4(a_normal, 0);\n color = a_color * a_color1;\n #endif\n uv = computeUV(a_texCoord.z, a_texCoord.xy, frameTile_velLenScale.xy) * mainTiling_Offset.xy + mainTiling_Offset.zw;\n pos = cc_matViewProj * pos;\n return pos;\n}\nvoid main() { gl_Position = lpvs_main(); }`, + "vert": `\nprecision highp float;\nvec4 quaternionFromAxis (vec3 xAxis,vec3 yAxis,vec3 zAxis){\n mat3 m = mat3(xAxis,yAxis,zAxis);\n float trace = m[0][0] + m[1][1] + m[2][2];\n vec4 quat;\n if (trace > 0.) {\n float s = 0.5 / sqrt(trace + 1.0);\n quat.w = 0.25 / s;\n quat.x = (m[2][1] - m[1][2]) * s;\n quat.y = (m[0][2] - m[2][0]) * s;\n quat.z = (m[1][0] - m[0][1]) * s;\n } else if ((m[0][0] > m[1][1]) && (m[0][0] > m[2][2])) {\n float s = 2.0 * sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]);\n quat.w = (m[2][1] - m[1][2]) / s;\n quat.x = 0.25 * s;\n quat.y = (m[0][1] + m[1][0]) / s;\n quat.z = (m[0][2] + m[2][0]) / s;\n } else if (m[1][1] > m[2][2]) {\n float s = 2.0 * sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]);\n quat.w = (m[0][2] - m[2][0]) / s;\n quat.x = (m[0][1] + m[1][0]) / s;\n quat.y = 0.25 * s;\n quat.z = (m[1][2] + m[2][1]) / s;\n } else {\n float s = 2.0 * sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]);\n quat.w = (m[1][0] - m[0][1]) / s;\n quat.x = (m[0][2] + m[2][0]) / s;\n quat.y = (m[1][2] + m[2][1]) / s;\n quat.z = 0.25 * s;\n }\n float len = quat.x * quat.x + quat.y * quat.y + quat.z * quat.z + quat.w * quat.w;\n if (len > 0.) {\n len = 1. / sqrt(len);\n quat.x = quat.x * len;\n quat.y = quat.y * len;\n quat.z = quat.z * len;\n quat.w = quat.w * len;\n }\n return quat;\n}\nvec4 quaternionFromEuler (vec3 angle){\n float x = angle.x / 2.;\n float y = angle.y / 2.;\n float z = angle.z / 2.;\n float sx = sin(x);\n float cx = cos(x);\n float sy = sin(y);\n float cy = cos(y);\n float sz = sin(z);\n float cz = cos(z);\n vec4 quat = vec4(0);\n quat.x = sx * cy * cz + cx * sy * sz;\n quat.y = cx * sy * cz + sx * cy * sz;\n quat.z = cx * cy * sz - sx * sy * cz;\n quat.w = cx * cy * cz - sx * sy * sz;\n return quat;\n}\nmat4 matrixFromRT (vec4 q, vec3 p){\n float x2 = q.x + q.x;\n float y2 = q.y + q.y;\n float z2 = q.z + q.z;\n float xx = q.x * x2;\n float xy = q.x * y2;\n float xz = q.x * z2;\n float yy = q.y * y2;\n float yz = q.y * z2;\n float zz = q.z * z2;\n float wx = q.w * x2;\n float wy = q.w * y2;\n float wz = q.w * z2;\n return mat4(\n 1. - (yy + zz), xy + wz, xz - wy, 0,\n xy - wz, 1. - (xx + zz), yz + wx, 0,\n xz + wy, yz - wx, 1. - (xx + yy), 0,\n p.x, p.y, p.z, 1\n );\n}\nmat4 matFromRTS (vec4 q, vec3 t, vec3 s){\n float x = q.x, y = q.y, z = q.z, w = q.w;\n float x2 = x + x;\n float y2 = y + y;\n float z2 = z + z;\n float xx = x * x2;\n float xy = x * y2;\n float xz = x * z2;\n float yy = y * y2;\n float yz = y * z2;\n float zz = z * z2;\n float wx = w * x2;\n float wy = w * y2;\n float wz = w * z2;\n float sx = s.x;\n float sy = s.y;\n float sz = s.z;\n return mat4((1. - (yy + zz)) * sx, (xy + wz) * sx, (xz - wy) * sx, 0,\n (xy - wz) * sy, (1. - (xx + zz)) * sy, (yz + wx) * sy, 0,\n (xz + wy) * sz, (yz - wx) * sz, (1. - (xx + yy)) * sz, 0,\n t.x, t.y, t.z, 1);\n}\nvec4 quatMultiply (vec4 a, vec4 b){\n vec4 quat;\n quat.x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;\n quat.y = a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z;\n quat.z = a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x;\n quat.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;\n return quat;\n}\nvoid rotateVecFromQuat (inout vec3 v, vec4 q){\n float ix = q.w * v.x + q.y * v.z - q.z * v.y;\n float iy = q.w * v.y + q.z * v.x - q.x * v.z;\n float iz = q.w * v.z + q.x * v.y - q.y * v.x;\n float iw = -q.x * v.x - q.y * v.y - q.z * v.z;\n v.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;\n v.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;\n v.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;\n}\nvec3 rotateInLocalSpace (vec3 pos, vec3 xAxis, vec3 yAxis, vec3 zAxis, vec4 q){\n vec4 viewQuat = quaternionFromAxis(xAxis, yAxis, zAxis);\n vec4 rotQuat = quatMultiply(viewQuat, q);\n rotateVecFromQuat(pos, rotQuat);\n return pos;\n}\nvoid rotateCorner (inout vec2 corner, float angle){\n float xOS = cos(angle) * corner.x - sin(angle) * corner.y;\n float yOS = sin(angle) * corner.x + cos(angle) * corner.y;\n corner.x = xOS;\n corner.y = yOS;\n}\nuniform vec4 mainTiling_Offset;\nuniform vec4 frameTile_velLenScale;\nuniform vec4 scale;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matViewInv;\nuniform highp mat4 cc_matViewProj;\nuniform highp vec4 cc_cameraPos;\nuniform highp mat4 cc_matWorld;\nvarying vec2 uv;\nvarying vec4 color;\nvoid computeVertPos (inout vec4 pos, vec2 vertOffset, vec4 q, vec3 s\n#if CC_RENDER_MODE == 0 || CC_RENDER_MODE == 3\n , mat4 viewInv\n#endif\n#if CC_RENDER_MODE == 1\n , vec3 eye\n , vec4 velocity\n , float velocityScale\n , float lengthScale\n , float xIndex\n#endif\n) {\n#if CC_RENDER_MODE == 0\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = normalize(vec3(viewInv[0][0], viewInv[1][0], viewInv[2][0]));\n vec3 camY = normalize(vec3(viewInv[0][1], viewInv[1][1], viewInv[2][1]));\n vec3 camZ = normalize(vec3(viewInv[0][2], viewInv[1][2], viewInv[2][2]));\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, camZ, q);\n#elif CC_RENDER_MODE == 1\n vec3 camRight = normalize(cross(pos.xyz - eye, velocity.xyz)) * s.x;\n vec3 camUp = velocity.xyz * velocityScale + normalize(velocity.xyz) * lengthScale * s.y;\n pos.xyz += (camRight * abs(vertOffset.x) * sign(vertOffset.y)) - camUp * xIndex;\n#elif CC_RENDER_MODE == 2\n vec3 viewSpaceVert = vec3(vertOffset.x * s.x, vertOffset.y * s.y, 0.);\n vec3 camX = vec3(1, 0, 0);\n vec3 camY = vec3(0, 0, -1);\n pos.xyz += rotateInLocalSpace(viewSpaceVert, camX, camY, cross(camX, camY), q);\n#elif CC_RENDER_MODE == 3\n vec2 viewSpaceVert = vec2(vertOffset.x * s.x, vertOffset.y * s.y);\n rotateCorner(viewSpaceVert, q.z);\n vec3 camX = normalize(vec3(cc_matView[0][0], cc_matView[1][0], cc_matView[2][0]));\n vec3 camY = vec3(0, 1, 0);\n vec3 offset = camX * viewSpaceVert.x + camY * viewSpaceVert.y;\n pos.xyz += offset;\n#else\n pos.x += vertOffset.x;\n pos.y += vertOffset.y;\n#endif\n}\nvec2 computeUV (float frameIndex, vec2 vertIndex, vec2 frameTile){\n vec2 aniUV = vec2(0, floor(frameIndex * frameTile.y));\n aniUV.x = floor(frameIndex * frameTile.x * frameTile.y - aniUV.y * frameTile.x);\n#if CC_RENDER_MODE != 4\n vertIndex.y = 1. - vertIndex.y;\n#endif\n return (aniUV.xy + vertIndex) / vec2(frameTile.x, frameTile.y);\n}\nattribute vec3 a_position;\nattribute vec3 a_texCoord;\nattribute vec3 a_texCoord1;\nattribute vec3 a_texCoord2;\nattribute vec4 a_color;\n#if CC_RENDER_MODE == 1\n attribute vec3 a_color1;\n#endif\n#if CC_RENDER_MODE == 4\n attribute vec3 a_texCoord3;\n attribute vec3 a_normal;\n attribute vec4 a_color1;\n#endif\nvec4 lpvs_main () {\n vec3 compScale = scale.xyz * a_texCoord1;\n vec4 pos = vec4(a_position, 1);\n #if CC_RENDER_MODE == 1\n vec4 velocity = vec4(a_color1.xyz, 0);\n #endif\n #if !CC_USE_WORLD_SPACE\n pos = cc_matWorld * pos;\n #if CC_RENDER_MODE == 1\n velocity = cc_matWorld * velocity;\n #endif\n #endif\n #if CC_RENDER_MODE != 4\n vec2 cornerOffset = vec2((a_texCoord.xy - 0.5));\n #if CC_RENDER_MODE == 0\n vec3 rotEuler = a_texCoord2;\n #elif CC_RENDER_MODE == 1\n vec3 rotEuler = vec3(0.);\n #else\n vec3 rotEuler = vec3(0., 0., a_texCoord2.z);\n #endif\n computeVertPos(pos, cornerOffset, quaternionFromEuler(rotEuler), compScale\n #if CC_RENDER_MODE == 0 || CC_RENDER_MODE == 3\n , cc_matViewInv\n #endif\n #if CC_RENDER_MODE == 1\n , cc_cameraPos.xyz\n , velocity\n , frameTile_velLenScale.z\n , frameTile_velLenScale.w\n , a_texCoord.x\n #endif\n );\n color = a_color;\n #else\n mat4 xformNoScale = matrixFromRT(quaternionFromEuler(a_texCoord2), pos.xyz);\n mat4 xform = matFromRTS(quaternionFromEuler(a_texCoord2), pos.xyz, compScale);\n pos = xform * vec4(a_texCoord3, 1);\n vec4 normal = xformNoScale * vec4(a_normal, 0);\n color = a_color * a_color1;\n #endif\n uv = computeUV(a_texCoord.z, a_texCoord.xy, frameTile_velLenScale.xy) * mainTiling_Offset.xy + mainTiling_Offset.zw;\n pos = cc_matViewProj * pos;\n return pos;\n}\nvoid main() { gl_Position = lpvs_main(); }`, "frag": `\nprecision mediump float;\nuniform mediump vec4 cc_exposure;\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvarying vec2 uv;\nvarying vec4 color;\nuniform sampler2D mainTexture;\nuniform vec4 tintColor;\nvec4 add () {\n vec4 col = 2.0 * color * tintColor * texture2D(mainTexture, uv);\n return CCFragOutput(col);\n}\nvoid main() { gl_FragColor = add(); }` }, "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[]}, "locals":{"blocks":[{"name":"CCLocal", "defines":[]}], "samplers":[]}}, @@ -132,13 +132,13 @@ export default [ "shaders": [ { "name": "builtin-sprite|sprite-vs:vert|sprite-fs:frag", - "hash": 203142693, + "hash": 543960898, "glsl3": { - "vert": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if USE_LOCAL\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nin vec3 a_position;\nin vec4 a_color;\nout vec4 color;\nin vec2 a_texCoord;\nout vec2 uv0;\nvec4 vert () {\n vec4 pos = vec4(a_position, 1);\n #if USE_LOCAL\n pos = cc_matViewProj * cc_matWorld * pos;\n #else\n pos = cc_matViewProj * pos;\n #endif\n uv0 = a_texCoord;\n color = a_color;\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if USE_LOCAL\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nin vec3 a_position;\nin vec4 a_color;\nout vec4 color;\nin vec2 a_texCoord;\nout vec2 uv0;\nvec4 vert () {\n vec4 pos = vec4(a_position, 1);\n #if USE_LOCAL\n pos = cc_matViewProj * cc_matWorld * pos;\n #else\n pos = cc_matViewProj * pos;\n #endif\n uv0 = a_texCoord;\n color = a_color;\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision mediump float;\nin vec4 color;\n#if USE_TEXTURE\n in vec2 uv0;\n uniform sampler2D mainTexture;\n#endif\nvec4 frag () {\n vec4 o = vec4(1, 1, 1, 1);\n #if USE_TEXTURE\n o *= texture(mainTexture, uv0);\n #if IS_GRAY\n float gray = 0.2126 * o.r + 0.7152 * o.g + 0.0722 * o.b;\n o.r = o.g = o.b = gray;\n #endif\n #endif\n o *= color;\n return o;\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { - "vert": `\nprecision mediump float;\nuniform mediump mat4 cc_matViewProj;\n#if USE_LOCAL\nuniform highp mat4 cc_matWorld;\n#endif\nattribute vec3 a_position;\nattribute vec4 a_color;\nvarying vec4 color;\nattribute vec2 a_texCoord;\nvarying vec2 uv0;\nvec4 vert () {\n vec4 pos = vec4(a_position, 1);\n #if USE_LOCAL\n pos = cc_matViewProj * cc_matWorld * pos;\n #else\n pos = cc_matViewProj * pos;\n #endif\n uv0 = a_texCoord;\n color = a_color;\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision mediump float;\nuniform highp mat4 cc_matViewProj;\n#if USE_LOCAL\nuniform highp mat4 cc_matWorld;\n#endif\nattribute vec3 a_position;\nattribute vec4 a_color;\nvarying vec4 color;\nattribute vec2 a_texCoord;\nvarying vec2 uv0;\nvec4 vert () {\n vec4 pos = vec4(a_position, 1);\n #if USE_LOCAL\n pos = cc_matViewProj * cc_matWorld * pos;\n #else\n pos = cc_matViewProj * pos;\n #endif\n uv0 = a_texCoord;\n color = a_color;\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision mediump float;\nvarying vec4 color;\n#if USE_TEXTURE\n varying vec2 uv0;\n uniform sampler2D mainTexture;\n#endif\nvec4 frag () {\n vec4 o = vec4(1, 1, 1, 1);\n #if USE_TEXTURE\n o *= texture2D(mainTexture, uv0);\n #if IS_GRAY\n float gray = 0.2126 * o.r + 0.7152 * o.g + 0.0722 * o.b;\n o.r = o.g = o.b = gray;\n #endif\n #endif\n o *= color;\n return o;\n}\nvoid main() { gl_FragColor = frag(); }` }, "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[]}, "locals":{"blocks":[{"name":"CCLocal", "defines":["USE_LOCAL"]}], "samplers":[]}}, @@ -163,18 +163,19 @@ export default [ "shaders": [ { "name": "builtin-standard|standard-vs:vert|standard-fs:frag", - "hash": 1870394218, + "hash": 4276757126, "glsl3": { - "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if CC_USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec4 a_tangent;\n#if CC_USE_SKINNING\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if CC_USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if CC_USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif CC_USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nuniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\n#if USE_VERTEX_COLOR\n in vec3 a_color;\n out vec3 v_color;\n#endif\nout vec3 v_position;\nout vec3 v_normal;\n#if USE_NORMAL_MAP\n out vec3 v_tangent;\n out vec3 v_bitangent;\n#endif\nin vec2 a_texCoord;\nout vec2 v_uv;\nin vec2 a_texCoord1;\nout vec2 v_uv1;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if CC_USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorldIT * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if CC_USE_IBL\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D texture, vec2 coord, float lod) {\n return textureLod(texture, coord, lod);\n}\nvec4 fragTextureLod (samplerCube texture, vec3 coord, float lod) {\n return textureLod(texture, coord, lod);\n}\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nuniform CCForwardLight {\n highp vec4 cc_sphereLitPos[2];\n vec4 cc_sphereLitSizeRange[2];\n vec4 cc_sphereLitColor[2];\n highp vec4 cc_spotLitPos[2];\n vec4 cc_spotLitSizeRangeAngle[2];\n vec4 cc_spotLitDir[2];\n vec4 cc_spotLitColor[2];\n};\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nvec3 CalcDynamicLighting (vec3 worldPos, vec3 N, vec3 V, vec3 diffuse, vec3 specular, float roughness) {\n vec3 lighting = vec3(0.0);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n for (int i = 0; i < 2; i++) {\n vec3 PLU = cc_sphereLitPos[i].xyz - worldPos;\n vec3 PL = normalize(PLU);\n vec3 PH = normalize(PL + V);\n float PNL = max(dot(N, PL), 0.001);\n float PNH = max(dot(N, PH), 0.0);\n float distSqr = dot(PLU, PLU);\n float litRadius = cc_sphereLitSizeRange[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_sphereLitSizeRange[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(roughness, PNH, PH, N);\n lighting += PNL * cc_sphereLitColor[i].rgb * cc_sphereLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n for (int i = 0; i < 2; i++) {\n vec3 SLU = cc_spotLitPos[i].xyz - worldPos;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_spotLitSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_spotLitSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float cosInner = max(dot(-cc_spotLitDir[i].xyz, SL), 0.01);\n float cosOuter = cc_spotLitSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n att *= GetAngleAtt(SL, -cc_spotLitDir[i].xyz, litAngleScale, litAngleOffset);\n vec3 lspec = specular * CalcSpecular(roughness, SNH, SH, N);\n lighting += SNL * cc_spotLitColor[i].rgb * cc_spotLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n return lighting;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\nvec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NV = max(abs(dot(N, V)), 0.001);\n float NL = max(dot(N, L), 0.001);\n float NH = max(dot(N, H), 0.0);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w * (diffuseContrib + specularContrib);\n finalColor += CalcDynamicLighting(s.position, N, V, diffuse, specular, s.roughness);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb) * cc_ambientSky.w;\n #endif\n finalColor += env * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n return vec4(finalColor, s.albedo.a);\n}\nvec3 ACESToneMap (vec3 color) {\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nuniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\nin vec3 v_position;\nin vec2 v_uv;\nin vec2 v_uv1;\nin vec3 v_normal;\n#if USE_VERTEX_COLOR\n in vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n in vec3 v_tangent;\n in vec3 v_bitangent;\n uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture(pbrMap, PBR_UV);\n pbr.x *= res.OCCLUSION_CHANNEL;\n pbr.y *= res.ROUGHNESS_CHANNEL;\n pbr.z *= res.METALLIC_CHANNEL;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture(metallicRoughnessMap, METALLIC_ROUGHNESS_UV);\n pbr.z *= metallicRoughness.METALLIC_CHANNEL;\n pbr.y *= metallicRoughness.ROUGHNESS_CHANNEL;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture(occlusionMap, OCCLUSION_UV).OCCLUSION_CHANNEL;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n return CCFragOutput(color);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` + "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec4 a_tangent;\n#if USE_SKINNING\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nuniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\n#if USE_VERTEX_COLOR\n in vec3 a_color;\n out vec3 v_color;\n#endif\nout vec3 v_position;\nout vec3 v_normal;\n#if USE_NORMAL_MAP\n out vec3 v_tangent;\n out vec3 v_bitangent;\n#endif\nin vec2 a_texCoord;\nout vec2 v_uv;\nin vec2 a_texCoord1;\nout vec2 v_uv1;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorldIT * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, + "frag": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if CC_USE_IBL\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D texture, vec2 coord, float lod) {\n return textureLod(texture, coord, lod);\n}\nvec4 fragTextureLod (samplerCube texture, vec3 coord, float lod) {\n return textureLod(texture, coord, lod);\n}\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nuniform CCForwardLight {\n highp vec4 cc_sphereLitPos[2];\n vec4 cc_sphereLitSizeRange[2];\n vec4 cc_sphereLitColor[2];\n highp vec4 cc_spotLitPos[2];\n vec4 cc_spotLitSizeRangeAngle[2];\n vec4 cc_spotLitDir[2];\n vec4 cc_spotLitColor[2];\n};\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nvec3 CalcDynamicLighting (vec3 worldPos, vec3 N, vec3 V, vec3 diffuse, vec3 specular, float roughness) {\n vec3 lighting = vec3(0.0);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n for (int i = 0; i < 2; i++) {\n vec3 PLU = cc_sphereLitPos[i].xyz - worldPos;\n vec3 PL = normalize(PLU);\n vec3 PH = normalize(PL + V);\n float PNL = max(dot(N, PL), 0.001);\n float PNH = max(dot(N, PH), 0.0);\n float distSqr = dot(PLU, PLU);\n float litRadius = cc_sphereLitSizeRange[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_sphereLitSizeRange[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(roughness, PNH, PH, N);\n lighting += PNL * cc_sphereLitColor[i].rgb * cc_sphereLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n for (int i = 0; i < 2; i++) {\n vec3 SLU = cc_spotLitPos[i].xyz - worldPos;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_spotLitSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_spotLitSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float cosInner = max(dot(-cc_spotLitDir[i].xyz, SL), 0.01);\n float cosOuter = cc_spotLitSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n att *= GetAngleAtt(SL, -cc_spotLitDir[i].xyz, litAngleScale, litAngleOffset);\n vec3 lspec = specular * CalcSpecular(roughness, SNH, SH, N);\n lighting += SNL * cc_spotLitColor[i].rgb * cc_spotLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n return lighting;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\nvec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NV = max(abs(dot(N, V)), 0.001);\n float NL = max(dot(N, L), 0.001);\n float NH = max(dot(N, H), 0.0);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w * (diffuseContrib + specularContrib);\n finalColor += CalcDynamicLighting(s.position, N, V, diffuse, specular, s.roughness);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb) * cc_ambientSky.w;\n #endif\n finalColor += env * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n return vec4(finalColor, s.albedo.a);\n}\nvec3 ACESToneMap (vec3 color) {\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nuniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\nin vec3 v_position;\nin vec2 v_uv;\nin vec2 v_uv1;\nin vec3 v_normal;\n#if USE_VERTEX_COLOR\n in vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n in vec3 v_tangent;\n in vec3 v_bitangent;\n uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture(pbrMap, PBR_UV);\n pbr.x *= res.OCCLUSION_CHANNEL;\n pbr.y *= res.ROUGHNESS_CHANNEL;\n pbr.z *= res.METALLIC_CHANNEL;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture(metallicRoughnessMap, METALLIC_ROUGHNESS_UV);\n pbr.z *= metallicRoughness.METALLIC_CHANNEL;\n pbr.y *= metallicRoughness.ROUGHNESS_CHANNEL;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture(occlusionMap, OCCLUSION_UV).OCCLUSION_CHANNEL;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n return CCFragOutput(color);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { - "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform mediump mat4 cc_matProj;\n#if CC_USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\nuniform highp mat4 cc_matWorldIT;\n#endif\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec3 a_position;\nattribute vec3 a_normal;\nattribute vec4 a_tangent;\n#if CC_USE_SKINNING\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if CC_USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if CC_USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif CC_USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nuniform vec4 tilingOffset;\n#if USE_VERTEX_COLOR\n attribute vec3 a_color;\n varying vec3 v_color;\n#endif\nvarying vec3 v_position;\nvarying vec3 v_normal;\n#if USE_NORMAL_MAP\n varying vec3 v_tangent;\n varying vec3 v_bitangent;\n#endif\nattribute vec2 a_texCoord;\nvarying vec2 v_uv;\nattribute vec2 a_texCoord1;\nvarying vec2 v_uv1;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if CC_USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorldIT * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\n #ifdef GL_EXT_shader_texture_lod\n #extension GL_EXT_shader_texture_lod : enable\n #endif\nprecision highp float;\nuniform mediump vec4 cc_cameraPos;\nuniform mediump vec4 cc_exposure;\nuniform mediump vec4 cc_mainLitDir;\nuniform mediump vec4 cc_mainLitColor;\nuniform mediump vec4 cc_ambientSky;\nuniform mediump vec4 cc_ambientGround;\n#if CC_USE_IBL\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D texture, vec2 coord, float lod) {\n #ifdef GL_EXT_shader_texture_lod\n return texture2DLodEXT(texture, coord, lod);\n #else\n return texture2D(texture, coord, lod);\n #endif\n}\nvec4 fragTextureLod (samplerCube texture, vec3 coord, float lod) {\n #ifdef GL_EXT_shader_texture_lod\n return textureCubeLodEXT(texture, coord, lod);\n #else\n return textureCube(texture, coord, lod);\n #endif\n}\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nuniform highp vec4 cc_sphereLitPos[2];\nuniform vec4 cc_sphereLitSizeRange[2];\nuniform vec4 cc_sphereLitColor[2];\nuniform highp vec4 cc_spotLitPos[2];\nuniform vec4 cc_spotLitSizeRangeAngle[2];\nuniform vec4 cc_spotLitDir[2];\nuniform vec4 cc_spotLitColor[2];\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nvec3 CalcDynamicLighting (vec3 worldPos, vec3 N, vec3 V, vec3 diffuse, vec3 specular, float roughness) {\n vec3 lighting = vec3(0.0);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n for (int i = 0; i < 2; i++) {\n vec3 PLU = cc_sphereLitPos[i].xyz - worldPos;\n vec3 PL = normalize(PLU);\n vec3 PH = normalize(PL + V);\n float PNL = max(dot(N, PL), 0.001);\n float PNH = max(dot(N, PH), 0.0);\n float distSqr = dot(PLU, PLU);\n float litRadius = cc_sphereLitSizeRange[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_sphereLitSizeRange[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(roughness, PNH, PH, N);\n lighting += PNL * cc_sphereLitColor[i].rgb * cc_sphereLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n for (int i = 0; i < 2; i++) {\n vec3 SLU = cc_spotLitPos[i].xyz - worldPos;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_spotLitSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_spotLitSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float cosInner = max(dot(-cc_spotLitDir[i].xyz, SL), 0.01);\n float cosOuter = cc_spotLitSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n att *= GetAngleAtt(SL, -cc_spotLitDir[i].xyz, litAngleScale, litAngleOffset);\n vec3 lspec = specular * CalcSpecular(roughness, SNH, SH, N);\n lighting += SNL * cc_spotLitColor[i].rgb * cc_spotLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n return lighting;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\nvec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NV = max(abs(dot(N, V)), 0.001);\n float NL = max(dot(N, L), 0.001);\n float NH = max(dot(N, H), 0.0);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w * (diffuseContrib + specularContrib);\n finalColor += CalcDynamicLighting(s.position, N, V, diffuse, specular, s.roughness);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb) * cc_ambientSky.w;\n #endif\n finalColor += env * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n return vec4(finalColor, s.albedo.a);\n}\nvec3 ACESToneMap (vec3 color) {\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nuniform vec4 albedo;\nuniform vec4 albedoScaleAndCutoff;\nuniform vec4 pbrParams;\nuniform vec4 emissive;\nuniform vec4 emissiveScaleParam;\nvarying vec3 v_position;\nvarying vec2 v_uv;\nvarying vec2 v_uv1;\nvarying vec3 v_normal;\n#if USE_VERTEX_COLOR\n varying vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n varying vec3 v_tangent;\n varying vec3 v_bitangent;\n uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture2D(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture2D(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture2D(pbrMap, PBR_UV);\n pbr.x *= res.OCCLUSION_CHANNEL;\n pbr.y *= res.ROUGHNESS_CHANNEL;\n pbr.z *= res.METALLIC_CHANNEL;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessMap, METALLIC_ROUGHNESS_UV);\n pbr.z *= metallicRoughness.METALLIC_CHANNEL;\n pbr.y *= metallicRoughness.ROUGHNESS_CHANNEL;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture2D(occlusionMap, OCCLUSION_UV).OCCLUSION_CHANNEL;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture2D(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n return CCFragOutput(color);\n}\nvoid main() { gl_FragColor = frag(); }` + "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\n#if USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\nuniform highp mat4 cc_matWorldIT;\n#endif\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec3 a_position;\nattribute vec3 a_normal;\nattribute vec4 a_tangent;\n#if USE_SKINNING\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nuniform vec4 tilingOffset;\n#if USE_VERTEX_COLOR\n attribute vec3 a_color;\n varying vec3 v_color;\n#endif\nvarying vec3 v_position;\nvarying vec3 v_normal;\n#if USE_NORMAL_MAP\n varying vec3 v_tangent;\n varying vec3 v_bitangent;\n#endif\nattribute vec2 a_texCoord;\nvarying vec2 v_uv;\nattribute vec2 a_texCoord1;\nvarying vec2 v_uv1;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorldIT * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, + "frag": `\n #ifdef GL_EXT_shader_texture_lod\n #extension GL_EXT_shader_texture_lod : enable\n #endif\nprecision highp float;\nuniform highp vec4 cc_cameraPos;\nuniform mediump vec4 cc_exposure;\nuniform mediump vec4 cc_mainLitDir;\nuniform mediump vec4 cc_mainLitColor;\nuniform mediump vec4 cc_ambientSky;\nuniform mediump vec4 cc_ambientGround;\n#if CC_USE_IBL\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D texture, vec2 coord, float lod) {\n #ifdef GL_EXT_shader_texture_lod\n return texture2DLodEXT(texture, coord, lod);\n #else\n return texture2D(texture, coord, lod);\n #endif\n}\nvec4 fragTextureLod (samplerCube texture, vec3 coord, float lod) {\n #ifdef GL_EXT_shader_texture_lod\n return textureCubeLodEXT(texture, coord, lod);\n #else\n return textureCube(texture, coord, lod);\n #endif\n}\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nuniform highp vec4 cc_sphereLitPos[2];\nuniform vec4 cc_sphereLitSizeRange[2];\nuniform vec4 cc_sphereLitColor[2];\nuniform highp vec4 cc_spotLitPos[2];\nuniform vec4 cc_spotLitSizeRangeAngle[2];\nuniform vec4 cc_spotLitDir[2];\nuniform vec4 cc_spotLitColor[2];\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nvec3 CalcDynamicLighting (vec3 worldPos, vec3 N, vec3 V, vec3 diffuse, vec3 specular, float roughness) {\n vec3 lighting = vec3(0.0);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n for (int i = 0; i < 2; i++) {\n vec3 PLU = cc_sphereLitPos[i].xyz - worldPos;\n vec3 PL = normalize(PLU);\n vec3 PH = normalize(PL + V);\n float PNL = max(dot(N, PL), 0.001);\n float PNH = max(dot(N, PH), 0.0);\n float distSqr = dot(PLU, PLU);\n float litRadius = cc_sphereLitSizeRange[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_sphereLitSizeRange[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(roughness, PNH, PH, N);\n lighting += PNL * cc_sphereLitColor[i].rgb * cc_sphereLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n for (int i = 0; i < 2; i++) {\n vec3 SLU = cc_spotLitPos[i].xyz - worldPos;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_spotLitSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_spotLitSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float cosInner = max(dot(-cc_spotLitDir[i].xyz, SL), 0.01);\n float cosOuter = cc_spotLitSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n att *= GetAngleAtt(SL, -cc_spotLitDir[i].xyz, litAngleScale, litAngleOffset);\n vec3 lspec = specular * CalcSpecular(roughness, SNH, SH, N);\n lighting += SNL * cc_spotLitColor[i].rgb * cc_spotLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n return lighting;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\nvec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NV = max(abs(dot(N, V)), 0.001);\n float NL = max(dot(N, L), 0.001);\n float NH = max(dot(N, H), 0.0);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w * (diffuseContrib + specularContrib);\n finalColor += CalcDynamicLighting(s.position, N, V, diffuse, specular, s.roughness);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb) * cc_ambientSky.w;\n #endif\n finalColor += env * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n return vec4(finalColor, s.albedo.a);\n}\nvec3 ACESToneMap (vec3 color) {\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nuniform vec4 albedo;\nuniform vec4 albedoScaleAndCutoff;\nuniform vec4 pbrParams;\nuniform vec4 emissive;\nuniform vec4 emissiveScaleParam;\nvarying vec3 v_position;\nvarying vec2 v_uv;\nvarying vec2 v_uv1;\nvarying vec3 v_normal;\n#if USE_VERTEX_COLOR\n varying vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n varying vec3 v_tangent;\n varying vec3 v_bitangent;\n uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture2D(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture2D(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture2D(pbrMap, PBR_UV);\n pbr.x *= res.OCCLUSION_CHANNEL;\n pbr.y *= res.ROUGHNESS_CHANNEL;\n pbr.z *= res.METALLIC_CHANNEL;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessMap, METALLIC_ROUGHNESS_UV);\n pbr.z *= metallicRoughness.METALLIC_CHANNEL;\n pbr.y *= metallicRoughness.ROUGHNESS_CHANNEL;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture2D(occlusionMap, OCCLUSION_UV).OCCLUSION_CHANNEL;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture2D(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n return CCFragOutput(color);\n}\nvoid main() { gl_FragColor = frag(); }` }, - "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[{"name":"cc_environment", "defines":["CC_USE_IBL"]}]}, "locals":{"blocks":[{"name":"CCLocalBatched", "defines":["CC_USE_BATCHING"]}, {"name":"CCLocal", "defines":[]}, {"name":"CCSkinningTexture", "defines":["CC_USE_SKINNING"]}, {"name":"CCSkinningAnimation", "defines":["CC_USE_SKINNING"]}, {"name":"CCForwardLight", "defines":[]}], "samplers":[{"name":"cc_jointsTexture", "defines":["CC_USE_SKINNING"]}]}}, + "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[{"name":"cc_environment", "defines":["CC_USE_IBL"]}]}, "locals":{"blocks":[{"name":"CCLocalBatched", "defines":["USE_BATCHING"]}, {"name":"CCLocal", "defines":[]}, {"name":"CCSkinningTexture", "defines":["USE_SKINNING"]}, {"name":"CCSkinningAnimation", "defines":["USE_SKINNING"]}, {"name":"CCForwardLight", "defines":[]}], "samplers":[{"name":"cc_jointsTexture", "defines":["USE_SKINNING"]}]}}, "defines": [ - {"name":"CC_USE_BATCHING", "type":"boolean"}, + {"name":"USE_BATCHING", "type":"boolean"}, + {"name":"USE_SKINNING", "type":"number", "range":[0, 3]}, {"name":"CC_USE_SKINNING", "type":"number", "range":[0, 2]}, {"name":"USE_VERTEX_COLOR", "type":"boolean"}, {"name":"USE_NORMAL_MAP", "type":"boolean"}, @@ -227,13 +228,13 @@ export default [ "shaders": [ { "name": "builtin-terrain|terrain-vs:vert|terrain-fs:frag", - "hash": 2180546135, + "hash": 1414533658, "glsl3": { - "vert": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec2 a_texCoord;\nout vec2 uvw;\nout vec2 uv0;\nout vec2 uv1;\nout vec2 uv2;\nout vec2 uv3;\nout vec3 diffuse;\nuniform TexCoords {\n vec4 UVScale;\n};\nvec4 vert () {\n vec4 pos = vec4(a_position, 1);\n pos = cc_matWorld * pos;\n pos = cc_matViewProj * pos;\n uvw = a_texCoord;\n uv0 = a_position.xz * UVScale.x;\n uv1 = a_position.xz * UVScale.y;\n uv2 = a_position.xz * UVScale.z;\n uv3 = a_position.xz * UVScale.w;\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 N = a_normal;\n float fAmb = dot(N, vec3(0.0, -1.0, 0.0)) * 0.5 + 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n diffuse = ambDiff + vec3(dot(N, L));\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\n in vec2 uvw;\n in vec2 uv0;\n in vec2 uv1;\n in vec2 uv2;\n in vec2 uv3;\n in vec3 diffuse;\n uniform sampler2D weightMap;\n uniform sampler2D detailMap0;\n uniform sampler2D detailMap1;\n uniform sampler2D detailMap2;\n uniform sampler2D detailMap3;\nvec4 frag () {\n vec4 color = vec4(0, 0, 0, 0);\n #if LAYERS == 1\n color = texture(detailMap0, uv0);\n #elif LAYERS == 2\n vec4 w = texture(weightMap, uvw);\n color += texture(detailMap0, uv0) * w.r;\n color += texture(detailMap1, uv1) * w.g;\n #elif LAYERS == 3\n vec4 w = texture(weightMap, uvw);\n color += texture(detailMap0, uv0) * w.r;\n color += texture(detailMap1, uv1) * w.g;\n color += texture(detailMap2, uv2) * w.b;\n #elif LAYERS == 4\n vec4 w = texture(weightMap, uvw);\n color += texture(detailMap0, uv0) * w.r;\n color += texture(detailMap1, uv1) * w.g;\n color += texture(detailMap2, uv2) * w.b;\n color += texture(detailMap3, uv3) * w.a;\n #else\n color = texture(detailMap0, uv0);\n #endif\n color.rgb *= diffuse;\n return CCFragOutput(color);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` + "vert": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec2 a_texCoord;\nout vec2 uvw;\nout vec2 uv0;\nout vec2 uv1;\nout vec2 uv2;\nout vec2 uv3;\nout vec3 diffuse;\nuniform TexCoords {\n vec4 UVScale;\n};\nvec4 vert () {\n vec4 pos = vec4(a_position, 1);\n pos = cc_matWorld * pos;\n pos = cc_matViewProj * pos;\n uvw = a_texCoord;\n uv0 = a_position.xz * UVScale.x;\n uv1 = a_position.xz * UVScale.y;\n uv2 = a_position.xz * UVScale.z;\n uv3 = a_position.xz * UVScale.w;\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 N = a_normal;\n float fAmb = dot(N, vec3(0.0, -1.0, 0.0)) * 0.5 + 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n diffuse = ambDiff + vec3(dot(N, L));\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, + "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\n in vec2 uvw;\n in vec2 uv0;\n in vec2 uv1;\n in vec2 uv2;\n in vec2 uv3;\n in vec3 diffuse;\n uniform sampler2D weightMap;\n uniform sampler2D detailMap0;\n uniform sampler2D detailMap1;\n uniform sampler2D detailMap2;\n uniform sampler2D detailMap3;\nvec4 frag () {\n vec4 color = vec4(0, 0, 0, 0);\n #if LAYERS == 1\n color = texture(detailMap0, uv0);\n #elif LAYERS == 2\n vec4 w = texture(weightMap, uvw);\n color += texture(detailMap0, uv0) * w.r;\n color += texture(detailMap1, uv1) * w.g;\n #elif LAYERS == 3\n vec4 w = texture(weightMap, uvw);\n color += texture(detailMap0, uv0) * w.r;\n color += texture(detailMap1, uv1) * w.g;\n color += texture(detailMap2, uv2) * w.b;\n #elif LAYERS == 4\n vec4 w = texture(weightMap, uvw);\n color += texture(detailMap0, uv0) * w.r;\n color += texture(detailMap1, uv1) * w.g;\n color += texture(detailMap2, uv2) * w.b;\n color += texture(detailMap3, uv3) * w.a;\n #else\n color = texture(detailMap0, uv0);\n #endif\n color.rgb *= diffuse;\n return CCFragOutput(color);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { - "vert": `\nprecision mediump float;\nuniform mediump mat4 cc_matViewProj;\nuniform mediump vec4 cc_mainLitDir;\nuniform mediump vec4 cc_ambientSky;\nuniform mediump vec4 cc_ambientGround;\nuniform highp mat4 cc_matWorld;\nattribute vec3 a_position;\nattribute vec3 a_normal;\nattribute vec2 a_texCoord;\nvarying vec2 uvw;\nvarying vec2 uv0;\nvarying vec2 uv1;\nvarying vec2 uv2;\nvarying vec2 uv3;\nvarying vec3 diffuse;\nuniform vec4 UVScale;\nvec4 vert () {\n vec4 pos = vec4(a_position, 1);\n pos = cc_matWorld * pos;\n pos = cc_matViewProj * pos;\n uvw = a_texCoord;\n uv0 = a_position.xz * UVScale.x;\n uv1 = a_position.xz * UVScale.y;\n uv2 = a_position.xz * UVScale.z;\n uv3 = a_position.xz * UVScale.w;\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 N = a_normal;\n float fAmb = dot(N, vec3(0.0, -1.0, 0.0)) * 0.5 + 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n diffuse = ambDiff + vec3(dot(N, L));\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision mediump float;\nuniform highp mat4 cc_matViewProj;\nuniform mediump vec4 cc_mainLitDir;\nuniform mediump vec4 cc_ambientSky;\nuniform mediump vec4 cc_ambientGround;\nuniform highp mat4 cc_matWorld;\nattribute vec3 a_position;\nattribute vec3 a_normal;\nattribute vec2 a_texCoord;\nvarying vec2 uvw;\nvarying vec2 uv0;\nvarying vec2 uv1;\nvarying vec2 uv2;\nvarying vec2 uv3;\nvarying vec3 diffuse;\nuniform vec4 UVScale;\nvec4 vert () {\n vec4 pos = vec4(a_position, 1);\n pos = cc_matWorld * pos;\n pos = cc_matViewProj * pos;\n uvw = a_texCoord;\n uv0 = a_position.xz * UVScale.x;\n uv1 = a_position.xz * UVScale.y;\n uv2 = a_position.xz * UVScale.z;\n uv3 = a_position.xz * UVScale.w;\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 N = a_normal;\n float fAmb = dot(N, vec3(0.0, -1.0, 0.0)) * 0.5 + 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n diffuse = ambDiff + vec3(dot(N, L));\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision mediump float;\nuniform mediump vec4 cc_exposure;\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\n varying vec2 uvw;\n varying vec2 uv0;\n varying vec2 uv1;\n varying vec2 uv2;\n varying vec2 uv3;\n varying vec3 diffuse;\n uniform sampler2D weightMap;\n uniform sampler2D detailMap0;\n uniform sampler2D detailMap1;\n uniform sampler2D detailMap2;\n uniform sampler2D detailMap3;\nvec4 frag () {\n vec4 color = vec4(0, 0, 0, 0);\n #if LAYERS == 1\n color = texture2D(detailMap0, uv0);\n #elif LAYERS == 2\n vec4 w = texture2D(weightMap, uvw);\n color += texture2D(detailMap0, uv0) * w.r;\n color += texture2D(detailMap1, uv1) * w.g;\n #elif LAYERS == 3\n vec4 w = texture2D(weightMap, uvw);\n color += texture2D(detailMap0, uv0) * w.r;\n color += texture2D(detailMap1, uv1) * w.g;\n color += texture2D(detailMap2, uv2) * w.b;\n #elif LAYERS == 4\n vec4 w = texture2D(weightMap, uvw);\n color += texture2D(detailMap0, uv0) * w.r;\n color += texture2D(detailMap1, uv1) * w.g;\n color += texture2D(detailMap2, uv2) * w.b;\n color += texture2D(detailMap3, uv3) * w.a;\n #else\n color = texture2D(detailMap0, uv0);\n #endif\n color.rgb *= diffuse;\n return CCFragOutput(color);\n}\nvoid main() { gl_FragColor = frag(); }` }, "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[]}, "locals":{"blocks":[{"name":"CCLocal", "defines":[]}], "samplers":[]}}, @@ -265,18 +266,19 @@ export default [ "shaders": [ { "name": "builtin-unlit|unlit-vs:vert|unlit-fs:frag", - "hash": 3482344375, + "hash": 240178625, "glsl3": { - "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if CC_USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nin vec3 a_position;\n#if CC_USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if CC_USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if CC_USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif CC_USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\n#if USE_VERTEX_COLOR\n in vec4 a_color;\n out vec4 v_color;\n#endif\n#if USE_TEXTURE\n in vec2 a_texCoord;\n out vec2 v_uv;\n uniform TexCoords {\n vec4 tilingOffset;\n };\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if CC_USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n #if USE_TEXTURE\n v_uv = a_texCoord;\n #if FLIP_UV\n v_uv.y = 1.0 - v_uv.y;\n #endif\n v_uv = v_uv * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * position;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\n#if USE_ALPHA_TEST\n#endif\n#if USE_TEXTURE\n in vec2 v_uv;\n uniform sampler2D mainTexture;\n#endif\nuniform Constant {\n vec4 mainColor;\n vec4 colorScaleAndCutoff;\n};\n#if USE_VERTEX_COLOR\n in vec4 v_color;\n#endif\nvec4 frag () {\n vec4 o = mainColor;\n o.rgb *= colorScaleAndCutoff.xyz;\n #if USE_VERTEX_COLOR\n o *= v_color;\n #endif\n #if USE_TEXTURE\n o *= texture(mainTexture, v_uv);\n #endif\n #if USE_ALPHA_TEST\n if (o.ALPHA_TEST_CHANNEL < colorScaleAndCutoff.w) discard;\n #endif\n return CCFragOutput(o);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` + "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nin vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\n#if USE_VERTEX_COLOR\n in vec4 a_color;\n out vec4 v_color;\n#endif\n#if USE_TEXTURE\n in vec2 a_texCoord;\n out vec2 v_uv;\n uniform TexCoords {\n vec4 tilingOffset;\n };\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n #if USE_TEXTURE\n v_uv = a_texCoord;\n #if FLIP_UV\n v_uv.y = 1.0 - v_uv.y;\n #endif\n v_uv = v_uv * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * position;\n}\nvoid main() { gl_Position = vert(); }`, + "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\n#if USE_ALPHA_TEST\n#endif\n#if USE_TEXTURE\n in vec2 v_uv;\n uniform sampler2D mainTexture;\n#endif\nuniform Constant {\n vec4 mainColor;\n vec4 colorScaleAndCutoff;\n};\n#if USE_VERTEX_COLOR\n in vec4 v_color;\n#endif\nvec4 frag () {\n vec4 o = mainColor;\n o.rgb *= colorScaleAndCutoff.xyz;\n #if USE_VERTEX_COLOR\n o *= v_color;\n #endif\n #if USE_TEXTURE\n o *= texture(mainTexture, v_uv);\n #endif\n #if USE_ALPHA_TEST\n if (o.ALPHA_TEST_CHANNEL < colorScaleAndCutoff.w) discard;\n #endif\n return CCFragOutput(o);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { - "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform mediump mat4 cc_matProj;\n#if CC_USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\n#endif\nattribute vec3 a_position;\n#if CC_USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if CC_USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if CC_USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif CC_USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\n#if USE_VERTEX_COLOR\n attribute vec4 a_color;\n varying vec4 v_color;\n#endif\n#if USE_TEXTURE\n attribute vec2 a_texCoord;\n varying vec2 v_uv;\n uniform vec4 tilingOffset;\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if CC_USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n #if USE_TEXTURE\n v_uv = a_texCoord;\n #if FLIP_UV\n v_uv.y = 1.0 - v_uv.y;\n #endif\n v_uv = v_uv * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * position;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\n#if USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\n#endif\nattribute vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\n#if USE_VERTEX_COLOR\n attribute vec4 a_color;\n varying vec4 v_color;\n#endif\n#if USE_TEXTURE\n attribute vec2 a_texCoord;\n varying vec2 v_uv;\n uniform vec4 tilingOffset;\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n #if USE_TEXTURE\n v_uv = a_texCoord;\n #if FLIP_UV\n v_uv.y = 1.0 - v_uv.y;\n #endif\n v_uv = v_uv * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * position;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision mediump float;\nuniform mediump vec4 cc_exposure;\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\n#if USE_ALPHA_TEST\n#endif\n#if USE_TEXTURE\n varying vec2 v_uv;\n uniform sampler2D mainTexture;\n#endif\nuniform vec4 mainColor;\nuniform vec4 colorScaleAndCutoff;\n#if USE_VERTEX_COLOR\n varying vec4 v_color;\n#endif\nvec4 frag () {\n vec4 o = mainColor;\n o.rgb *= colorScaleAndCutoff.xyz;\n #if USE_VERTEX_COLOR\n o *= v_color;\n #endif\n #if USE_TEXTURE\n o *= texture2D(mainTexture, v_uv);\n #endif\n #if USE_ALPHA_TEST\n if (o.ALPHA_TEST_CHANNEL < colorScaleAndCutoff.w) discard;\n #endif\n return CCFragOutput(o);\n}\nvoid main() { gl_FragColor = frag(); }` }, - "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[]}, "locals":{"blocks":[{"name":"CCLocalBatched", "defines":["CC_USE_BATCHING"]}, {"name":"CCLocal", "defines":[]}, {"name":"CCSkinningTexture", "defines":["CC_USE_SKINNING"]}, {"name":"CCSkinningAnimation", "defines":["CC_USE_SKINNING"]}], "samplers":[{"name":"cc_jointsTexture", "defines":["CC_USE_SKINNING"]}]}}, + "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[]}, "locals":{"blocks":[{"name":"CCLocalBatched", "defines":["USE_BATCHING"]}, {"name":"CCLocal", "defines":[]}, {"name":"CCSkinningTexture", "defines":["USE_SKINNING"]}, {"name":"CCSkinningAnimation", "defines":["USE_SKINNING"]}], "samplers":[{"name":"cc_jointsTexture", "defines":["USE_SKINNING"]}]}}, "defines": [ - {"name":"CC_USE_BATCHING", "type":"boolean"}, + {"name":"USE_BATCHING", "type":"boolean"}, + {"name":"USE_SKINNING", "type":"number", "range":[0, 3]}, {"name":"CC_USE_SKINNING", "type":"number", "range":[0, 2]}, {"name":"USE_VERTEX_COLOR", "type":"boolean"}, {"name":"USE_TEXTURE", "type":"boolean"}, @@ -309,18 +311,19 @@ export default [ "shaders": [ { "name": "pipeline/planar-shadow|planar-shadow-vs:vert|planar-shadow-fs:frag", - "hash": 3776520139, + "hash": 2703119772, "glsl3": { - "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if CC_USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nuniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n lowp vec4 cc_shadowColor;\n};\nin vec3 a_position;\n#if CC_USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if CC_USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if CC_USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif CC_USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if CC_USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\nprecision mediump float;\nuniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n lowp vec4 cc_shadowColor;\n};\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvec4 frag () {\n return CCFragOutput(cc_shadowColor);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` + "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nuniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n lowp vec4 cc_shadowColor;\n};\nin vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, + "frag": `\nprecision mediump float;\nuniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n lowp vec4 cc_shadowColor;\n};\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvec4 frag () {\n return CCFragOutput(cc_shadowColor);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { - "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform mediump mat4 cc_matProj;\n#if CC_USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\n#endif\nuniform highp mat4 cc_matLightPlaneProj;\nattribute vec3 a_position;\n#if CC_USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if CC_USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if CC_USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif CC_USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if CC_USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\n#if USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\n#endif\nuniform highp mat4 cc_matLightPlaneProj;\nattribute vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision mediump float;\nuniform lowp vec4 cc_shadowColor;\nuniform mediump vec4 cc_exposure;\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvec4 frag () {\n return CCFragOutput(cc_shadowColor);\n}\nvoid main() { gl_FragColor = frag(); }` }, - "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}, {"name":"CCShadow", "defines":[]}], "samplers":[]}, "locals":{"blocks":[{"name":"CCLocalBatched", "defines":["CC_USE_BATCHING"]}, {"name":"CCLocal", "defines":[]}, {"name":"CCSkinningTexture", "defines":["CC_USE_SKINNING"]}, {"name":"CCSkinningAnimation", "defines":["CC_USE_SKINNING"]}], "samplers":[{"name":"cc_jointsTexture", "defines":["CC_USE_SKINNING"]}]}}, + "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}, {"name":"CCShadow", "defines":[]}], "samplers":[]}, "locals":{"blocks":[{"name":"CCLocalBatched", "defines":["USE_BATCHING"]}, {"name":"CCLocal", "defines":[]}, {"name":"CCSkinningTexture", "defines":["USE_SKINNING"]}, {"name":"CCSkinningAnimation", "defines":["USE_SKINNING"]}], "samplers":[{"name":"cc_jointsTexture", "defines":["USE_SKINNING"]}]}}, "defines": [ - {"name":"CC_USE_BATCHING", "type":"boolean"}, + {"name":"USE_BATCHING", "type":"boolean"}, + {"name":"USE_SKINNING", "type":"number", "range":[0, 3]}, {"name":"CC_USE_SKINNING", "type":"number", "range":[0, 2]}, {"name":"CC_USE_HDR", "type":"boolean"} ], @@ -338,13 +341,13 @@ export default [ "shaders": [ { "name": "pipeline/skybox|sky-vs:vert|sky-fs:frag", - "hash": 2321956030, + "hash": 2632866196, "glsl3": { - "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nin vec3 a_position;\nout vec4 viewDir;\nvec4 vert () {\n viewDir = vec4(a_position, 1.0);\n mat4 matViewRotOnly = mat4(mat3(cc_matView));\n vec4 pos = matViewRotOnly * viewDir;\n vec2 f = cc_matProj[3][3] > 0.0 ? vec2(4.8, 2.4) : vec2(cc_matProj[1][1]);\n pos.xy *= vec2(cc_screenSize.y * cc_screenSize.z, 1.0) * f;\n pos.zw = vec2(-0.99999 * pos.z, -pos.z);\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec3 ACESToneMap (vec3 color) {\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nin vec4 viewDir;\nvec4 frag () {\n #if USE_RGBE_CUBEMAP\n vec3 c = unpackRGBE(texture(cc_environment, viewDir.xyz));\n #else\n vec3 c = SRGBToLinear(texture(cc_environment, viewDir.xyz).rgb) * cc_ambientSky.w;\n #endif\n return CCFragOutput(vec4(c, 1.0));\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` + "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nin vec3 a_position;\nout vec4 viewDir;\nvec4 vert () {\n viewDir = vec4(a_position, 1.0);\n mat4 matViewRotOnly = mat4(mat3(cc_matView));\n vec4 pos = matViewRotOnly * viewDir;\n vec2 f = cc_matProj[3][3] > 0.0 ? vec2(4.8, 2.4) : vec2(cc_matProj[1][1]);\n pos.xy *= vec2(cc_screenSize.y * cc_screenSize.z, 1.0) * f;\n pos.zw = vec2(-0.99999 * pos.z, -pos.z);\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, + "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec3 ACESToneMap (vec3 color) {\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nin vec4 viewDir;\nvec4 frag () {\n #if USE_RGBE_CUBEMAP\n vec3 c = unpackRGBE(texture(cc_environment, viewDir.xyz));\n #else\n vec3 c = SRGBToLinear(texture(cc_environment, viewDir.xyz).rgb) * cc_ambientSky.w;\n #endif\n return CCFragOutput(vec4(c, 1.0));\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { - "vert": `\nprecision highp float;\nuniform mediump vec4 cc_screenSize;\nuniform highp mat4 cc_matView;\nuniform mediump mat4 cc_matProj;\nattribute vec3 a_position;\nvarying vec4 viewDir;\nvec4 vert () {\n viewDir = vec4(a_position, 1.0);\n mat4 matViewRotOnly = mat4(mat3(cc_matView));\n vec4 pos = matViewRotOnly * viewDir;\n vec2 f = cc_matProj[3][3] > 0.0 ? vec2(4.8, 2.4) : vec2(cc_matProj[1][1]);\n pos.xy *= vec2(cc_screenSize.y * cc_screenSize.z, 1.0) * f;\n pos.zw = vec2(-0.99999 * pos.z, -pos.z);\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision highp float;\nuniform mediump vec4 cc_screenSize;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\nattribute vec3 a_position;\nvarying vec4 viewDir;\nvec4 vert () {\n viewDir = vec4(a_position, 1.0);\n mat4 matViewRotOnly = mat4(mat3(cc_matView));\n vec4 pos = matViewRotOnly * viewDir;\n vec2 f = cc_matProj[3][3] > 0.0 ? vec2(4.8, 2.4) : vec2(cc_matProj[1][1]);\n pos.xy *= vec2(cc_screenSize.y * cc_screenSize.z, 1.0) * f;\n pos.zw = vec2(-0.99999 * pos.z, -pos.z);\n return pos;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision mediump float;\nuniform mediump vec4 cc_ambientSky;\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec3 ACESToneMap (vec3 color) {\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nvarying vec4 viewDir;\nvec4 frag () {\n #if USE_RGBE_CUBEMAP\n vec3 c = unpackRGBE(textureCube(cc_environment, viewDir.xyz));\n #else\n vec3 c = SRGBToLinear(textureCube(cc_environment, viewDir.xyz).rgb) * cc_ambientSky.w;\n #endif\n return CCFragOutput(vec4(c, 1.0));\n}\nvoid main() { gl_FragColor = frag(); }` }, "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[{"name":"cc_environment", "defines":[]}]}, "locals":{"blocks":[], "samplers":[]}}, @@ -369,8 +372,8 @@ export default [ "name": "util/profiler|profiler-vs:vert|profiler-fs:frag", "hash": 1827451161, "glsl3": { - "vert": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nin vec3 a_position;\nin vec4 a_color;\nout vec2 v_uv;\nuniform Constants {\n vec4 offset;\n vec4 symbols[4];\n};\nuniform PerFrameInfo {\n vec4 digits[8 * 9 / 4];\n};\nfloat getComponent(vec4 v, float i) {\n if (i < 1.0) { return v[0]; }\n else if (i < 2.0) { return v[1]; }\n else if (i < 3.0) { return v[2]; }\n else { return v[3]; }\n}\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n position.x *= cc_screenSize.y * cc_screenSize.z;\n position.xy += offset.xy + abs(position.xy);\n v_uv = a_color.xy;\n if (a_color.z >= 0.0) {\n float n = getComponent(digits[int(a_color.z)], a_color.w);\n float row = floor(n / 4.0), col = n - row * 4.0;\n v_uv += vec2(getComponent(symbols[int(row)], col), 0.0);\n }\n return position;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n mediump mat4 cc_matViewInv;\n mediump mat4 cc_matProj;\n mediump mat4 cc_matProjInv;\n mediump mat4 cc_matViewProj;\n mediump mat4 cc_matViewProjInv;\n mediump vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nin vec2 v_uv;\nuniform sampler2D mainTexture;\nvec4 frag () {\n return CCFragOutput(texture(mainTexture, v_uv));\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` + "vert": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nin vec3 a_position;\nin vec4 a_color;\nout vec2 v_uv;\nuniform Constants {\n vec4 offset;\n vec4 symbols[4];\n};\nuniform PerFrameInfo {\n vec4 digits[8 * 9 / 4];\n};\nfloat getComponent(vec4 v, float i) {\n if (i < 1.0) { return v[0]; }\n else if (i < 2.0) { return v[1]; }\n else if (i < 3.0) { return v[2]; }\n else { return v[3]; }\n}\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n position.x *= cc_screenSize.y * cc_screenSize.z;\n position.xy += offset.xy + abs(position.xy);\n v_uv = a_color.xy;\n if (a_color.z >= 0.0) {\n float n = getComponent(digits[int(a_color.z)], a_color.w);\n float row = floor(n / 4.0), col = n - row * 4.0;\n v_uv += vec2(getComponent(symbols[int(row)], col), 0.0);\n }\n return position;\n}\nvoid main() { gl_Position = vert(); }`, + "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nin vec2 v_uv;\nuniform sampler2D mainTexture;\nvec4 frag () {\n return CCFragOutput(texture(mainTexture, v_uv));\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { "vert": `\nprecision mediump float;\nuniform mediump vec4 cc_screenSize;\nattribute vec3 a_position;\nattribute vec4 a_color;\nvarying vec2 v_uv;\nuniform vec4 offset;\nuniform vec4 symbols[4];\nuniform vec4 digits[18];\nfloat getComponent(vec4 v, float i) {\n if (i < 1.0) { return v[0]; }\n else if (i < 2.0) { return v[1]; }\n else if (i < 3.0) { return v[2]; }\n else { return v[3]; }\n}\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n position.x *= cc_screenSize.y * cc_screenSize.z;\n position.xy += offset.xy + abs(position.xy);\n v_uv = a_color.xy;\n if (a_color.z >= 0.0) {\n float n = getComponent(digits[int(a_color.z)], a_color.w);\n float row = floor(n / 4.0), col = n - row * 4.0;\n v_uv += vec2(getComponent(symbols[int(row)], col), 0.0);\n }\n return position;\n}\nvoid main() { gl_Position = vert(); }`, diff --git a/cocos/core/3d/builtin/init.ts b/cocos/core/3d/builtin/init.ts index d18b7b17115..7d7660071f1 100644 --- a/cocos/core/3d/builtin/init.ts +++ b/cocos/core/3d/builtin/init.ts @@ -147,7 +147,7 @@ class BuiltinResMgr { const type = selectJointsMediumType(device); missingSkinningMtl.initialize({ effectName: 'builtin-unlit', - defines: { USE_COLOR: true, CC_USE_SKINNING: type }, + defines: { USE_COLOR: true, USE_SKINNING: type }, }); missingSkinningMtl.setProperty('color', cc.color('#ff00ff')); resources[missingSkinningMtl._uuid] = missingSkinningMtl; diff --git a/cocos/core/3d/framework/renderable-component.ts b/cocos/core/3d/framework/renderable-component.ts index eb7819753a1..5baff269a6f 100644 --- a/cocos/core/3d/framework/renderable-component.ts +++ b/cocos/core/3d/framework/renderable-component.ts @@ -141,7 +141,7 @@ export class RenderableComponent extends Component { * @zh 获取相对应序号的材质实例。 * @param idx Look for the material list number */ - public getMaterialInstance (idx: number): MaterialInstance | null { + public getMaterialInstance (idx: number): Material | null { const mat = this._materials[idx]; if (!mat) { return null; @@ -161,7 +161,7 @@ export class RenderableComponent extends Component { * @param index 材质序号 * @param matInst 材质实例 */ - public setMaterialInstance (index: number, matInst: MaterialInstance | null) { + public setMaterialInstance (index: number, matInst: Material | null) { if (matInst && matInst.parent) { if (matInst !== this._materialInstances[index]) { this._materialInstances[index] = matInst as MaterialInstance; diff --git a/cocos/core/assets/material.ts b/cocos/core/assets/material.ts index 3109e6053d0..92f3f9bcd05 100644 --- a/cocos/core/assets/material.ts +++ b/cocos/core/assets/material.ts @@ -31,6 +31,7 @@ import { ccclass, property } from '../../core/data/class-decorator'; import { murmurhash2_32_gc } from '../../core/utils/murmurhash2_gc'; import { builtinResMgr } from '../3d/builtin/init'; +import { RenderableComponent } from '../3d/framework/renderable-component'; import { GFXBindingType } from '../gfx/define'; import { GFXTextureView } from '../gfx/texture-view'; import { IDefineMap } from '../renderer'; @@ -143,6 +144,9 @@ export class Material extends Asset { return this._hash; } + get parent (): Material | null { return null; } + get owner (): RenderableComponent | null { return null; } + constructor () { super(); this.loaded = false; diff --git a/cocos/core/components/ui-base/ui-render-component.ts b/cocos/core/components/ui-base/ui-render-component.ts index 4a6b558fa15..aad096ad19b 100644 --- a/cocos/core/components/ui-base/ui-render-component.ts +++ b/cocos/core/components/ui-base/ui-render-component.ts @@ -32,15 +32,16 @@ import { ccclass, property } from '../../../core/data/class-decorator'; import { Color } from '../../../core/math'; import { SystemEventType } from '../../../core/platform/event-manager/event-enum'; import { ccenum } from '../../../core/value-types/enum'; +import { builtinResMgr } from '../../3d/builtin/init'; import { Material } from '../../assets'; import { GFXBlendFactor } from '../../gfx/define'; import { MaterialInstance } from '../../renderer'; +import { IMaterialInstanceInfo } from '../../renderer/core/material-instance'; import { IAssembler, IAssemblerManager } from '../../renderer/ui/base'; import { RenderData } from '../../renderer/ui/render-data'; import { UI } from '../../renderer/ui/ui'; import { Node } from '../../scene-graph'; import { TransformBit } from '../../scene-graph/node-enum'; -import { IMaterial } from '../../utils/material-interface'; import { UIComponent } from './ui-component'; // hack @@ -70,6 +71,12 @@ export enum InstanceMaterialType { GRAYSCALE = 2, } +const _matInsInfo: IMaterialInstanceInfo = { + parent: null!, + owner: null!, + subModelIdx: 0, +}; + /** * @zh * 所有支持渲染的 UI 组件的基类。 @@ -91,7 +98,7 @@ export class UIRenderComponent extends UIComponent { @property({ type: GFXBlendFactor, displayOrder: 0, - tooltip:'原图混合模式', + tooltip: '原图混合模式', }) get srcBlendFactor () { return this._srcBlendFactor; @@ -119,7 +126,7 @@ export class UIRenderComponent extends UIComponent { @property({ type: GFXBlendFactor, displayOrder: 1, - tooltip:'目标混合模式', + tooltip: '目标混合模式', }) get dstBlendFactor () { return this._dstBlendFactor; @@ -142,7 +149,7 @@ export class UIRenderComponent extends UIComponent { */ @property({ displayOrder: 2, - tooltip:'渲染颜色', + tooltip: '渲染颜色', }) // @constget get color (): Readonly { @@ -168,7 +175,7 @@ export class UIRenderComponent extends UIComponent { @property({ type: Material, displayOrder: 3, - tooltip:'源材质', + tooltip: '源材质', visible: false, }) get sharedMaterial () { @@ -225,7 +232,7 @@ export class UIRenderComponent extends UIComponent { protected _renderFlag = true; // 特殊渲染节点,给一些不在节点树上的组件做依赖渲染(例如 mask 组件内置两个 graphics 来渲染) protected _delegateSrc: Node | null = null; - protected _material: IMaterial | null = null; + protected _material: Material | null = null; protected _instanceMaterialType = InstanceMaterialType.ADDCOLORANDTEXTURE; protected _blendTemplate = { blendState: { @@ -320,7 +327,7 @@ export class UIRenderComponent extends UIComponent { public updateAssembler (render: UI) { super.updateAssembler(render); - if(this._renderFlag){ + if (this._renderFlag){ this._checkAndUpdateRenderData(); this._render(render); } @@ -351,7 +358,7 @@ export class UIRenderComponent extends UIComponent { return this.material !== null && this.enabled && (this._delegateSrc ? this._delegateSrc.activeInHierarchy : this.enabledInHierarchy); } - protected _postCanRender(){} + protected _postCanRender (){} protected _updateColor () { if (this._assembler && this._assembler.updateColor) { @@ -359,7 +366,7 @@ export class UIRenderComponent extends UIComponent { } } - protected _updateMaterial (material: IMaterial | null) { + protected _updateMaterial (material: Material | null) { this._material = material; this._updateBlendFunc(); @@ -395,19 +402,24 @@ export class UIRenderComponent extends UIComponent { } protected _instanceMaterial () { - let mat: IMaterial | null = null; + let mat: Material | null = null; + _matInsInfo.owner = new RenderableComponent(); if (this._sharedMaterial) { - mat = new MaterialInstance(this._sharedMaterial, new RenderableComponent()); + _matInsInfo.parent = this._sharedMaterial; + mat = new MaterialInstance(_matInsInfo); } else { - switch (this._instanceMaterialType){ + switch (this._instanceMaterialType) { case InstanceMaterialType.ADDCOLOR: - mat = new MaterialInstance(cc.builtinResMgr.get('ui-base-material'), new RenderableComponent()); + _matInsInfo.parent = builtinResMgr.get('ui-base-material'); + mat = new MaterialInstance(_matInsInfo); break; case InstanceMaterialType.ADDCOLORANDTEXTURE: - mat = new MaterialInstance(cc.builtinResMgr.get('ui-sprite-material'), new RenderableComponent()); + _matInsInfo.parent = builtinResMgr.get('ui-sprite-material'); + mat = new MaterialInstance(_matInsInfo); break; case InstanceMaterialType.GRAYSCALE: - mat = new MaterialInstance(cc.builtinResMgr.get('ui-sprite-gray-material'), new RenderableComponent()); + _matInsInfo.parent = builtinResMgr.get('ui-sprite-gray-material'); + mat = new MaterialInstance(_matInsInfo); break; } } diff --git a/cocos/core/renderer/core/program-lib.ts b/cocos/core/renderer/core/program-lib.ts index 17f4c3605bf..2b154b6fd16 100644 --- a/cocos/core/renderer/core/program-lib.ts +++ b/cocos/core/renderer/core/program-lib.ts @@ -34,6 +34,7 @@ import { GFXAPI, GFXDevice } from '../../gfx/device'; import { GFXShader, GFXUniformBlock } from '../../gfx/shader'; import { IInternalBindingDesc, localBindingsDesc } from '../../pipeline/define'; import { RenderPipeline } from '../../pipeline/render-pipeline'; +import { selectJointsMediumType } from '../models/skeletal-animation-utils'; import { genHandle, IDefineMap } from './pass-utils'; interface IDefineRecord extends IDefineInfo { @@ -300,6 +301,7 @@ class ProgramLib { */ public getGFXShader (device: GFXDevice, name: string, defines: IDefineMap, pipeline: RenderPipeline) { Object.assign(defines, pipeline.macros); + if (defines.USE_SKINNING) { defines.USE_SKINNING = selectJointsMediumType(device); } const key = this.getKey(name, defines); const res = this._cache[key]; if (res) { return res; } diff --git a/cocos/core/renderer/index.ts b/cocos/core/renderer/index.ts index 2a3d9df9acd..73132a483c6 100644 --- a/cocos/core/renderer/index.ts +++ b/cocos/core/renderer/index.ts @@ -10,8 +10,8 @@ export * from './core/pass'; export * from './core/program-lib'; export * from './core/sampler-lib'; export * from './core/texture-buffer-pool'; -export { MaterialInstance } from './core/material-instance'; -export { PassInstance } from './core/pass-instance'; +export * from './core/material-instance'; +export * from './core/pass-instance'; export * from './models/skeletal-animation-utils'; export * from './models/skinning-model'; diff --git a/cocos/core/renderer/models/skinning-model.ts b/cocos/core/renderer/models/skinning-model.ts index e11ad7391ab..d4ad54df9de 100644 --- a/cocos/core/renderer/models/skinning-model.ts +++ b/cocos/core/renderer/models/skinning-model.ts @@ -36,11 +36,11 @@ import { GFXBufferUsageBit, GFXMemoryUsageBit } from '../../gfx/define'; import { Vec3 } from '../../math'; import { UBOSkinningAnimation, UBOSkinningTexture, UniformJointsTexture } from '../../pipeline/define'; import { Node } from '../../scene-graph'; -import { IPass } from '../../utils/pass-interface'; +import { Pass } from '../core/pass'; import { samplerLib } from '../core/sampler-lib'; import { DataPoolManager } from '../data-pool-manager'; import { Model } from '../scene/model'; -import { IAnimInfo, IJointsTextureHandle, jointsTextureSamplerHash, selectJointsMediumType } from './skeletal-animation-utils'; +import { IAnimInfo, IJointsTextureHandle, jointsTextureSamplerHash } from './skeletal-animation-utils'; interface IJointsInfo { buffer: GFXBuffer | null; @@ -158,11 +158,7 @@ export class SkinningModel extends Model { } } - protected createPipelineState (pass: IPass) { - pass.beginChangeStatesSilently(); - // warning:this behavior is now forbidden. - pass.tryCompile({ CC_USE_SKINNING: selectJointsMediumType(this._device) }); - pass.endChangeStatesSilently(); + protected createPipelineState (pass: Pass) { const pso = super.createPipelineState(pass); const { buffer, texture, animInfo } = this._jointsMedium; const bindingLayout = pso.pipelineLayout.layouts[0]; diff --git a/cocos/core/renderer/scene/model.ts b/cocos/core/renderer/scene/model.ts index a2594ad93e8..eb422548d47 100644 --- a/cocos/core/renderer/scene/model.ts +++ b/cocos/core/renderer/scene/model.ts @@ -1,5 +1,5 @@ // Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. -import { IPassStates } from '../../assets/effect-asset'; +import { Material } from '../../assets/material'; import { IRenderingSubmesh } from '../../assets/mesh'; import { aabb } from '../../geom-utils'; import { GFXBuffer } from '../../gfx/buffer'; @@ -12,12 +12,10 @@ import { Pool } from '../../memop'; import { IInternalBindingInst, UBOForwardLight, UBOLocal } from '../../pipeline/define'; import { Node } from '../../scene-graph'; import { Layers } from '../../scene-graph/layers'; -import { IMaterial } from '../../utils/material-interface'; -import { IPass } from '../../utils/pass-interface'; +import { Pass } from '../core/pass'; import { customizationManager } from './customization-manager'; import { RenderScene } from './render-scene'; import { SubModel } from './submodel'; -import { IDefineMap } from '../core/pass-utils'; const m4_1 = new Mat4(); @@ -157,8 +155,8 @@ export class Model { protected _modelBounds: aabb | null = null; protected _subModels: SubModel[] = []; protected _implantPSOs: GFXPipelineState[] = []; - protected _matPSORecord = new Map(); - protected _matRefCount = new Map(); + protected _matPSORecord = new Map(); + protected _matRefCount = new Map(); protected _uboLocal = new UBOLocal(); protected _localUBO: GFXBuffer | null = null; protected _localBindings = new Map(); @@ -240,7 +238,6 @@ export class Model { return false; } this._uboUpdated = true; - // @ts-ignore if (this._transformUpdated && !this._isDynamicBatching) { // @ts-ignore const worldMatrix = this._transform._mat; @@ -273,7 +270,7 @@ export class Model { this._modelBounds.transform(this._transform._mat, this._transform._pos, this._transform._rot, this._transform._scale, this._worldBounds); } - public initSubModel (idx: number, subMeshData: IRenderingSubmesh, mat: IMaterial) { + public initSubModel (idx: number, subMeshData: IRenderingSubmesh, mat: Material) { this.initLocalBindings(mat); if (this._subModels[idx] == null) { this._subModels[idx] = _subMeshPool.alloc(); @@ -294,7 +291,7 @@ export class Model { this._subModels[idx].subMeshData = subMeshData; } - public setSubModelMaterial (idx: number, mat: IMaterial | null) { + public setSubModelMaterial (idx: number, mat: Material | null) { if (this._subModels[idx] == null) { return; } @@ -342,7 +339,7 @@ export class Model { if (idx >= 0) { this._implantPSOs.splice(idx, 1); } } - protected createPipelineStates (mat: IMaterial): GFXPipelineState[] { + protected createPipelineStates (mat: Material): GFXPipelineState[] { const ret = new Array(mat.passes.length); for (let i = 0; i < ret.length; i++) { const pass = mat.passes[i]; @@ -352,7 +349,7 @@ export class Model { return ret; } - protected destroyPipelineStates (mat: IMaterial, pso: GFXPipelineState[]) { + protected destroyPipelineStates (mat: Material, pso: GFXPipelineState[]) { for (let i = 0; i < mat.passes.length; i++) { const pass = mat.passes[i]; pass.destroyPipelineState(pso[i]); @@ -360,15 +357,8 @@ export class Model { } } - protected createPipelineState (pass: IPass, defineOverrides?: IDefineMap) { - defineOverrides = defineOverrides || {}; - if (pass.blendState.targets[0].blend) { - this._isDynamicBatching = false; - } - pass.beginChangeStatesSilently(); - // warning:this behavior is now forbidden. - pass.tryCompile({ CC_USE_BATCHING: this._isDynamicBatching }); - pass.endChangeStatesSilently(); + protected createPipelineState (pass: Pass) { + if (pass.blendState.targets[0].blend) { this._isDynamicBatching = false; } const pso = pass.createPipelineState()!; pso.pipelineLayout.layouts[0].bindBuffer(UBOLocal.BLOCK.binding, this._localBindings.get(UBOLocal.BLOCK.name)!.buffer!); if (this._localBindings.has(UBOForwardLight.BLOCK.name)) { @@ -377,7 +367,7 @@ export class Model { return pso; } - protected onSetLocalBindings (mat: IMaterial) { + protected onSetLocalBindings (mat: Material) { if (!this._localBindings.has(UBOLocal.BLOCK.name)) { this._localBindings.set(UBOLocal.BLOCK.name, { type: GFXBindingType.UNIFORM_BUFFER, @@ -401,7 +391,7 @@ export class Model { } } - protected initLocalBindings (mat: IMaterial | null) { + protected initLocalBindings (mat: Material | null) { if (mat) { this.onSetLocalBindings(mat); const lbIter = this._localBindings.values(); @@ -420,7 +410,7 @@ export class Model { } } - private _updatePass (psos: GFXPipelineState[], mat: IMaterial) { + private _updatePass (psos: GFXPipelineState[], mat: Material) { for (let i = 0; i < mat.passes.length; i++) { mat.passes[i].update(); } @@ -429,7 +419,7 @@ export class Model { } } - private allocatePSO (mat: IMaterial) { + private allocatePSO (mat: Material) { if (this._matRefCount.get(mat) == null) { this._matRefCount.set(mat, 1); this._matPSORecord.set(mat, this.createPipelineStates(mat)); @@ -438,7 +428,7 @@ export class Model { } } - private releasePSO (mat: IMaterial) { + private releasePSO (mat: Material) { this._matRefCount.set(mat, this._matRefCount.get(mat)! - 1); if (this._matRefCount.get(mat) === 0) { this.destroyPipelineStates(mat, this._matPSORecord.get(mat)!); diff --git a/cocos/core/renderer/scene/planar-shadows.ts b/cocos/core/renderer/scene/planar-shadows.ts index e07f93d73c4..3437d6d5e8d 100644 --- a/cocos/core/renderer/scene/planar-shadows.ts +++ b/cocos/core/renderer/scene/planar-shadows.ts @@ -1,5 +1,5 @@ -import { EffectAsset } from '../../assets/effect-asset'; +import { Material } from '../../assets/material'; import { aabb, frustum, intersect } from '../../geom-utils'; import { GFXCommandBuffer, IGFXCommandBufferInfo } from '../../gfx/command-buffer'; import { GFXCommandBufferType, GFXStatus } from '../../gfx/define'; @@ -8,8 +8,6 @@ import { GFXPipelineState } from '../../gfx/pipeline-state'; import { Color, Mat4, Quat, Vec3 } from '../../math'; import { CachedArray } from '../../memop/cached-array'; import { IInternalBindingInst, UBOShadow } from '../../pipeline/define'; -import { Pass } from '../core/pass'; -import { selectJointsMediumType } from '../models/skeletal-animation-utils'; import { SkinningModel } from '../models/skinning-model'; import { DirectionalLight } from './directional-light'; import { Model } from './model'; @@ -88,17 +86,17 @@ export class PlanarShadows { protected _cmdBuffCount = 0; protected _psoRecord = new Map(); protected _cbRecord = new Map(); - protected _passNormal: Pass; - protected _passSkinning: Pass; + protected _matNormal: Material; + protected _matSkinning: Material; constructor (scene: RenderScene) { this._scene = scene; this._globalBindings = scene.root.pipeline.globalBindings.get(UBOShadow.BLOCK.name)!; this._cmdBuffs = new CachedArray(64); - const effectAsset = EffectAsset.get('pipeline/planar-shadow')!; - const defines = { CC_USE_SKINNING: selectJointsMediumType(scene.root.device) }; - this._passNormal = Pass.createPasses(effectAsset, { techIdx: 0, defines: [], states: [] })[0]; - this._passSkinning = Pass.createPasses(effectAsset, { techIdx: 0, defines: [ defines ], states: [] })[0]; + this._matNormal = new Material(); + this._matNormal.initialize({ effectName: 'pipeline/planar-shadow' }); + this._matSkinning = new Material(); + this._matSkinning.initialize({ effectName: 'pipeline/planar-shadow', defines: { USE_SKINNING: true } }); } public updateSphereLight (light: SphereLight) { @@ -217,22 +215,22 @@ export class PlanarShadows { public destroy () { this.onGlobalPipelineStateChanged(); - this._passNormal.destroy(); - this._passSkinning.destroy(); + this._matNormal.destroy(); + this._matSkinning.destroy(); } protected _createPSO (model: Model) { - const pass = model instanceof SkinningModel ? this._passSkinning : this._passNormal; + const mat = model instanceof SkinningModel ? this._matSkinning : this._matNormal; // @ts-ignore TS2445 - const pso = model.createPipelineState(pass); + const pso = model.createPipelineState(mat.passes[0]); model.insertImplantPSO(pso); // add back to model to sync binding layouts pso.pipelineLayout.layouts[0].update(); return pso; } protected _destroyPSO (model: Model, pso: GFXPipelineState) { - const pass = model instanceof SkinningModel ? this._passSkinning : this._passNormal; - model.removeImplantPSO(pso); pass.destroyPipelineState(pso); + const mat = model instanceof SkinningModel ? this._matSkinning : this._matNormal; + model.removeImplantPSO(pso); mat.passes[0].destroyPipelineState(pso); } protected _createOrReuseCommandBuffer (cb?: GFXCommandBuffer) { diff --git a/cocos/core/renderer/scene/submodel.ts b/cocos/core/renderer/scene/submodel.ts index c2dcfa0cf05..7e63c705c28 100644 --- a/cocos/core/renderer/scene/submodel.ts +++ b/cocos/core/renderer/scene/submodel.ts @@ -1,3 +1,4 @@ +import { Material } from '../../assets/material'; import { IRenderingSubmesh } from '../../assets/mesh'; import { GFXCommandBuffer } from '../../gfx/command-buffer'; import { GFXCommandBufferType, GFXStatus } from '../../gfx/define'; @@ -5,13 +6,12 @@ import { GFXDevice } from '../../gfx/device'; import { GFXInputAssembler, IGFXInputAssemblerInfo } from '../../gfx/input-assembler'; import { GFXPipelineState } from '../../gfx/pipeline-state'; import { RenderPriority } from '../../pipeline/define'; -import { IMaterial } from '../../utils/material-interface'; -import { IPass } from '../../utils/pass-interface'; +import { Pass } from '../core/pass'; export class SubModel { protected _subMeshObject: IRenderingSubmesh | null; protected _inputAssembler: GFXInputAssembler | null; - private _material: IMaterial | null; + private _material: Material | null; private _cmdBuffers: GFXCommandBuffer[]; private _psos: GFXPipelineState[] | null; private _priority: RenderPriority; @@ -25,7 +25,7 @@ export class SubModel { this._priority = RenderPriority.DEFAULT; } - public initialize (subMesh: IRenderingSubmesh, mat: IMaterial, psos: GFXPipelineState[]) { + public initialize (subMesh: IRenderingSubmesh, mat: Material, psos: GFXPipelineState[]) { this._psos = psos; this.subMeshData = subMesh; @@ -87,7 +87,7 @@ export class SubModel { this._psos = val; } - set material (material: IMaterial | null) { + set material (material: Material | null) { this._material = material; if (material == null) { return; @@ -95,7 +95,7 @@ export class SubModel { this.updateCommandBuffer(); } - get material (): IMaterial | null { + get material (): Material | null { return this._material; } @@ -147,7 +147,7 @@ export class SubModel { cmdBuff.end(); } - get passes (): IPass[] { + get passes (): Pass[] { return this._material!.passes; } diff --git a/cocos/core/renderer/ui/render-data.ts b/cocos/core/renderer/ui/render-data.ts index 88c01230efd..5e14f10256e 100644 --- a/cocos/core/renderer/ui/render-data.ts +++ b/cocos/core/renderer/ui/render-data.ts @@ -27,10 +27,9 @@ * @hidden */ -import { Material } from '../../assets'; +import { Material } from '../../assets/material'; import { Color } from '../../math'; import { Pool, RecyclePool } from '../../memop'; -import { IMaterial } from '../../utils/material-interface'; export interface IRenderData { x: number; @@ -42,7 +41,7 @@ export interface IRenderData { } export class BaseRenderData { - public material: IMaterial | null = null; + public material: Material | null = null; public vertexCount: number = 0; public indiceCount: number = 0; } diff --git a/cocos/core/renderer/ui/stencil-manager.ts b/cocos/core/renderer/ui/stencil-manager.ts index 6b57fec5cb1..3d8e4092b98 100644 --- a/cocos/core/renderer/ui/stencil-manager.ts +++ b/cocos/core/renderer/ui/stencil-manager.ts @@ -28,8 +28,6 @@ import { Material } from '../../assets/material'; import { GFXComparisonFunc, GFXStencilOp } from '../../gfx/define'; -import { IMaterial } from '../../utils/material-interface'; -import { IPass } from '../../utils/pass-interface'; import { Pass } from '../core/pass'; // import { GFXStencilOp } from '../../gfx/define'; @@ -120,7 +118,7 @@ export class StencilManager { } } - public handleMaterial (mat: IMaterial){ + public handleMaterial (mat: Material) { const pattern = this._stencilPattern; if (this.stage === Stage.DISABLED) { pattern.stencilTest = false; @@ -206,7 +204,7 @@ export class StencilManager { this.stage = Stage.DISABLED; } - private _changed (pass: IPass) { + private _changed (pass: Pass) { const stencilState = pass.depthStencilState; const pattern = this._stencilPattern; if (pattern.stencilTest !== stencilState.stencilTestFront || diff --git a/cocos/core/renderer/ui/ui-batch-model.ts b/cocos/core/renderer/ui/ui-batch-model.ts index 5875331b217..8902585df8d 100644 --- a/cocos/core/renderer/ui/ui-batch-model.ts +++ b/cocos/core/renderer/ui/ui-batch-model.ts @@ -26,9 +26,9 @@ * @hidden */ +import { Material } from '../../assets/material'; import { GFXInputAssembler } from '../../gfx/input-assembler'; import { GFXPipelineState } from '../../gfx/pipeline-state'; -import { IMaterial } from '../../utils/material-interface'; import { Model } from '../scene/model'; import { SubModel } from '../scene/submodel'; import { UIDrawBatch } from './ui-draw-batch'; @@ -65,7 +65,7 @@ class UISubModel extends SubModel { this.psos = []; } - public directInitialize (ia: GFXInputAssembler, mat: IMaterial, pso: GFXPipelineState) { + public directInitialize (ia: GFXInputAssembler, mat: Material, pso: GFXPipelineState) { this._inputAssembler = ia; this.psos![0] = pso; this.material = mat; diff --git a/cocos/core/renderer/ui/ui-draw-batch.ts b/cocos/core/renderer/ui/ui-draw-batch.ts index 6190c37c6ea..e9b6d0f3f23 100644 --- a/cocos/core/renderer/ui/ui-draw-batch.ts +++ b/cocos/core/renderer/ui/ui-draw-batch.ts @@ -3,10 +3,10 @@ */ import { MeshBuffer } from '../../../ui'; +import { Material } from '../../assets/material'; import { GFXPipelineState, GFXTextureView } from '../../gfx'; import { GFXBindingLayout } from '../../gfx/binding-layout'; import { Node } from '../../scene-graph'; -import { IMaterial } from '../../utils/material-interface'; import { Camera } from '../scene/camera'; import { Model } from '../scene/model'; import { UI } from './ui'; @@ -15,7 +15,7 @@ export class UIDrawBatch { public camera: Camera | null = null; public bufferBatch: MeshBuffer | null = null; public model: Model | null = null; - public material: IMaterial | null = null; + public material: Material | null = null; public texView: GFXTextureView | null = null; public firstIdx: number = 0; public idxCount: number = 0; diff --git a/cocos/core/renderer/ui/ui-material.ts b/cocos/core/renderer/ui/ui-material.ts index 7a4c636a89d..55a6180c0d5 100644 --- a/cocos/core/renderer/ui/ui-material.ts +++ b/cocos/core/renderer/ui/ui-material.ts @@ -30,15 +30,15 @@ import { Material } from '../../assets/material'; import { GFXPipelineState } from '../../gfx/pipeline-state'; import { Pool } from '../../memop'; import { Pass } from '../../renderer/core/pass'; -import { IMaterial } from '../../utils/material-interface'; +import { MaterialInstance } from '../core/material-instance'; export interface IUIMaterialInfo { - material: IMaterial; + material: Material; } export class UIMaterial { - public get material (): IMaterial { + public get material (): Material { return this._material!; } @@ -63,7 +63,7 @@ export class UIMaterial { this._material = new Material(); - this._material.copy(info.material instanceof Material ? info.material : info.material.parent as Material); + this._material.copy(info.material instanceof MaterialInstance ? info.material.parent : info.material); this._pass = this._material.passes[0]; this._pass.update(); diff --git a/cocos/core/renderer/ui/ui.ts b/cocos/core/renderer/ui/ui.ts index f428dc895f6..624dbd3457b 100644 --- a/cocos/core/renderer/ui/ui.ts +++ b/cocos/core/renderer/ui/ui.ts @@ -30,7 +30,7 @@ import { UIStaticBatchComponent } from '../../../ui'; import { Material } from '../../assets/material'; import { CanvasComponent, UIComponent, UIRenderComponent } from '../../components/ui-base'; import { GFXCommandBuffer } from '../../gfx/command-buffer'; -import { GFXCommandBufferType } from '../../gfx/define'; +import { GFXCommandBufferType } from '../../gfx/define'; import { GFXDevice } from '../../gfx/device'; import { IGFXAttribute } from '../../gfx/input-assembler'; import { GFXTextureView } from '../../gfx/texture-view'; @@ -42,7 +42,6 @@ import { Model } from '../../renderer/scene/model'; import { RenderScene } from '../../renderer/scene/render-scene'; import { Root } from '../../root'; import { Layers, Node } from '../../scene-graph'; -import { IMaterial } from '../../utils/material-interface'; import { MeshBuffer } from './mesh-buffer'; import { StencilManager } from './stencil-manager'; import { UIBatchModel } from './ui-batch-model'; @@ -65,7 +64,7 @@ export class UI { } set currBufferBatch (value) { - if (!value){ + if (!value) { return; } @@ -96,7 +95,7 @@ export class UI { private _modelInUse: CachedArray; // batcher private _emptyMaterial = new Material(); - private _currMaterial: IMaterial = this._emptyMaterial; + private _currMaterial: Material = this._emptyMaterial; private _currTexView: GFXTextureView | null = null; private _currCanvas: CanvasComponent | null = null; private _currMeshBuffer: MeshBuffer | null = null; @@ -164,7 +163,7 @@ export class UI { return Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this), 'renderScene')!.get!.bind(this); } - public _getUIMaterial (mat: IMaterial): UIMaterial { + public _getUIMaterial (mat: Material): UIMaterial { if (this._uiMaterials.has(mat.hash)) { return this._uiMaterials.get(mat.hash)!; } else { @@ -175,7 +174,7 @@ export class UI { } } - public _removeUIMaterial (hash: number){ + public _removeUIMaterial (hash: number) { if (this._uiMaterials.has(hash)) { if (this._uiMaterials.get(hash)!.decrease() === 0) { this._uiMaterials.delete(hash); @@ -195,9 +194,9 @@ export class UI { const screens = this._screens; for (let i = 0; i < screens.length; i++) { const element = screens[i]; - if(element.camera){ + if (element.camera) { element.camera.view.visibility = Layers.BitMask.UI_2D | (i + 1); - if (!this._canvasMaterials.has(element.camera.view.visibility)){ + if (!this._canvasMaterials.has(element.camera.view.visibility)) { this._canvasMaterials.set(element.camera.view.visibility, new Map()); } } @@ -274,7 +273,7 @@ export class UI { this._reset(); } - public sortScreens(){ + public sortScreens () { this._screens.sort(this._screenSort); } @@ -364,15 +363,15 @@ export class UI { * @param model - 提交渲染的 model 数据。 * @param mat - 提交渲染的材质。 */ - public commitModel (comp: UIComponent, model: Model | null, mat: IMaterial | null) { + public commitModel (comp: UIComponent, model: Model | null, mat: Material | null) { // if the last comp is spriteComp, previous comps should be batched. if (this._currMaterial !== this._emptyMaterial) { this.autoMergeBatches(); } - if (mat){ + if (mat) { const rebuild = StencilManager.sharedManager!.handleMaterial(mat); - if (rebuild && model){ + if (rebuild && model) { for (let i = 0; i < model.subModelNum; i++) { model.setSubModelMaterial(i, mat); } @@ -408,12 +407,12 @@ export class UI { * @zh * UI 渲染数据合批 */ - public autoMergeBatches (){ + public autoMergeBatches () { const mat = this._currMaterial; const buffer = this._currMeshBuffer!; const indicsStart = buffer.indiceStart; const vCount = buffer.indiceOffset - indicsStart; - if (!vCount || !mat){ + if (!vCount || !mat) { return; } @@ -452,7 +451,7 @@ export class UI { this.autoMergeBatches(); } - public finishMergeBatches (){ + public finishMergeBatches () { this.autoMergeBatches(); this._currMaterial = this._emptyMaterial; this._currTexView = null; @@ -503,7 +502,7 @@ export class UI { } private _preprocess (c: Node) { - if(!c._uiProps.uiTransformComp){ + if (!c._uiProps.uiTransformComp) { return; } @@ -556,7 +555,7 @@ export class UI { return batch; } - private _requireBufferBatch (){ + private _requireBufferBatch () { if (this._meshBufferUseCount >= this._meshBuffers.length) { this._currMeshBuffer = this._createMeshBuffer(); } else { @@ -564,7 +563,7 @@ export class UI { } this._meshBufferUseCount++; - if (arguments.length === 2){ + if (arguments.length === 2) { this._currMeshBuffer.request(arguments[0], arguments[1]); } } diff --git a/cocos/core/utils/profiler/profiler.ts b/cocos/core/utils/profiler/profiler.ts index 7f0faadfa11..6cd27a28606 100644 --- a/cocos/core/utils/profiler/profiler.ts +++ b/cocos/core/utils/profiler/profiler.ts @@ -32,9 +32,9 @@ import { GFXDevice } from '../../gfx/device'; import { GFXTexture } from '../../gfx/texture'; import { GFXTextureView } from '../../gfx/texture-view'; import { Vec4 } from '../../math'; +import { IBlock } from '../../renderer/core/pass'; import { Layers } from '../../scene-graph'; import { Node } from '../../scene-graph/node'; -import { IBlock } from '../pass-interface'; import { ICounterOption } from './counter'; import { PerfCounter } from './perf-counter'; diff --git a/cocos/particle/models/particle-batch-model.ts b/cocos/particle/models/particle-batch-model.ts index 8c74cb31b38..3b108a55b9e 100644 --- a/cocos/particle/models/particle-batch-model.ts +++ b/cocos/particle/models/particle-batch-model.ts @@ -27,6 +27,7 @@ * @hidden */ +import { Material } from '../../core/assets/material'; import { IRenderingSubmesh, Mesh } from '../../core/assets/mesh'; import { GFX_DRAW_INFO_SIZE, GFXBuffer, IGFXIndirectBuffer } from '../../core/gfx/buffer'; import { GFXAttributeName, GFXBufferUsageBit, GFXFormatInfos, @@ -34,7 +35,6 @@ import { GFXAttributeName, GFXBufferUsageBit, GFXFormatInfos, import { IGFXAttribute } from '../../core/gfx/input-assembler'; import { Color } from '../../core/math/color'; import { Model } from '../../core/renderer/scene/model'; -import { IMaterial } from '../../core/utils/material-interface'; export default class ParticleBatchModel extends Model { @@ -204,7 +204,7 @@ export default class ParticleBatchModel extends Model { return vBuffer; } - public setSubModelMaterial (idx: number, mat: IMaterial | null) { + public setSubModelMaterial (idx: number, mat: Material | null) { this.initLocalBindings(mat); super.setSubModelMaterial(idx, mat); } diff --git a/cocos/particle/renderer/particle-system-renderer.ts b/cocos/particle/renderer/particle-system-renderer.ts index aadc3b6bdca..c2209360bb3 100644 --- a/cocos/particle/renderer/particle-system-renderer.ts +++ b/cocos/particle/renderer/particle-system-renderer.ts @@ -6,9 +6,8 @@ import { GFXAttributeName, GFXFormat } from '../../core/gfx/define'; import { IGFXAttribute } from '../../core/gfx/input-assembler'; import { Mat4, Vec2, Vec3, Vec4 } from '../../core/math'; import { RecyclePool } from '../../core/memop'; -import { MaterialInstance } from '../../core/renderer/core/material-instance'; +import { MaterialInstance, IMaterialInstanceInfo } from '../../core/renderer/core/material-instance'; import { IDefineMap } from '../../core/renderer/core/pass-utils'; -import { IMaterial } from '../../core/utils/material-interface'; import { RenderMode, Space } from '../enum'; import ParticleBatchModel from '../models/particle-batch-model'; import Particle from '../particle'; @@ -61,6 +60,12 @@ const _vertex_attrs_mesh = [ { name: GFXAttributeName.ATTR_COLOR1, format: GFXFormat.RGBA8, isNormalized: true }, // mesh color ]; +const _matInsInfo: IMaterialInstanceInfo = { + parent: null!, + owner: null!, + subModelIdx: 0, +}; + @ccclass('cc.ParticleSystemRenderer') export default class ParticleSystemRenderer { @@ -209,8 +214,8 @@ export default class ParticleSystemRenderer { private attrs: any[]; private _vertAttrs: IGFXAttribute[] = []; private _particles: RecyclePool | null = null; - private _defaultMat: IMaterial | null = null; - private _defaultTrailMat: IMaterial | null = null; + private _defaultMat: Material | null = null; + private _defaultTrailMat: Material | null = null; constructor () { this._model = null; @@ -460,9 +465,12 @@ export default class ParticleSystemRenderer { this._particleSystem.setMaterial(null, 0); } if (this._particleSystem.sharedMaterial == null && this._defaultMat == null) { - this._defaultMat = new MaterialInstance(builtinResMgr.get('default-particle-material'), this._particleSystem); + _matInsInfo.parent = builtinResMgr.get('default-particle-material'); + _matInsInfo.owner = this._particleSystem; + _matInsInfo.subModelIdx = 0; + this._defaultMat = new MaterialInstance(_matInsInfo); } - const mat: IMaterial | null = this._particleSystem.getMaterialInstance(0) || this._defaultMat; + const mat: Material | null = this._particleSystem.getMaterialInstance(0) || this._defaultMat; if (this._particleSystem._simulationSpace === Space.World) { this._defines[CC_USE_WORLD_SPACE] = true; } else { @@ -506,7 +514,10 @@ export default class ParticleSystemRenderer { } let mat = this._particleSystem.getMaterialInstance(1); if (mat === null && this._defaultTrailMat === null) { - this._defaultTrailMat = new MaterialInstance(builtinResMgr.get('default-trail-material'), this._particleSystem); + _matInsInfo.parent = builtinResMgr.get('default-trail-material'); + _matInsInfo.owner = this._particleSystem; + _matInsInfo.subModelIdx = 1; + this._defaultTrailMat = new MaterialInstance(_matInsInfo); } if (mat === null) { mat = this._defaultTrailMat; diff --git a/cocos/ui/components/graphics-component.ts b/cocos/ui/components/graphics-component.ts index 5a34b82e4f3..cf78f7eed33 100644 --- a/cocos/ui/components/graphics-component.ts +++ b/cocos/ui/components/graphics-component.ts @@ -34,12 +34,18 @@ import { InstanceMaterialType, UIRenderComponent } from '../../core/components/u import { ccclass, executionOrder, menu, property } from '../../core/data/class-decorator'; import { director } from '../../core/director'; import { Color } from '../../core/math'; -import { MaterialInstance, Model } from '../../core/renderer'; +import { IMaterialInstanceInfo, MaterialInstance, Model } from '../../core/renderer'; import { IAssembler } from '../../core/renderer/ui/base'; import { UI } from '../../core/renderer/ui/ui'; import { LineCap, LineJoin } from '../assembler/graphics/types'; import { Impl } from '../assembler/graphics/webgl/impl'; +const _matInsInfo: IMaterialInstanceInfo = { + parent: null!, + owner: null!, + subModelIdx: 0, +}; + /** * @zh * 自定义图形类 @@ -72,7 +78,7 @@ export class GraphicsComponent extends UIRenderComponent { */ @property({ type: LineJoin, - tooltip:'两条线相交时,所创建的拐角类型', + tooltip: '两条线相交时,所创建的拐角类型', }) get lineJoin () { return this._lineJoin; @@ -93,7 +99,7 @@ export class GraphicsComponent extends UIRenderComponent { */ @property({ type: LineCap, - tooltip:'线条的结束端点样式', + tooltip: '线条的结束端点样式', }) get lineCap () { return this._lineCap; @@ -113,7 +119,7 @@ export class GraphicsComponent extends UIRenderComponent { * 线段颜色。 */ @property({ - tooltip:'笔触的颜色', + tooltip: '笔触的颜色', }) // @constget get strokeColor (): Readonly { @@ -134,7 +140,7 @@ export class GraphicsComponent extends UIRenderComponent { * 填充颜色。 */ @property({ - tooltip:'填充绘画的颜色', + tooltip: '填充绘画的颜色', }) // @constget get fillColor (): Readonly { @@ -155,7 +161,7 @@ export class GraphicsComponent extends UIRenderComponent { * 设置斜接面限制比例。 */ @property({ - tooltip:'最大斜接长度', + tooltip: '最大斜接长度', }) get miterLimit () { return this._miterLimit; @@ -211,14 +217,14 @@ export class GraphicsComponent extends UIRenderComponent { this.impl = this._assembler && (this._assembler as IAssembler).createImpl!(this); } - public onLoad() { + public onLoad () { this._sceneGetter = director.root!.ui.getRenderSceneGetter(); if (!this.model) { this.model = director.root!.createModel(Model); } } - public onEnable() { + public onEnable () { super.onEnable(); this._attachToScene(); @@ -474,10 +480,13 @@ export class GraphicsComponent extends UIRenderComponent { */ public helpInstanceMaterial () { let mat: MaterialInstance | null = null; + _matInsInfo.owner = new RenderableComponent(); if (this._sharedMaterial) { - mat = new MaterialInstance(this._sharedMaterial, new RenderableComponent()); + _matInsInfo.parent = this._sharedMaterial; + mat = new MaterialInstance(_matInsInfo); } else { - mat = new MaterialInstance(builtinResMgr.get('ui-base-material'), new RenderableComponent()); + _matInsInfo.parent = builtinResMgr.get('ui-base-material'); + mat = new MaterialInstance(_matInsInfo); mat.recompileShaders({ USE_LOCAL: true }); } @@ -488,7 +497,7 @@ export class GraphicsComponent extends UIRenderComponent { } } - protected _render(render: UI) { + protected _render (render: UI) { render.commitModel(this, this.model, this._material); } @@ -512,7 +521,7 @@ export class GraphicsComponent extends UIRenderComponent { return !!this.model && this.model.inited; } - protected _attachToScene() { + protected _attachToScene () { const scene = director.root!.ui.renderScene; if (!this.model) { return; @@ -523,7 +532,7 @@ export class GraphicsComponent extends UIRenderComponent { scene.addModel(this.model!); } - protected _detachFromScene() { + protected _detachFromScene () { if (this.model && this.model.scene) { this.model.scene.removeModel(this.model); } From 59c2ef0b66235b1aa435f29c4c29d2c99f14416e Mon Sep 17 00:00:00 2001 From: zxg <247274249@qq.com> Date: Tue, 24 Dec 2019 16:09:45 +0800 Subject: [PATCH 06/13] fix some defects --- cocos/core/3d/framework/model-component.ts | 4 +- .../core/3d/framework/renderable-component.ts | 12 ++-- cocos/core/assets/material.ts | 13 ++-- cocos/core/renderer/core/material-instance.ts | 4 +- cocos/core/renderer/core/pass-instance.ts | 31 +++++++-- cocos/core/renderer/core/pass.ts | 69 ++++++++++--------- cocos/core/renderer/ui/ui-material.ts | 2 +- 7 files changed, 84 insertions(+), 51 deletions(-) diff --git a/cocos/core/3d/framework/model-component.ts b/cocos/core/3d/framework/model-component.ts index 8234c579b5c..2293d52f9e3 100644 --- a/cocos/core/3d/framework/model-component.ts +++ b/cocos/core/3d/framework/model-component.ts @@ -268,9 +268,7 @@ export class ModelComponent extends RenderableComponent { this._model.isDynamicBatching = this._enableDynamicBatching; // should pass this in before create PSO const meshCount = this._mesh ? this._mesh.subMeshCount : 0; for (let i = 0; i < meshCount; ++i) { - // warning:这里先改成model总是使用材质实例,等model中的createPipelineState修改完后再替换成getRenderMaterial - const material = this.getMaterialInstance(i); - // const material = this.getRenderMaterial(i); + const material = this.getRenderMaterial(i); const renderingMesh = this._mesh.renderingMesh; if (renderingMesh) { const subMeshData = renderingMesh.getSubmesh(i); diff --git a/cocos/core/3d/framework/renderable-component.ts b/cocos/core/3d/framework/renderable-component.ts index 5baff269a6f..7ce0476030d 100644 --- a/cocos/core/3d/framework/renderable-component.ts +++ b/cocos/core/3d/framework/renderable-component.ts @@ -114,14 +114,18 @@ export class RenderableComponent extends Component { * @param material 材质对象 */ public setMaterial (material: Material | null, index: number) { + if (material && material instanceof MaterialInstance) { + console.error('Can\'t set a material instance to a sharedMaterial slot'); + } this._materials[index] = material; if (this._materialInstances[index]) { - if (this._materialInstances[index]!.parent !== material) { - this.getMaterialInstance(index); - this._onMaterialModified(index, material); + if (this._materialInstances[index]!.parent !== this._materials[index]) { + this._materialInstances[index]!.destroy(); + this._materialInstances[index] = null; + this._onMaterialModified(index, this._materials[index]); } } else { - this._onMaterialModified(index, material); + this._onMaterialModified(index, this._materials[index]); } } diff --git a/cocos/core/assets/material.ts b/cocos/core/assets/material.ts index 92f3f9bcd05..5dcc47adc24 100644 --- a/cocos/core/assets/material.ts +++ b/cocos/core/assets/material.ts @@ -144,8 +144,13 @@ export class Material extends Asset { return this._hash; } - get parent (): Material | null { return null; } - get owner (): RenderableComponent | null { return null; } + get parent (): Material | null { + return null; + } + + get owner (): RenderableComponent | null { + return null; + } constructor () { super(); @@ -189,7 +194,7 @@ export class Material extends Asset { * @param passIdx 要编译的 pass 索引,默认编译所有 pass。 */ public recompileShaders (overrides: IDefineMap, passIdx?: number) { - console.warn('shaders in material asset cannot be modified at runtime, please instantiate the material first'); + console.warn('Material:' + this.name + ' \'s shader cannot be modified at runtime, please use material instance.'); } /** @@ -199,7 +204,7 @@ export class Material extends Asset { * @param passIdx 要重载的 pass 索引,默认重载所有 pass。 */ public overridePipelineStates (overrides: PassOverrides, passIdx?: number) { - console.warn('pipeline states in material asset cannot be modified at runtime, please instantiate the material first'); + console.warn('Material:' + this.name + ' \'s pipeline states cannot be modified at runtime, please use material instance.'); } /** diff --git a/cocos/core/renderer/core/material-instance.ts b/cocos/core/renderer/core/material-instance.ts index 33633ee3200..9e350127e1a 100644 --- a/cocos/core/renderer/core/material-instance.ts +++ b/cocos/core/renderer/core/material-instance.ts @@ -44,11 +44,11 @@ export interface IMaterialInstanceInfo { */ export class MaterialInstance extends Material { - get parent () { + get parent (): Material | null { return this._parent; } - get owner () { + get owner (): RenderableComponent | null { return this._owner; } diff --git a/cocos/core/renderer/core/pass-instance.ts b/cocos/core/renderer/core/pass-instance.ts index 09a7a8c1255..9b9cf827367 100644 --- a/cocos/core/renderer/core/pass-instance.ts +++ b/cocos/core/renderer/core/pass-instance.ts @@ -29,9 +29,10 @@ import { IPassInfo } from '../../assets/effect-asset'; import { GFXBlendState, GFXDepthStencilState, GFXRasterizerState } from '../../gfx/pipeline-state'; +import { isBuiltinBinding } from '../../pipeline/define'; import { MaterialInstance } from './material-instance'; -import { Pass, PassOverrides } from './pass'; -import { IDefineMap } from './pass-utils'; +import { IBlock, Pass, PassOverrides } from './pass'; +import { assignDefines, IDefineMap } from './pass-utils'; export class PassInstance extends Pass { @@ -45,7 +46,27 @@ export class PassInstance extends Pass { super(parent.device); this._parent = parent; this._owner = owner; - this.initialize(this._parent); + this.resetPassInfo(this._parent); + for (const u of this._shaderInfo.blocks) { + if (isBuiltinBinding(u.binding)) { + continue; + } + const block: IBlock = this._blocks[u.binding]; + const parentBlock: IBlock = this._parent.blocks[u.binding]; + block.view.set(parentBlock.view); + block.dirty = true; + } + + for (const u of this._shaderInfo.samplers) { + if (isBuiltinBinding(u.binding)) { + continue; + } + // @ts-ignore 2466 + this._textureViews[u.binding] = this._parent._textureViews[u.binding]; + // @ts-ignore 2466 + this._samplers[u.binding] = this._parent._samplers[u.binding]; + } + this.tryCompile(); } public overridePipelineStates (original: IPassInfo, overrides: PassOverrides): void { @@ -59,7 +80,9 @@ export class PassInstance extends Pass { public tryCompile (defineOverrides?: IDefineMap) { if (defineOverrides) { - this._defines = Object.assign({}, this._defines, defineOverrides); + if (!assignDefines(this._defines, defineOverrides)) { + return false; + } } const res = super.tryCompile(); this._onStateChange(); diff --git a/cocos/core/renderer/core/pass.ts b/cocos/core/renderer/core/pass.ts index c41f7115125..76d576748c5 100644 --- a/cocos/core/renderer/core/pass.ts +++ b/cocos/core/renderer/core/pass.ts @@ -220,39 +220,7 @@ export class Pass { * 根据指定参数初始化当前 pass,shader 会在这一阶段就尝试编译。 */ public initialize (info: IPassInfoFull) { - this._idxInTech = info.idxInTech; - this._programName = info.program; - this._defines = info.defines; - this._shaderInfo = programLib.getTemplate(info.program); - this._properties = info.properties || this._properties; - // pipeline state - const device = this._device; - Pass.fillinPipelineInfo(this, info); - if (info.stateOverrides) { Pass.fillinPipelineInfo(this, info.stateOverrides); } - this._hash = Pass.getPSOHash(this); - - const blocks = this._shaderInfo.blocks; - for (let i = 0; i < blocks.length; i++) { - const { size, binding } = blocks[i]; - if (isBuiltinBinding(binding)) { continue; } - // create gfx buffer resource - _bfInfo.size = Math.ceil(size / 16) * 16; // https://bugs.chromium.org/p/chromium/issues/detail?id=988988 - this._buffers[binding] = device.createBuffer(_bfInfo); - // non-builtin UBO data pools, note that the effect compiler - // guarantees these bindings to be consecutive, starting from 0 - const buffer = new ArrayBuffer(size); - this._blocks[binding] = { buffer, dirty: false, view: new Float32Array(buffer) }; - } - // store handles - const directHandleMap = this._handleMap = this._shaderInfo.handleMap; - const indirectHandleMap: Record = {}; - for (const name in this._properties) { - const prop = this._properties[name]; - if (!prop.handleInfo) { continue; } - indirectHandleMap[name] = this.getHandle.apply(this, prop.handleInfo)!; - } - Object.assign(directHandleMap, indirectHandleMap); - + this.resetPassInfo(info); this.resetUBOs(); this.resetTextures(); this.tryCompile(); @@ -454,6 +422,41 @@ export class Pass { } } + public resetPassInfo (info: IPassInfoFull) { + this._idxInTech = info.idxInTech; + this._programName = info.program; + this._defines = info.defines; + this._shaderInfo = programLib.getTemplate(info.program); + this._properties = info.properties || this._properties; + // pipeline state + const device = this._device; + Pass.fillinPipelineInfo(this, info); + if (info.stateOverrides) { Pass.fillinPipelineInfo(this, info.stateOverrides); } + this._hash = Pass.getPSOHash(this); + + const blocks = this._shaderInfo.blocks; + for (let i = 0; i < blocks.length; i++) { + const { size, binding } = blocks[i]; + if (isBuiltinBinding(binding)) { continue; } + // create gfx buffer resource + _bfInfo.size = Math.ceil(size / 16) * 16; // https://bugs.chromium.org/p/chromium/issues/detail?id=988988 + this._buffers[binding] = device.createBuffer(_bfInfo); + // non-builtin UBO data pools, note that the effect compiler + // guarantees these bindings to be consecutive, starting from 0 + const buffer = new ArrayBuffer(size); + this._blocks[binding] = { buffer, dirty: false, view: new Float32Array(buffer) }; + } + // store handles + const directHandleMap = this._handleMap = this._shaderInfo.handleMap; + const indirectHandleMap: Record = {}; + for (const name in this._properties) { + const prop = this._properties[name]; + if (!prop.handleInfo) { continue; } + indirectHandleMap[name] = this.getHandle.apply(this, prop.handleInfo)!; + } + Object.assign(directHandleMap, indirectHandleMap); + } + /** * @zh * 重置所有 UBO 为初始默认值。 diff --git a/cocos/core/renderer/ui/ui-material.ts b/cocos/core/renderer/ui/ui-material.ts index 55a6180c0d5..a5857513196 100644 --- a/cocos/core/renderer/ui/ui-material.ts +++ b/cocos/core/renderer/ui/ui-material.ts @@ -63,7 +63,7 @@ export class UIMaterial { this._material = new Material(); - this._material.copy(info.material instanceof MaterialInstance ? info.material.parent : info.material); + this._material.copy(info.material instanceof MaterialInstance ? info.material.parent! : info.material); this._pass = this._material.passes[0]; this._pass.update(); From 48dd734b7fa18a5bf682264115d6e7d26dba182e Mon Sep 17 00:00:00 2001 From: Yun Hsiao Wu Date: Tue, 24 Dec 2019 16:42:28 +0800 Subject: [PATCH 07/13] fix batching (#7) --- cocos/core/3d/framework/model-component.ts | 170 +++++-------------- cocos/core/gfx/webgl/webgl-device.ts | 3 +- cocos/core/pipeline/forward/forward-stage.ts | 23 ++- cocos/core/renderer/core/pass-instance.ts | 4 - cocos/core/renderer/core/pass.ts | 13 +- cocos/core/renderer/scene/model.ts | 1 - 6 files changed, 58 insertions(+), 156 deletions(-) diff --git a/cocos/core/3d/framework/model-component.ts b/cocos/core/3d/framework/model-component.ts index 2293d52f9e3..cc68b20353e 100644 --- a/cocos/core/3d/framework/model-component.ts +++ b/cocos/core/3d/framework/model-component.ts @@ -61,27 +61,13 @@ const ModelShadowCastingMode = Enum({ @executeInEditMode export class ModelComponent extends RenderableComponent { - /** - * @en The mesh of the model - * @zh 模型网格。 - */ - @property({ - type: Mesh, - tooltip: '模型网格', - }) - get mesh () { - return this._mesh; - } + public static ShadowCastingMode = ModelShadowCastingMode; - set mesh (val) { - const old = this._mesh; - this._mesh = val; - this._onMeshChanged(old); - this._updateModels(); - if (this.node.activeInHierarchy) { - this._attachToScene(); - } - } + @property + protected _mesh: Mesh | null = null; + + @property + protected _shadowCastingMode = ModelShadowCastingMode.OFF; /** * @en The shadow casting mode @@ -101,72 +87,34 @@ export class ModelComponent extends RenderableComponent { } /** - * @en Does this model receive shadows? - * @zh 是否接受阴影? + * @en The mesh of the model + * @zh 模型网格。 */ - // @property - get receiveShadows () { - return this._receiveShadows; + @property({ + type: Mesh, + tooltip: '模型网格', + }) + get mesh () { + return this._mesh; } - set receiveShadows (val) { - this._receiveShadows = val; - this._updateReceiveShadow(); + set mesh (val) { + const old = this._mesh; + this._mesh = val; + this._onMeshChanged(old); + this._updateModels(); + if (this.node.activeInHierarchy) { + this._attachToScene(); + } } get model () { return this._model; } - /** - * @zh 是否启用动态合批? - */ - @property({ - tooltip: '是否启用动态合批', - }) - set enableDynamicBatching (enable: boolean) { - if (this._enableDynamicBatching === enable) { return; } - this._enableDynamicBatching = enable; - if (this._mesh) { - if (enable) { this._mesh.createFlatBuffers(); } - else { this._mesh.destroyFlatBuffers(); } - } - if (this._model) { - this._model.isDynamicBatching = enable; - this._model.onGlobalPipelineStateChanged(); // update material - for (let i = 0; i < this._model.subModels.length; ++i) { - const subModel = this._model.subModels[i]; - for (let p = 0; p < subModel.passes.length; ++p) { - const pass = subModel.passes[p]; - if (enable) { pass.createBatchedBuffer(); } - else { pass.clearBatchedBuffer(); } - } - } - } - } - - get enableDynamicBatching (): boolean { - return this._enableDynamicBatching; - } - - public static ShadowCastingMode = ModelShadowCastingMode; - protected _modelType: typeof Model; - protected _model: Model | null = null; - @property - protected _enableDynamicBatching = false; - - @property - protected _mesh: Mesh | null = null; - - @property - private _shadowCastingMode = ModelShadowCastingMode.OFF; - - @property - private _receiveShadows = false; - constructor () { super(); this._modelType = Model; @@ -175,7 +123,6 @@ export class ModelComponent extends RenderableComponent { public onLoad () { this._updateModels(); this._updateCastShadow(); - this._updateReceiveShadow(); } public onEnable () { @@ -217,21 +164,6 @@ export class ModelComponent extends RenderableComponent { if (this._model) { this._model.createBoundingShape(this._mesh.minPosition, this._mesh.maxPosition); this._model.enabled = true; - - if (this._enableDynamicBatching) { - if (!this._mesh.hasFlatBuffers) { - this._mesh.createFlatBuffers(); - } - for (let i = 0; i < this._model.subModels.length; ++i) { - const subModel = this._model.subModels[i]; - for (let p = 0; p < subModel.passes.length; ++p) { - const pass = subModel.passes[p]; - if (!pass.batchedBuffer) { - pass.createBatchedBuffer(); - } - } - } - } } } @@ -261,11 +193,10 @@ export class ModelComponent extends RenderableComponent { } protected _updateModelParams () { - if (!this._mesh || !this._model) { - return; - } + if (!this._mesh || !this._model) { return; } this.node.hasChangedFlags = this._model.transform.hasChangedFlags = TransformBit.POSITION; - this._model.isDynamicBatching = this._enableDynamicBatching; // should pass this in before create PSO + const batching = this._model.isDynamicBatching = this._isBatchingEnabled(); + if (batching) { this._mesh.createFlatBuffers(); } const meshCount = this._mesh ? this._mesh.subMeshCount : 0; for (let i = 0; i < meshCount; ++i) { const material = this.getRenderMaterial(i); @@ -280,36 +211,22 @@ export class ModelComponent extends RenderableComponent { } protected _onMaterialModified (idx: number, material: Material | null) { - if (this._model == null || !this._model.inited) { - return; - } + if (!this._model || !this._model.inited) { return; } this._onRebuildPSO(idx, material || this._getBuiltinMaterial()); - - if (this._enableDynamicBatching) { - if (material) { - for (let p = 0; p < material.passes.length; ++p) { - const pass = material.passes[p]; - if (!pass.batchedBuffer) { - pass.createBatchedBuffer(); - } - } - } - } } protected _onRebuildPSO (idx: number, material: Material) { - if (this._model && this._model.inited) { - this._model.setSubModelMaterial(idx, material); - } + if (!this._model || !this._model.inited) { return; } + const batching = this._model.isDynamicBatching = this._isBatchingEnabled(); + if (batching && this._mesh) { this._mesh.createFlatBuffers(); } + this._model.setSubModelMaterial(idx, material); } protected _onMeshChanged (old: Mesh | null) { } protected _clearMaterials () { - if (this._model == null) { - return; - } + if (!this._model) { return; } for (let i = 0; i < this._model.subModelNum; ++i) { this._onMaterialModified(i, null); } @@ -320,10 +237,9 @@ export class ModelComponent extends RenderableComponent { return builtinResMgr.get('missing-material'); } - protected _onVisiblityChange (val) { - if (this._model) { - this._model.visFlags = val; - } + protected _onVisiblityChange (val: number) { + if (!this._model) { return; } + this._model.visFlags = val; } private _updateCastShadow () { @@ -337,15 +253,15 @@ export class ModelComponent extends RenderableComponent { } } - private _updateReceiveShadow () { - if (!this.enabledInHierarchy || !this._model) { - return; + private _isBatchingEnabled () { + if (!this._model || !this._mesh) { return false; } + for (let i = 0; i < this._model.subModels.length; ++i) { + const subModel = this._model.subModels[i]; + for (let p = 0; p < subModel.passes.length; ++p) { + const pass = subModel.passes[p]; + if (pass.batchedBuffer) { return true; } + } } - // for (let i = 0; i < this._model.subModelNum; ++i) { - // const subModel = this._model.getSubModel(i); - // if (subModel._defines['CC_USE_SHADOW_MAP'] != undefined) { - // this.getMaterial(i).define('CC_USE_SHADOW_MAP', this._receiveShadows); - // } - // } + return false; } } diff --git a/cocos/core/gfx/webgl/webgl-device.ts b/cocos/core/gfx/webgl/webgl-device.ts index 97003477d5a..7a7b84c03f2 100644 --- a/cocos/core/gfx/webgl/webgl-device.ts +++ b/cocos/core/gfx/webgl/webgl-device.ts @@ -375,7 +375,8 @@ export class WebGLGFXDevice extends GFXDevice { if (this._OES_vertex_array_object) { if (CC_RUNTIME_BASED) { // @ts-ignore - if (typeof loadRuntime === 'function' && typeof loadRuntime().getFeature === 'function' && loadRuntime().getFeature("webgl.extensions.oes_vertex_array_object.revision") > 0 ) { + if (typeof loadRuntime === 'function' && typeof loadRuntime().getFeature === 'function' && loadRuntime() + .getFeature('webgl.extensions.oes_vertex_array_object.revision') > 0 ) { this._useVAO = true; } } else if ((sys.platform !== sys.WECHAT_GAME || sys.os !== sys.OS_IOS)) { this._useVAO = true; } diff --git a/cocos/core/pipeline/forward/forward-stage.ts b/cocos/core/pipeline/forward/forward-stage.ts index 595dd5ca84a..736e8ccc4ff 100644 --- a/cocos/core/pipeline/forward/forward-stage.ts +++ b/cocos/core/pipeline/forward/forward-stage.ts @@ -97,28 +97,27 @@ export class ForwardStage extends RenderStage { for (let i = 0; i < renderObjects.length; ++i) { const ro = renderObjects[i]; if (ro.model.isDynamicBatching) { - for (let m = 0; m < ro.model.subModels.length; ++m) { + for (let m = 0; m < ro.model.subModelNum; ++m) { const subModel = ro.model.subModels[m]; const passes = subModel.passes; for (let p = 0; p < passes.length; ++p) { - const pass = subModel.passes[p]; + const pass = passes[p]; + const pso = subModel.psos![p]; if (pass.batchedBuffer) { - const pso = subModel.psos![p]; - const isTransparent = pso.blendState.targets[0].blend; - if (!isTransparent) { - pass.batchedBuffer.merge(subModel, ro, pso); - this._opaqueBatchedQueue.queue.add(pass.batchedBuffer); - } else { - this._renderQueues[1].insertRenderPass(ro, m, p); + pass.batchedBuffer.merge(subModel, ro, pso); + this._opaqueBatchedQueue.queue.add(pass.batchedBuffer); + } else { + for (let k = 0; k < this._renderQueues.length; k++) { + this._renderQueues[k].insertRenderPass(ro, m, p); } } } } } else { - for (let l = 0; l < ro.model.subModelNum; l++) { - for (let j = 0; j < ro.model.getSubModel(l).passes.length; j++) { + for (let m = 0; m < ro.model.subModelNum; m++) { + for (let p = 0; p < ro.model.getSubModel(m).passes.length; p++) { for (let k = 0; k < this._renderQueues.length; k++) { - this._renderQueues[k].insertRenderPass(ro, l, j); + this._renderQueues[k].insertRenderPass(ro, m, p); } } } diff --git a/cocos/core/renderer/core/pass-instance.ts b/cocos/core/renderer/core/pass-instance.ts index 9b9cf827367..3bd3ff14b9f 100644 --- a/cocos/core/renderer/core/pass-instance.ts +++ b/cocos/core/renderer/core/pass-instance.ts @@ -93,10 +93,6 @@ export class PassInstance extends Pass { console.warn('pass instance have no batched buffer.'); } - public clearBatchedBuffer () { - console.warn('pass instance have no batched buffer.'); - } - public beginChangeStatesSilently () { this._dontNotify = true; } diff --git a/cocos/core/renderer/core/pass.ts b/cocos/core/renderer/core/pass.ts index 76d576748c5..7fff4b71be6 100644 --- a/cocos/core/renderer/core/pass.ts +++ b/cocos/core/renderer/core/pass.ts @@ -508,6 +508,7 @@ export class Pass { * @param defineOverrides shader 预处理宏定义重载 */ public tryCompile () { + if (this._defines.USE_BATCHING) { this.createBatchedBuffer(); } const pipeline = (cc.director.root as Root).pipeline; if (!pipeline) { return null; } this._renderPass = pipeline.getRenderPass(this._stage); @@ -591,21 +592,11 @@ export class Pass { * 创建合批缓冲。 */ public createBatchedBuffer () { - if (!this._batchedBuffer) { + if (!this._batchedBuffer && !this._bs.targets[0].blend) { this._batchedBuffer = new BatchedBuffer(this); } } - /** - * @zh - * 清空合批缓冲。 - */ - public clearBatchedBuffer () { - if (this._batchedBuffer) { - this._batchedBuffer.clearUBO(); - } - } - // internal use public beginChangeStatesSilently () {} public endChangeStatesSilently () {} diff --git a/cocos/core/renderer/scene/model.ts b/cocos/core/renderer/scene/model.ts index eb422548d47..aa5c84ba7e9 100644 --- a/cocos/core/renderer/scene/model.ts +++ b/cocos/core/renderer/scene/model.ts @@ -358,7 +358,6 @@ export class Model { } protected createPipelineState (pass: Pass) { - if (pass.blendState.targets[0].blend) { this._isDynamicBatching = false; } const pso = pass.createPipelineState()!; pso.pipelineLayout.layouts[0].bindBuffer(UBOLocal.BLOCK.binding, this._localBindings.get(UBOLocal.BLOCK.name)!.buffer!); if (this._localBindings.has(UBOForwardLight.BLOCK.name)) { From ccd98a8689b67fba3e9107138c11e0fcb9379189 Mon Sep 17 00:00:00 2001 From: Yun Hsiao Wu Date: Tue, 24 Dec 2019 16:57:34 +0800 Subject: [PATCH 08/13] better format (#8) --- cocos/core/assets/material.ts | 4 +- cocos/core/renderer/core/material-instance.ts | 234 +++++++++--------- cocos/core/renderer/core/pass-instance.ts | 209 ++++++++-------- cocos/core/renderer/core/pass.ts | 74 +++--- 4 files changed, 257 insertions(+), 264 deletions(-) diff --git a/cocos/core/assets/material.ts b/cocos/core/assets/material.ts index 5dcc47adc24..42a2df4eabd 100644 --- a/cocos/core/assets/material.ts +++ b/cocos/core/assets/material.ts @@ -194,7 +194,7 @@ export class Material extends Asset { * @param passIdx 要编译的 pass 索引,默认编译所有 pass。 */ public recompileShaders (overrides: IDefineMap, passIdx?: number) { - console.warn('Material:' + this.name + ' \'s shader cannot be modified at runtime, please use material instance.'); + console.warn('Shaders in material asset \'' + this.name + '\' cannot be modified at runtime, please instantiate the material first.'); } /** @@ -204,7 +204,7 @@ export class Material extends Asset { * @param passIdx 要重载的 pass 索引,默认重载所有 pass。 */ public overridePipelineStates (overrides: PassOverrides, passIdx?: number) { - console.warn('Material:' + this.name + ' \'s pipeline states cannot be modified at runtime, please use material instance.'); + console.warn('Pipeline states in material asset \'' + this.name + '\' cannot be modified at runtime, please instantiate the material first.'); } /** diff --git a/cocos/core/renderer/core/material-instance.ts b/cocos/core/renderer/core/material-instance.ts index 9e350127e1a..0b2d8053d19 100644 --- a/cocos/core/renderer/core/material-instance.ts +++ b/cocos/core/renderer/core/material-instance.ts @@ -1,117 +1,117 @@ -/* - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos.com - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated engine source code (the "Software"), a limited, - worldwide, royalty-free, non-assignable, revocable and non-exclusive license - to use Cocos Creator solely to develop games on your target platforms. You shall - not use Cocos Creator software for developing other software or tools that's - used for developing games. You are not granted to publish, distribute, - sublicense, and/or sell copies of Cocos Creator. - - The software or tools in this License Agreement are licensed, not sold. - Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -/** - * @category material - */ - -import { RenderableComponent } from '../../3d/framework/renderable-component'; -import { Material } from '../../assets/material'; -import { PassInstance } from './pass-instance'; -import { IDefineMap } from './pass-utils'; - -export interface IMaterialInstanceInfo { - parent: Material; - owner: RenderableComponent; - subModelIdx: number; -} - -/** - * @zh - * 材质实例,当有材质修改需求时,根据材质资源创建的,可任意定制的实例。 - */ -export class MaterialInstance extends Material { - - get parent (): Material | null { - return this._parent; - } - - get owner (): RenderableComponent | null { - return this._owner; - } - - protected _passes: PassInstance[] = []; - - private _parent: Material; - private _owner: RenderableComponent; - private _subModelIdx = 0; - - constructor (info: IMaterialInstanceInfo) { - super(); - this._parent = info.parent; - this._owner = info.owner; - this._subModelIdx = info.subModelIdx; - this.copy(this._parent); - } - - public recompileShaders (overrides: IDefineMap, passIdx?: number): void { - if (!this._passes || !this.effectAsset) { return; } - if (passIdx === undefined) { - for (const pass of this._passes) { - pass.tryCompile(overrides); - } - } else { - this._passes[passIdx].tryCompile(overrides); - } - } - - public overridePipelineStates (overrides: any, passIdx?: number): void { - if (!this._passes || !this.effectAsset) { return; } - const passInfos = this.effectAsset.techniques[this.technique].passes; - if (passIdx === undefined) { - for (let i = 0; i < this._passes.length; i++) { - const pass = this._passes[i]; - this._states[i] = overrides; - pass.overridePipelineStates(passInfos[pass.idxInTech], overrides); - } - } else { - this._states[passIdx] = overrides; - this._passes[passIdx].overridePipelineStates(passInfos[passIdx], overrides); - } - } - - public destroy () { - this._doDestroy(); - return true; - } - - public onPassStateChange (dontNotify: boolean) { - this._hash = Material.getHash(this); - if (!dontNotify) { - // @ts-ignore - this.owner._onRebuildPSO(this._subModelIdx, this); - } - } - - protected _createPasses () { - const passes: PassInstance[] = []; - const parentPasses = this._parent.passes; - if (!parentPasses) { return passes; } - for (let k = 0; k < parentPasses.length; ++k) { - passes.push(new PassInstance(parentPasses[k], this)); - } - return passes; - } -} +/* + Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + + http://www.cocos.com + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated engine source code (the "Software"), a limited, + worldwide, royalty-free, non-assignable, revocable and non-exclusive license + to use Cocos Creator solely to develop games on your target platforms. You shall + not use Cocos Creator software for developing other software or tools that's + used for developing games. You are not granted to publish, distribute, + sublicense, and/or sell copies of Cocos Creator. + + The software or tools in this License Agreement are licensed, not sold. + Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/** + * @category material + */ + +import { RenderableComponent } from '../../3d/framework/renderable-component'; +import { Material } from '../../assets/material'; +import { PassInstance } from './pass-instance'; +import { IDefineMap } from './pass-utils'; + +export interface IMaterialInstanceInfo { + parent: Material; + owner: RenderableComponent; + subModelIdx: number; +} + +/** + * @zh + * 材质实例,当有材质修改需求时,根据材质资源创建的,可任意定制的实例。 + */ +export class MaterialInstance extends Material { + + get parent () { + return this._parent; + } + + get owner () { + return this._owner; + } + + protected _passes: PassInstance[] = []; + + private _parent: Material; + private _owner: RenderableComponent; + private _subModelIdx = 0; + + constructor (info: IMaterialInstanceInfo) { + super(); + this._parent = info.parent; + this._owner = info.owner; + this._subModelIdx = info.subModelIdx; + this.copy(this._parent); + } + + public recompileShaders (overrides: IDefineMap, passIdx?: number): void { + if (!this._passes || !this.effectAsset) { return; } + if (passIdx === undefined) { + for (const pass of this._passes) { + pass.tryCompile(overrides); + } + } else { + this._passes[passIdx].tryCompile(overrides); + } + } + + public overridePipelineStates (overrides: any, passIdx?: number): void { + if (!this._passes || !this.effectAsset) { return; } + const passInfos = this.effectAsset.techniques[this.technique].passes; + if (passIdx === undefined) { + for (let i = 0; i < this._passes.length; i++) { + const pass = this._passes[i]; + this._states[i] = overrides; + pass.overridePipelineStates(passInfos[pass.idxInTech], overrides); + } + } else { + this._states[passIdx] = overrides; + this._passes[passIdx].overridePipelineStates(passInfos[passIdx], overrides); + } + } + + public destroy () { + this._doDestroy(); + return true; + } + + public onPassStateChange (dontNotify: boolean) { + this._hash = Material.getHash(this); + if (!dontNotify) { + // @ts-ignore + this.owner._onRebuildPSO(this._subModelIdx, this); + } + } + + protected _createPasses () { + const passes: PassInstance[] = []; + const parentPasses = this._parent.passes; + if (!parentPasses) { return passes; } + for (let k = 0; k < parentPasses.length; ++k) { + passes.push(new PassInstance(parentPasses[k], this)); + } + return passes; + } +} diff --git a/cocos/core/renderer/core/pass-instance.ts b/cocos/core/renderer/core/pass-instance.ts index 3bd3ff14b9f..14bf6cc547b 100644 --- a/cocos/core/renderer/core/pass-instance.ts +++ b/cocos/core/renderer/core/pass-instance.ts @@ -1,108 +1,101 @@ -/* - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos.com - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated engine source code (the "Software"), a limited, - worldwide, royalty-free, non-assignable, revocable and non-exclusive license - to use Cocos Creator solely to develop games on your target platforms. You shall - not use Cocos Creator software for developing other software or tools that's - used for developing games. You are not granted to publish, distribute, - sublicense, and/or sell copies of Cocos Creator. - - The software or tools in this License Agreement are licensed, not sold. - Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -/** - * @category material - */ - -import { IPassInfo } from '../../assets/effect-asset'; -import { GFXBlendState, GFXDepthStencilState, GFXRasterizerState } from '../../gfx/pipeline-state'; -import { isBuiltinBinding } from '../../pipeline/define'; -import { MaterialInstance } from './material-instance'; -import { IBlock, Pass, PassOverrides } from './pass'; -import { assignDefines, IDefineMap } from './pass-utils'; - -export class PassInstance extends Pass { - - get parent () { return this._parent; } - - private _parent: Pass; - private _owner: MaterialInstance; - private _dontNotify = false; - - constructor (parent: Pass, owner: MaterialInstance) { - super(parent.device); - this._parent = parent; - this._owner = owner; - this.resetPassInfo(this._parent); - for (const u of this._shaderInfo.blocks) { - if (isBuiltinBinding(u.binding)) { - continue; - } - const block: IBlock = this._blocks[u.binding]; - const parentBlock: IBlock = this._parent.blocks[u.binding]; - block.view.set(parentBlock.view); - block.dirty = true; - } - - for (const u of this._shaderInfo.samplers) { - if (isBuiltinBinding(u.binding)) { - continue; - } - // @ts-ignore 2466 - this._textureViews[u.binding] = this._parent._textureViews[u.binding]; - // @ts-ignore 2466 - this._samplers[u.binding] = this._parent._samplers[u.binding]; - } - this.tryCompile(); - } - - public overridePipelineStates (original: IPassInfo, overrides: PassOverrides): void { - this._bs = new GFXBlendState(); - this._dss = new GFXDepthStencilState(); - this._rs = new GFXRasterizerState(); - Pass.fillinPipelineInfo(this as unknown as Pass, original); - Pass.fillinPipelineInfo(this as unknown as Pass, overrides); - this._onStateChange(); - } - - public tryCompile (defineOverrides?: IDefineMap) { - if (defineOverrides) { - if (!assignDefines(this._defines, defineOverrides)) { - return false; - } - } - const res = super.tryCompile(); - this._onStateChange(); - return res; - } - - public createBatchedBuffer () { - console.warn('pass instance have no batched buffer.'); - } - - public beginChangeStatesSilently () { - this._dontNotify = true; - } - - public endChangeStatesSilently () { - this._dontNotify = false; - } - - protected _onStateChange () { - this._hash = Pass.getPSOHash(this); - this._owner.onPassStateChange(this._dontNotify); - } -} +/* + Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + + http://www.cocos.com + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated engine source code (the "Software"), a limited, + worldwide, royalty-free, non-assignable, revocable and non-exclusive license + to use Cocos Creator solely to develop games on your target platforms. You shall + not use Cocos Creator software for developing other software or tools that's + used for developing games. You are not granted to publish, distribute, + sublicense, and/or sell copies of Cocos Creator. + + The software or tools in this License Agreement are licensed, not sold. + Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/** + * @category material + */ + +import { IPassInfo } from '../../assets/effect-asset'; +import { GFXBlendState, GFXDepthStencilState, GFXRasterizerState } from '../../gfx/pipeline-state'; +import { isBuiltinBinding } from '../../pipeline/define'; +import { MaterialInstance } from './material-instance'; +import { Pass, PassOverrides } from './pass'; +import { assignDefines, IDefineMap } from './pass-utils'; + +export class PassInstance extends Pass { + + get parent () { return this._parent; } + + private _parent: Pass; + private _owner: MaterialInstance; + private _dontNotify = false; + + constructor (parent: Pass, owner: MaterialInstance) { + super(parent.device); + this._parent = parent; + this._owner = owner; + this._doInit(this._parent); + this._defines = Object.assign({}, parent.defines); // defines may change now + for (const u of this._shaderInfo.blocks) { + if (isBuiltinBinding(u.binding)) { continue; } + const block = this._blocks[u.binding]; + const parentBlock = this._parent.blocks[u.binding]; + block.view.set(parentBlock.view); + block.dirty = true; + } + for (const u of this._shaderInfo.samplers) { + if (isBuiltinBinding(u.binding)) { continue; } + this._textureViews[u.binding] = (this._parent as PassInstance)._textureViews[u.binding]; // TS2446 + this._samplers[u.binding] = (this._parent as PassInstance)._samplers[u.binding]; // TS2446 + } + } + + public overridePipelineStates (original: IPassInfo, overrides: PassOverrides): void { + this._bs = new GFXBlendState(); + this._dss = new GFXDepthStencilState(); + this._rs = new GFXRasterizerState(); + Pass.fillinPipelineInfo(this, original); + Pass.fillinPipelineInfo(this, overrides); + this._onStateChange(); + } + + public tryCompile (defineOverrides?: IDefineMap) { + if (defineOverrides) { + if (!assignDefines(this._defines, defineOverrides)) { + return false; + } + } + const res = super.tryCompile(); + this._onStateChange(); + return res; + } + + public createBatchedBuffer () { + console.warn('pass instance have no batched buffer.'); + } + + public beginChangeStatesSilently () { + this._dontNotify = true; + } + + public endChangeStatesSilently () { + this._dontNotify = false; + } + + protected _onStateChange () { + this._hash = Pass.getPSOHash(this); + this._owner.onPassStateChange(this._dontNotify); + } +} diff --git a/cocos/core/renderer/core/pass.ts b/cocos/core/renderer/core/pass.ts index 7fff4b71be6..d62759d8123 100644 --- a/cocos/core/renderer/core/pass.ts +++ b/cocos/core/renderer/core/pass.ts @@ -220,10 +220,9 @@ export class Pass { * 根据指定参数初始化当前 pass,shader 会在这一阶段就尝试编译。 */ public initialize (info: IPassInfoFull) { - this.resetPassInfo(info); + this._doInit(info); this.resetUBOs(); this.resetTextures(); - this.tryCompile(); } /** @@ -422,41 +421,6 @@ export class Pass { } } - public resetPassInfo (info: IPassInfoFull) { - this._idxInTech = info.idxInTech; - this._programName = info.program; - this._defines = info.defines; - this._shaderInfo = programLib.getTemplate(info.program); - this._properties = info.properties || this._properties; - // pipeline state - const device = this._device; - Pass.fillinPipelineInfo(this, info); - if (info.stateOverrides) { Pass.fillinPipelineInfo(this, info.stateOverrides); } - this._hash = Pass.getPSOHash(this); - - const blocks = this._shaderInfo.blocks; - for (let i = 0; i < blocks.length; i++) { - const { size, binding } = blocks[i]; - if (isBuiltinBinding(binding)) { continue; } - // create gfx buffer resource - _bfInfo.size = Math.ceil(size / 16) * 16; // https://bugs.chromium.org/p/chromium/issues/detail?id=988988 - this._buffers[binding] = device.createBuffer(_bfInfo); - // non-builtin UBO data pools, note that the effect compiler - // guarantees these bindings to be consecutive, starting from 0 - const buffer = new ArrayBuffer(size); - this._blocks[binding] = { buffer, dirty: false, view: new Float32Array(buffer) }; - } - // store handles - const directHandleMap = this._handleMap = this._shaderInfo.handleMap; - const indirectHandleMap: Record = {}; - for (const name in this._properties) { - const prop = this._properties[name]; - if (!prop.handleInfo) { continue; } - indirectHandleMap[name] = this.getHandle.apply(this, prop.handleInfo)!; - } - Object.assign(directHandleMap, indirectHandleMap); - } - /** * @zh * 重置所有 UBO 为初始默认值。 @@ -601,6 +565,42 @@ export class Pass { public beginChangeStatesSilently () {} public endChangeStatesSilently () {} + protected _doInit (info: IPassInfoFull) { + this._idxInTech = info.idxInTech; + this._programName = info.program; + this._defines = info.defines; + this._shaderInfo = programLib.getTemplate(info.program); + this._properties = info.properties || this._properties; + // pipeline state + const device = this._device; + Pass.fillinPipelineInfo(this, info); + if (info.stateOverrides) { Pass.fillinPipelineInfo(this, info.stateOverrides); } + this._hash = Pass.getPSOHash(this); + + const blocks = this._shaderInfo.blocks; + for (let i = 0; i < blocks.length; i++) { + const { size, binding } = blocks[i]; + if (isBuiltinBinding(binding)) { continue; } + // create gfx buffer resource + _bfInfo.size = Math.ceil(size / 16) * 16; // https://bugs.chromium.org/p/chromium/issues/detail?id=988988 + this._buffers[binding] = device.createBuffer(_bfInfo); + // non-builtin UBO data pools, note that the effect compiler + // guarantees these bindings to be consecutive, starting from 0 + const buffer = new ArrayBuffer(size); + this._blocks[binding] = { buffer, dirty: false, view: new Float32Array(buffer) }; + } + // store handles + const directHandleMap = this._handleMap = this._shaderInfo.handleMap; + const indirectHandleMap: Record = {}; + for (const name in this._properties) { + const prop = this._properties[name]; + if (!prop.handleInfo) { continue; } + indirectHandleMap[name] = this.getHandle.apply(this, prop.handleInfo)!; + } + Object.assign(directHandleMap, indirectHandleMap); + this.tryCompile(); + } + // states get priority () { return this._priority; } get primitive () { return this._primitive; } From 1881339e75b7471cfbd206f8aeeb4d1e49e97f55 Mon Sep 17 00:00:00 2001 From: zxg <247274249@qq.com> Date: Tue, 24 Dec 2019 17:00:22 +0800 Subject: [PATCH 09/13] fix --- cocos/core/renderer/core/pass.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cocos/core/renderer/core/pass.ts b/cocos/core/renderer/core/pass.ts index d62759d8123..4ff54e5ba36 100644 --- a/cocos/core/renderer/core/pass.ts +++ b/cocos/core/renderer/core/pass.ts @@ -556,8 +556,12 @@ export class Pass { * 创建合批缓冲。 */ public createBatchedBuffer () { - if (!this._batchedBuffer && !this._bs.targets[0].blend) { - this._batchedBuffer = new BatchedBuffer(this); + if (!this._batchedBuffer) { + if (this._bs.targets[0].blend) { + console.error('Transparent pass(' + this.program + ') can\'t use dynamic batching!'); + } else { + this._batchedBuffer = new BatchedBuffer(this); + } } } From 0e2806f037560c2eba9253f6b968f6ef0e2febcd Mon Sep 17 00:00:00 2001 From: Yun Hsiao Wu Date: Tue, 24 Dec 2019 17:44:47 +0800 Subject: [PATCH 10/13] fix batching & skybox (#9) --- cocos/core/3d/framework/model-component.ts | 9 +++++---- cocos/core/3d/framework/renderable-component.ts | 10 +++++----- cocos/core/assets/mesh.ts | 4 ++-- cocos/core/renderer/core/material-instance.ts | 14 +++++++------- cocos/core/renderer/scene/skybox.ts | 6 ++++-- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/cocos/core/3d/framework/model-component.ts b/cocos/core/3d/framework/model-component.ts index cc68b20353e..70a9cac7660 100644 --- a/cocos/core/3d/framework/model-component.ts +++ b/cocos/core/3d/framework/model-component.ts @@ -255,10 +255,11 @@ export class ModelComponent extends RenderableComponent { private _isBatchingEnabled () { if (!this._model || !this._mesh) { return false; } - for (let i = 0; i < this._model.subModels.length; ++i) { - const subModel = this._model.subModels[i]; - for (let p = 0; p < subModel.passes.length; ++p) { - const pass = subModel.passes[p]; + for (let i = 0; i < this._materials.length; ++i) { + const mat = this._materials[i]; + if (!mat) { continue; } + for (let p = 0; p < mat.passes.length; ++p) { + const pass = mat.passes[p]; if (pass.batchedBuffer) { return true; } } } diff --git a/cocos/core/3d/framework/renderable-component.ts b/cocos/core/3d/framework/renderable-component.ts index 7ce0476030d..21f088a0d60 100644 --- a/cocos/core/3d/framework/renderable-component.ts +++ b/cocos/core/3d/framework/renderable-component.ts @@ -66,11 +66,11 @@ export class RenderableComponent extends Component { * @en The material of the model * @zh 模型材质。 */ - @property({ - type: Material, - visible: false, - animatable: true, - }) + // @property({ + // type: Material, + // visible: false, + // animatable: true, + // }) get materials () { for (let i = 0; i < this._materials.length; i++) { this._materialInstances[i] = this.getMaterialInstance(i) as MaterialInstance; diff --git a/cocos/core/assets/mesh.ts b/cocos/core/assets/mesh.ts index 46895c7796a..4f01dc79e63 100644 --- a/cocos/core/assets/mesh.ts +++ b/cocos/core/assets/mesh.ts @@ -974,7 +974,7 @@ export class Mesh extends Asset { * 生成平铺的缓冲(用于动态合批)。 */ public createFlatBuffers (): boolean { - if (this._renderingMesh && !this._hasFlatBuffers) { + if (!this._hasFlatBuffers) { const gfxDevice: GFXDevice = cc.director.root!.device; let idxCount = 0; @@ -982,7 +982,7 @@ export class Mesh extends Asset { let ibView: Uint8Array | Uint16Array | Uint32Array; for (let i = 0; i < this._struct.primitives.length; ++i) { const prim = this._struct.primitives[i]; - const subMesh = this._renderingMesh.subMeshes[i]; + const subMesh = this.renderingMesh.subMeshes[i]; if (prim.indexView) { idxCount = prim.indexView.count; } diff --git a/cocos/core/renderer/core/material-instance.ts b/cocos/core/renderer/core/material-instance.ts index 0b2d8053d19..73867152011 100644 --- a/cocos/core/renderer/core/material-instance.ts +++ b/cocos/core/renderer/core/material-instance.ts @@ -34,8 +34,8 @@ import { IDefineMap } from './pass-utils'; export interface IMaterialInstanceInfo { parent: Material; - owner: RenderableComponent; - subModelIdx: number; + owner?: RenderableComponent; + subModelIdx?: number; } /** @@ -55,14 +55,14 @@ export class MaterialInstance extends Material { protected _passes: PassInstance[] = []; private _parent: Material; - private _owner: RenderableComponent; + private _owner: RenderableComponent | null; private _subModelIdx = 0; constructor (info: IMaterialInstanceInfo) { super(); this._parent = info.parent; - this._owner = info.owner; - this._subModelIdx = info.subModelIdx; + this._owner = info.owner || null; + this._subModelIdx = info.subModelIdx || 0; this.copy(this._parent); } @@ -99,9 +99,9 @@ export class MaterialInstance extends Material { public onPassStateChange (dontNotify: boolean) { this._hash = Material.getHash(this); - if (!dontNotify) { + if (!dontNotify && this._owner) { // @ts-ignore - this.owner._onRebuildPSO(this._subModelIdx, this); + this._owner._onRebuildPSO(this._subModelIdx, this); } } diff --git a/cocos/core/renderer/scene/skybox.ts b/cocos/core/renderer/scene/skybox.ts index 1c427467b74..48a94f4e86e 100644 --- a/cocos/core/renderer/scene/skybox.ts +++ b/cocos/core/renderer/scene/skybox.ts @@ -5,6 +5,7 @@ import { Mesh } from '../../assets/mesh'; import { TextureCube } from '../../assets/texture-cube'; import { IInternalBindingInst, UNIFORM_ENVIRONMENT } from '../../pipeline/define'; import { box } from '../../primitive'; +import { MaterialInstance } from '../core/material-instance'; import { samplerLib } from '../core/sampler-lib'; import { Model } from './model'; import { RenderScene } from './render-scene'; @@ -55,8 +56,9 @@ export class Skybox extends Model { this._scene = scene; this._globalBinding = this._scene.root.pipeline.globalBindings.get(UNIFORM_ENVIRONMENT.name)!; if (!skybox_material) { - skybox_material = new Material(); - skybox_material.initialize({ effectName: 'pipeline/skybox', defines: { USE_RGBE_CUBEMAP: this._isRGBE } }); + const mat = new Material(); + mat.initialize({ effectName: 'pipeline/skybox', defines: { USE_RGBE_CUBEMAP: this._isRGBE } }); + skybox_material = new MaterialInstance({ parent: mat }); } if (!skybox_mesh) { skybox_mesh = createMesh(box({ width: 2, height: 2, length: 2 })); } this.initSubModel(0, skybox_mesh.renderingMesh.getSubmesh(0), skybox_material); From 9d17374e46778dd6e156332b779cfb498f87e606 Mon Sep 17 00:00:00 2001 From: Yun Hsiao Wu Date: Tue, 24 Dec 2019 18:25:48 +0800 Subject: [PATCH 11/13] fix skinning (#10) --- cocos/core/3d/builtin/effects.ts | 27 +++++++++++-------------- cocos/core/renderer/core/program-lib.ts | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/cocos/core/3d/builtin/effects.ts b/cocos/core/3d/builtin/effects.ts index c2b50159565..cc204639aaa 100644 --- a/cocos/core/3d/builtin/effects.ts +++ b/cocos/core/3d/builtin/effects.ts @@ -163,20 +163,19 @@ export default [ "shaders": [ { "name": "builtin-standard|standard-vs:vert|standard-fs:frag", - "hash": 4276757126, + "hash": 603742667, "glsl3": { - "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec4 a_tangent;\n#if USE_SKINNING\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nuniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\n#if USE_VERTEX_COLOR\n in vec3 a_color;\n out vec3 v_color;\n#endif\nout vec3 v_position;\nout vec3 v_normal;\n#if USE_NORMAL_MAP\n out vec3 v_tangent;\n out vec3 v_bitangent;\n#endif\nin vec2 a_texCoord;\nout vec2 v_uv;\nin vec2 a_texCoord1;\nout vec2 v_uv1;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorldIT * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec4 a_tangent;\n#if USE_SKINNING\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nuniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\n#if USE_VERTEX_COLOR\n in vec3 a_color;\n out vec3 v_color;\n#endif\nout vec3 v_position;\nout vec3 v_normal;\n#if USE_NORMAL_MAP\n out vec3 v_tangent;\n out vec3 v_bitangent;\n#endif\nin vec2 a_texCoord;\nout vec2 v_uv;\nin vec2 a_texCoord1;\nout vec2 v_uv1;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorldIT * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if CC_USE_IBL\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D texture, vec2 coord, float lod) {\n return textureLod(texture, coord, lod);\n}\nvec4 fragTextureLod (samplerCube texture, vec3 coord, float lod) {\n return textureLod(texture, coord, lod);\n}\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nuniform CCForwardLight {\n highp vec4 cc_sphereLitPos[2];\n vec4 cc_sphereLitSizeRange[2];\n vec4 cc_sphereLitColor[2];\n highp vec4 cc_spotLitPos[2];\n vec4 cc_spotLitSizeRangeAngle[2];\n vec4 cc_spotLitDir[2];\n vec4 cc_spotLitColor[2];\n};\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nvec3 CalcDynamicLighting (vec3 worldPos, vec3 N, vec3 V, vec3 diffuse, vec3 specular, float roughness) {\n vec3 lighting = vec3(0.0);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n for (int i = 0; i < 2; i++) {\n vec3 PLU = cc_sphereLitPos[i].xyz - worldPos;\n vec3 PL = normalize(PLU);\n vec3 PH = normalize(PL + V);\n float PNL = max(dot(N, PL), 0.001);\n float PNH = max(dot(N, PH), 0.0);\n float distSqr = dot(PLU, PLU);\n float litRadius = cc_sphereLitSizeRange[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_sphereLitSizeRange[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(roughness, PNH, PH, N);\n lighting += PNL * cc_sphereLitColor[i].rgb * cc_sphereLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n for (int i = 0; i < 2; i++) {\n vec3 SLU = cc_spotLitPos[i].xyz - worldPos;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_spotLitSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_spotLitSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float cosInner = max(dot(-cc_spotLitDir[i].xyz, SL), 0.01);\n float cosOuter = cc_spotLitSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n att *= GetAngleAtt(SL, -cc_spotLitDir[i].xyz, litAngleScale, litAngleOffset);\n vec3 lspec = specular * CalcSpecular(roughness, SNH, SH, N);\n lighting += SNL * cc_spotLitColor[i].rgb * cc_spotLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n return lighting;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\nvec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NV = max(abs(dot(N, V)), 0.001);\n float NL = max(dot(N, L), 0.001);\n float NH = max(dot(N, H), 0.0);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w * (diffuseContrib + specularContrib);\n finalColor += CalcDynamicLighting(s.position, N, V, diffuse, specular, s.roughness);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb) * cc_ambientSky.w;\n #endif\n finalColor += env * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n return vec4(finalColor, s.albedo.a);\n}\nvec3 ACESToneMap (vec3 color) {\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nuniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\nin vec3 v_position;\nin vec2 v_uv;\nin vec2 v_uv1;\nin vec3 v_normal;\n#if USE_VERTEX_COLOR\n in vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n in vec3 v_tangent;\n in vec3 v_bitangent;\n uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture(pbrMap, PBR_UV);\n pbr.x *= res.OCCLUSION_CHANNEL;\n pbr.y *= res.ROUGHNESS_CHANNEL;\n pbr.z *= res.METALLIC_CHANNEL;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture(metallicRoughnessMap, METALLIC_ROUGHNESS_UV);\n pbr.z *= metallicRoughness.METALLIC_CHANNEL;\n pbr.y *= metallicRoughness.ROUGHNESS_CHANNEL;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture(occlusionMap, OCCLUSION_UV).OCCLUSION_CHANNEL;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n return CCFragOutput(color);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { - "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\n#if USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\nuniform highp mat4 cc_matWorldIT;\n#endif\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec3 a_position;\nattribute vec3 a_normal;\nattribute vec4 a_tangent;\n#if USE_SKINNING\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nuniform vec4 tilingOffset;\n#if USE_VERTEX_COLOR\n attribute vec3 a_color;\n varying vec3 v_color;\n#endif\nvarying vec3 v_position;\nvarying vec3 v_normal;\n#if USE_NORMAL_MAP\n varying vec3 v_tangent;\n varying vec3 v_bitangent;\n#endif\nattribute vec2 a_texCoord;\nvarying vec2 v_uv;\nattribute vec2 a_texCoord1;\nvarying vec2 v_uv1;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorldIT * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\n#if USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\nuniform highp mat4 cc_matWorldIT;\n#endif\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec3 a_position;\nattribute vec3 a_normal;\nattribute vec4 a_tangent;\n#if USE_SKINNING\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nuniform vec4 tilingOffset;\n#if USE_VERTEX_COLOR\n attribute vec3 a_color;\n varying vec3 v_color;\n#endif\nvarying vec3 v_position;\nvarying vec3 v_normal;\n#if USE_NORMAL_MAP\n varying vec3 v_tangent;\n varying vec3 v_bitangent;\n#endif\nattribute vec2 a_texCoord;\nvarying vec2 v_uv;\nattribute vec2 a_texCoord1;\nvarying vec2 v_uv1;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorldIT * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\n #ifdef GL_EXT_shader_texture_lod\n #extension GL_EXT_shader_texture_lod : enable\n #endif\nprecision highp float;\nuniform highp vec4 cc_cameraPos;\nuniform mediump vec4 cc_exposure;\nuniform mediump vec4 cc_mainLitDir;\nuniform mediump vec4 cc_mainLitColor;\nuniform mediump vec4 cc_ambientSky;\nuniform mediump vec4 cc_ambientGround;\n#if CC_USE_IBL\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D texture, vec2 coord, float lod) {\n #ifdef GL_EXT_shader_texture_lod\n return texture2DLodEXT(texture, coord, lod);\n #else\n return texture2D(texture, coord, lod);\n #endif\n}\nvec4 fragTextureLod (samplerCube texture, vec3 coord, float lod) {\n #ifdef GL_EXT_shader_texture_lod\n return textureCubeLodEXT(texture, coord, lod);\n #else\n return textureCube(texture, coord, lod);\n #endif\n}\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nuniform highp vec4 cc_sphereLitPos[2];\nuniform vec4 cc_sphereLitSizeRange[2];\nuniform vec4 cc_sphereLitColor[2];\nuniform highp vec4 cc_spotLitPos[2];\nuniform vec4 cc_spotLitSizeRangeAngle[2];\nuniform vec4 cc_spotLitDir[2];\nuniform vec4 cc_spotLitColor[2];\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nvec3 CalcDynamicLighting (vec3 worldPos, vec3 N, vec3 V, vec3 diffuse, vec3 specular, float roughness) {\n vec3 lighting = vec3(0.0);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n for (int i = 0; i < 2; i++) {\n vec3 PLU = cc_sphereLitPos[i].xyz - worldPos;\n vec3 PL = normalize(PLU);\n vec3 PH = normalize(PL + V);\n float PNL = max(dot(N, PL), 0.001);\n float PNH = max(dot(N, PH), 0.0);\n float distSqr = dot(PLU, PLU);\n float litRadius = cc_sphereLitSizeRange[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_sphereLitSizeRange[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(roughness, PNH, PH, N);\n lighting += PNL * cc_sphereLitColor[i].rgb * cc_sphereLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n for (int i = 0; i < 2; i++) {\n vec3 SLU = cc_spotLitPos[i].xyz - worldPos;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_spotLitSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_spotLitSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float cosInner = max(dot(-cc_spotLitDir[i].xyz, SL), 0.01);\n float cosOuter = cc_spotLitSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n att *= GetAngleAtt(SL, -cc_spotLitDir[i].xyz, litAngleScale, litAngleOffset);\n vec3 lspec = specular * CalcSpecular(roughness, SNH, SH, N);\n lighting += SNL * cc_spotLitColor[i].rgb * cc_spotLitColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n return lighting;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\nvec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NV = max(abs(dot(N, V)), 0.001);\n float NL = max(dot(N, L), 0.001);\n float NH = max(dot(N, H), 0.0);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w * (diffuseContrib + specularContrib);\n finalColor += CalcDynamicLighting(s.position, N, V, diffuse, specular, s.roughness);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb) * cc_ambientSky.w;\n #endif\n finalColor += env * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n return vec4(finalColor, s.albedo.a);\n}\nvec3 ACESToneMap (vec3 color) {\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nuniform vec4 albedo;\nuniform vec4 albedoScaleAndCutoff;\nuniform vec4 pbrParams;\nuniform vec4 emissive;\nuniform vec4 emissiveScaleParam;\nvarying vec3 v_position;\nvarying vec2 v_uv;\nvarying vec2 v_uv1;\nvarying vec3 v_normal;\n#if USE_VERTEX_COLOR\n varying vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n varying vec3 v_tangent;\n varying vec3 v_bitangent;\n uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture2D(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture2D(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture2D(pbrMap, PBR_UV);\n pbr.x *= res.OCCLUSION_CHANNEL;\n pbr.y *= res.ROUGHNESS_CHANNEL;\n pbr.z *= res.METALLIC_CHANNEL;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessMap, METALLIC_ROUGHNESS_UV);\n pbr.z *= metallicRoughness.METALLIC_CHANNEL;\n pbr.y *= metallicRoughness.ROUGHNESS_CHANNEL;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture2D(occlusionMap, OCCLUSION_UV).OCCLUSION_CHANNEL;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture2D(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n return CCFragOutput(color);\n}\nvoid main() { gl_FragColor = frag(); }` }, "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[{"name":"cc_environment", "defines":["CC_USE_IBL"]}]}, "locals":{"blocks":[{"name":"CCLocalBatched", "defines":["USE_BATCHING"]}, {"name":"CCLocal", "defines":[]}, {"name":"CCSkinningTexture", "defines":["USE_SKINNING"]}, {"name":"CCSkinningAnimation", "defines":["USE_SKINNING"]}, {"name":"CCForwardLight", "defines":[]}], "samplers":[{"name":"cc_jointsTexture", "defines":["USE_SKINNING"]}]}}, "defines": [ {"name":"USE_BATCHING", "type":"boolean"}, - {"name":"USE_SKINNING", "type":"number", "range":[0, 3]}, - {"name":"CC_USE_SKINNING", "type":"number", "range":[0, 2]}, + {"name":"USE_SKINNING", "type":"boolean"}, {"name":"USE_VERTEX_COLOR", "type":"boolean"}, {"name":"USE_NORMAL_MAP", "type":"boolean"}, {"name":"CC_USE_IBL", "type":"number", "range":[0, 2]}, @@ -266,20 +265,19 @@ export default [ "shaders": [ { "name": "builtin-unlit|unlit-vs:vert|unlit-fs:frag", - "hash": 240178625, + "hash": 1543680674, "glsl3": { - "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nin vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\n#if USE_VERTEX_COLOR\n in vec4 a_color;\n out vec4 v_color;\n#endif\n#if USE_TEXTURE\n in vec2 a_texCoord;\n out vec2 v_uv;\n uniform TexCoords {\n vec4 tilingOffset;\n };\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n #if USE_TEXTURE\n v_uv = a_texCoord;\n #if FLIP_UV\n v_uv.y = 1.0 - v_uv.y;\n #endif\n v_uv = v_uv * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * position;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nin vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\n#if USE_VERTEX_COLOR\n in vec4 a_color;\n out vec4 v_color;\n#endif\n#if USE_TEXTURE\n in vec2 a_texCoord;\n out vec2 v_uv;\n uniform TexCoords {\n vec4 tilingOffset;\n };\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n #if USE_TEXTURE\n v_uv = a_texCoord;\n #if FLIP_UV\n v_uv.y = 1.0 - v_uv.y;\n #endif\n v_uv = v_uv * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * position;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision mediump float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\n#if USE_ALPHA_TEST\n#endif\n#if USE_TEXTURE\n in vec2 v_uv;\n uniform sampler2D mainTexture;\n#endif\nuniform Constant {\n vec4 mainColor;\n vec4 colorScaleAndCutoff;\n};\n#if USE_VERTEX_COLOR\n in vec4 v_color;\n#endif\nvec4 frag () {\n vec4 o = mainColor;\n o.rgb *= colorScaleAndCutoff.xyz;\n #if USE_VERTEX_COLOR\n o *= v_color;\n #endif\n #if USE_TEXTURE\n o *= texture(mainTexture, v_uv);\n #endif\n #if USE_ALPHA_TEST\n if (o.ALPHA_TEST_CHANNEL < colorScaleAndCutoff.w) discard;\n #endif\n return CCFragOutput(o);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { - "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\n#if USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\n#endif\nattribute vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\n#if USE_VERTEX_COLOR\n attribute vec4 a_color;\n varying vec4 v_color;\n#endif\n#if USE_TEXTURE\n attribute vec2 a_texCoord;\n varying vec2 v_uv;\n uniform vec4 tilingOffset;\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n #if USE_TEXTURE\n v_uv = a_texCoord;\n #if FLIP_UV\n v_uv.y = 1.0 - v_uv.y;\n #endif\n v_uv = v_uv * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * position;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\n#if USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\n#endif\nattribute vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\n#if USE_VERTEX_COLOR\n attribute vec4 a_color;\n varying vec4 v_color;\n#endif\n#if USE_TEXTURE\n attribute vec2 a_texCoord;\n varying vec2 v_uv;\n uniform vec4 tilingOffset;\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n #if USE_TEXTURE\n v_uv = a_texCoord;\n #if FLIP_UV\n v_uv.y = 1.0 - v_uv.y;\n #endif\n v_uv = v_uv * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n return cc_matProj * (cc_matView * matWorld) * position;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision mediump float;\nuniform mediump vec4 cc_exposure;\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\n#if USE_ALPHA_TEST\n#endif\n#if USE_TEXTURE\n varying vec2 v_uv;\n uniform sampler2D mainTexture;\n#endif\nuniform vec4 mainColor;\nuniform vec4 colorScaleAndCutoff;\n#if USE_VERTEX_COLOR\n varying vec4 v_color;\n#endif\nvec4 frag () {\n vec4 o = mainColor;\n o.rgb *= colorScaleAndCutoff.xyz;\n #if USE_VERTEX_COLOR\n o *= v_color;\n #endif\n #if USE_TEXTURE\n o *= texture2D(mainTexture, v_uv);\n #endif\n #if USE_ALPHA_TEST\n if (o.ALPHA_TEST_CHANNEL < colorScaleAndCutoff.w) discard;\n #endif\n return CCFragOutput(o);\n}\nvoid main() { gl_FragColor = frag(); }` }, "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}], "samplers":[]}, "locals":{"blocks":[{"name":"CCLocalBatched", "defines":["USE_BATCHING"]}, {"name":"CCLocal", "defines":[]}, {"name":"CCSkinningTexture", "defines":["USE_SKINNING"]}, {"name":"CCSkinningAnimation", "defines":["USE_SKINNING"]}], "samplers":[{"name":"cc_jointsTexture", "defines":["USE_SKINNING"]}]}}, "defines": [ {"name":"USE_BATCHING", "type":"boolean"}, - {"name":"USE_SKINNING", "type":"number", "range":[0, 3]}, - {"name":"CC_USE_SKINNING", "type":"number", "range":[0, 2]}, + {"name":"USE_SKINNING", "type":"boolean"}, {"name":"USE_VERTEX_COLOR", "type":"boolean"}, {"name":"USE_TEXTURE", "type":"boolean"}, {"name":"FLIP_UV", "type":"boolean"}, @@ -311,20 +309,19 @@ export default [ "shaders": [ { "name": "pipeline/planar-shadow|planar-shadow-vs:vert|planar-shadow-fs:frag", - "hash": 2703119772, + "hash": 1086841741, "glsl3": { - "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nuniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n lowp vec4 cc_shadowColor;\n};\nin vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision highp float;\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\n#if USE_BATCHING\n in float a_dyn_batch_id;\n uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nuniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n};\n#endif\nuniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n lowp vec4 cc_shadowColor;\n};\nin vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec4 a_weights;\nin vec4 a_joints;\nuniform CCSkinningTexture {\n highp vec4 cc_jointsTextureInfo;\n};\nuniform CCSkinningAnimation {\n highp vec4 cc_jointsAnimInfo;\n};\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision mediump float;\nuniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n lowp vec4 cc_shadowColor;\n};\nuniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvec4 frag () {\n return CCFragOutput(cc_shadowColor);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { - "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\n#if USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\n#endif\nuniform highp mat4 cc_matLightPlaneProj;\nattribute vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision highp float;\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\n#if USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\n#endif\nuniform highp mat4 cc_matLightPlaneProj;\nattribute vec3 a_position;\n#if USE_SKINNING\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec4 a_weights;\nattribute vec4 a_joints;\nuniform highp vec4 cc_jointsTextureInfo;\nuniform highp vec4 cc_jointsAnimInfo;\nuniform sampler2D cc_jointsTexture;\n#if USE_SKINNING == 1\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n#endif\n#if USE_SKINNING == 1\n mat4 getJointMatrix (float i) {\n highp float j = 12.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointsTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointsTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#elif USE_SKINNING == 2\n mat4 getJointMatrix (float i) {\n highp float j = 3.0 * (cc_jointsAnimInfo.x * i + cc_jointsAnimInfo.y) + cc_jointsTextureInfo.z;\n highp float invSize = cc_jointsTextureInfo.y;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointsTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointsTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointsTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointsTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y;\n + getJointMatrix(a_joints.z) * a_weights.z;\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id + 0.5)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision mediump float;\nuniform lowp vec4 cc_shadowColor;\nuniform mediump vec4 cc_exposure;\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvec4 frag () {\n return CCFragOutput(cc_shadowColor);\n}\nvoid main() { gl_FragColor = frag(); }` }, "builtins": {"globals":{"blocks":[{"name":"CCGlobal", "defines":[]}, {"name":"CCShadow", "defines":[]}], "samplers":[]}, "locals":{"blocks":[{"name":"CCLocalBatched", "defines":["USE_BATCHING"]}, {"name":"CCLocal", "defines":[]}, {"name":"CCSkinningTexture", "defines":["USE_SKINNING"]}, {"name":"CCSkinningAnimation", "defines":["USE_SKINNING"]}], "samplers":[{"name":"cc_jointsTexture", "defines":["USE_SKINNING"]}]}}, "defines": [ {"name":"USE_BATCHING", "type":"boolean"}, - {"name":"USE_SKINNING", "type":"number", "range":[0, 3]}, - {"name":"CC_USE_SKINNING", "type":"number", "range":[0, 2]}, + {"name":"USE_SKINNING", "type":"boolean"}, {"name":"CC_USE_HDR", "type":"boolean"} ], "blocks": [], diff --git a/cocos/core/renderer/core/program-lib.ts b/cocos/core/renderer/core/program-lib.ts index 2b154b6fd16..b3c579f9749 100644 --- a/cocos/core/renderer/core/program-lib.ts +++ b/cocos/core/renderer/core/program-lib.ts @@ -68,7 +68,7 @@ function getBitCount (cnt: number) { function mapDefine (info: IDefineInfo, def: number | string | boolean) { switch (info.type) { - case 'boolean': return def as boolean ? '1' : '0'; + case 'boolean': return (typeof def === 'number' ? def : (def ? 1 : 0)) + ''; case 'string': return def !== undefined ? def as string : info.options![0]; case 'number': return (def !== undefined ? def as number : info.range![0]) + ''; } From c86209bf610d63727553907cc7430abb3b27619c Mon Sep 17 00:00:00 2001 From: zxg <247274249@qq.com> Date: Wed, 25 Dec 2019 17:14:35 +0800 Subject: [PATCH 12/13] change sharedMaterial decorator --- cocos/core/3d/framework/renderable-component.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cocos/core/3d/framework/renderable-component.ts b/cocos/core/3d/framework/renderable-component.ts index 21f088a0d60..a4440bb33af 100644 --- a/cocos/core/3d/framework/renderable-component.ts +++ b/cocos/core/3d/framework/renderable-component.ts @@ -41,7 +41,6 @@ export class RenderableComponent extends Component { type: Material, displayName: 'Materials', tooltip: '源材质', - animatable: false, }) get sharedMaterials () { // if we don't create an array copy, the editor will modify the original array directly. @@ -66,11 +65,6 @@ export class RenderableComponent extends Component { * @en The material of the model * @zh 模型材质。 */ - // @property({ - // type: Material, - // visible: false, - // animatable: true, - // }) get materials () { for (let i = 0; i < this._materials.length; i++) { this._materialInstances[i] = this.getMaterialInstance(i) as MaterialInstance; From f6b3c2d4de6ef2319021e23c3b6aefdf84588b01 Mon Sep 17 00:00:00 2001 From: zxg <247274249@qq.com> Date: Wed, 25 Dec 2019 17:38:00 +0800 Subject: [PATCH 13/13] add modelcomponent property deprecated --- cocos/core/3d/framework/deprecated.ts | 11 +++++++++++ cocos/core/3d/framework/index.ts | 3 +++ 2 files changed, 14 insertions(+) create mode 100644 cocos/core/3d/framework/deprecated.ts diff --git a/cocos/core/3d/framework/deprecated.ts b/cocos/core/3d/framework/deprecated.ts new file mode 100644 index 00000000000..1ce4aafbaf0 --- /dev/null +++ b/cocos/core/3d/framework/deprecated.ts @@ -0,0 +1,11 @@ +import { removeProperty } from '../../utils'; +import { ModelComponent } from './model-component'; + +removeProperty(ModelComponent.prototype, 'ModelComponent.prototype', [ + { + name: 'enableDynamicBatching', + }, + { + name: 'receiveShadows', + }, +]); diff --git a/cocos/core/3d/framework/index.ts b/cocos/core/3d/framework/index.ts index 9cb779f9f4f..8fcfda568a4 100644 --- a/cocos/core/3d/framework/index.ts +++ b/cocos/core/3d/framework/index.ts @@ -68,3 +68,6 @@ cc.LightComponent = LightComponent; cc.DirectionalLightComponent = DirectionalLightComponent; cc.SphereLightComponent = SphereLightComponent; cc.SpotLightComponent = SpotLightComponent; + +/** deprecated */ +import './deprecated';