webgl readpixels 始终返回 0,0,0,0

发布于 2024-12-01 10:21:10 字数 283 浏览 2 评论 0原文

我正在尝试在 WebGl 中进行挑选。我渲染了两个形状,每个形状上映射了不同的纹理。我正在尝试抓取某些坐标上的像素。这是一个例子。

var pixelValues = new Uint8Array(4);
gl.readPixels(10, 35, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixelValues);
console.log(pixelValues);

但像素值始终包含 [0,0,0,0]。我做错了什么?我需要做一些与帧缓冲区相关的事情吗?

I am trying to do picking in WebGl. I have two shapes rendered along with different texture mapped on each. I am trying to grab pixel on certain co-ordinates. Here is the example.

var pixelValues = new Uint8Array(4);
gl.readPixels(10, 35, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixelValues);
console.log(pixelValues);

But pixelValues always contain [0,0,0,0]. What am I doing wrong? Do I need to do something related to framebuffer?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

千里故人稀 2024-12-08 10:21:10

您不需要 preserveDrawingBuffer: true 来调用 readPixels。您需要的是在退出当前事件之前调用readPixels

规范规定,如果您调用任何影响画布的函数(gl.clear、gl.drawXXX),那么浏览器将在下一次复合操作后清除画布。复合操作何时发生取决于浏览器。可能是在处理多个鼠标事件或键盘事件或单击事件之后。顺序未定义。定义的是在当前事件退出之前它不会执行此操作,因此

render
read

const gl = document.querySelector("canvas").getContext("webgl");

render();
read();  // read in same event

function render() {
  gl.clearColor(.25, .5, .75, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
}

function read() {
  const pixel = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log(pixel);
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}
<canvas></canvas>

地方起作用

render
setTimeout(read, 1000);  // some other event

在 as不起作用的

const gl = document.querySelector("canvas").getContext("webgl");

render();
setTimeout(read, 1000);  // read in other event

function render() {
  gl.clearColor(.25, .5, .75, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
}

function read() {
  const pixel = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log(pixel);
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}
<canvas></canvas>

请注意,由于复合操作(浏览器实际上使用 HTML 的其余部分在页面上绘制画布)触发了清除,因此如果画布不在页面上,则不会复合,也不会被清除。

换句话说,上面不起作用的情况在这里起作用

// create an offscreen canvas. Because it's offscreen it won't be composited
// and therefore will not be cleared.
const gl = document.createElement("canvas").getContext("webgl");

render();
setTimeout(read, 1000);  // read in other event

function render() {
  gl.clearColor(.25, .5, .75, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
}

function read() {
  const pixel = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log(pixel);
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}

现在,如果您想在其他事件中调用 readPixels,例如当用户单击某个元素时,那么您至少有 2 个选项

  1. Set preserveDrawingBuffer: true< /p>

  2. 在事件中再次渲染

    screenshotElement.addEventListener('click', event => {
      使成为();  
      gl.readPixels(...);
    });
    

You don't need preserveDrawingBuffer: true to call readPixels. What you need is to call readPixels before exiting the current event.

The spec says if you call any function that affects the canvas (gl.clear, gl.drawXXX) then the browser will clear the canvas after the next composite operation. When that composite operation happens is up to the browser. It could be after it processes several mouse events or keyboard events or click events. The order is undefined. What is defined is that it won't do it until the current event exits so

render
read

const gl = document.querySelector("canvas").getContext("webgl");

render();
read();  // read in same event

function render() {
  gl.clearColor(.25, .5, .75, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
}

function read() {
  const pixel = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log(pixel);
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}
<canvas></canvas>

works where as

render
setTimeout(read, 1000);  // some other event

does not work

const gl = document.querySelector("canvas").getContext("webgl");

render();
setTimeout(read, 1000);  // read in other event

function render() {
  gl.clearColor(.25, .5, .75, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
}

function read() {
  const pixel = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log(pixel);
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}
<canvas></canvas>

Note that since it's the composite operation (the browser actually drawing the canvas on the page with the rest of the HTML) that triggers the clear, if the canvas is not on the page then it's not composited and won't be cleared.

In other words the case that didn't work above does work here

// create an offscreen canvas. Because it's offscreen it won't be composited
// and therefore will not be cleared.
const gl = document.createElement("canvas").getContext("webgl");

render();
setTimeout(read, 1000);  // read in other event

function render() {
  gl.clearColor(.25, .5, .75, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
}

function read() {
  const pixel = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log(pixel);
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}

Now, if you want to call readPixels in some other event, like when the user clicks an element, then you have at least 2 options

  1. Set preserveDrawingBuffer: true

  2. Render again in your event

    screenshotElement.addEventListener('click', event => {
      render();  
      gl.readPixels(...);
    });
    
雨后咖啡店 2024-12-08 10:21:10

根据 WebGL 规范,您需要调用 getContext 设置 preserveDrawingBuffer 标志,例如:

var ctx = canvas.getContext("webgl", {preserveDrawingBuffer: true});

如果您打算在退出渲染 GL 上下文的事件后读取像素。这可以防止绘图缓冲区(颜色、深度、模板)在绘制到屏幕后被清除。请记住,这可能会导致性能损失。

或者,您可以在呈现像素之前读取像素,这也应该可行。

According to WebGL specs, you need to call getContext setting the preserveDrawingBuffer flag, like:

var ctx = canvas.getContext("webgl", {preserveDrawingBuffer: true});

if you plan to read the pixels after exiting the event where the GL context is rendered. This prevents the drawing buffer (color, depth, stencil) from being cleared after they are draw to screen. Keep in mind that settings this may cause a performance penalty.

Alternatively, you can read the pixels before they are presented, which should also work.

最笨的告白 2024-12-08 10:21:10

我渲染了两个形状,每个形状上映射了不同的纹理。

gl.readPixels(10, 35, 1, 1, ...);

我确信您认为 gl.readPixels 从左上角开始读取像素,但事实并非如此。 gl.readPixels左下角开始读取它们。

输入图片此处描述

来自 WebGLRenderingContext.readPixels() 文档:

参数

x

指定从矩形像素块的左下角读取的第一个水平像素的 GLint。

指定从矩形像素块的左下角读取的第一个垂直像素的 GLint。

输入图像此处描述

<!DOCTYPE html>

<body>

    <head>
        <title>Pick object by click. WebGL, JavaScript</title>

        <script src="https://cdn.jsdelivr.net/npm/[email protected]/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) => {
                // Get coordinates of mouse pick
                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;
                // console.log("mouse pick coords:", pickX, pickY);

                // Set the click flag and color id
                gl.uniform1i(uClickLocation, 1);
                gl.clearColor(0, 0, 0, 1);
                gl.clear(gl.COLOR_BUFFER_BIT);

                // Draw objects for picking
                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);
                // console.log("pick color:", pixels[0], pixels[1], pixels[2], pixels[3]);
                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>

I have two shapes rendered along with different texture mapped on each.

gl.readPixels(10, 35, 1, 1, ...);

I'm sure you thought gl.readPixels starts reading pixels from the top left corner, but it doesn't. gl.readPixels starts reading them from the lower left corner.

enter image description here

From the WebGLRenderingContext.readPixels() documentation:

Parameters

x

A GLint specifying the first horizontal pixel that is read from the lower left corner of a rectangular block of pixels.

y

A GLint specifying the first vertical pixel that is read from the lower left corner of a rectangular block of pixels.

enter image description here

<!DOCTYPE html>

<body>

    <head>
        <title>Pick object by click. WebGL, JavaScript</title>

        <script src="https://cdn.jsdelivr.net/npm/[email protected]/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) => {
                // Get coordinates of mouse pick
                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;
                // console.log("mouse pick coords:", pickX, pickY);

                // Set the click flag and color id
                gl.uniform1i(uClickLocation, 1);
                gl.clearColor(0, 0, 0, 1);
                gl.clear(gl.COLOR_BUFFER_BIT);

                // Draw objects for picking
                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);
                // console.log("pick color:", pixels[0], pixels[1], pixels[2], pixels[3]);
                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>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文