UNPKG

cione-comp-lib

Version:

`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`

394 lines (393 loc) 13.6 kB
import Shader from "../../../claygl/src/Shader.mjs"; import Texture2D from "../../../claygl/src/Texture2D.mjs"; import Texture from "../../../claygl/src/Texture.mjs"; import FrameBuffer from "../../../claygl/src/FrameBuffer.mjs"; import createCompositor from "../../../claygl/src/createCompositor.mjs"; import SSAOPass from "./SSAOPass.mjs"; import SSRPass from "./SSRPass.mjs"; import poissonKernel from "./poissonKernel.mjs"; import graphicGL from "../util/graphicGL.mjs"; import NormalPass from "./NormalPass.mjs"; import EdgePass from "./EdgePass.mjs"; import effectJson from "./composite.mjs"; import blurCode from "../../../claygl/src/shader/source/compositor/blur.glsl.mjs"; import lutCode from "../../../claygl/src/shader/source/compositor/lut.glsl.mjs"; import outputCode from "../../../claygl/src/shader/source/compositor/output.glsl.mjs"; import brightCode from "../../../claygl/src/shader/source/compositor/bright.glsl.mjs"; import downsampleCode from "../../../claygl/src/shader/source/compositor/downsample.glsl.mjs"; import upsampleCode from "../../../claygl/src/shader/source/compositor/upsample.glsl.mjs"; import hdrCode from "../../../claygl/src/shader/source/compositor/hdr.glsl.mjs"; import blendCode from "../../../claygl/src/shader/source/compositor/blend.glsl.mjs"; import fxaaCode from "../../../claygl/src/shader/source/compositor/fxaa.glsl.mjs"; import DOFCode from "./DOF.glsl.mjs"; import edgeCode from "./edge.glsl.mjs"; Shader["import"](blurCode); Shader["import"](lutCode); Shader["import"](outputCode); Shader["import"](brightCode); Shader["import"](downsampleCode); Shader["import"](upsampleCode); Shader["import"](hdrCode); Shader["import"](blendCode); Shader["import"](fxaaCode); Shader["import"](DOFCode); Shader["import"](edgeCode); function makeCommonOutputs(getWidth, getHeight) { return { color: { parameters: { width: getWidth, height: getHeight } } }; } var FINAL_NODES_CHAIN = ["composite", "FXAA"]; function EffectCompositor() { this._width; this._height; this._dpr; this._sourceTexture = new Texture2D({ type: Texture.HALF_FLOAT }); this._depthTexture = new Texture2D({ format: Texture.DEPTH_COMPONENT, type: Texture.UNSIGNED_INT }); this._framebuffer = new FrameBuffer(); this._framebuffer.attach(this._sourceTexture); this._framebuffer.attach(this._depthTexture, FrameBuffer.DEPTH_ATTACHMENT); this._normalPass = new NormalPass(); this._compositor = createCompositor(effectJson); var sourceNode = this._compositor.getNodeByName("source"); sourceNode.texture = this._sourceTexture; var cocNode = this._compositor.getNodeByName("coc"); this._sourceNode = sourceNode; this._cocNode = cocNode; this._compositeNode = this._compositor.getNodeByName("composite"); this._fxaaNode = this._compositor.getNodeByName("FXAA"); this._dofBlurNodes = ["dof_far_blur", "dof_near_blur", "dof_coc_blur"].map(function(name) { return this._compositor.getNodeByName(name); }, this); this._dofBlurKernel = 0; this._dofBlurKernelSize = new Float32Array(0); this._finalNodesChain = FINAL_NODES_CHAIN.map(function(name) { return this._compositor.getNodeByName(name); }, this); var gBufferObj = { normalTexture: this._normalPass.getNormalTexture(), depthTexture: this._normalPass.getDepthTexture() }; this._ssaoPass = new SSAOPass(gBufferObj); this._ssrPass = new SSRPass(gBufferObj); this._edgePass = new EdgePass(gBufferObj); } EffectCompositor.prototype.resize = function(width, height, dpr) { dpr = dpr || 1; var width = width * dpr; var height = height * dpr; var sourceTexture = this._sourceTexture; var depthTexture = this._depthTexture; sourceTexture.width = width; sourceTexture.height = height; depthTexture.width = width; depthTexture.height = height; var rendererMock = { getWidth: function() { return width; }, getHeight: function() { return height; }, getDevicePixelRatio: function() { return dpr; } }; function wrapCallback(obj, key) { if (typeof obj[key] === "function") { var oldFunc = obj[key].__original || obj[key]; obj[key] = function(renderer) { return oldFunc.call(this, rendererMock); }; obj[key].__original = oldFunc; } } this._compositor.nodes.forEach(function(node) { for (var outKey in node.outputs) { var parameters = node.outputs[outKey].parameters; if (parameters) { wrapCallback(parameters, "width"); wrapCallback(parameters, "height"); } } for (var paramKey in node.parameters) { wrapCallback(node.parameters, paramKey); } }); this._width = width; this._height = height; this._dpr = dpr; }; EffectCompositor.prototype.getWidth = function() { return this._width; }; EffectCompositor.prototype.getHeight = function() { return this._height; }; EffectCompositor.prototype._ifRenderNormalPass = function() { return this._enableSSAO || this._enableEdge || this._enableSSR; }; EffectCompositor.prototype._getPrevNode = function(node) { var idx = FINAL_NODES_CHAIN.indexOf(node.name) - 1; var prevNode = this._finalNodesChain[idx]; while (prevNode && !this._compositor.getNodeByName(prevNode.name)) { idx -= 1; prevNode = this._finalNodesChain[idx]; } return prevNode; }; EffectCompositor.prototype._getNextNode = function(node) { var idx = FINAL_NODES_CHAIN.indexOf(node.name) + 1; var nextNode = this._finalNodesChain[idx]; while (nextNode && !this._compositor.getNodeByName(nextNode.name)) { idx += 1; nextNode = this._finalNodesChain[idx]; } return nextNode; }; EffectCompositor.prototype._addChainNode = function(node) { var prevNode = this._getPrevNode(node); var nextNode = this._getNextNode(node); if (!prevNode) { return; } node.inputs.texture = prevNode.name; if (nextNode) { node.outputs = makeCommonOutputs(this.getWidth.bind(this), this.getHeight.bind(this)); nextNode.inputs.texture = node.name; } else { node.outputs = null; } this._compositor.addNode(node); }; EffectCompositor.prototype._removeChainNode = function(node) { var prevNode = this._getPrevNode(node); var nextNode = this._getNextNode(node); if (!prevNode) { return; } if (nextNode) { prevNode.outputs = makeCommonOutputs(this.getWidth.bind(this), this.getHeight.bind(this)); nextNode.inputs.texture = prevNode.name; } else { prevNode.outputs = null; } this._compositor.removeNode(node); }; EffectCompositor.prototype.updateNormal = function(renderer, scene, camera, frame) { if (this._ifRenderNormalPass()) { this._normalPass.update(renderer, scene, camera); } }; EffectCompositor.prototype.updateSSAO = function(renderer, scene, camera, frame) { this._ssaoPass.update(renderer, camera, frame); }; EffectCompositor.prototype.enableSSAO = function() { this._enableSSAO = true; }; EffectCompositor.prototype.disableSSAO = function() { this._enableSSAO = false; }; EffectCompositor.prototype.enableSSR = function() { this._enableSSR = true; }; EffectCompositor.prototype.disableSSR = function() { this._enableSSR = false; }; EffectCompositor.prototype.getSSAOTexture = function() { return this._ssaoPass.getTargetTexture(); }; EffectCompositor.prototype.getSourceFrameBuffer = function() { return this._framebuffer; }; EffectCompositor.prototype.getSourceTexture = function() { return this._sourceTexture; }; EffectCompositor.prototype.disableFXAA = function() { this._removeChainNode(this._fxaaNode); }; EffectCompositor.prototype.enableFXAA = function() { this._addChainNode(this._fxaaNode); }; EffectCompositor.prototype.enableBloom = function() { this._compositeNode.inputs.bloom = "bloom_composite"; this._compositor.dirty(); }; EffectCompositor.prototype.disableBloom = function() { this._compositeNode.inputs.bloom = null; this._compositor.dirty(); }; EffectCompositor.prototype.enableDOF = function() { this._compositeNode.inputs.texture = "dof_composite"; this._compositor.dirty(); }; EffectCompositor.prototype.disableDOF = function() { this._compositeNode.inputs.texture = "source"; this._compositor.dirty(); }; EffectCompositor.prototype.enableColorCorrection = function() { this._compositeNode.define("COLOR_CORRECTION"); this._enableColorCorrection = true; }; EffectCompositor.prototype.disableColorCorrection = function() { this._compositeNode.undefine("COLOR_CORRECTION"); this._enableColorCorrection = false; }; EffectCompositor.prototype.enableEdge = function() { this._enableEdge = true; }; EffectCompositor.prototype.disableEdge = function() { this._enableEdge = false; }; EffectCompositor.prototype.setBloomIntensity = function(value) { this._compositeNode.setParameter("bloomIntensity", value); }; EffectCompositor.prototype.setSSAOParameter = function(name, value) { switch (name) { case "quality": var kernelSize = { low: 6, medium: 12, high: 32, ultra: 62 }[value] || 12; this._ssaoPass.setParameter("kernelSize", kernelSize); break; case "radius": this._ssaoPass.setParameter(name, value); this._ssaoPass.setParameter("bias", value / 200); break; case "intensity": this._ssaoPass.setParameter(name, value); break; } }; EffectCompositor.prototype.setDOFParameter = function(name, value) { switch (name) { case "focalDistance": case "focalRange": case "fstop": this._cocNode.setParameter(name, value); break; case "blurRadius": for (var i = 0; i < this._dofBlurNodes.length; i++) { this._dofBlurNodes[i].setParameter("blurRadius", value); } break; case "quality": var kernelSize = { low: 4, medium: 8, high: 16, ultra: 32 }[value] || 8; this._dofBlurKernelSize = kernelSize; for (var i = 0; i < this._dofBlurNodes.length; i++) { this._dofBlurNodes[i].pass.material.define("POISSON_KERNEL_SIZE", kernelSize); } this._dofBlurKernel = new Float32Array(kernelSize * 2); break; } }; EffectCompositor.prototype.setSSRParameter = function(name, value) { if (value == null) { return; } switch (name) { case "quality": var maxIteration = { low: 10, medium: 15, high: 30, ultra: 80 }[value] || 20; var pixelStride = { low: 32, medium: 16, high: 8, ultra: 4 }[value] || 16; this._ssrPass.setParameter("maxIteration", maxIteration); this._ssrPass.setParameter("pixelStride", pixelStride); break; case "maxRoughness": this._ssrPass.setParameter("minGlossiness", Math.max(Math.min(1 - value, 1), 0)); break; case "physical": this.setPhysicallyCorrectSSR(value); break; default: console.warn("Unkown SSR parameter " + name); } }; EffectCompositor.prototype.setPhysicallyCorrectSSR = function(physical) { this._ssrPass.setPhysicallyCorrect(physical); }; EffectCompositor.prototype.setEdgeColor = function(value) { var color = graphicGL.parseColor(value); this._edgePass.setParameter("edgeColor", color); }; EffectCompositor.prototype.setExposure = function(value) { this._compositeNode.setParameter("exposure", Math.pow(2, value)); }; EffectCompositor.prototype.setColorLookupTexture = function(image, api) { this._compositeNode.pass.material.setTextureImage("lut", this._enableColorCorrection ? image : "none", api, { minFilter: graphicGL.Texture.NEAREST, magFilter: graphicGL.Texture.NEAREST, flipY: false }); }; EffectCompositor.prototype.setColorCorrection = function(type, value) { this._compositeNode.setParameter(type, value); }; EffectCompositor.prototype.isSSREnabled = function() { return this._enableSSR; }; EffectCompositor.prototype.composite = function(renderer, scene, camera, framebuffer, frame) { var sourceTexture = this._sourceTexture; var targetTexture = sourceTexture; if (this._enableEdge) { this._edgePass.update(renderer, camera, sourceTexture, frame); sourceTexture = targetTexture = this._edgePass.getTargetTexture(); } if (this._enableSSR) { this._ssrPass.update(renderer, camera, sourceTexture, frame); targetTexture = this._ssrPass.getTargetTexture(); this._ssrPass.setSSAOTexture(this._enableSSAO ? this._ssaoPass.getTargetTexture() : null); } this._sourceNode.texture = targetTexture; this._cocNode.setParameter("depth", this._depthTexture); var blurKernel = this._dofBlurKernel; var blurKernelSize = this._dofBlurKernelSize; var frameAll = Math.floor(poissonKernel.length / 2 / blurKernelSize); var kernelOffset = frame % frameAll; for (var i = 0; i < blurKernelSize * 2; i++) { blurKernel[i] = poissonKernel[i + kernelOffset * blurKernelSize * 2]; } for (var i = 0; i < this._dofBlurNodes.length; i++) { this._dofBlurNodes[i].setParameter("percent", frame / 30); this._dofBlurNodes[i].setParameter("poissonKernel", blurKernel); } this._cocNode.setParameter("zNear", camera.near); this._cocNode.setParameter("zFar", camera.far); this._compositor.render(renderer, framebuffer); }; EffectCompositor.prototype.dispose = function(renderer) { this._sourceTexture.dispose(renderer); this._depthTexture.dispose(renderer); this._framebuffer.dispose(renderer); this._compositor.dispose(renderer); this._normalPass.dispose(renderer); this._ssaoPass.dispose(renderer); }; export { EffectCompositor as default };