Selecting Texture Coordinates

My goal is to pinpoint where a user has clicked on a texture of an object to trigger a response by redrawing the texture.

I've been able to achieve this by rendering my objects with a color-coded texture onto a separate render target and using gl.readPixels to determine which coded pixel was clicked. From there, I calculate the corresponding X and Y coordinates on the texture.

While I can reliably do this for the Y axis, I'm facing some challenges with the X axis.

Here is my simplified Three.js setup:

const canvas = document.getElementByID("output"),
    renderer = new THREE.WebGLRenderer({
        canvas: canvas,
        alpha: true,
        antialias: true
    }),
    back = new THREE.WebGLRenderTarget(canvas.width, canvas.height),
    scene = new THREE.Scene(),
    pickingScene = new THREE.Scene(),
    pickingPixelBuffer = new Uint8Array(4),
    camera = new THREE.PerspectiveCamera(50, canvas.width / canvas.height, 0.1, 1000),
    textureWidth = 1024,
    textureHeight = 1024,
    texture = generateTexture(textureWidth, textureHeight),
    pickingTexture = generatePickingTexture(textureWidth, textureHeight), 
    obj = textured(shell(w, 5, 10), texture),
    objPicker = textured(shell(w, 5, 10), pickingTexture);
    
    back.generateMipmaps = false;
    
    scene.add(camera);
    scene.add(obj);
    pickingScene.add(objPicker);
    

For an object like this:

The picking texture will look like this:

The generateTexture function isn't crucial. The textured function simply applies a texture to a geometry object:

function textured(geometry, txt){
        const material = new THREE.MeshBasicMaterial({
            color: 0xffffff,
            map: txt,
            transparent: false,
            shading: THREE.FlatShading,
            side: THREE.DoubleSide
        });
    
        const obj = new THREE.Mesh(geometry, material);
        return obj;        
    }
    

And here is the generatePickingTexture function:

function generatePickingTexture(w, h){
        const canvas = document.createElement("canvas");
        canvas.width = w;
        canvas.height = h;
        const texture = new THREE.Texture(canvas);
        const gfx = texture.image.getContext("2d"),
                l = w * h,
                pixels = gfx.createImageData(w, h);
        for(let i = 0, p = 0; 
                i < l; 
                ++i, p += 4){
            pixels.data[p]   = (0xff0000 & i) >> 16;
            pixels.data[p+1] = (0x00ff00 & i) >> 8;
            pixels.data[p+2] = 0x0000ff & i;
            pixels.data[p+3] = 0xff;
        }
        gfx.putImageData(pixels, 0, 0);
    
        texture.needsUpdate = true;
        return texture;
    }
    

Next, the picking operation is performed:

function pick(){
        renderer.render(pickingScene, camera, back, true);
    
        const gl = renderer.getContext();
        gl.readPixels(pointerX, canvas.height - pointerY, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pickingPixelBuffer);
        const i = (pickingPixelBuffer[0] << 16) | 
                (pickingPixelBuffer[1] << 8) | 
                pickingPixelBuffer[2],
                x = (i - Math.floor(textureWidth / 512) * 256) % textureWidth,
                y = i / textureWidth;
        console.log(x, y);
    }
    

While the y coordinate calculation is accurate, the x coordinate is consistently off. As the mouse is dragged down the screen, the x coordinate shifts to the right, moving approximately 1/4th of the texture width. When the mouse is moved horizontally without vertical changes, the x coordinate aligns with the correct offset but is inaccurately located. It appears to shift positions at every 1/4 mark.

Given that the offset is 1/4th, it suggests that my approach to generating the texture might be flawed. However, I've been unable to pinpoint the issue.

Upon narrowing down my texture to 256 pixels wide, the functionality works flawlessly.

After implementing a workaround in the pick function, I have resolved the problem, although the reason behind its success eludes me.

Regarding different orientations, unrelated to the X coordinate issue, there are still some remaining challenges that seem linked to texture resampling.

Ultimately, the root cause turned out to be the default texture filtering settings.

Answer №1

Finally, I discovered that the issue all along was related to the texture filtering. I made a crucial adjustment to my generatePickingTexture function:

function modifyPickingTexture(width, height){
    var canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    var texture = new THREE.Texture(canvas, THREE.UVMapping, THREE.RepeatWrapping, THREE.RepeatWrapping, THREE.NearestFilter, THREE.NearestFilter);
    var graphics = canvas.getContext("2d"),
            size = width * height,
            pixels = graphics.createImageData(width, height);
    for(var i = 0, p = 0; i < size; ++i, p += 4){
        pixels.data[p]   = (0xff0000 & i) >> 16;
        pixels.data[p+1] = (0x00ff00 & i) >> 8;
        pixels.data[p+2] = (0x0000ff & i) >> 0;
        pixels.data[p+3] = 0xff;
    }
    graphics.putImageData(pixels, 0, 0);

    texture.needsUpdate = true;
    return texture;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I successfully merged two arrays (decks of cards) without using recursion, but I'm curious to understand where I went wrong with the recursive approach

Currently, I am working on a function that shuffles two arrays together using recursion. The goal is to combine the top and bottom halves of a deck of cards into a single array with elements interleaved. For example: The first element should come from the ...

What is the best way to dynamically update form fields in a database after making a selection in a <select> component?

Currently, I have a form that displays a list of stars (stellar objects) with a <select> control and two <inputs>. I am seeking guidance on how to populate the two inputs from the database when the user changes the selection in the <select&g ...

Guide to incorporating tesseract OCR into a Cordova/Phonegap application

My attempts to use Tesseract OCR with my app have been unsuccessful despite following the instructions provided here. After inspecting the code using Google Chrome Dev console through the WebView, I encountered an error: Uncaught SyntaxError: Unexpected ...

Is there a convenient method to combine arrays of objects in JavaScript using ellipses or an equivalent approach?

let array = [ {id: 1, data: {foo: "bar 1"}}, {id: 2, data: {foo: "bar 2"}} ]; //If ID doesn't exist, add new element to the array array = [...array, {id: 3, data: {foo: "bar 3"}}] console.log(array); //If ID exists, replace data object with new ...

In IE7, the string comparison in jQuery exhibits unique behavior

When using the following code snippet with a jQuery UI autocomplete element (#search), it works as expected in Firefox, Chrome, and other browsers, always returning true for the selected element. However, Internet Explorer 7 does not behave as expected. $ ...

Tips for properly panning across the canvas

I added event listeners to capture mouse movement, clicks, and releases in my code. canvas.addEventListener('mousemove', onMouseMove, false); canvas.addEventListener('mousedown', onMouseDown,false); canvas.addEventListener('mouseu ...

The feature to prevent multiple selections in JSTree is not functioning as expected

Incorporating JSTree into my application involves the code below. this.CreateTreeView = function () { $('#jstree_demo_div').jstree({ 'core': { 'multiple': false, 'data': [ ...

Next.js directs API requests to the root URL

I'm currently working with an API handler pages/api/[slug]/[uid].ts My goal is to redirect the requests to the main root of my application, specifically: http://localhost:3000/[slug]/[uid] What steps do I need to take in next.config in order to mak ...

Is there a way to extract a specific element from an array stored within a form element's value?

I am encountering an issue with retrieving values from an array in an HTML form element using jQuery. Despite my efforts to explain and provide code, I am not getting the desired results. Can someone help me understand what is going wrong in my code? Thank ...

Performance problem with 'Point-along-path' d3 visualization

I recently explored a d3 visualization where a point moves along a path, following the code example provided at https://bl.ocks.org/mbostock/1705868. During this movement, I observed that the CPU usage ranges from 7 to 11%. In my current project, there ar ...

Accessing router parameters in Vuex actions

Is there a more efficient way to pass router params into Vuex actions for a large form? edit_sport_type({ rootState, state, commit }, event) { const sportName = rootState.route.params.sportName <------- const payload = {sportName, event} ...

Retrieve JavaScript Variable Value when Button is Clicked via asp:HiddenField

Having limited experience with JavaScript and jQuery, I decided to make some modifications to a jQuery Slider for adjusting dates. You can check out what I've done so far here: http://jsfiddle.net/ryn_90/Tq7xK/6/. I managed to get the slider working ...

Injecting variable styles into my VueJS component

I am currently working on developing a custom progress bar to visualize the percentage of completed tasks. The approach I am taking involves using v-bind:styles and passing {width: dynamicWidth + '%'} to regulate the progression of the bar. To ac ...

Exploring the world of jQuery animation and background colors with Animate()

I'm currently attempting to implement a basic pulse effect by utilizing JQuery to modify the background color. However, I am facing issues with animating the backgroundColor property. function show_user(dnid) { /* dnid represents the HTML ID of a ...

Is there a way to programmatically click on an href link in Firefox? The method that is typically used in Internet Explorer

http://jsfiddle.net/HVGre/1/ - check out this test link. I have a link in my HTML code that needs to be clickable dynamically. While it functions well with the .click() method in Internet Explorer, it fails in Firefox. Unfortunately, changing the link to ...

Trouble arises when adding a .js script to the webpage

I'm feeling quite puzzled by this small piece of code, as it appears to be the simplest thing you'll come across today. Despite that, I can't help but seek guidance because I've been staring at it for what feels like an eternity and can ...

Can you provide the name of the slideshow plugin used on the Wipro website?

Can anyone tell me the name of the image slide show featured on: http://www.wipro.com/index.htm? Also, does anyone know where I can find the script for free? I am looking to incorporate it into a page that is coded in php, html, css, and javascript. Than ...

tips on displaying a div dynamically in a specific location

Currently, I have implemented HTML textBoxes on my website. However, I am looking to validate these textBoxes using JavaScript. Rather than displaying a traditional alert popup for invalid data input, I would like to show a div next to the specific textBox ...

Retrieving data from a nested object with varying key names through ng-repeat

My JSON object contains various properties with unique names: var definitions = { foo: { bar: {abc: '123'}, baz: 'def' }, qux: { broom: 'mop', earth: { tree: 'leaf', water: 'fi ...

Utilize Bootstrap modal to input information into the DataTables library

I am trying to use a bootstrap modal to insert data, but I am encountering an error on the action index. As a result, the button that I added is not functioning correctly. Can someone please review my code to see if there are any mistakes? User Action Con ...