单击 three.js 的网格获取像素的颜色值

Getting the color value of a pixel on click of a mesh with three.js

我正在使用 three.js 的最新版本,我得到了一个带有 2D 网格和渐变颜色的场景。颜色取决于分配给每个顶点的值。我想通过用鼠标单击它来获取渐变的每个点的值(通过获取颜色,并为我的值做一些数学运算)

我尝试使用像这样的系统,因为它在这里工作:http://jsbin.com/wepuca/2/edit?html,js,output

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

function echoColor(e){
    var imgData = ctx.getImageData(e.pageX, e.pageX, 1, 1);
    red = imgData.data[0];
    green = imgData.data[1];
    blue = imgData.data[2];
    alpha = imgData.data[3];
    console.log(red + " " + green + " " + blue + " " + alpha);  
}

我的问题是,当显示图像而不是网格时,此技术用于从 canvas 获取数据。当我尝试在我的网格上使用它时,出现了错误:

"TypeError: ctx is null" 或 "imageData is not a function"(取决于我如何声明我的 canvas 和他的上下文)。

因为我没有找到这个方法是否可以用在mesh上,所以我在这里问是否可以,而不是如何做。

提前致谢

首先,您无法从已经在使用 WebGL 上下文的 canvas 中获取 2D 上下文。这就是您收到 ctx is null 错误的原因。

要获取像素颜色,您有两种选择。

1.将 WebGL canvas 图像传输到具有 2D 上下文的 canvas。

为此,创建一个新的 canvas 并将其大小调整为与您的 THREE.js canvas 相同的大小,并从中获取二维上下文。然后,您可以使用 2D 上下文将 THREE.js canvas 中的渲染图像作为图像绘制到新的 canvas 上:

var img2D = new Image();
twoDeeCanvasImage.addEventListener("load", function () {
    ctx2D.clearRect(0, 0, canvas2D.width, canvas2D.height);
    ctx2D.drawImage(img2D, 0, 0);
    // from here, get your pixel data
});
img2D.src = renderer.domElement.toDataURL("img/png");

从那里您可以像以前一样使用 getImageData

此方法的一个警告是,通过 toDataURL 导出图像时,您可能会看到由于引入压缩而导致的图像质量下降。在某些情况下您可以规避此问题:

if(ctx2D.imageSmoothingEnabled !== undefined){
    ctx2D.imageSmoothingEnabled  = false;
}
else if(ctx2D.mozImageSmoothingEnabled  !== undefined){
    ctx2D.mozImageSmoothingEnabled   = false;
}
else if(ctx2D.webkitImageSmoothingEnabled  !== undefined){
    ctx2D.webkitImageSmoothingEnabled   = false;
}
else{
    console.warn("Browser does not support disabling canvas antialiasing. Results image may be blurry.");
}

2。您也可以直接从渲染器获取像素值,但这会花费您额外的渲染通道。

查看此 THREE.js 示例:https://threejs.org/examples/?q=instanc#webgl_interactive_instances_gpu

此示例在 THREE.WebGLRenderer 中使用 readRenderTargetPixelshttps://threejs.org/docs/#api/renderers/WebGLRenderer

我没有任何使用此方法的个人经验,所以希望其他人可以填补一些空白。