代码之家  ›  专栏  ›  技术社区  ›  Enoy

当我们使用Javascript单击网格时,如何获得网格的像素颜色?

  •  1
  • Enoy  · 技术社区  · 6 年前

    当前在页面中,我们有一个加载了TreeJS的网格,并显示在画布中: enter image description here

    我们怎样才能得到点击点的颜色?

    我已经按照这里的建议进行了尝试: Getting the color value of a pixel on click of a mesh with three.js ,以使用webgl上下文在画布上创建一个二维上下文。

    问题是,当我们将模型转换为PNG时,图像是白色的:

    我们的img 2d src:

    enter image description here

    如果我们点击它:

    enter image description here

    因此,控制台记录颜色为: 0 0 0 0

    此外,我将显示生成webgl画布和2d画布的代码:

    // this class handles the load and the canva for a nrrd
    // Using programming based on prototype: https://javascript.info/class
    // This class should be improved:
    //   - Canvas Width and height
    
    InitCanvas = function (IdDiv, Filename) {
    
    
        this.IdDiv = IdDiv;
        this.Filename = Filename
    }
    
    InitCanvas.prototype = {
    
        constructor: InitCanvas,
    
        init: function () {
    
            this.container = document.getElementById(this.IdDiv);
    
            // this should be changed.
            this.container.innerHeight = 600;
            this.container.innerWidth = 800;
    
            //These statenments should be changed to improve the image position
            this.camera = new THREE.PerspectiveCamera(60, this.container.innerWidth / this.container.innerHeight, 0.01, 1e10);
            this.camera.position.z = 300;
    
            let scene = new THREE.Scene();
            scene.add(this.camera);
    
            // light
    
            let dirLight = new THREE.DirectionalLight(0xffffff);
            dirLight.position.set(200, 200, 1000).normalize();
    
            this.camera.add(dirLight);
            this.camera.add(dirLight.target);
    
    
            // read file
    
            let loader = new THREE.NRRDLoader();
            loader.load(this.Filename, function (volume) {
    
                //z plane
                let sliceZ = volume.extractSlice('z', Math.floor(volume.RASDimensions[2] / 4));
    
                this.container.innerWidth = sliceZ.iLength;
                this.container.innerHeight = sliceZ.jLength;
    
                sliceZ.mesh.material.color.setRGB(0,1,1);
    
    
                console.log('Our slice is: ', sliceZ);
    
                scene.add(sliceZ.mesh);
            }.bind(this));
    
    
            this.scene = scene;
    
    
    
            var canvas2d = document.createElement('canvas');
    
            canvas2d.id = "canvas2D";
            canvas2d.style.width = `${this.container.innerWidth}px`;
            canvas2d.style.height = `${this.container.innerHeight}px`;
            canvas2d.style.zIndex = 8;
    
    
    
    
            this.container.appendChild(canvas2d);
    
    
    
    
    
            // renderer
            this.renderer = new THREE.WebGLRenderer({alpha: true});
            this.renderer.setPixelRatio(this.container.devicePixelRatio);
            this.renderer.setSize(this.container.innerWidth, this.container.innerHeight);
    
            // add canvas in container
            this.container.appendChild(this.renderer.domElement);
    
    
    
    
    
        },
    
        animate: function () {
    
            this.renderer.render(this.scene, this.camera);
        }
    
    }
    

    我们也在逻辑中使用它。js公司

    if (!Detector.webgl) Detector.addGetWebGLMessage();
    
    // global variables for this scripts
    let OriginalImg,
        SegmentImg,
        myFileReader;
    
    var mouse = new THREE.Vector2();
    var raycaster = new THREE.Raycaster();
    var mousePressed = false;
    var clickCount = 0;
    var allText;
    
    
    init();
    animate();
    
    
    // initilize the page
    function init() {
    
    
        readTextFile("columna01-es-latin1.txt");
    
        let originalImgPath = getParameterByName('originalImgPath');
        let filename = originalImgPath || "models/nrrd/columna02.nrrd"; // change your nrrd file
        let idDiv = 'original';
        OriginalImg = new InitCanvas(idDiv, filename);
        OriginalImg.init();
        console.log(OriginalImg);
    
        let segmentedImgPath = getParameterByName('segmentedImgPath');
    
        filename = segmentedImgPath || "models/nrrd/columnasegmentado02.nrrd"; // change your nrrd file
        idDiv = 'segment';
        SegmentImg = new InitCanvas(idDiv, filename);
        SegmentImg.init();
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        let canvas2D = document.getElementById('canvas2D');
        let ctx2D = canvas2D.getContext('2d');
    
        var img2D = new Image();
        img2D.src = OriginalImg.renderer.domElement.toDataURL("img/png");
        console.log('Our img 2d source is:::: ',img2D.src);
        img2D.addEventListener("load", function () {
            ctx2D.clearRect(0, 0, canvas2D.width, canvas2D.height);
            ctx2D.drawImage(img2D, 0, 0);
            // from here, get your pixel data
            var imgData = ctx2D.getImageData(10, 10, 1, 1);
            red = imgData.data[0];
            green = imgData.data[1];
            blue = imgData.data[2];
            alpha = imgData.data[3];
            console.log(red + " " + green + " " + blue + " " + alpha);
        });
    }
    
    function getParameterByName(name, url) {
        if (!url) url = window.location.href;
        name = name.replace(/[\[\]]/g, "\\$&");
        var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
            results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, " "));
    }
    
    let originalCanvas = document.getElementById('original');
    originalCanvas.addEventListener('mousedown', onDocumentMouseDown, false);
    originalCanvas.addEventListener('mouseup', onDocumentMouseUp, false);
    
    
    function onDocumentMouseDown(event) {
        mousePressed = true;
    
        clickCount++;
    
        let realClickedCanvasX = event.offsetX;
        let realClickedCanvasY = event.offsetY;
    
        mouse.x = ( ( event.clientX - OriginalImg.renderer.domElement.offsetLeft ) / OriginalImg.renderer.domElement.clientWidth ) * 2 - 1;
        mouse.y = -( ( event.clientY - OriginalImg.renderer.domElement.offsetTop ) / OriginalImg.renderer.domElement.clientHeight ) * 2 + 1
    
    
        console.log('Mouse x position is: ', realClickedCanvasX, 'the click number was: ', clickCount);
        console.log('Mouse x position is: ', realClickedCanvasY, 'the click number was: ', clickCount);
    
        //console.log('Mouse x position is: ', mouse.x, 'the click number was: ', clickCount);
        //console.log('Mouse Y position is: ', mouse.y);
    
        raycaster.setFromCamera(mouse.clone(), OriginalImg.camera);
        var objects = raycaster.intersectObjects(OriginalImg.scene.children);
    
        console.log(objects);
    }
    
    function onDocumentMouseUp(event) {
        mousePressed = false
    }
    
    
    function animate() {
    
    
        requestAnimationFrame(animate);
        OriginalImg.animate();
        SegmentImg.animate();
    
    
    }
    

    我也读过:

    ThreeJS How to pick the intersection point color of an object

    Get pixel color from an image

    How to get a pixel's x,y coordinate color from an image?

    getPixel from HTML Canvas?

    https://johnresig.com/blog/ocr-and-neural-nets-in-javascript/

    https://dev.opera.com/articles/html5-canvas-basics/#pixelbasedmanipulation

    Get the mouse coordinates when clicking on canvas

    HTML5 Dynamically create Canvas

    Canvas width and height in HTML5

    Set Canvas size using javascript

    提前感谢您的帮助。

    编辑:

    感谢TheJim01的帮助。

    我尝试了您的建议,并使用以下代码:

    进入OnDocumentMouseDown函数:

    var target = OriginalImg.renderer.getRenderTarget();
        console.log('Our target which should be a WebGLRenderTarget is: ');
        console.log(target);
    
        var outputBuffer = new Uint8Array( OriginalImg.renderer.width * OriginalImg.renderer.height * 4 );
    
        OriginalImg.renderer.readRenderTargetPixels ( target, 0, 0, OriginalImg.renderer.width, OriginalImg.renderer.height, outputBuffer );
    
        var pixelIndex = ((realClickedCanvasX * OriginalImg.renderer.width) + realClickedCanvasY) * 4;
    
        var color = {
            r: outputBuffer[pixelIndex + 0],
            g: outputBuffer[pixelIndex + 1],
            b: outputBuffer[pixelIndex + 2],
            a: outputBuffer[pixelIndex + 3]
        };
    
        console.log('Color of clicked pixel is: ');
        console.log(color);
    

    我们在web控制台中看到:

    Our target which sould be a WebGLRenderTarget is: 
    
    null
    
    THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.
    
    Color of clicked pixel is: 
    
    Object { r: undefined, g: undefined, b: undefined, a: undefined }
    

    我试图了解发生了什么并解决这个问题,我读到:

    Three.js render to texture

    我添加了一个WebGlRenderTarget,如下所示:

    ... more code...
    
        this.renderTarget = new THREE.WebGLRenderTarget(this.renderer.domElement.clientWidth, this.renderer.domElement.clientHeight);
    
            this.renderer.render(this.scene, this.camera, this.renderTarget);
    
    ... more code...
    

    现在我们在web控制台中看到:

        Error: WebGL warning: clear: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0 has no width or height
        three.js:21370:4
        Error: WebGL warning: clear: Framebuffer must be complete.
        three.js:21370:4
        Error: WebGL warning: clear: Framebuffer not complete. (status: 0x8cd6) COLOR_ATTACHMENT0 has no width or height
        three.js:21370:4
        Error: WebGL warning: clear: Framebuffer must be complete.
        three.js:21370:4
      ...
    

    我尝试过寻找它,我在GitHub中看到了这个问题:

    https://github.com/pixijs/pixi.js/issues/3767

    然而,我不认为这可能是相关的。

    编辑2:

    感谢TheJim01的帮助,我很感激!! 在您的帮助和代码的帮助下,渲染目标问题看起来已经解决了。事实上,我在web控制台中看到一个奇怪的警告:

    Error: WebGL warning: Exceeded 16 live WebGL contexts for this principal, losing the least recently used one.
    

    在搜索此警告后,我看到了一个很棒的主题: Error: WebGL: Exceeded 16 live WebGL contexts for this principal, losing the least recently used one

    在关闭选项卡并重新加载项目后,它就消失了。

    此外,我们获得的颜色尚未定义,我将显示控制台日志:

    Our OriginalImg where we want to get the color is: 
    
    Object { IdDiv: "original", Filename: "models/nrrd/columna02.nrrd", container: div#original.column, camera: {…}, scene: {…}, renderer: {…} }
    
    Error: WebGL warning: Exceeded 16 live WebGL contexts for this principal, losing the least recently used one.
    
    Error: WebGL warning: Exceeded 16 live WebGL contexts for this principal, losing the least recently used one.
    
    The target being used in this click is: 
    
    Object { uuid: "8EAEFD8F-5C55-4973-84BC-471D43C006F8", width: undefined, height: undefined, scissor: {…}, scissorTest: false, viewport: {…}, texture: {…}, depthBuffer: true, stencilBuffer: true, depthTexture: null }
    
    Our target which should be a WebGLRenderTarget is: 
    onMouseDownLogic.js:23:5
    Object { uuid: "8EAEFD8F-5C55-4973-84BC-471D43C006F8", width: 800, height: 600, scissor: {…}, scissorTest: false, viewport: {…}, texture: {…}, depthBuffer: true, stencilBuffer: true, depthTexture: null, … }
    onMouseDownLogic.js:24:5
    Color of clicked pixel is: 
    onMouseDownLogic.js:39:5
    {…}
    ​
    a: undefined
    ​
    b: undefined
    ​
    g: undefined
    ​
    r: undefined
    ​
    __proto__: Object { … }
    

    为了更好地理解我所写的内容,我重构了代码以更好地解释和编写它。

    我们有逻辑。js wich旨在初始化画布并为其设置动画:

    if (!Detector.webgl) Detector.addGetWebGLMessage();
    
    // global variables for this scripts
    let OriginalImg,
        SegmentImg;
    
    var mouse = new THREE.Vector2();
    var raycaster = new THREE.Raycaster();
    var allText;
    
    init();
    animate();
    
    // initilize the page
    function init() {
    
        readTextFile("columna01-es-latin1.txt");
        OriginalImg = initCanvasOfOriginalImg();
        initCanvasOfSegmentedImg();
    
    }
    
    let originalCanvas = document.getElementById('original');
    originalCanvas.addEventListener('mousedown', onDocumentMouseDown, false);
    
    // re-usable objects defined outside your mouse event
    console.log('Our OriginalImg where we want to get the color is: ');
    console.log(OriginalImg);
    
    var size = OriginalImg.renderer.getSize();
    var reusableTarget = new THREE.WebGLRenderTarget(OriginalImg.renderer.width, OriginalImg.renderer.height);
    
    function onDocumentMouseDown(event) {
    
        let {realClickedCanvasX, realClickedCanvasY} = calculateClickedPointWindowCoordinates(event);
        let OriginalImgRenderer = calculateNormalizedClickedPointCoordinates(event);
    
    
        var target = OriginalImgRenderer.getRenderTarget() || reusableTarget;
        console.log('The target being used in this click is: ');
        console.log(target);
    
        size = OriginalImgRenderer.getSize();
        target.setSize(size.width, size.height);
    
        OriginalImgRenderer.render( OriginalImg.scene, OriginalImg.camera, target );
    
        calculateClickedPointColor(OriginalImgRenderer, realClickedCanvasX, realClickedCanvasY);
        projectRayAndGetIntersectedObject();
    }
    
    function animate() {
    
    
        requestAnimationFrame(animate);
        OriginalImg.animate();
        SegmentImg.animate();
    
    
    }
    

    然后是InitCanvas。js是连接div的原型,加载画布和模型:

    // this class handles the load and the canva for a nrrd
    // Using programming based on prototype: https://javascript.info/class
    // This class should be improved:
    //   - Canvas Width and height
    
    InitCanvas = function (IdDiv, Filename) {
    
    
        this.IdDiv = IdDiv;
        this.Filename = Filename
    }
    
    InitCanvas.prototype = {
    
        constructor: InitCanvas,
    
        init: function () {
    
            this.container = document.getElementById(this.IdDiv);
    
            // this should be changed.
            this.container.innerHeight = 600;
            this.container.innerWidth = 800;
    
            //These statenments should be changed to improve the image position
            this.camera = new THREE.PerspectiveCamera(60, this.container.innerWidth / this.container.innerHeight, 0.01, 1e10);
            this.camera.position.z = 300;
    
            let scene = new THREE.Scene();
            scene.add(this.camera);
    
            // light
    
            let dirLight = new THREE.DirectionalLight(0xffffff);
            dirLight.position.set(200, 200, 1000).normalize();
    
            this.camera.add(dirLight);
            this.camera.add(dirLight.target);
    
    
            // read file
    
            let loader = new THREE.NRRDLoader();
            loader.load(this.Filename, function (volume) {
    
                //z plane
                let sliceZ = volume.extractSlice('z', Math.floor(volume.RASDimensions[2] / 4));
    
                this.container.innerWidth = sliceZ.iLength;
                this.container.innerHeight = sliceZ.jLength;
    
                sliceZ.mesh.material.color.setRGB(0, 1, 1);
    
    
               // console.log('Our slice is: ', sliceZ);
    
                scene.add(sliceZ.mesh);
            }.bind(this));
    
    
            this.scene = scene;
    
    
            // renderer
            this.renderer = new THREE.WebGLRenderer({alpha: true});
            this.renderer.setPixelRatio(this.container.devicePixelRatio);
            this.renderer.setSize(this.container.innerWidth, this.container.innerHeight);
    
            // add canvas in container
            this.container.appendChild(this.renderer.domElement);
    
    
        },
    
        animate: function () {
    
            this.renderer.render(this.scene, this.camera);
        }
    
    }
    

    此外,我们还有在OnDocumentMouseDown()中单击鼠标时使用的函数:

    let projectRayAndGetIntersectedObject = function () {
        raycaster.setFromCamera(mouse.clone(), OriginalImg.camera);
        var objects = raycaster.intersectObjects(OriginalImg.scene.children);
    
        console.log(objects);
    };
    
    let calculateClickedPointWindowCoordinates = function (event) {
        let realClickedCanvasX = event.offsetX;
        let realClickedCanvasY = event.offsetY;
        return {realClickedCanvasX, realClickedCanvasY};
    };
    
    let calculateNormalizedClickedPointCoordinates = function (event) {
        let OriginalImgRenderer = OriginalImg.renderer;
        mouse.x = ( ( event.clientX - OriginalImgRenderer.domElement.offsetLeft ) / OriginalImgRenderer.domElement.clientWidth ) * 2 - 1;
        mouse.y = -( ( event.clientY - OriginalImgRenderer.domElement.offsetTop ) / OriginalImgRenderer.domElement.clientHeight ) * 2 + 1
        return OriginalImgRenderer;
    };
    
    let calculateClickedPointColor = function (OriginalImgRenderer, realClickedCanvasX, realClickedCanvasY) {
        var target = OriginalImgRenderer.getRenderTarget();
        console.log('Our target which should be a WebGLRenderTarget is: ');
        console.log(target);
    
        var outputBuffer = new Uint8Array(OriginalImgRenderer.width * OriginalImgRenderer.height * 4);
    
        OriginalImgRenderer.readRenderTargetPixels(target, 0, 0, OriginalImgRenderer.width, OriginalImgRenderer.height, outputBuffer);
    
        var pixelIndex = ((realClickedCanvasX * OriginalImgRenderer.width) + realClickedCanvasY) * 4;
    
        var color = {
            r: outputBuffer[pixelIndex + 0],
            g: outputBuffer[pixelIndex + 1],
            b: outputBuffer[pixelIndex + 2],
            a: outputBuffer[pixelIndex + 3]
        };
    
        console.log('Color of clicked pixel is: ');
        console.log(color);
    };
    

    我不知道我们如何解决这个问题。

    编辑:3

    谢谢@TheJim01您的示例代码解决了这个问题,这里我展示了我正在使用的示例代码:

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8"/>
        <meta http-equiv="X-UA-Compatible" content="chrome=1,IE=edge">
        <title>TEST</title>
    
        <script src="https://threejs.org/build/three.js"></script>
        <script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
        <script src="js/NRRDLoader.js"></script>
        <script src="js/Volume.js"></script>
        <script src="js/VolumeSlice.js"></script>
    
    </head>
    
    <body>
    
    <canvas id="view" width="500" height="500" style="border: 1px black solid;"></canvas>
    
    
    <script type="text/javascript">
        /**********************/
        /*   Initialization   */
        /**********************/
    
        let realClickedCanvasX, realClickedCanvasY, clickCount=0;
    
        var pixelBuffer = new Uint8Array(500 * 500 * 4);
    
        function testPixelBuffer() {
            var x, y, r, g, b, a, i1, i2;
            i1 = realClickedCanvasX * size.width;
            i2 = i1 + realClickedCanvasY;
            i2 *= 4;
            r = pixelBuffer[i2 + 0];
            g = pixelBuffer[i2 + 1];
            b = pixelBuffer[i2 + 2];
            a = pixelBuffer[i2 + 3];
                console.log(i2, r, g, b, a);
    
    
        }
    
        document.getElementById('view').addEventListener('mousedown', onDocumentMouseDown, false);
    
        function onDocumentMouseDown(event) {
            clickCount++;
            realClickedCanvasX = event.offsetX;
            realClickedCanvasY = event.offsetY;
            console.log('You have clicked on: ' + realClickedCanvasY
                + ' , ' + realClickedCanvasY +
                ' it is the click number: ' +
                clickCount);
            testPixelBuffer();
        }
    
        var renderer = new THREE.WebGLRenderer({
            canvas: document.getElementById("view"),
            antialias: true,
            alpha: true
        });
    
        var scene = new THREE.Scene();
    
        var camera = new THREE.PerspectiveCamera(28, 1, 1, 1000);
        camera.position.z = 50;
    
        camera.add(new THREE.PointLight(0xffffff, 1, Infinity));
    
        scene.add(camera);
    
        var controls = new THREE.TrackballControls(camera, renderer.domElement);
        controls.addEventListener("change", render);
    
        /**********************/
        /* Populate the Scene */
        /**********************/
    
        let loader = new THREE.NRRDLoader();
        loader.load('models/nrrd/columnasegmentado01.nrrd', function (volume) {
            //z plane
            let sliceZ = volume.extractSlice('z', Math.floor(volume.RASDimensions[2] / 4));
            scene.add(sliceZ.mesh);
        });
    
        /**********************/
        /*   Render Function  */
        /**********************/
    
        var externalTarget = new THREE.WebGLRenderTarget();
        var size = renderer.getSize();
        externalTarget.setSize(size.width, size.height);
    
        function render() {
            renderer.render(scene, camera);
            renderer.render(scene, camera, externalTarget);
        }
    
        render();
    
        /**********************/
        /*   Animation Loop   */
        /**********************/
    
        function animate() {
            requestAnimationFrame(animate);
            renderer.readRenderTargetPixels(externalTarget, 0, 0, size.width, size.height, pixelBuffer);
            controls.update();
        }
    
        animate();
    
    </script>
    </body>
    
    </html>
    

    我已单击以下区域:

    enter image description here

    结果是:

    You have clicked on: 81 , 81 it is the click number: 1
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 194324 0 0 0 255
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 94 , 94 it is the click number: 2
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 440376 23 23 23 255
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 150 , 150 it is the click number: 3
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 246600 23 23 23 255
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 195 , 195 it is the click number: 4
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 122780 0 0 0 0
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 210 , 210 it is the click number: 5
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 12840 0 0 0 0
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 310 , 310 it is the click number: 6
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 69240 0 0 0 0
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 271 , 271 it is the click number: 7
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 255084 255 255 255 255
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 360 , 360 it is the click number: 8
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 495440 23 23 23 255
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 318 , 318 it is the click number: 9
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 511272 23 23 23 255
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 291 , 291 it is the click number: 10
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 685164 92 92 92 255
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 283 , 283 it is the click number: 11
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 963132 0 0 0 0
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 180 , 180 it is the click number: 12
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 960720 0 0 0 0
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 174 , 174 it is the click number: 13
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 864696 0 0 0 0
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:51 You have clicked on: 216 , 216 it is the click number: 14
    index.html?_ijt=uvc1m089ec37ho5kobp4qir885:40 510864 46 46 46 255
    

    我想知道为什么区域2、3被记录为具有相同的颜色!

    我还想知道为什么区域4、5、6会被记录下来,因为它们的颜色是一样的!。

    我不完全理解您示例中的以下代码:

    function testPixelBuffer() {
            var x, y, r, g, b, a, i1, i2;
            i1 = realClickedCanvasX * size.width;
            i2 = i1 + realClickedCanvasY;
            i2 *= 4;
    

    你能帮帮我吗?

    提前感谢您!

    1 回复  |  直到 6 年前
        1
  •  2
  •   TheJim01    6 年前

    WebGLRenderer.readRenderTargetPixels

    这使您可以访问渲染目标的缓冲区,就像直接从2D画布的 ImageData 缓冲器

    // re-usable objects defined outside your mouse event
    var size = renderer.getSize();
    var reusableTarget = new THREE.WebGLRenderTarget(renderer.width, renderer.height);
    
    // inside your mouse event...
    var target = renderer.getRenderTarget() || reusableTarget;
    
    size = renderer.getSize();
    target.setSize(size.width, size.height);
    
    renderer.render( scene, camera, target );
    
    var outputBuffer = new Uint8Array( width * height * 4 );
    
    renderer.readRenderTargetPixels( target, 0, 0, width, height, outputBuffer );
    
    var pixelIndex = ((mousePosition.y * width) + mousePosition.x) * 4;
    
    var color = {
      r: outputBuffer[pixelIndex + 0],
      g: outputBuffer[pixelIndex + 1],
      b: outputBuffer[pixelIndex + 2],
      a: outputBuffer[pixelIndex + 3]
    };
    

    编辑:

    没错,必须渲染到外部渲染目标。我已经编辑了上面的代码。

    如果尝试渲染到外部渲染目标时出错,我认为这值得创建一个单独的问题(它超出了“如何在x,y处获得像素颜色”的范围)。参考/链接这个问题,以便读者了解整个故事。

    解决渲染目标问题后,此问题可能会在过程中得到解决。

    添加基于代码段的测试:

    老实说,我不知道你为什么会得到这样的结果。下面您可以找到一个实现 readRenderTargetPixels ,并成功。

    (在浏览器中打开开发人员控制台以查看结果。)

    /**********************/
    /*   Initialization   */
    /**********************/
    
    var pixelBuffer = new Uint8Array( 500 * 500 * 4 );
    function testPixelBuffer () {
    	var x, y, r, g, b, a, i1, i2;
    	for ( x = 0; x < size.width; ++x ) {
    		i1 = x * size.width;
    		for ( y = 0; y < size.height; ++y ) {
    			i2 = i1 + y;
    			i2 *= 4;
    			r = pixelBuffer[ i2 + 0 ];
    			g = pixelBuffer[ i2 + 1 ];
    			b = pixelBuffer[ i2 + 2 ];
    			a = pixelBuffer[ i2 + 3 ];
    			if ( a > 0 ) {
    				console.log( i2, r, g, b, a );
            console.count("Colored pixels count:");
    			}
    		}
    	}
    }
    document.getElementById("test").addEventListener("click", testPixelBuffer);
    
    var renderer = new THREE.WebGLRenderer( {
    	canvas: document.getElementById( "view" ),
    	antialias: true,
    	alpha: true
    } );
    
    var scene = new THREE.Scene();
    
    var camera = new THREE.PerspectiveCamera( 28, 1, 1, 1000 );
    camera.position.z = 50;
    
    camera.add( new THREE.PointLight( 0xffffff, 1, Infinity ) );
    
    scene.add( camera );
    
    var controls = new THREE.TrackballControls( camera, renderer.domElement );
    controls.addEventListener( "change", render );
    
    /**********************/
    /* Populate the Scene */
    /**********************/
    
    var geo = new THREE.BoxBufferGeometry( 5, 5, 5 );
    
    var mat = new THREE.MeshPhongMaterial( {
    	color: "red"
    } );
    
    var mesh = new THREE.Mesh( geo, mat );
    
    scene.add( mesh );
    
    /**********************/
    /*   Render Function  */
    /**********************/
    
    var externalTarget = new THREE.WebGLRenderTarget();
    var size = renderer.getSize();
    externalTarget.setSize( size.width, size.height );
    
    function render () {
    	renderer.render( scene, camera );
    	renderer.render( scene, camera, externalTarget );
    }
    render();
    
    /**********************/
    /*   Animation Loop   */
    /**********************/
    
    function animate () {
    	requestAnimationFrame( animate );
    	renderer.readRenderTargetPixels( externalTarget, 0, 0, size.width, size.height, pixelBuffer );
    	controls.update();
    }
    animate();
    <!DOCTYPE html>
    <html>
    
    <head>
    	<meta charset="utf-8" />
    	<meta http-equiv="X-UA-Compatible" content="chrome=1,IE=edge">
    	<title>TEST</title>
    
    	<script src="https://threejs.org/build/three.js"></script>
    	<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
    
    </head>
    
    <body>
    
    	<input id="test" value="Test Pixel Buffer" type="button" /><br />
    
    	<canvas id="view" width="500" height="500" style="border: 1px black solid;"></canvas>
    
    </body>
    
    </html>