cione-comp-lib
Version:
`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`
178 lines (177 loc) • 6.39 kB
JavaScript
import Matrix4 from "../../../claygl/src/math/Matrix4.mjs";
import Vector3 from "../../../claygl/src/math/Vector3.mjs";
import Texture2D from "../../../claygl/src/Texture2D.mjs";
import Texture from "../../../claygl/src/Texture.mjs";
import Pass from "../../../claygl/src/compositor/Pass.mjs";
import Shader from "../../../claygl/src/Shader.mjs";
import FrameBuffer from "../../../claygl/src/FrameBuffer.mjs";
import halton from "./halton.mjs";
import SSAOGLSL from "./SSAO.glsl.mjs";
Shader.import(SSAOGLSL);
function generateNoiseData(size) {
var data = new Uint8Array(size * size * 4);
var n = 0;
var v3 = new Vector3();
for (var i = 0; i < size; i++) {
for (var j = 0; j < size; j++) {
v3.set(Math.random() * 2 - 1, Math.random() * 2 - 1, 0).normalize();
data[n++] = (v3.x * 0.5 + 0.5) * 255;
data[n++] = (v3.y * 0.5 + 0.5) * 255;
data[n++] = 0;
data[n++] = 255;
}
}
return data;
}
function generateNoiseTexture(size) {
return new Texture2D({
pixels: generateNoiseData(size),
wrapS: Texture.REPEAT,
wrapT: Texture.REPEAT,
width: size,
height: size
});
}
function generateKernel(size, offset, hemisphere) {
var kernel = new Float32Array(size * 3);
offset = offset || 0;
for (var i = 0; i < size; i++) {
var phi = halton(i + offset, 2) * (hemisphere ? 1 : 2) * Math.PI;
var theta = halton(i + offset, 3) * Math.PI;
var r = Math.random();
var x = Math.cos(phi) * Math.sin(theta) * r;
var y = Math.cos(theta) * r;
var z = Math.sin(phi) * Math.sin(theta) * r;
kernel[i * 3] = x;
kernel[i * 3 + 1] = y;
kernel[i * 3 + 2] = z;
}
return kernel;
}
function SSAOPass(opt) {
opt = opt || {};
this._ssaoPass = new Pass({
fragment: Shader.source("ecgl.ssao.estimate")
});
this._blurPass = new Pass({
fragment: Shader.source("ecgl.ssao.blur")
});
this._framebuffer = new FrameBuffer({
depthBuffer: false
});
this._ssaoTexture = new Texture2D();
this._blurTexture = new Texture2D();
this._blurTexture2 = new Texture2D();
this._depthTex = opt.depthTexture;
this._normalTex = opt.normalTexture;
this.setNoiseSize(4);
this.setKernelSize(opt.kernelSize || 12);
if (opt.radius != null) {
this.setParameter("radius", opt.radius);
}
if (opt.power != null) {
this.setParameter("power", opt.power);
}
if (!this._normalTex) {
this._ssaoPass.material.disableTexture("normalTex");
this._blurPass.material.disableTexture("normalTex");
}
if (!this._depthTex) {
this._blurPass.material.disableTexture("depthTex");
}
this._blurPass.material.setUniform("normalTex", this._normalTex);
this._blurPass.material.setUniform("depthTex", this._depthTex);
}
SSAOPass.prototype.setDepthTexture = function(depthTex) {
this._depthTex = depthTex;
};
SSAOPass.prototype.setNormalTexture = function(normalTex) {
this._normalTex = normalTex;
this._ssaoPass.material[normalTex ? "enableTexture" : "disableTexture"]("normalTex");
this.setKernelSize(this._kernelSize);
};
SSAOPass.prototype.update = function(renderer, camera, frame) {
var width = renderer.getWidth();
var height = renderer.getHeight();
var ssaoPass = this._ssaoPass;
var blurPass = this._blurPass;
ssaoPass.setUniform("kernel", this._kernels[frame % this._kernels.length]);
ssaoPass.setUniform("depthTex", this._depthTex);
if (this._normalTex != null) {
ssaoPass.setUniform("normalTex", this._normalTex);
}
ssaoPass.setUniform("depthTexSize", [this._depthTex.width, this._depthTex.height]);
var viewInverseTranspose = new Matrix4();
Matrix4.transpose(viewInverseTranspose, camera.worldTransform);
ssaoPass.setUniform("projection", camera.projectionMatrix.array);
ssaoPass.setUniform("projectionInv", camera.invProjectionMatrix.array);
ssaoPass.setUniform("viewInverseTranspose", viewInverseTranspose.array);
var ssaoTexture = this._ssaoTexture;
var blurTexture = this._blurTexture;
var blurTexture2 = this._blurTexture2;
ssaoTexture.width = width / 2;
ssaoTexture.height = height / 2;
blurTexture.width = width;
blurTexture.height = height;
blurTexture2.width = width;
blurTexture2.height = height;
this._framebuffer.attach(ssaoTexture);
this._framebuffer.bind(renderer);
renderer.gl.clearColor(1, 1, 1, 1);
renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT);
ssaoPass.render(renderer);
blurPass.setUniform("textureSize", [width / 2, height / 2]);
blurPass.setUniform("projection", camera.projectionMatrix.array);
this._framebuffer.attach(blurTexture);
blurPass.setUniform("direction", 0);
blurPass.setUniform("ssaoTexture", ssaoTexture);
blurPass.render(renderer);
this._framebuffer.attach(blurTexture2);
blurPass.setUniform("textureSize", [width, height]);
blurPass.setUniform("direction", 1);
blurPass.setUniform("ssaoTexture", blurTexture);
blurPass.render(renderer);
this._framebuffer.unbind(renderer);
var clearColor = renderer.clearColor;
renderer.gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
};
SSAOPass.prototype.getTargetTexture = function() {
return this._blurTexture2;
};
SSAOPass.prototype.setParameter = function(name, val) {
if (name === "noiseTexSize") {
this.setNoiseSize(val);
} else if (name === "kernelSize") {
this.setKernelSize(val);
} else if (name === "intensity") {
this._ssaoPass.material.set("intensity", val);
} else {
this._ssaoPass.setUniform(name, val);
}
};
SSAOPass.prototype.setKernelSize = function(size) {
this._kernelSize = size;
this._ssaoPass.material.define("fragment", "KERNEL_SIZE", size);
this._kernels = this._kernels || [];
for (var i = 0; i < 30; i++) {
this._kernels[i] = generateKernel(size, i * size, !!this._normalTex);
}
};
SSAOPass.prototype.setNoiseSize = function(size) {
var texture = this._ssaoPass.getUniform("noiseTex");
if (!texture) {
texture = generateNoiseTexture(size);
this._ssaoPass.setUniform("noiseTex", generateNoiseTexture(size));
} else {
texture.data = generateNoiseData(size);
texture.width = texture.height = size;
texture.dirty();
}
this._ssaoPass.setUniform("noiseTexSize", [size, size]);
};
SSAOPass.prototype.dispose = function(renderer) {
this._blurTexture.dispose(renderer);
this._ssaoTexture.dispose(renderer);
this._blurTexture2.dispose(renderer);
};
export { SSAOPass as default };