cione-comp-lib
Version:
`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`
394 lines (393 loc) • 13.6 kB
JavaScript
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 };