From 08552687664c641351ce911c51d8e8ac5b7c33e0 Mon Sep 17 00:00:00 2001 From: Yun Hsiao Wu Date: Mon, 14 Jan 2019 15:26:26 +0800 Subject: [PATCH] pass: rebuild with overrides --- cocos/3d/assets/material.ts | 16 ++++- cocos/3d/framework/model-component.js | 3 +- .../renderer/particle-system-renderer.js | 2 +- .../3d/framework/skinning-model-component.js | 2 +- cocos/3d/framework/skybox-component.js | 2 +- cocos/3d/misc/utils.js | 69 +++++++++++++++++++ cocos/gfx/webgl/webgl-device.ts | 2 +- cocos/pipeline/testcase/test-model-stage.ts | 2 +- cocos/renderer/core/effect.ts | 6 +- cocos/renderer/core/pass.ts | 27 ++++++-- cocos/renderer/scene/render-scene.ts | 2 +- cocos/renderer/utils.js | 6 +- playground/simple.html | 2 +- 13 files changed, 122 insertions(+), 19 deletions(-) create mode 100644 cocos/3d/misc/utils.js diff --git a/cocos/3d/assets/material.ts b/cocos/3d/assets/material.ts index 578d4f8e461..cfc9f86801e 100644 --- a/cocos/3d/assets/material.ts +++ b/cocos/3d/assets/material.ts @@ -26,8 +26,8 @@ import { Asset } from '../../assets/asset'; import { ccclass, property } from '../../core/data/class-decorator'; import { GFXBindingType } from '../../gfx/define'; import { Effect } from '../../renderer/core/effect'; -import { Pass } from '../../renderer/core/pass'; -import { EffectAsset } from './effect-asset'; +import { Pass, IPassOverrides } from '../../renderer/core/pass'; +import { EffectAsset, IPassInfo, ITechniqueInfo } from './effect-asset'; @ccclass('cc.Material') export class Material extends Asset { @@ -133,6 +133,18 @@ export class Material extends Asset { this.update(); } + public rebuildWithOverrides (overrides: IPassOverrides, idx?: number) { + if (!this._passes || !this._effectAsset) { return; } + const passInfos = Effect.getPassInfos(this._effectAsset, this._techIdx); + if (idx === undefined) { + for (let i = 0; i < this._passes.length; i++) { + this._passes[i].rebuildWithOverrides(passInfos[i], overrides); + } + } else { + this._passes[idx].rebuildWithOverrides(passInfos[idx], overrides); + } + } + public update (asset: EffectAsset | string | null = this._effectAsset, keepProps: boolean = true) { // get effect asset if (typeof asset === 'string') { diff --git a/cocos/3d/framework/model-component.js b/cocos/3d/framework/model-component.js index 7735de0780b..66dc454c297 100644 --- a/cocos/3d/framework/model-component.js +++ b/cocos/3d/framework/model-component.js @@ -116,6 +116,7 @@ export default class ModelComponent extends RenderableComponent { set mesh(val) { this._mesh = val; + this._updateModels(); } /** @@ -184,7 +185,7 @@ export default class ModelComponent extends RenderableComponent { } _updateModels() { - if (!this.enabled) return; + if (!this.node._scene) return; let meshCount = this._mesh ? this._mesh.subMeshCount : 0; for (let i = 0; i < meshCount; ++i) { diff --git a/cocos/3d/framework/particle/renderer/particle-system-renderer.js b/cocos/3d/framework/particle/renderer/particle-system-renderer.js index 64d34152266..1a15a0a7e6a 100644 --- a/cocos/3d/framework/particle/renderer/particle-system-renderer.js +++ b/cocos/3d/framework/particle/renderer/particle-system-renderer.js @@ -89,7 +89,7 @@ export default class ParticleSystemRenderer extends RenderableComponent { this.frameTile = cc.v2(1, 1); this.attrs = new Array(5); - this.device = cc.game._renderContext; + this.device = cc.game._gfxDevice; } onInit() { diff --git a/cocos/3d/framework/skinning-model-component.js b/cocos/3d/framework/skinning-model-component.js index 46aaf107f3a..07295e2d309 100644 --- a/cocos/3d/framework/skinning-model-component.js +++ b/cocos/3d/framework/skinning-model-component.js @@ -187,7 +187,7 @@ export default class SkinningModelComponent extends ModelComponent { return; } - if (cc.game._renderContext.allowFloatTexture()) { + if (cc.game._gfxDevice.allowFloatTexture()) { this._jointsTexture = utils.createJointsTexture(this._skeleton); this._jointMatricesData = new Float32Array(this._jointsTexture._width * this._jointsTexture._height * 4); } else { diff --git a/cocos/3d/framework/skybox-component.js b/cocos/3d/framework/skybox-component.js index a9138714137..13cf122025a 100644 --- a/cocos/3d/framework/skybox-component.js +++ b/cocos/3d/framework/skybox-component.js @@ -82,7 +82,7 @@ export default class SkyboxComponent extends Component { onLoad() { this._model.setNode(this.node); - let ia = renderer.createIA(cc.game._renderContext, box(2, 2, 2)); + let ia = renderer.createIA(cc.game._gfxDevice, box(2, 2, 2)); this._model.setInputAssembler(ia); if (!this._material) { diff --git a/cocos/3d/misc/utils.js b/cocos/3d/misc/utils.js new file mode 100644 index 00000000000..a6256437a40 --- /dev/null +++ b/cocos/3d/misc/utils.js @@ -0,0 +1,69 @@ +import { renderer } from '../../renderer'; +import find from '../../scene-graph/find'; +import { Mesh, RenderingMesh } from '../assets/mesh'; +import gfx from '../../renderer/gfx/index'; +import { GFXPrimitiveMode } from '../../gfx/define'; + +/** + * + * @param {import("../assets/skeleton").default} skinning + */ +function createJointsTexture(skinning) { + const jointCount = skinning.joints.length; + + // Set jointsTexture. + // A squared texture with side length N(N > 1) multiples of 2 can store + // 2 ^ (2 * N - 2) matrices. + // We support most 1024 joints. + let size; + if (jointCount > 1024) { + throw "To many joints(more than 1024)."; + } else if (jointCount > 256) { + size = 64; + } else if (jointCount > 64) { + size = 32; + } else if (jointCount > 16) { + size = 16; + } else if (jointCount > 4) { + size = 8; + } else { + size = 4; + } + + return new gfx.Texture2D(cc.game._gfxDevice, { + width: size, + height: size, + format: gfx.TEXTURE_FMT_RGBA32F, + minFilter: gfx.FILTER_NEAREST, + magFilter: gfx.FILTER_NEAREST, + wrapS: gfx.WRAP_CLAMP, + wrapT: gfx.WRAP_CLAMP, + mipmap: false + }); +} + +function createMesh(context, data) { + let ia = renderer.createIA(context, data); + let meshAsset = new Mesh(); + const primitiveMode = data.primitiveMode === undefined ? GFXPrimitiveMode.TRIANGLE_LIST : data.primitiveMode; + meshAsset._renderingMesh = new RenderingMesh([{inputAssembler: ia, primitiveMode}], [], []); + meshAsset._minPosition = data.minPos; + meshAsset._maxPosition = data.maxPos; + + return meshAsset; +} + +/** + * @param {Uint8Array} buffer + */ +function toPPM(buffer, w, h) { + return `P3 ${w} ${h} 255\n${buffer.filter((e, i) => i % 4 < 3).toString()}\n`; +} + +export default { + createJointsTexture, + createMesh, + + find, + toPPM +}; diff --git a/cocos/gfx/webgl/webgl-device.ts b/cocos/gfx/webgl/webgl-device.ts index 152f8c3bde4..d27b91aabf1 100644 --- a/cocos/gfx/webgl/webgl-device.ts +++ b/cocos/gfx/webgl/webgl-device.ts @@ -199,7 +199,7 @@ export class WebGLGFXDevice extends GFXDevice { private _webGLRC: WebGLRenderingContext | null = null; private _isAntialias: boolean = true; - private _isPremultipliedAlpha: boolean = false; + private _isPremultipliedAlpha: boolean = true; private _extensions: string[] | null = null; private _EXT_texture_filter_anisotropic: EXT_texture_filter_anisotropic | null = null; diff --git a/cocos/pipeline/testcase/test-model-stage.ts b/cocos/pipeline/testcase/test-model-stage.ts index 1da32b2d3a1..742bdb6fab2 100644 --- a/cocos/pipeline/testcase/test-model-stage.ts +++ b/cocos/pipeline/testcase/test-model-stage.ts @@ -85,7 +85,7 @@ export class TestModelStage extends RenderStage { this._scene._scene = this._scene; const modelCom = this._scene.addComponent('cc.ModelComponent'); modelCom.material = this._material; - modelCom.mesh = cc.utils.createMesh(cc.game._renderContext, cc.primitives.box({length: 1, width: 1, height: 1})); + modelCom.mesh = cc.utils.createMesh(cc.game._gfxDevice, cc.primitives.box({length: 1, width: 1, height: 1})); this._model = modelCom._models[0]; this._scene.setRotationFromEuler(45, 45, 45); this._scene._rot = this._scene._lrot; diff --git a/cocos/renderer/core/effect.ts b/cocos/renderer/core/effect.ts index 7169ad0e89f..00e88c5f9cc 100644 --- a/cocos/renderer/core/effect.ts +++ b/cocos/renderer/core/effect.ts @@ -64,9 +64,13 @@ const getDefines = (name: string, prog: IShaderInfo) => { }; export class Effect { + public static getPassInfos (effect: EffectAsset, techIdx: number) { + return effect.techniques[techIdx].passes; + } + public static parseEffect (effect: EffectAsset, info?: IEffectInfo) { // techniques - const { techIdx, defines } = info || {} as IEffectInfo; + const { techIdx, defines } = info || {} as IEffectInfo; const tech = effect.techniques[techIdx || 0]; const passNum = tech.passes.length; const passes: Pass[] = new Array(passNum); diff --git a/cocos/renderer/core/pass.ts b/cocos/renderer/core/pass.ts index 23ce0921336..c89a96c36ef 100644 --- a/cocos/renderer/core/pass.ts +++ b/cocos/renderer/core/pass.ts @@ -8,7 +8,7 @@ import { GFXBindingType, GFXBufferUsageBit, GFXMemoryUsageBit, GFXPrimitiveMode, import { GFXDevice } from '../../gfx/device'; import { GFXPipelineLayout } from '../../gfx/pipeline-layout'; import { GFXBlendState, GFXBlendTarget, GFXDepthStencilState, - GFXInputState, GFXPipelineState, GFXRasterizerState } from '../../gfx/pipeline-state'; + GFXInputState, GFXPipelineState, GFXRasterizerState, IGFXPipelineStateInfo } from '../../gfx/pipeline-state'; import { GFXRenderPass } from '../../gfx/render-pass'; import { GFXSampler } from '../../gfx/sampler'; import { GFXShader } from '../../gfx/shader'; @@ -24,6 +24,13 @@ export interface IPassInfoFull extends IPassInfo { globals: GFXBuffer; } +export interface IPassOverrides { + bs: GFXBlendState; + dss: GFXDepthStencilState; + rs: GFXRasterizerState; + primitive: GFXPrimitiveMode; +} + const _type2fn = { [GFXType.INT]: (a: Float32Array, v: any) => a[0] = v, [GFXType.INT2]: (a: Float32Array, v: any) => vec2.array(a, v), @@ -114,7 +121,7 @@ export class Pass { if (!this._pipelineLayout) { console.error('create pipeline layout failed'); return; } this._shader = info.shader; this._renderPass = info.renderPass; - this.createPipelineState(info); + this._createPipelineState(info); for (const u of info.blocks) { if (builtinRE.test(u.name)) { @@ -199,9 +206,18 @@ export class Pass { (this._bindingLayout as GFXBindingLayout).bindSampler(binding, value); } - public setStates (info: IPassInfo) { + public rebuildWithOverrides (info: Partial, overrides: IPassOverrides) { if (this._pipelineState) { this._pipelineState.destroy(); } - this.createPipelineState(info); + const ors = Object.assign({}, overrides); + this._createPipelineState(info, (states) => { + Object.assign(states.rs, ors.rs); + Object.assign(states.dss, ors.dss); + for (let i = 0; i < ors.bs.targets.length; i++) { + Object.assign(states.bs.targets[i], ors.bs.targets[i]); + } + delete ors.bs.targets; + Object.assign(states.bs, ors.bs); + }); } public destroy () { @@ -224,7 +240,7 @@ export class Pass { (this._bindingLayout as GFXBindingLayout).update(); } - protected createPipelineState (info: IPassInfo) { + protected _createPipelineState (info: Partial, override?: (states: IGFXPipelineStateInfo) => any) { if (info.primitive) { this._primitive = info.primitive; } if (info.stage) { this._stage = info.stage; } @@ -252,6 +268,7 @@ export class Pass { rs: Object.assign(new GFXRasterizerState(), info.rasterizerState), shader: this._shader, }; + if (override) { override(stateInfo); } if (this._pipelineState) { this._pipelineState.initialize(stateInfo); } else { diff --git a/cocos/renderer/scene/render-scene.ts b/cocos/renderer/scene/render-scene.ts index ab3f5aa4397..3138f8323a3 100644 --- a/cocos/renderer/scene/render-scene.ts +++ b/cocos/renderer/scene/render-scene.ts @@ -2,11 +2,11 @@ import { intersect, ray, triangle } from '../../3d/geom-utils'; import { RecyclePool } from '../../3d/memop'; import { _createSceneFun, Root } from '../../core/root'; import { mat4, vec3 } from '../../core/vmath'; +import { GFXPrimitiveMode } from '../../gfx/define'; import { Layers } from '../../scene-graph/layers'; import { Camera, ICameraInfo } from './camera'; import { Light } from './light'; import { Model } from './model'; -import { GFXPrimitiveMode } from '../../gfx/define'; export interface IRenderSceneInfo { name: string; diff --git a/cocos/renderer/utils.js b/cocos/renderer/utils.js index e437a9c6d49..dc5bc986bc5 100644 --- a/cocos/renderer/utils.js +++ b/cocos/renderer/utils.js @@ -37,7 +37,7 @@ export function createIA(device, data) { vfmt.push({ name: GFXAttributeName.ATTR_COLOR, format: GFXFormat.RGB32F }); } - let vb = cc.director.root.device.createBuffer({ + let vb = device.createBuffer({ usage: GFXBufferUsageBit.VERTEX, memUsage: GFXMemoryUsageBit.HOST | GFXMemoryUsageBit.DEVICE, size: verts.length * 4, @@ -46,7 +46,7 @@ export function createIA(device, data) { vb.update(new Float32Array(verts)); - let ib = cc.director.root.device.createBuffer({ + let ib = device.createBuffer({ usage: GFXBufferUsageBit.INDEX, memUsage: GFXMemoryUsageBit.HOST | GFXMemoryUsageBit.DEVICE, size: data.indices.length * 2, @@ -55,7 +55,7 @@ export function createIA(device, data) { ib.update(new Uint16Array(data.indices)); - return cc.director.root.device.createInputAssembler({ + return device.createInputAssembler({ attributes: vfmt, vertexBuffers: [vb], indexBuffer: ib, diff --git a/playground/simple.html b/playground/simple.html index b2e57b0d8f7..a59f36f59db 100644 --- a/playground/simple.html +++ b/playground/simple.html @@ -63,7 +63,7 @@ modelNode.parent = scene; const modelCom = modelNode.addComponent('cc.ModelComponent'); modelCom.material = material; - modelCom.mesh = cc.utils.createMesh(cc.game._renderContext, cc.primitives.box()); + modelCom.mesh = cc.utils.createMesh(cc.game._gfxDevice, cc.primitives.box()); modelNode.setRotationFromEuler(45, 45, 45); cc.director.runSceneImmediate(scene);