Public
Edited
Dec 5, 2022
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
{
let colorTexture = renderSceneA();
let brightnessTexture = renderBrightnessScene(colorTexture);
let blurTexture = renderBlurredScene(brightnessTexture);
// To check if your colorTexture is rendered properly, uncomment the next line and comment out renderBlendScene(colorTexture, blurTexture);
// it also works for brightnessTexture and blurTexture
// renderTexture(colorTexture);

renderBlendScene(colorTexture, blurTexture);

return gl.canvas;

}
Insert cell
function renderTexture(texture) {
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
quaduniforms.colortxt = texture;

gl.useProgram(textureRenderProgramInfo.program);

twgl.setUniforms(textureRenderProgramInfo, quaduniforms);
twgl.setBuffersAndAttributes(gl, textureRenderProgramInfo, quadInfo);
twgl.drawBufferInfo(gl, quadInfo);

}
Insert cell
function renderBlendScene(colorTexture, blurTexture)
{
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

quaduniforms.colortxt = colorTexture;
quaduniforms.blurtxt = blurTexture;
gl.useProgram(blendprogramInfo.program);

twgl.setUniforms(blendprogramInfo, quaduniforms);
twgl.setBuffersAndAttributes(gl, blendprogramInfo, quadInfo);
twgl.drawBufferInfo(gl, quadInfo);

}
Insert cell
function renderBlurredScene(texture) {
let blurTexture = createColorTexture();
let blurFrameBuffer = createColorBuffer(blurTexture);
gl.bindFramebuffer(gl.FRAMEBUFFER, blurFrameBuffer);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
quaduniforms.horizontal = true;
quaduniforms.colortxt = texture;

gl.useProgram(blurprogramInfo.program);

twgl.setUniforms(blurprogramInfo, quaduniforms);
twgl.setBuffersAndAttributes(gl, blurprogramInfo, quadInfo);
twgl.drawBufferInfo(gl, quadInfo);

gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return blurTexture;
}
Insert cell
function renderBrightnessScene(texture) {
let brightnessTexture = createColorTexture();
let brightnessFrameBuffer = createColorBuffer(brightnessTexture);
gl.bindFramebuffer(gl.FRAMEBUFFER, brightnessFrameBuffer);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.clearColor(...hex2rgb(colorParameters.background), 1);
quaduniforms.colortxt = texture;
gl.useProgram(brightnessprogramInfo.program);

twgl.setUniforms(brightnessprogramInfo, quaduniforms);
twgl.setBuffersAndAttributes(gl, brightnessprogramInfo, quadInfo);
twgl.drawBufferInfo(gl, quadInfo);

gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return brightnessTexture
}
Insert cell
function renderSceneA() {
let colorTexture = createColorTexture();
let colorFrameBuffer = createColorBuffer(colorTexture);
gl.bindFramebuffer(gl.FRAMEBUFFER, colorFrameBuffer);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)
return "Framebuffer Incomplete";
gl.useProgram(baseprogramInfo.program);

twgl.setUniforms(baseprogramInfo, uniforms[0]);
twgl.setBuffersAndAttributes(gl, baseprogramInfo, boxbufferInfo);
twgl.drawBufferInfo(gl, boxbufferInfo);

twgl.setUniforms(baseprogramInfo, uniforms[3]);
twgl.setBuffersAndAttributes(gl, baseprogramInfo, planebufferInfo);
twgl.drawBufferInfo(gl, planebufferInfo);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return colorTexture;
}
Insert cell
function renderSceneB() {
let colorTexture = createColorTexture();
let colorFrameBuffer = createColorBuffer(colorTexture);

gl.bindFramebuffer(gl.FRAMEBUFFER, colorFrameBuffer);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

gl.useProgram(baseprogramInfo.program);
modelBufferInfoArray.forEach((bufferInfo) => {
twgl.setBuffersAndAttributes(gl, baseprogramInfo, bufferInfo);
twgl.setUniforms(baseprogramInfo, uniformb);
twgl.drawBufferInfo(gl, bufferInfo);
});

twgl.setUniforms(baseprogramInfo, uniforms[3]);
twgl.setBuffersAndAttributes(gl, baseprogramInfo, planebufferInfo);
twgl.drawBufferInfo(gl, planebufferInfo);

gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return colorTexture;

}
Insert cell
gl = {
const canvas = DOM.canvas(width, width);
const gl = canvas.getContext("webgl2");

gl.clearColor(...hex2rgb(colorParameters.background), 1);
gl.clearDepth(1);

gl.enable(gl.DEPTH_TEST);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

return gl;
}
Insert cell
Insert cell
shaders = ({
vs: `#version 300 es

precision mediump float;

in vec3 position;
in vec3 normal;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 normalMatrix;

out vec3 fragPosition;
out vec3 fragNormal;

void main() {
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
fragNormal = normalize( (normalMatrix * vec4(normal, 0.0f)).xyz );
fragPosition = worldPosition.xyz;
gl_Position = projectionMatrix * viewMatrix * worldPosition;
}`,

fs: `#version 300 es
precision mediump float;

out vec4 outColor;

in vec3 fragNormal;
in vec3 fragPosition;

uniform vec4 light;
uniform vec3 eyePosition;

uniform vec3 materialColor;
uniform float ambientIntensity;
uniform vec3 specularColor;
uniform float shininess;
uniform float K_s;

void main () {
vec3 N = normalize(fragNormal);

vec3 L;
if (light.w==0.0){
L = normalize(light.xyz);
}
else{
L = normalize(light.xyz-fragPosition);
}
vec3 V = normalize(eyePosition-fragPosition);
vec3 H = normalize(L+V);

vec3 ambient = ambientIntensity*materialColor;
vec3 diffuse = materialColor * clamp(dot(L,N), 0.,1.);
vec3 specular = specularColor * pow(clamp(dot(H,N),0.,1.), shininess);
vec3 color = (1.-K_s)*diffuse + K_s*specular + ambient;
outColor = vec4(color, 1);
}`
})
Insert cell
baseprogramInfo = {
errorBlock.style.height = "20px";
errorBlock.innerHTML = "Program Shader compilation successful";
return twgl.createProgramInfo(gl, [shaders.vs, shaders.fs], (message) => {
errorBlock.style.height = "400px";
errorBlock.innerHTML = "Program Shader compilation error\n" + message;
});
}
Insert cell
Insert cell
brightnessShader = ({
vs: `#version 300 es

precision mediump float;

in vec2 position;
in vec2 uvs;

out vec2 fragUV;

void main() {
gl_Position = vec4(position, 0.0, 1.0);
fragUV = uvs;
}`,

fs: `#version 300 es
precision mediump float;

in vec2 fragUV;
out vec4 FragColor;

uniform sampler2D colortxt;

void main(){
vec3 texColor = texture(colortxt, fragUV).rgb;

//Convert color to gray scale
float brightness = dot(texColor, vec3(0.2126, 0.7152, 0.0722));
if(brightness > 0.5){
FragColor = vec4(texColor, 1.0);
}else{
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
// FragColor = vec4(texColor, 1.0);

}`
})
Insert cell
brightnessprogramInfo = {
errorBlock2.style.height = "20px";
errorBlock2.innerHTML = "Program Shader compilation successful";
return twgl.createProgramInfo(
gl,
[brightnessShader.vs, brightnessShader.fs],
(message) => {
errorBlock2.style.height = "400px";
errorBlock2.innerHTML = "Program Shader compilation error\n" + message;
}
);
}
Insert cell
Insert cell
blurShader = ({
vs: `#version 300 es

precision mediump float;

in vec2 position;
in vec2 uvs;

out vec2 fragUV;

void main() {
gl_Position = vec4(position, 0.0, 1.0);
fragUV = uvs;
}`,

fs: `#version 300 es
precision mediump float;

in vec2 fragUV;
out vec4 FragColor;

uniform bool horizontal;
uniform sampler2D colortxt;

const float weight[5] = float[5](0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);

void main(){

vec2 tex_offset = vec2((1.0 / float(textureSize(colortxt, 0).x)), (1.0 / float(textureSize(colortxt, 0).y))); // gets size of single texel
vec3 result = texture(colortxt, fragUV).rgb * weight[0];

if(horizontal)
{
for(int i = 1; i < 5; ++i)
{
result += texture(colortxt, fragUV + vec2(tex_offset.x * float(i), 0.0)).rgb * weight[i];
result += texture(colortxt, fragUV - vec2(tex_offset.x * float(i), 0.0)).rgb * weight[i];
}
}
else
{
for(int i = 1; i < 5; ++i)
{
result += texture(colortxt, fragUV + vec2(0.0, tex_offset.y * float(i))).rgb * weight[i];
result += texture(colortxt, fragUV - vec2(0.0, tex_offset.y * float(i))).rgb * weight[i];
}
}
FragColor = vec4(result, 1.0);
}`
})
Insert cell
Insert cell
Insert cell
blendShader = ({
vs: `#version 300 es

precision mediump float;

in vec2 position;
in vec2 uvs;

out vec2 fragUV;

void main() {
gl_Position = vec4(position, 0.0, 1.0);
fragUV = uvs;
}`,

fs: `#version 300 es
precision mediump float;

in vec2 fragUV;
out vec4 FragColor;

uniform sampler2D colortxt;
uniform sampler2D blurtxt;
uniform float exposure;
uniform float gamma;

void main(){

vec3 sceneColor = texture(colortxt, fragUV).rgb;
vec3 bloomColor = texture(blurtxt, fragUV).rgb;
sceneColor += bloomColor;

vec3 result = vec3(1.0, 1.0, 1.0) - exp(-sceneColor * exposure);

result = pow(result, vec3(1.0 / gamma));

FragColor = vec4(result, 1.0);

// FragColor = vec4(texture(colortxt, fragUV).rgb, 1.0);
// // FragColor = vec4(0.5, 0.5, 0.5, 1.0);

}`
})
Insert cell
Insert cell
Insert cell
textureRenderShader = ({
vs: `#version 300 es

precision mediump float;

in vec2 position;
in vec2 uvs;

out vec2 fragUV;

void main() {
gl_Position = vec4(position, 0.0, 1.0);
fragUV = uvs;
}`,

fs: `#version 300 es
precision mediump float;

in vec2 fragUV;
out vec4 FragColor;

uniform sampler2D colortxt;

void main(){
vec3 texColor = texture(colortxt, fragUV).rgb;
FragColor = vec4(texColor, 1.0);

}`
})
Insert cell
errorBlock5 = html`<textarea style="height : 20px; width : ${width}px; font-size: 0.8em; display: block"></textarea>`
Insert cell
textureRenderProgramInfo = {
errorBlock5.style.height = "20px";
errorBlock5.innerHTML = "Program Shader compilation successful";
return twgl.createProgramInfo(
gl,
[textureRenderShader.vs, textureRenderShader.fs],
(message) => {
errorBlock5.style.height = "400px";
errorBlock5.innerHTML = "Program Shader compilation error\n" + message;
}
);
}
Insert cell
Insert cell
uniforms = [
{
modelMatrix: m4.multiply(m4.identity(), scaleMatrix),
viewMatrix: viewMatrix,
projectionMatrix: perspectiveMatrix,
normalMatrix: m4.transpose(
m4.inverse(m4.multiply(m4.identity(), scaleMatrix))
),
light: light,
eyePosition: eyePosition,
materialColor: hex2rgb(colorParameters.material),
ambientIntensity: lightParameters.ambient,
specularColor: hex2rgb(colorParameters.specular),
shininess: specularProperty.shininess,
K_s: specularProperty.K_s
},
{
modelMatrix: m4.multiply(translateLeft, scaleMatrix),
viewMatrix: viewMatrix,
projectionMatrix: perspectiveMatrix,
normalMatrix: m4.transpose(
m4.inverse(m4.multiply(translateLeft, scaleMatrix))
),
light: light,
eyePosition: eyePosition,
materialColor: hex2rgb(colorParameters.material),
ambientIntensity: lightParameters.ambient,
specularColor: hex2rgb(colorParameters.specular),
shininess: specularProperty.shininess,
K_s: specularProperty.K_s
},
{
modelMatrix: m4.multiply(translateRight, scaleMatrix),
viewMatrix: viewMatrix,
projectionMatrix: perspectiveMatrix,
normalMatrix: m4.transpose(
m4.inverse(m4.multiply(translateRight, scaleMatrix))
),
light: light,
eyePosition: eyePosition,
materialColor: hex2rgb(colorParameters.material),
ambientIntensity: lightParameters.ambient,
specularColor: hex2rgb(colorParameters.specular),
shininess: specularProperty.shininess,
K_s: specularProperty.K_s
},
{
modelMatrix: m4.multiply(translateDown, scaleMatrix),
viewMatrix: viewMatrix,
projectionMatrix: perspectiveMatrix,
normalMatrix: m4.transpose(
m4.inverse(m4.multiply(translateDown, scaleMatrix))
),
light: light,
eyePosition: eyePosition,
materialColor: [0.4, 0.4, 0.4],
ambientIntensity: lightParameters.ambient,
specularColor: hex2rgb(colorParameters.specular),
shininess: specularProperty.shininess,
K_s: specularProperty.K_s
}
]
Insert cell
uniformb = ({
modelMatrix: m4.multiply(scaleMatrix, modelTranslate),
viewMatrix: viewMatrix,
projectionMatrix: perspectiveMatrix,
normalMatrix: m4.transpose(
m4.inverse(m4.multiply(scaleMatrix, modelTranslate))
),
light: light,
eyePosition: eyePosition,
materialColor: hex2rgb(colorParameters.material),
ambientIntensity: lightParameters.ambient,
specularColor: hex2rgb(colorParameters.specular),
shininess: specularProperty.shininess,
K_s: specularProperty.K_s
})
Insert cell
quaduniforms = ({
colortxt: null,
horizontal: false,
exposure: effects.exposure,
gamma: effects.gamma,
blurtxt: null
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
modelvertexAttributes = modelObj.map((d) => ({
position: { numComponents: 3, data: d.sc.positions },
normal: { numComponents: 3, data: d.sc.normals }
}))
Insert cell
modelBufferInfoArray = modelvertexAttributes.map((vertexAttributes) =>
twgl.createBufferInfoFromArrays(gl, vertexAttributes)
)
Insert cell
Insert cell
Insert cell
Insert cell
modelDim = computeModelExtent(modelObj)
Insert cell
Insert cell
cameraLookAt = {
if (Scene == 1) return [0, 0, 0];
if (Scene == 2) return modelDim.center;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewMatrix = {
const cameraMatrix = m4.lookAt(eyePosition, cameraLookAt, [0, 1, 0]);
return m4.inverse(cameraMatrix);
}
Insert cell
perspectiveMatrix = {
if (Scene == 1)
return m4.perspective(
Math.PI / 3,
gl.canvas.width / gl.canvas.height,
0.1,
10
);
if (Scene == 2)
return m4.perspective(
Math.PI / 3,
gl.canvas.width / gl.canvas.height,
0.1 * modelDim.dia,
10 * modelDim.dia
);
}
Insert cell
Insert cell
Insert cell
Insert cell
modelTranslate = m4.translation([
-modelDim.center[0],
-modelDim.center[1],
-modelDim.center[2]
])
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function createColorTexture() {
const colorTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
gl.texImage2D(
gl.TEXTURE_2D, // target
0, // mip level
gl.RGBA, // internal format
gl.canvas.width, // width
gl.canvas.height, // height
0, // border
gl.RGBA, // format
gl.UNSIGNED_BYTE, // type
null
); // data
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

return colorTexture;
}
Insert cell
function createColorBuffer(colorTexture) {
const colorFramebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, colorFramebuffer);
gl.framebufferTexture2D(
gl.FRAMEBUFFER, // target
gl.COLOR_ATTACHMENT0, // attachment point
gl.TEXTURE_2D, // texture target
colorTexture, // texture
0
); // mip level

const renderB = gl.createRenderbuffer();

gl.bindRenderbuffer(gl.RENDERBUFFER, renderB);
gl.renderbufferStorage(
gl.RENDERBUFFER,
gl.DEPTH24_STENCIL8,
gl.canvas.width,
gl.canvas.height
);
gl.framebufferRenderbuffer(
gl.FRAMEBUFFER,
gl.DEPTH_STENCIL_ATTACHMENT,
gl.RENDERBUFFER,
renderB
);

return colorFramebuffer;
}
Insert cell
// {
// gl.bindFramebuffer(gl.FRAMEBUFFER, colorFrameBuffer);
// if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)
// return "Framebuffer Incomplete";
// }
Insert cell
// colorTexture = createColorTexture()
Insert cell
// colorFrameBuffer = createColorBuffer(colorTexture)
Insert cell
// fbtext1 = createColorTexture()
Insert cell
// fbtext2 = createColorTexture()
Insert cell
// fbo1 = createColorBuffer(fbtext1)
Insert cell
// fbo2 = createColorBuffer(fbtext2)
Insert cell
// brightTexture = createColorTexture()
Insert cell
// brightBuffer = createColorBuffer(brightTexture)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more