hefeihvac_java/node_modules/echarts-gl/lib/effect/EffectCompositor.js

615 lines
15 KiB
JavaScript
Raw Permalink Normal View History

2024-04-07 18:15:00 +08:00
import Shader from 'claygl/src/Shader';
import Texture2D from 'claygl/src/Texture2D';
import Texture from 'claygl/src/Texture';
import FrameBuffer from 'claygl/src/FrameBuffer';
import createCompositor from 'claygl/src/compositor/createCompositor';
import SSAOPass from './SSAOPass';
import SSRPass from './SSRPass';
import poissonKernel from './poissonKernel';
import graphicGL from '../util/graphicGL';
import NormalPass from './NormalPass';
import EdgePass from './EdgePass';
import effectJson from './composite.js';
import blurCode from 'claygl/src/shader/source/compositor/blur.glsl.js';
import lutCode from 'claygl/src/shader/source/compositor/lut.glsl.js';
import outputCode from 'claygl/src/shader/source/compositor/output.glsl.js';
import brightCode from 'claygl/src/shader/source/compositor/bright.glsl.js';
import downsampleCode from 'claygl/src/shader/source/compositor/downsample.glsl.js';
import upsampleCode from 'claygl/src/shader/source/compositor/upsample.glsl.js';
import hdrCode from 'claygl/src/shader/source/compositor/hdr.glsl.js';
import blendCode from 'claygl/src/shader/source/compositor/blend.glsl.js';
import fxaaCode from 'claygl/src/shader/source/compositor/fxaa.glsl.js';
import DOFCode from './DOF.glsl.js';
import edgeCode from './edge.glsl.js';
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]; // Use viewport width/height instead of renderer width/height
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);
};
/**
* Update normal
*/
EffectCompositor.prototype.updateNormal = function (renderer, scene, camera, frame) {
if (this._ifRenderNormalPass()) {
this._normalPass.update(renderer, scene, camera);
}
};
/**
* Render SSAO after render the scene, before compositing
*/
EffectCompositor.prototype.updateSSAO = function (renderer, scene, camera, frame) {
this._ssaoPass.update(renderer, camera, frame);
};
/**
* Enable SSAO effect
*/
EffectCompositor.prototype.enableSSAO = function () {
this._enableSSAO = true;
};
/**
* Disable SSAO effect
*/
EffectCompositor.prototype.disableSSAO = function () {
this._enableSSAO = false;
};
/**
* Enable SSR effect
*/
EffectCompositor.prototype.enableSSR = function () {
this._enableSSR = true; // this._normalPass.enableTargetTexture3 = true;
};
/**
* Disable SSR effect
*/
EffectCompositor.prototype.disableSSR = function () {
this._enableSSR = false; // this._normalPass.enableTargetTexture3 = false;
};
/**
* Render SSAO after render the scene, before compositing
*/
EffectCompositor.prototype.getSSAOTexture = function () {
return this._ssaoPass.getTargetTexture();
};
/**
* @return {clay.FrameBuffer}
*/
EffectCompositor.prototype.getSourceFrameBuffer = function () {
return this._framebuffer;
};
/**
* @return {clay.Texture2D}
*/
EffectCompositor.prototype.getSourceTexture = function () {
return this._sourceTexture;
};
/**
* Disable fxaa effect
*/
EffectCompositor.prototype.disableFXAA = function () {
this._removeChainNode(this._fxaaNode);
};
/**
* Enable fxaa effect
*/
EffectCompositor.prototype.enableFXAA = function () {
this._addChainNode(this._fxaaNode);
};
/**
* Enable bloom effect
*/
EffectCompositor.prototype.enableBloom = function () {
this._compositeNode.inputs.bloom = 'bloom_composite';
this._compositor.dirty();
};
/**
* Disable bloom effect
*/
EffectCompositor.prototype.disableBloom = function () {
this._compositeNode.inputs.bloom = null;
this._compositor.dirty();
};
/**
* Enable depth of field effect
*/
EffectCompositor.prototype.enableDOF = function () {
this._compositeNode.inputs.texture = 'dof_composite';
this._compositor.dirty();
};
/**
* Disable depth of field effect
*/
EffectCompositor.prototype.disableDOF = function () {
this._compositeNode.inputs.texture = 'source';
this._compositor.dirty();
};
/**
* Enable color correction
*/
EffectCompositor.prototype.enableColorCorrection = function () {
this._compositeNode.define('COLOR_CORRECTION');
this._enableColorCorrection = true;
};
/**
* Disable color correction
*/
EffectCompositor.prototype.disableColorCorrection = function () {
this._compositeNode.undefine('COLOR_CORRECTION');
this._enableColorCorrection = false;
};
/**
* Enable edge detection
*/
EffectCompositor.prototype.enableEdge = function () {
this._enableEdge = true;
};
/**
* Disable edge detection
*/
EffectCompositor.prototype.disableEdge = function () {
this._enableEdge = false;
};
/**
* Set bloom intensity
* @param {number} value
*/
EffectCompositor.prototype.setBloomIntensity = function (value) {
this._compositeNode.setParameter('bloomIntensity', value);
};
EffectCompositor.prototype.setSSAOParameter = function (name, value) {
switch (name) {
case 'quality':
// PENDING
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;
default:
if (process.env.NODE_ENV !== 'production') {
console.warn('Unkown SSAO parameter ' + name);
}
}
};
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;
default:
if (process.env.NODE_ENV !== 'production') {
console.warn('Unkown DOF parameter ' + name);
}
}
};
EffectCompositor.prototype.setSSRParameter = function (name, value) {
if (value == null) {
return;
}
switch (name) {
case 'quality':
// PENDING
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.0 - value, 1.0), 0.0));
break;
case 'physical':
this.setPhysicallyCorrectSSR(value);
break;
default:
console.warn('Unkown SSR parameter ' + name);
}
};
EffectCompositor.prototype.setPhysicallyCorrectSSR = function (physical) {
this._ssrPass.setPhysicallyCorrect(physical);
};
/**
* Set color of edge
*/
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); // var lights = scene.getLights();
// for (var i = 0; i < lights.length; i++) {
// if (lights[i].cubemap) {
// this._ssrPass.setAmbientCubemap(lights[i].cubemap, lights[i].intensity);
// }
// }
}
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.0);
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 default EffectCompositor;