<!DOCTYPE html>
<body>
<head>
<title>Pick object by click. WebGL, JavaScript</title>
<script src="https://cdn.jsdelivr.net/npm/gl-matrix@3.4.3/gl-matrix-min.js"></script>
<style>
#renderCanvas {
position: absolute;
}
#outputEN {
position: absolute;
top: 210px;
left: 20px;
}
#outputRU {
position: absolute;
top: 235px;
left: 20px;
}
#outputCH {
position: absolute;
top: 260px;
left: 20px;
}
#outputPinyin {
position: absolute;
top: 285px;
left: 20px;
}
</style>
</head>
<body>
<div>
<canvas id="renderCanvas" width="300" height="300"></canvas>
<span id="outputEN">Click on any object or outside</span>
<span id="outputRU">Кликните на любой объект или мимо</span>
<span id="outputCH">单击任何对象或外部</span>
<span id="outputPinyin">Dān jí rènhé duìxiàng huò wàibù</span>
</div>
<script id="vertexShader" type="x-shader/x-vertex">
attribute vec2 aPosition;
uniform mat4 uMvpMatrix;
void main() {
gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision mediump float;
uniform vec3 uColor;
uniform bool uClick;
uniform vec3 uPickColor;
void main() {
if (!uClick) {
gl_FragColor = vec4(uColor, 1.0);
} else {
gl_FragColor = vec4(uPickColor, 1.0);
}
}
</script>
<script>
const gl = document.getElementById("renderCanvas").getContext("webgl");
const outputEN = document.getElementById("outputEN");
const outputRU = document.getElementById("outputRU");
const vShader = gl.createShader(gl.VERTEX_SHADER);
const vSrc = document.getElementById("vertexShader").firstChild.textContent;
gl.shaderSource(vShader, vSrc);
gl.compileShader(vShader);
let ok = gl.getShaderParameter(vShader, gl.COMPILE_STATUS);
if (!ok) {
console.log("vert: " + gl.getShaderInfoLog(vShader));
};
const fShader = gl.createShader(gl.FRAGMENT_SHADER);
const fSrc = document.getElementById("fragmentShader").firstChild.textContent;
gl.shaderSource(fShader, fSrc);
gl.compileShader(fShader);
ok = gl.getShaderParameter(fShader, gl.COMPILE_STATUS);
if (!ok) {
console.log("frag: " + gl.getShaderInfoLog(fShader));
};
const program = gl.createProgram();
gl.attachShader(program, vShader);
gl.attachShader(program, fShader);
gl.linkProgram(program);
ok = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!ok) {
console.log("link: " + gl.getProgramInfoLog(program));
};
gl.useProgram(program);
const vertPositions = [
-0.5, -0.5,
-0.5, 0.5,
0.5, -0.5,
0.5, 0.5
];
const vertPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertPosBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertPositions), gl.STATIC_DRAW);
const aPositionLocation = gl.getAttribLocation(program, "aPosition");
gl.vertexAttribPointer(aPositionLocation, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aPositionLocation);
const modelMatrix = glMatrix.mat4.create();
const mvpMatrix = glMatrix.mat4.create();
const projMatrix = glMatrix.mat4.create();
glMatrix.mat4.ortho(projMatrix, -0.5, 2.5, 2.5, -0.5, 10, -10);
const viewMatrix = glMatrix.mat4.create();
glMatrix.mat4.lookAt(viewMatrix, [0, 0, 10], [0, 0, 0], [0, 1, 0]);
const projViewMatrix = glMatrix.mat4.create();
glMatrix.mat4.mul(projViewMatrix, projMatrix, viewMatrix);
const uMvpMatrixLocation = gl.getUniformLocation(program, "uMvpMatrix");
const uColorLocation = gl.getUniformLocation(program, "uColor");
const uClickLocation = gl.getUniformLocation(program, "uClick");
const uPickColorLocation = gl.getUniformLocation(program, "uPickColor");
gl.uniform1i(uClickLocation, 0);
const firstObj = {
pos: glMatrix.vec3.fromValues(0, 0, 0),
scale: glMatrix.vec3.fromValues(0.7, 0.7, 1),
color: glMatrix.vec3.fromValues(0.50, 0.84, 0.22)
};
const secondObj = {
pos: glMatrix.vec3.fromValues(1, 0, 0),
scale: glMatrix.vec3.fromValues(0.7, 0.7, 1),
color: glMatrix.vec3.fromValues(0.07, 0.59, 0.09)
};
const thirdObj = {
pos: glMatrix.vec3.fromValues(2, 0, 0),
scale: glMatrix.vec3.fromValues(0.7, 0.7, 1),
color: glMatrix.vec3.fromValues(0.12, 0.88, 0.48)
};
const fourthObj = {
pos: glMatrix.vec3.fromValues(0, 1, 0),
scale: glMatrix.vec3.fromValues(0.7, 0.7, 1),
color: glMatrix.vec3.fromValues(0.65, 0.37, 0.07)
};
const pickColors = {
first: glMatrix.vec3.fromValues(255, 0, 0),
second: glMatrix.vec3.fromValues(0, 255, 0),
third: glMatrix.vec3.fromValues(0, 0, 255),
fourth: glMatrix.vec3.fromValues(255, 255, 0)
};
gl.canvas.onmousedown = (e) => {
const rect = gl.canvas.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
const pickX = mouseX;
const pickY = rect.bottom - rect.top - mouseY - 1;
gl.uniform1i(uClickLocation, 1);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniform3fv(uPickColorLocation, pickColors.first);
glMatrix.mat4.fromTranslation(modelMatrix, firstObj.pos);
glMatrix.mat4.scale(modelMatrix, modelMatrix, firstObj.scale);
glMatrix.mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.uniform3fv(uPickColorLocation, pickColors.second);
glMatrix.mat4.fromTranslation(modelMatrix, secondObj.pos);
glMatrix.mat4.scale(modelMatrix, modelMatrix, secondObj.scale);
glMatrix.mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.uniform3fv(uPickColorLocation, pickColors.third);
glMatrix.mat4.fromTranslation(modelMatrix, thirdObj.pos);
glMatrix.mat4.scale(modelMatrix, modelMatrix, thirdObj.scale);
glMatrix.mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.uniform3fv(uPickColorLocation, pickColors.fourth);
glMatrix.mat4.fromTranslation(modelMatrix, fourthObj.pos);
glMatrix.mat4.scale(modelMatrix, modelMatrix, fourthObj.scale);
glMatrix.mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
const pixels = new Uint8Array(4);
gl.readPixels(pickX, pickY, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
const pickResult = glMatrix.vec3.fromValues(pixels[0], pixels[1],
pixels[2]);
let messageEN = "";
let messageRU = "";
let messageCH = "";
let messagePinyin = "";
if (glMatrix.vec3.exactEquals(pickResult, pickColors.first)) {
messageEN = "First object";
messageRU = "Первый объект";
messageCH = "第一个对象";
messagePinyin = "Dì yī gè duìxiàng";
} else if (glMatrix.vec3.exactEquals(pickResult, pickColors.second)) {
messageEN = "Second object";
messageRU = "Второй объект";
messageCH = "第二个对象";
messagePinyin = "Dì èr gè duìxiàng";
} else if (glMatrix.vec3.exactEquals(pickResult, pickColors.third)) {
messageEN = "Third object";
messageRU = "Третий объект";
messageCH = "第三个对象";
messagePinyin = "Dì sān gè duìxiàng";
} else if (glMatrix.vec3.exactEquals(pickResult, pickColors.fourth)) {
messageEN = "Fourth object";
messageRU = "Четвёртый объект";
messageCH = "第四个对象";
messagePinyin = "Dì sì gè duìxiàng";
} else {
messageEN = "You didn't click on the objects";
messageRU = "Вы не кликнули по объектам";
messageCH = "你没有点击对象";
messagePinyin = "Nǐ méiyǒu diǎnjī duìxiàng";
}
console.log(messageEN);
outputEN.innerText = messageEN;
outputRU.innerText = messageRU;
outputCH.innerText = messageCH;
outputPinyin.innerText = messagePinyin;
gl.uniform1i(uClickLocation, 0);
draw();
};
function draw() {
gl.clearColor(0.9, 0.9, 0.95, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
glMatrix.mat4.fromTranslation(modelMatrix, firstObj.pos);
glMatrix.mat4.scale(modelMatrix, modelMatrix, firstObj.scale);
glMatrix.mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
gl.uniform3fv(uColorLocation, firstObj.color);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
glMatrix.mat4.fromTranslation(modelMatrix, secondObj.pos);
glMatrix.mat4.scale(modelMatrix, modelMatrix, secondObj.scale);
glMatrix.mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
gl.uniform3fv(uColorLocation, secondObj.color);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
glMatrix.mat4.fromTranslation(modelMatrix, thirdObj.pos);
glMatrix.mat4.scale(modelMatrix, modelMatrix, thirdObj.scale);
glMatrix.mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
gl.uniform3fv(uColorLocation, thirdObj.color);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
glMatrix.mat4.fromTranslation(modelMatrix, fourthObj.pos);
glMatrix.mat4.scale(modelMatrix, modelMatrix, fourthObj.scale);
glMatrix.mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
gl.uniform3fv(uColorLocation, fourthObj.color);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
draw();
</script>
</body>
</body>
preserveDrawingBuffer: true
的上下文进行渲染,然后通过设置preserveDrawingBuffer: true
并获取像素从同一画布中获取另一个上下文,那么后者的readPixels
是否能够正常工作?第二个上下文的新配置是否会影响第一个上下文?我期望它们是相同的对象。这样对吗? - hackjutsuc = $0.getContext("webgl2", {preserveDrawingBuffer: true}); bitmapData = new Uint8Array($0.width * $0.height * 4); c.readPixels(0, 0, $0.width, $0.height, c.RGBA, c.UNSIGNED_BYTE, bitmapData); bitmapData.reduce((a,b)=>a+b)
返回0。 - Nakilon$0 = document.createElement('canvas'); c = $0.getContext("webgl2", {preserveDrawingBuffer: true}); c.clearColor(1,0,0,1); c.clear(c.COLOR_BUFFER_BIT); bitmapData = new Uint8Array($0.width * $0.height * 4); c.readPixels(0, 0, $0.width, $0.height, c.RGBA, c.UNSIGNED_BYTE, bitmapData); bitmapData.reduce((a,b)=>a+b)
返回 22950000。 - gman