* 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 { IFramebuffer } from './IFramebuffer';
import { ITexture2D } from './ITexture2D';
export enum PassType {
Normal = 'normal',
@ -16,7 +17,7 @@ export interface IPass<InitializationOptions> {
getName(): string;
getType(): PassType;
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;
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 {

View File

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

View File

@ -6,6 +6,7 @@ import { gl } from '../gl';
import { IFramebuffer } from '../IFramebuffer';
import { IPostProcessingPass, IPostProcessor } from '../IMultiPassRenderer';
import { IRendererService } from '../IRendererService';
import { ITexture2D } from '../ITexture2D';
/**
* ported from Three.js EffectComposer
@ -28,24 +29,69 @@ export default class PostProcessor implements IPostProcessor {
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) {
for (let i = 0; i < this.passes.length; i++) {
const pass = this.passes[i];
// last pass should render to screen
pass.setRenderToScreen(this.isLastEnabledPass(i));
await pass.render(layer);
// pingpong
if (i !== this.passes.length - 1) {
this.swap();
}
// if (pass.getName() === 'bloom') {
// await pass.render(layer);
// this.swap();
// await pass.render(layer);
// 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);
// pingpong
if (i !== this.passes.length - 1) {
this.swap();
}
}
}
}

View File

@ -7,7 +7,9 @@ import { IUniform } from '../../IUniform';
import BasePostProcessingPass from '../BasePostProcessingPass';
export interface IBloomPassConfig {
bloomBaseRadio: number;
bloomRadius: number;
bloomIntensity: number;
}
@injectable()
@ -47,6 +49,12 @@ export default class BloomPass extends BasePostProcessingPass<
if (!isNil(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;
}

View File

@ -1,9 +1,13 @@
varying vec2 v_UV;
uniform float u_BloomFinal: 0.0;
uniform sampler2D u_Texture;
uniform sampler2D u_Texture2;
uniform vec2 u_ViewportSize: [1.0, 1.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
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;
}
float luminance(vec4 color) {
return 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
}
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);
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));
// c2 *= luminance(c2);
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 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;
if(baselum <= 0.0) {
// float lum = luminance(inbloomColor);
// inbloomColor.rgb *= lum;
gl_FragColor += inbloomColor * u_intensity;
}
// gl_FragColor = inbloomColor * baseColor + baseColor;
// gl_FragColor = baseColor + bloom * 0.5;
} else {
gl_FragColor = inbloomColor;
}
// gl_FragColor = inbloomColor;
float h = 0.01;
vec4 baseColor = texture2D(u_Texture, v_UV);
// 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 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 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 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;
vec4 bloomColor =
color11 +
color12 +
color13 +
color21 +
color21 +
color23 +
color31 +
color32 +
color33;
if(baseColor.a > 0.0) {
// 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.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 = 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,
min = gl.NEAREST,
colorSpace = gl.BROWSER_DEFAULT_WEBGL,
x = 0,
y = 0,
copy = false,
} = options;
this.width = width;
this.height = height;
@ -56,6 +59,11 @@ export default class ReglTexture2D implements ITexture2D {
colorSpace: colorSpaceMap[colorSpace],
premultiplyAlpha,
aniso,
// copy pixels from current bind framebuffer
x,
y,
copy,
};
if (data) {

View File

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