import { Utils } from "../utils/Utils";
import { BlendMode } from "../data/BlendMode";
import { BaseRenderer } from "./BaseRenderer";
/**
* @typedef {Object} AmbientOcclusionMapRendererConfig
* @extends {RendererConfig}
* @property {TextureInfo} sourceTexture
* @property {TextureInfo} heightMap
*/
/**
* <pre>
* Ambient occlusion map renderer
* - Creates an ambient occlusion texture from a height map texture
* </pre>
* @extends {BaseRenderer}
*/
export class AmbientOcclusionMapRenderer extends BaseRenderer {
/**
* Creates an instance of AmbientOcclusionMapRenderer.
* @constructor
* @param {AmbientOcclusionMapRendererConfig} options
*/
constructor(options = {}) {
options.config = Utils.initRendererConfig(options.config);
// prettier-ignore
options.config.locations = options.config.locations.concat([
"uSTTex",
"uR",
"uS",
"uM",
"uDM",
"uUSTT",
]);
super(options);
this.clearBeforeRender = true;
this.clearColor.set(0, 0, 0, 1);
this.sourceTexture = options.sourceTexture;
this.heightMap = options.heightMap;
this.radius = options.radius ?? 4;
this.samples = options.samples ?? 4;
this.multiplier = options.multiplier ?? 1;
this.depthMultiplier = options.depthMultiplier ?? 1;
}
/**
* @ignore
*/
$render() {
this.context.setBlendMode(BlendMode.NORMAL);
this.$useTextureAt(this.heightMap, this.$locations.uTex, 0);
if (this.sourceTexture) {
this.$useTextureAt(this.sourceTexture, this.$locations.uSTTex, 1);
this.$gl.uniform1f(this.$locations.uUSTT, 1);
} else this.$gl.uniform1f(this.$locations.uUSTT, 0);
this.$gl.uniform1f(this.$locations.uR, this.radius);
this.$gl.uniform1f(this.$locations.uS, this.samples);
this.$gl.uniform1f(this.$locations.uM, this.multiplier);
this.$gl.uniform1f(this.$locations.uDM, this.depthMultiplier);
this.$uploadBuffers();
this.$drawInstanced(1);
}
// prettier-ignore
/**
* @param {AmbientOcclusionMapRendererConfig} options
* @returns {string}
* @ignore
*/
$createVertexShader(options) {
return Utils.GLSL.VERSION +
"precision highp float;\n" +
"in vec2 " +
"aPos;" +
"uniform float " +
"uFlpY;" +
"out vec2 " +
"vTUv;" +
"void main(void){" +
"gl_Position=vec4(aPos*2.-1.,1,1);" +
"vTUv=vec2(aPos.x,1.-aPos.y);" +
"gl_Position.y*=uFlpY;" +
"}";
}
// prettier-ignore
/**
* @param {AmbientOcclusionMapRendererConfig} options
* @returns {string}
* @ignore
*/
$createFragmentShader(options) {
return Utils.GLSL.VERSION +
"precision highp float;\n" +
Utils.GLSL.DEFINE.HEIGHT +
Utils.GLSL.DEFINE.RADIAN_360 +
"in vec2 " +
"vTUv;" +
"uniform sampler2D " +
"uSTTex," +
"uTex;" +
"uniform float " +
"uFlpY," +
"uR," +
"uS," +
"uUSTT," +
"uM," +
"uDM;" +
"out vec4 " +
"oCl;" +
Utils.GLSL.RANDOM +
"void main(void){" +
"float " +
"tx=texture(uTex,vTUv).g," +
"v=0.;" +
"if(uS>0.&&uR>0.){" +
"vec2 " +
"its=vec2(textureSize(uTex,0))," +
"rnd=(vec2(rand(vTUv,1.),rand(vTUv,2.))*2.-1.)/its," +
"p;" +
"float " +
"t=RADIAN_360/uS," +
"uRH=uR/HEIGHT," +
"rad," +
"i;" +
"for(i=0.;i<uS;++i){" +
"rad=i*t;" +
"p=vec2(" +
"cos(rad)," +
"sin(rad)" +
")*uR/its;" +
"v+=uM*max(" +
"0.," +
"min(" +
"1.," +
"(" +
"texture(" +
"uTex," +
"vTUv+p.xy+rnd" +
").g-tx" +
")/uRH" +
")" +
");" +
"}" +
"v/=uS;" +
"}" +
"vec3 " +
"stCl=uUSTT<1.?vec3(1):texture(uSTTex,vTUv).rgb;" +
"oCl=vec4(stCl*(vec3(((1.-uDM)*.5+tx*uDM))*(1.-v)),1);" +
"}";
}
}