{
if(renderer.timerNextFrame) {
clearTimeout(renderer.timerNextFrame);
renderer.timerNextFrame = undefined;
}
let spectrumScaler = input_spectrum / 40;
let renderIterations = 256;
let accumulate = false;
let exposure = input_exposure / 50;
let accumulateScaler = 1;
let doRenderNextFrame = (accumulate) => {
let sampled = importance_sample();
let samplesCount = sampled.count;
let cBuffer = sampled.samples;
gl.disable(gl.DEPTH_TEST);
gl.bindFramebuffer(gl.FRAMEBUFFER, renderer.framebuffer);
gl.viewport(0, 0, renderer.renderWidth, renderer.renderHeight);
gl.clearColor(0, 0, 0, 1);
if (!accumulate) {
gl.clear(gl.COLOR_BUFFER_BIT);
}
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE);
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.feedbackBuffer1);
gl.bufferData(gl.ARRAY_BUFFER, 12 * samplesCount, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.feedbackBuffer2);
gl.bufferData(gl.ARRAY_BUFFER, 12 * samplesCount, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.useProgram(shader_buddhabrot_escape);
gl.uniform1f(gl.getUniformLocation(shader_buddhabrot_escape, "u_spectrum_scaler"), spectrumScaler);
gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
gl.enableVertexAttribArray(gl.getAttribLocation(shader_buddhabrot_escape, "a_position"));
gl.vertexAttribPointer(gl.getAttribLocation(shader_buddhabrot_escape, "a_position"), 3, gl.FLOAT, false, 12, 0);
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, renderer.transformFeedback);
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, renderer.feedbackBuffer1);
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.feedbackBuffer2);
gl.beginTransformFeedback(gl.POINTS);
gl.enable(gl.RASTERIZER_DISCARD);
gl.drawArrays(gl.POINTS, 0, samplesCount);
gl.disable(gl.RASTERIZER_DISCARD);
gl.endTransformFeedback();
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
// Iteratively render using transform feedback
gl.useProgram(shader_buddhabrot);
gl.uniform1f(gl.getUniformLocation(shader_buddhabrot, "u_aspect_ratio"), renderer.renderWidth / renderer.renderHeight);
gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
gl.enableVertexAttribArray(gl.getAttribLocation(shader_buddhabrot, "a_position"));
gl.vertexAttribPointer(gl.getAttribLocation(shader_buddhabrot, "a_position"), 3, gl.FLOAT, false, 12, 0);
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE);
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, renderer.transformFeedback);
for (let i = 0; i < renderIterations; i++) {
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, renderer.feedbackBuffer2);
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.feedbackBuffer1);
gl.enableVertexAttribArray(gl.getAttribLocation(shader_buddhabrot, "i_position"));
gl.vertexAttribPointer(gl.getAttribLocation(shader_buddhabrot, "i_position"), 3, gl.FLOAT, false, 12, 0);
gl.beginTransformFeedback(gl.POINTS);
if (i < 4) {
gl.enable(gl.RASTERIZER_DISCARD);
}
gl.drawArrays(gl.POINTS, 0, samplesCount);
gl.disable(gl.RASTERIZER_DISCARD);
gl.endTransformFeedback();
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);
let t = renderer.feedbackBuffer1;
renderer.feedbackBuffer1 = renderer.feedbackBuffer2;
renderer.feedbackBuffer2 = t;
}
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
// Generate the colored fractal
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.disable(gl.BLEND);
let vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, -1, 1, 1, -1, 1, 1]), gl.STATIC_DRAW);
gl.useProgram(shader_color);
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.enableVertexAttribArray(gl.getAttribLocation(shader_color, "a_position"));
gl.vertexAttribPointer(gl.getAttribLocation(shader_color, "a_position"), 2, gl.FLOAT, false, 8, 0);
gl.uniform1i(gl.getUniformLocation(shader_color, "texture"), 0);
gl.uniform1i(gl.getUniformLocation(shader_color, "textureColor"), 1);
gl.uniform1f(gl.getUniformLocation(shader_color, "colormapSize"), colormap.colormapSize);
gl.uniform1f(gl.getUniformLocation(shader_color, "colormapScaler"), Math.pow(2, -exposure) * (renderIterations - 4) / 6000 * accumulateScaler / sampler.scaler / 1 / 4);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, colormap.textureColor);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, renderer.framebufferTexture);
gl.generateMipmap(gl.TEXTURE_2D);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, null);
accumulateScaler += 1;
if(accumulateScaler < 1000) {
renderer.timerNextFrame = setTimeout(() => {
doRenderNextFrame(true);
}, 100);
}
}
doRenderNextFrame(false);
}