cione-comp-lib
Version:
`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`
190 lines (189 loc) • 6.57 kB
JavaScript
import Texture2D from "../Texture2D.mjs";
import TextureCube from "../TextureCube.mjs";
import Texture from "../Texture.mjs";
import FrameBuffer from "../FrameBuffer.mjs";
import Pass from "../compositor/Pass.mjs";
import Material from "../Material.mjs";
import Shader from "../Shader.mjs";
import Skybox from "../plugin/Skybox.mjs";
import Scene from "../Scene.mjs";
import EnvironmentMapPass from "../prePass/EnvironmentMap.mjs";
import vendor from "../core/vendor.mjs";
import textureUtil from "./texture.mjs";
import integrateBRDFShaderCode from "./shader/integrateBRDF.glsl.mjs";
import prefilterFragCode from "./shader/prefilter.glsl.mjs";
var cubemapUtil = {};
var targets = ["px", "nx", "py", "ny", "pz", "nz"];
cubemapUtil.prefilterEnvironmentMap = function(renderer, envMap, textureOpts, normalDistribution, brdfLookup) {
if (!brdfLookup || !normalDistribution) {
normalDistribution = cubemapUtil.generateNormalDistribution();
brdfLookup = cubemapUtil.integrateBRDF(renderer, normalDistribution);
}
textureOpts = textureOpts || {};
var width = textureOpts.width || 64;
var height = textureOpts.height || 64;
var textureType = textureOpts.type || envMap.type;
var prefilteredCubeMap = new TextureCube({
width,
height,
type: textureType,
flipY: false,
mipmaps: []
});
if (!prefilteredCubeMap.isPowerOfTwo()) {
console.warn("Width and height must be power of two to enable mipmap.");
}
var size = Math.min(width, height);
var mipmapNum = Math.log(size) / Math.log(2) + 1;
var prefilterMaterial = new Material({
shader: new Shader({
vertex: Shader.source("clay.skybox.vertex"),
fragment: prefilterFragCode
})
});
prefilterMaterial.set("normalDistribution", normalDistribution);
textureOpts.encodeRGBM && prefilterMaterial.define("fragment", "RGBM_ENCODE");
textureOpts.decodeRGBM && prefilterMaterial.define("fragment", "RGBM_DECODE");
var dummyScene = new Scene();
var skyEnv;
if (envMap.textureType === "texture2D") {
var envCubemap = new TextureCube({
width,
height,
type: textureType === Texture.FLOAT ? Texture.HALF_FLOAT : textureType
});
textureUtil.panoramaToCubeMap(renderer, envMap, envCubemap, {
encodeRGBM: textureOpts.decodeRGBM
});
envMap = envCubemap;
}
skyEnv = new Skybox({
scene: dummyScene,
material: prefilterMaterial
});
skyEnv.material.set("environmentMap", envMap);
var envMapPass = new EnvironmentMapPass({
texture: prefilteredCubeMap
});
if (textureOpts.encodeRGBM) {
textureType = prefilteredCubeMap.type = Texture.UNSIGNED_BYTE;
}
var renderTargetTmp = new Texture2D({
width,
height,
type: textureType
});
var frameBuffer = new FrameBuffer({
depthBuffer: false
});
var ArrayCtor = vendor[textureType === Texture.UNSIGNED_BYTE ? "Uint8Array" : "Float32Array"];
for (var i = 0; i < mipmapNum; i++) {
prefilteredCubeMap.mipmaps[i] = {
pixels: {}
};
skyEnv.material.set("roughness", i / (mipmapNum - 1));
var n = renderTargetTmp.width;
var fov = 2 * Math.atan(n / (n - 0.5)) / Math.PI * 180;
for (var j = 0; j < targets.length; j++) {
var pixels = new ArrayCtor(renderTargetTmp.width * renderTargetTmp.height * 4);
frameBuffer.attach(renderTargetTmp);
frameBuffer.bind(renderer);
var camera = envMapPass.getCamera(targets[j]);
camera.fov = fov;
renderer.render(dummyScene, camera);
renderer.gl.readPixels(
0,
0,
renderTargetTmp.width,
renderTargetTmp.height,
Texture.RGBA,
textureType,
pixels
);
frameBuffer.unbind(renderer);
prefilteredCubeMap.mipmaps[i].pixels[targets[j]] = pixels;
}
renderTargetTmp.width /= 2;
renderTargetTmp.height /= 2;
renderTargetTmp.dirty();
}
frameBuffer.dispose(renderer);
renderTargetTmp.dispose(renderer);
skyEnv.dispose(renderer);
normalDistribution.dispose(renderer);
return {
environmentMap: prefilteredCubeMap,
brdfLookup,
normalDistribution,
maxMipmapLevel: mipmapNum
};
};
cubemapUtil.integrateBRDF = function(renderer, normalDistribution) {
normalDistribution = normalDistribution || cubemapUtil.generateNormalDistribution();
var framebuffer = new FrameBuffer({
depthBuffer: false
});
var pass = new Pass({
fragment: integrateBRDFShaderCode
});
var texture = new Texture2D({
width: 512,
height: 256,
type: Texture.HALF_FLOAT,
wrapS: Texture.CLAMP_TO_EDGE,
wrapT: Texture.CLAMP_TO_EDGE,
minFilter: Texture.NEAREST,
magFilter: Texture.NEAREST,
useMipmap: false
});
pass.setUniform("normalDistribution", normalDistribution);
pass.setUniform("viewportSize", [512, 256]);
pass.attachOutput(texture);
pass.render(renderer, framebuffer);
framebuffer.dispose(renderer);
return texture;
};
cubemapUtil.generateNormalDistribution = function(roughnessLevels, sampleSize) {
var roughnessLevels = roughnessLevels || 256;
var sampleSize = sampleSize || 1024;
var normalDistribution = new Texture2D({
width: roughnessLevels,
height: sampleSize,
type: Texture.FLOAT,
minFilter: Texture.NEAREST,
magFilter: Texture.NEAREST,
wrapS: Texture.CLAMP_TO_EDGE,
wrapT: Texture.CLAMP_TO_EDGE,
useMipmap: false
});
var pixels = new Float32Array(sampleSize * roughnessLevels * 4);
var tmp = [];
for (var j = 0; j < roughnessLevels; j++) {
var roughness = j / roughnessLevels;
var a = roughness * roughness;
for (var i = 0; i < sampleSize; i++) {
var y = (i << 16 | i >>> 16) >>> 0;
y = ((y & 1431655765) << 1 | (y & 2863311530) >>> 1) >>> 0;
y = ((y & 858993459) << 2 | (y & 3435973836) >>> 2) >>> 0;
y = ((y & 252645135) << 4 | (y & 4042322160) >>> 4) >>> 0;
y = (((y & 16711935) << 8 | (y & 4278255360) >>> 8) >>> 0) / 4294967296;
var cosTheta = Math.sqrt((1 - y) / (1 + (a * a - 1) * y));
tmp[i] = cosTheta;
}
for (var i = 0; i < sampleSize; i++) {
var offset = (i * roughnessLevels + j) * 4;
var cosTheta = tmp[i];
var sinTheta = Math.sqrt(1 - cosTheta * cosTheta);
var x = i / sampleSize;
var phi = 2 * Math.PI * x;
pixels[offset] = sinTheta * Math.cos(phi);
pixels[offset + 1] = cosTheta;
pixels[offset + 2] = sinTheta * Math.sin(phi);
pixels[offset + 3] = 1;
}
}
normalDistribution.pixels = pixels;
return normalDistribution;
};
var cubemapUtil$1 = cubemapUtil;
export { cubemapUtil$1 as default };