* feat: 优化后处理 bloom 的效果

* feat: 修改交替绘制 bloom 的写法

* style: lint style
This commit is contained in:
YiQianYao 2022-02-09 16:19:36 +08:00 committed by GitHub
parent 556f9c5c75
commit ef1d867ba7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 189 additions and 52 deletions

View File

@ -1,5 +1,6 @@
import { ILayer } from '../layer/ILayerService'; import { ILayer } from '../layer/ILayerService';
import { IFramebuffer } from './IFramebuffer'; import { IFramebuffer } from './IFramebuffer';
import { ITexture2D } from './ITexture2D';
export enum PassType { export enum PassType {
Normal = 'normal', Normal = 'normal',
@ -16,7 +17,7 @@ export interface IPass<InitializationOptions> {
getName(): string; getName(): string;
getType(): PassType; getType(): PassType;
init(layer: ILayer, config?: Partial<InitializationOptions>): void; init(layer: ILayer, config?: Partial<InitializationOptions>): void;
render(layer: ILayer): void; render(layer: ILayer, tex?: ITexture2D): void;
} }
/** /**

View File

@ -76,6 +76,19 @@ export interface ITexture2DInitializationOptions {
colorSpace?: gl.NONE | gl.BROWSER_DEFAULT_WEBGL; colorSpace?: gl.NONE | gl.BROWSER_DEFAULT_WEBGL;
mipmap?: boolean | gl.DONT_CARE | gl.NICEST | gl.FASTEST; mipmap?: boolean | gl.DONT_CARE | gl.NICEST | gl.FASTEST;
/* 是否复制当前的 framebuffer */
x?: number;
y?: number;
copy?: boolean;
// From the pixels in the current frame buffer
// var copyPixels = regl.texture({
// x: 5,
// y: 1,
// width: 10,
// height: 10,
// copy: true
// })
} }
export interface ITexture2D { export interface ITexture2D {

View File

@ -10,6 +10,7 @@ import quad from '../../../shaders/post-processing/quad.glsl';
import { TYPES } from '../../../types'; import { TYPES } from '../../../types';
import { ILayer } from '../../layer/ILayerService'; import { ILayer } from '../../layer/ILayerService';
import { IPostProcessingPass, PassType } from '../IMultiPassRenderer'; import { IPostProcessingPass, PassType } from '../IMultiPassRenderer';
import { ITexture2D } from '../ITexture2D';
import { IUniform } from '../IUniform'; import { IUniform } from '../IUniform';
/** /**
@ -106,7 +107,7 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
}); });
} }
public render(layer: ILayer) { public render(layer: ILayer, tex?: ITexture2D) {
const postProcessor = layer.multiPassRenderer.getPostProcessor(); const postProcessor = layer.multiPassRenderer.getPostProcessor();
const { useFramebuffer, getViewportSize, clear } = this.rendererService; const { useFramebuffer, getViewportSize, clear } = this.rendererService;
const { width, height } = getViewportSize(); const { width, height } = getViewportSize();
@ -119,12 +120,20 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
depth: 1, depth: 1,
stencil: 0, stencil: 0,
}); });
this.model.draw({
uniforms: { const uniformOptions: { [key: string]: any } = {
u_BloomFinal: 0.0,
u_Texture: postProcessor.getReadFBO(), u_Texture: postProcessor.getReadFBO(),
// u_Texture: tex ? tex : postProcessor.getReadFBO(),
u_ViewportSize: [width, height], u_ViewportSize: [width, height],
...this.convertOptionsToUniforms(this.optionsToUpdate), ...this.convertOptionsToUniforms(this.optionsToUpdate),
}, };
if (tex) {
uniformOptions.u_BloomFinal = 1.0;
uniformOptions.u_Texture2 = tex;
}
this.model.draw({
uniforms: uniformOptions,
}); });
}, },
); );

View File

@ -6,6 +6,7 @@ import { gl } from '../gl';
import { IFramebuffer } from '../IFramebuffer'; import { IFramebuffer } from '../IFramebuffer';
import { IPostProcessingPass, IPostProcessor } from '../IMultiPassRenderer'; import { IPostProcessingPass, IPostProcessor } from '../IMultiPassRenderer';
import { IRendererService } from '../IRendererService'; import { IRendererService } from '../IRendererService';
import { ITexture2D } from '../ITexture2D';
/** /**
* ported from Three.js EffectComposer * ported from Three.js EffectComposer
@ -28,24 +29,69 @@ export default class PostProcessor implements IPostProcessor {
return this.writeFBO; return this.writeFBO;
} }
/**
* framebuffer
* @returns
*/
public getCurrentFBOTex() {
const { getViewportSize, createTexture2D } = this.rendererService;
const { width, height } = getViewportSize();
return createTexture2D({
x: 0,
y: 0,
width,
height,
copy: true,
});
}
/**
* readFBO
* @returns
*/
public getReadFBOTex() {
const { useFramebuffer } = this.rendererService;
return new Promise((resolve, reject) => {
useFramebuffer(this.readFBO, async () => {
resolve(this.getCurrentFBOTex());
});
});
}
public async renderBloomPass(
layer: ILayer,
pass: IPostProcessingPass<unknown>,
) {
const tex = (await this.getReadFBOTex()) as ITexture2D;
// count 定义 bloom 交替绘制的次数
let count = 0;
while (count < 4) {
await pass.render(layer, tex);
this.swap();
count++;
}
}
public async render(layer: ILayer) { public async render(layer: ILayer) {
for (let i = 0; i < this.passes.length; i++) { for (let i = 0; i < this.passes.length; i++) {
const pass = this.passes[i]; const pass = this.passes[i];
// last pass should render to screen // last pass should render to screen
pass.setRenderToScreen(this.isLastEnabledPass(i)); pass.setRenderToScreen(this.isLastEnabledPass(i));
// await pass.render(layer);
// // pingpong
// if (i !== this.passes.length - 1) {
// this.swap();
// }
if (pass.getName() === 'bloom') {
await this.renderBloomPass(layer, pass);
} else {
await pass.render(layer); await pass.render(layer);
// pingpong // pingpong
if (i !== this.passes.length - 1) { if (i !== this.passes.length - 1) {
this.swap(); this.swap();
} }
}
// if (pass.getName() === 'bloom') {
// await pass.render(layer);
// this.swap();
// await pass.render(layer);
// this.swap();
// }
} }
} }

View File

@ -7,7 +7,9 @@ import { IUniform } from '../../IUniform';
import BasePostProcessingPass from '../BasePostProcessingPass'; import BasePostProcessingPass from '../BasePostProcessingPass';
export interface IBloomPassConfig { export interface IBloomPassConfig {
bloomBaseRadio: number;
bloomRadius: number; bloomRadius: number;
bloomIntensity: number;
} }
@injectable() @injectable()
@ -47,6 +49,12 @@ export default class BloomPass extends BasePostProcessingPass<
if (!isNil(options.bloomRadius)) { if (!isNil(options.bloomRadius)) {
uniforms.u_radius = options.bloomRadius; uniforms.u_radius = options.bloomRadius;
} }
if (!isNil(options.bloomIntensity)) {
uniforms.u_intensity = options.bloomIntensity;
}
if (!isNil(options.bloomBaseRadio)) {
uniforms.u_baseRadio = options.bloomBaseRadio;
}
return uniforms; return uniforms;
} }

View File

@ -1,9 +1,13 @@
varying vec2 v_UV; varying vec2 v_UV;
uniform float u_BloomFinal: 0.0;
uniform sampler2D u_Texture; uniform sampler2D u_Texture;
uniform sampler2D u_Texture2;
uniform vec2 u_ViewportSize: [1.0, 1.0]; uniform vec2 u_ViewportSize: [1.0, 1.0];
uniform float u_radius: 5.0; uniform float u_radius: 5.0;
uniform float u_intensity: 0.3;
uniform float u_baseRadio: 0.5;
// https://github.com/Jam3/glsl-fast-gaussian-blur/blob/master/9.glsl // https://github.com/Jam3/glsl-fast-gaussian-blur/blob/master/9.glsl
vec4 blur9(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) { vec4 blur9(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
@ -18,51 +22,97 @@ vec4 blur9(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
return color; return color;
} }
float luminance(vec4 color) {
return 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
}
void main() { void main() {
// vec4 baseColor = texture2D(u_Texture, v_UV);
// float lum = luminance(baseColor);
// baseColor.a *= lum;
// gl_FragColor = baseColor;
// if(u_BloomFinal > 0.0) { //
// gl_FragColor = baseColor; //--
// }
float r = sqrt(u_radius); float r = sqrt(u_radius);
vec4 c1 = blur9(u_Texture, v_UV, u_ViewportSize, vec2(u_radius, 0.0)); vec4 c1 = blur9(u_Texture, v_UV, u_ViewportSize, vec2(u_radius, 0.0));
// c1 *= luminance(c1);
vec4 c2 = blur9(u_Texture, v_UV, u_ViewportSize, vec2(0.0, u_radius)); vec4 c2 = blur9(u_Texture, v_UV, u_ViewportSize, vec2(0.0, u_radius));
// c2 *= luminance(c2);
vec4 c3 = blur9(u_Texture, v_UV, u_ViewportSize, vec2(r, r)); vec4 c3 = blur9(u_Texture, v_UV, u_ViewportSize, vec2(r, r));
// c3 *= luminance(c3);
vec4 c4 = blur9(u_Texture, v_UV, u_ViewportSize, vec2(r, -r)); vec4 c4 = blur9(u_Texture, v_UV, u_ViewportSize, vec2(r, -r));
vec4 inbloomColor = c1 * 0.25 + c2 * 0.25 + c3 * 0.25 + c4 * 0.25; // c4 *= luminance(c4);
vec4 inbloomColor = (c1 + c2 + c3 + c4) * 0.25;
// float lum = luminance(inbloomColor);
// inbloomColor.rgb *= lum;
if(u_BloomFinal > 0.0) {
vec4 baseColor = texture2D(u_Texture2, v_UV);
float baselum = luminance(baseColor);
// float lum = luminance(inbloomColor);
// vec4 bloom = vec4(lum);
// inbloomColor.a *= lum;
// gl_FragColor = inbloomColor * u_intensity + texture2D(u_Texture2, v_UV);
// gl_FragColor = inbloomColor * 0.5 + texture2D(u_Texture2, v_UV);
// gl_FragColor = baseColor;
// gl_FragColor = inbloomColor;
// vec4 mixColor = mix(baseColor, inbloomColor, max(u_intensity - 0.3, 0.0));
// mixColor.a = max(baseColor.a, mixColor.a);
gl_FragColor = mix(inbloomColor, baseColor, max(1.0 - u_intensity, u_baseRadio));
// gl_FragColor = mixColor;
// gl_FragColor = baseColor;
float h = 0.01; if(baselum <= 0.0) {
vec4 baseColor = texture2D(u_Texture, v_UV); // float lum = luminance(inbloomColor);
// inbloomColor.rgb *= lum;
vec4 color11 = texture2D( u_Texture, vec2( v_UV.x - 1.0 * h, v_UV.y + 1.0 * h) ); gl_FragColor += inbloomColor * u_intensity;
vec4 color12 = texture2D( u_Texture, vec2( v_UV.x - 0.0 * h, v_UV.y + 1.0 * h) );
vec4 color13 = texture2D( u_Texture, vec2( v_UV.x + 1.0 * h, v_UV.y + 1.0 * h) );
vec4 color21 = texture2D( u_Texture, vec2( v_UV.x - 1.0 * h, v_UV.y) );
vec4 color23 = texture2D( u_Texture, vec2( v_UV.x + 1.0 * h, v_UV.y) );
vec4 color31 = texture2D( u_Texture, vec2( v_UV.x - 1.0 * h, v_UV.y-1.0*h) );
vec4 color32 = texture2D( u_Texture, vec2( v_UV.x - 0.0 * h, v_UV.y-1.0*h) );
vec4 color33 = texture2D( u_Texture, vec2( v_UV.x + 1.0 * h, v_UV.y-1.0*h) );
vec4 bloomColor =
color11 +
color12 +
color13 +
color21 +
color21 +
color23 +
color31 +
color32 +
color33;
if(baseColor.a > 0.0) {
gl_FragColor.r = min(bloomColor.r, baseColor.r);
gl_FragColor.g = min(bloomColor.g, baseColor.g);
gl_FragColor.b = min(bloomColor.b, baseColor.b);
gl_FragColor.a = min(bloomColor.a, baseColor.a);
gl_FragColor = mix(inbloomColor, gl_FragColor, 0.7);
} else {
gl_FragColor = bloomColor/9.0;
} }
// gl_FragColor = inbloomColor * baseColor + baseColor;
// gl_FragColor = baseColor + bloom * 0.5;
} else {
gl_FragColor = inbloomColor;
}
// gl_FragColor = inbloomColor;
// float h = 0.01;
// vec4 color11 = texture2D( u_Texture, vec2( v_UV.x - 1.0 * h, v_UV.y + 1.0 * h) );
// vec4 color12 = texture2D( u_Texture, vec2( v_UV.x - 0.0 * h, v_UV.y + 1.0 * h) );
// vec4 color13 = texture2D( u_Texture, vec2( v_UV.x + 1.0 * h, v_UV.y + 1.0 * h) );
// vec4 color21 = texture2D( u_Texture, vec2( v_UV.x - 1.0 * h, v_UV.y) );
// vec4 color23 = texture2D( u_Texture, vec2( v_UV.x + 1.0 * h, v_UV.y) );
// vec4 color31 = texture2D( u_Texture, vec2( v_UV.x - 1.0 * h, v_UV.y-1.0*h) );
// vec4 color32 = texture2D( u_Texture, vec2( v_UV.x - 0.0 * h, v_UV.y-1.0*h) );
// vec4 color33 = texture2D( u_Texture, vec2( v_UV.x + 1.0 * h, v_UV.y-1.0*h) );
// vec4 bloomColor =
// color11 +
// color12 +
// color13 +
// color21 +
// color21 +
// color23 +
// color31 +
// color32 +
// color33;
// if(baseColor.a > 0.0) {
// gl_FragColor.r = min(bloomColor.r, baseColor.r);
// gl_FragColor.g = min(bloomColor.g, baseColor.g);
// gl_FragColor.b = min(bloomColor.b, baseColor.b);
// gl_FragColor.a = min(bloomColor.a, baseColor.a);
// gl_FragColor = mix(inbloomColor, gl_FragColor, 0.7);
// } else {
// gl_FragColor = bloomColor/9.0;
// }
} }

View File

@ -36,6 +36,9 @@ export default class ReglTexture2D implements ITexture2D {
mag = gl.NEAREST, mag = gl.NEAREST,
min = gl.NEAREST, min = gl.NEAREST,
colorSpace = gl.BROWSER_DEFAULT_WEBGL, colorSpace = gl.BROWSER_DEFAULT_WEBGL,
x = 0,
y = 0,
copy = false,
} = options; } = options;
this.width = width; this.width = width;
this.height = height; this.height = height;
@ -56,6 +59,11 @@ export default class ReglTexture2D implements ITexture2D {
colorSpace: colorSpaceMap[colorSpace], colorSpace: colorSpaceMap[colorSpace],
premultiplyAlpha, premultiplyAlpha,
aniso, aniso,
// copy pixels from current bind framebuffer
x,
y,
copy,
}; };
if (data) { if (data) {

View File

@ -26,14 +26,14 @@ export default class Bloom extends React.Component {
const scene = new Scene({ const scene = new Scene({
id: 'map', id: 'map',
map: new Mapbox({ map: new Mapbox({
// style: 'mapbox://styles/mapbox/streets-v9', style: 'mapbox://styles/mapbox/streets-v9',
style: 'blank', // style: 'blank',
center: [110.19382669582967, 50.258134], center: [110.19382669582967, 50.258134],
pitch: 0, pitch: 0,
zoom: 3, zoom: 3,
}), }),
}); });
scene.setBgColor('#000'); // scene.setBgColor('#000');
const layer = new PolygonLayer({ const layer = new PolygonLayer({
zIndex: 0, zIndex: 0,
// enablePicking: true, // enablePicking: true,
@ -43,7 +43,9 @@ export default class Bloom extends React.Component {
[ [
'bloom', 'bloom',
{ {
bloomRadius: 8, // bloomBaseRadio: 0.5,
bloomRadius: 25,
bloomIntensity: 1,
}, },
], ],
], ],