Published
Edited
Jul 13, 2022
1 fork
Insert cell
md`# WebGL Triangle #6: Texture`
Insert cell
canvas = DOM.canvas(width, height);
Insert cell
{
draw()
}
Insert cell
function draw() {
// clear
gl.clearColor(1., 1., 1., 1.);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

{
// connect buffers and attributes
const numComponents = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(
attributeLocations.position,
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(attributeLocations.position);
}
{
// connect buffers and attributes
const numComponents = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.vertexAttribPointer(
attributeLocations.texCoord,
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(attributeLocations.texCoord);
}
{
// connect uniforms
gl.uniform2f(uniformLocations.resolution, width, height);
gl.uniform4fv(uniformLocations.color, new Float32Array(data.color));
gl.uniformMatrix4fv(uniformLocations.transform, false, new Float32Array(transform));

}

{
// bind textures
const textureUnit = 0;
// Bind the texture to texture unit 0
gl.activeTexture(gl.TEXTURE0 + textureUnit);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.uniform1i(uniformLocations.sampler, textureUnit);
}

// use program
gl.useProgram(program);

// draw
const offset = 0;
const vertexCount = 3;
// gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
gl.drawArrays(gl.TRIANGLES, offset, vertexCount)
}
Insert cell
// texture = loadTexture(gl, FileAttachment("三国杀界刘备.jpg").image())
texture = loadTextureFromUrl(gl,
'https://brickmaker.static.observableusercontent.com/files/63737287a6c197978aa17abbc1e7e0db452e1303fe10d9efdacada95dccb25fc8bdd73c77c4a95d0ed7920d02feea995f4ce5558d3c6f7dc77bdce4a62f28de8?response-content-disposition=attachment%3Bfilename*%3DUTF-8%27%27%25E4%25B8%2589%25E5%259B%25BD%25E6%259D%2580%25E7%2595%258C%25E5%2588%2598%25E5%25A4%2587.jpg&Expires=1657756800&Key-Pair-Id=APKAIQVKCV7GBKVBR2KA&Signature=YIlEurNqAJpVmCHiRgfXrdoTNq7WWvMmU6qarzJzvKqxdtBqbr26Q0taR02HL44dgRj~xWEXj~8WVRUoKX-AneKn14d2lytp7ditGEydTsUxluzJnSPVB8NrRsta5cCgWUUz9rotyWUJcxcJ6umOCog4mCOn7KDepPRzU12A8JtZCcX~f~bK4pYRkzoD1uIiZEOEp~65GrNShCUtXvZjNFCkxOy5v7VFXMqgILoTgF3n~MEWQxVv0uvJ407kRea8j4ZI5vI3XNh8z25yty1SNSiYF6F66PWeSovL4BdrTKIudmqg7XUpN8aJS3xsjUozTkufdTuEWI7H2UkUurwE8g__')
Insert cell
image = FileAttachment("三国杀界刘备.jpg").image()
Insert cell
Insert cell
Insert cell
positionBuffer = createBuffer(gl, data.positions)
Insert cell
texCoords = [0, 1, 1, 1, 0.5, 0.]
Insert cell
texCoordBuffer = createBuffer(gl, texCoords)
Insert cell
attributeLocations = {
return {
position: gl.getAttribLocation(program, "in_position"),
texCoord: gl.getAttribLocation(program, "in_texCoord")
}
}
Insert cell
uniformLocations = {
return {
sampler: gl.getUniformLocation(program, 'u_sampler'),
resolution: gl.getUniformLocation(program, "u_resolution"),
transform: gl.getUniformLocation(program, "u_transform"),
color: gl.getUniformLocation(program, "u_color")
}
}
Insert cell
program = createProgram(gl, vertexShaderSource, fragmentShaderSource)
Insert cell
gl = canvas.getContext('webgl2')
Insert cell
height = width * 0.75
Insert cell
Insert cell
Insert cell
//
// Initialize a texture and load an image.
// When the image finished loading copy it into the texture.
//
function loadTexture(gl, image) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);

// Because images have to be downloaded over the internet
// they might take a moment until they are ready.
// Until then put a single pixel in the texture so we can
// use it immediately. When the image has finished downloading
// we'll update the texture with the contents of the image.
const level = 0;
const internalFormat = gl.RGBA;
const width = 1;
const height = 1;
const border = 0;
const srcFormat = gl.RGBA;
const srcType = gl.UNSIGNED_BYTE;
const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
width, height, border, srcFormat, srcType,
pixel);

image.onload = function() {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
srcFormat, srcType, image);

// WebGL1 has different requirements for power of 2 images
// vs non power of 2 images so check if the image is a
// power of 2 in both dimensions.
if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
// Yes, it's a power of 2. Generate mips.
gl.generateMipmap(gl.TEXTURE_2D);
} else {
// No, it's not a power of 2. Turn off mips and set
// wrapping to clamp to edge
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);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
}
};

return texture;
}
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