Three.js is experiencing difficulties in loading textures for custom Geometry with ShaderMaterial

A Geometry (pyramid) is defined here with four vertices and 4 faces -

var geom = new THREE.Geometry();
geom.vertices.push(new THREE.Vector3(0,100,0), new THREE.Vector3(-100,-100,100), new THREE.Vector3(0,-100,-100), new THREE.Vector3(100,-100,100));
geom.faces.push( new THREE.Face3( 0, 2, 1), new THREE.Face3( 0, 1, 3), new THREE.Face3( 0, 3, 2), new THREE.Face3( 1, 2, 3) );
geom.computeFaceNormals();

The RawShaderMaterial used for this geometry is shown below -

var geomMaterial = new THREE.RawShaderMaterial({
        vertexShader: [
            'precision highp float;',
            'precision highp int;',
            'uniform mat4 modelViewMatrix;',
            'uniform mat4 projectionMatrix;',
            'attribute vec3 position;',
            'attribute vec2 uv;',
            'varying vec2 interpolatedUV;',
            'void main() {',
            'interpolatedUV = uv;',
            'gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);',
            '}'
        ].join('\n'),
        fragmentShader: [
            'precision highp float;',
            'precision highp int;',
            'uniform sampler2D texSampler;',
            'varying vec2 interpolatedUV;',
            'void main() {',
            'gl_FragColor = texture2D(texSampler, interpolatedUV);',
            '}'
        ].join('\n'),
        uniforms: {
            texSampler: {
                type: 't',
                value: new THREE.ImageUtils.loadTexture("images/test.png")
            }
        }
    });

Despite having "images/test.png" accessible from the script, only a white pyramid is displayed without the expected texture.

Please advise on what could have caused this issue?

UPDATE:

After further investigation, it was discovered that providing UV mapping for the custom geometry is essential. This information has been incorporated as follows -

var uvs = [];
    uvs.push(new THREE.Vector2(0.5, 1.0));
    uvs.push(new THREE.Vector2(0.5, 0.0));
    uvs.push(new THREE.Vector2(0.0, 0.0));
    uvs.push(new THREE.Vector2(1.0, 0.0));

    geom.faces.push( new THREE.Face3( 0, 2, 1));
    geom.faceVertexUvs[0].push(uvs[0], uvs[2], uvs[1]);

    geom.faces.push( new THREE.Face3( 0, 1, 3));
    geom.faceVertexUvs[0].push(uvs[0], uvs[1], uvs[3]);

    geom.faces.push( new THREE.Face3( 0, 3, 2));
    geom.faceVertexUvs[0].push(uvs[0], uvs[3], uvs[2]);

    geom.faces.push( new THREE.Face3( 1, 2, 3));
    geom.faceVertexUvs[0].push(uvs[1], uvs[2], uvs[3]);

Despite the UV mapping inclusion, the issue persists with the white pyramid rendering and the additional error message -

THREE.BufferAttribute.copyVector2sArray(): vector is undefined 0 THREE.BufferAttribute.copyVector2sArray(): vector is undefined 1 ... THREE.BufferAttribute.copyVector2sArray(): vector is undefined 11

Any insights on how to resolve this?

Answer №1

Upon thorough examination of the Three.js code, I was able to pinpoint the issue and am sharing it here as an answer for the benefit of others who may encounter a similar problem.

In Three.js, Geometry.faceVertexUvs are treated as an array containing sets of UVs where each set represents all UVs of a single face. Below is a snippet of the code where UVs are extracted from GeometryVertexUvs:

if(!0===e){
     w=d[0][k];// where d=GeometryVertexUvs and k=index of the face

     if(void 0!==w)
       this.uvs.push(w[0],w[1],w[2]);
     else{
       console.warn("THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ", k);
       this.uvs.push(new THREE.Vector2,new THREE.Vector2,new THREE.Vector2);
     }
}

The solution lies in providing GeometryVertexUvs as an array of FaceUVs. Here is a rudimentary approach that demonstrates how to achieve this:

var faceUvs = [[],[],[],[]];
faceUvs[0].push(uvs[0], uvs[2], uvs[1]);
faceUvs[1].push(uvs[0], uvs[1], uvs[3]);
faceUvs[2].push(uvs[0], uvs[3], uvs[2]);
faceUvs[3].push(uvs[1], uvs[2], uvs[3]);
geom.faceVertexUvs[0].push(faceUvs[0]);
geom.faceVertexUvs[0].push(faceUvs[1]);
geom.faceVertexUvs[0].push(faceUvs[2]);
geom.faceVertexUvs[0].push(faceUvs[3]);

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

Node.js Express.js Module for Asynchronous SqLite Operations

Currently, I am working on a task that involves making synchronous requests to a database and passing the data to Express. Here is the code snippet: app.get('/', (req, res) => { let db = new sqlite3.Database('./Problems.db'); ...

What is the best way to convert a List of objects to JSON using a dynamic variable?

I have a need to serialize a list of objects in a specific way: Imagine I have the following C# class: public class Test { public string Key; public string Value; } List<Test> tests; When I serialize this list (return Json(tests.ToArray()) ...

The Soundcloud ajax response failed to be delivered

I'm attempting to retrieve user data from SoundCloud using this query. Although I can see the successful call in the Chrome network tab after clicking, the JSON response is not reaching the javascript alert as expected. This is preventing me from addi ...

Using lodash to combine the values of identical objects

As a newcomer to development, I am looking to group similar objects within an array of JSON objects. Here is an example of my JSON array: var data = [ { zone: "Bottom", group: "Bottom girders", original: 7, ...

Tips for passing input fields from a React Function component to a function

How can I retrieve the values from 4 input fields in my react functional component using a function called contactMeButtonPressed? The inputs include name, email, company name, and message when the contact me button is clicked. Do I need to implement stat ...

The issue with CSS and JavaScript is causing the appended elements to not display properly in PHP code

I am currently facing issues with retrieving the grandchildren from my database table named referrals. Surprisingly, my code successfully retrieves the username of my grandchildren, but it does not display below the line of my child and there are no errors ...

The code is nearly identical except for one issue that causes an infinite loop within useEffect

Hey, I'm new to reactjs and I've encountered a puzzling situation with the following two code snippets. I can't figure out why using the "First code" results in an infinite loop (endless '123' log outs in my browser console) while ...

Activate divs with Bootstrap5 modal toggle functionality

What adjustments must be made to the Bootstrap 5 example below in order to achieve the following two objectives: The "afterAcceptingTerms" division should remain hidden until the user clicks on the Accept Terms modal button, ensuring that only the "before ...

The storage capacity of localStorage is insufficient for retaining data

While I was trying to troubleshoot an error, I encountered another issue. var save_button = document.getElementById('overlayBtn'); if(save_button){ save_button.addEventListener('click', updateOutput);} This led to the following ...

Deactivate all functions of a complete row in the table

I'm working with a table that contains various user interaction controls in its cells, such as buttons and links. I'm looking to gray out certain rows of the table so that all operations related to those rows are disabled. Does anyone have sugge ...

The POST method in my Express Node.JS API is malfunctioning, throwing a SyntaxError stating "Unexpected token ' in JSON at position 68" when attempting to parse the data

Struggling to get this post API to function properly, where it's supposed to post data to a database table. However, whenever I test it on Postman, I keep encountering this error: SyntaxError: Unexpected token ' in JSON at position 68 at JSON ...

"The `Head.js` method called `.js()` allows for dynamic

Recently, I came across some code that was passed down to me from work, and it involves making an api call using head.js: head.js( { 'application' : 'someurl.com/foo.js' }); I'm curious if this actually registers the javascript a ...

Transfer information from one input field to another and then proceed to submit the form

I need to move the content of an input field that is located higher up the page to a form field at the bottom of the page and then submit the form. Below is what I have attempted so far, but it is not working: $('#move_down').click(function() ...

Python-JavaScript Integration Problem

I'm a beginner when it comes to Javascript, Python, and PHP. In my Javascript program, I have a button that triggers a Python script and displays the returned value on the screen. My goal is to steer clear of using Jquery and Json. Here are the snipp ...

Are there numerous instances of jQuery references both preceding and following the use of '$.noConflict'?

Managing a large project with thousands of PHP files can be challenging, especially when dealing with conflicting jQuery references that hinder the implementation of a desired plugin. Consider this scenario: <html> <head> ...

Storing information upon refresh in Angular 8

When it comes to inter-component communication in my Angular project, I am utilizing BehaviourSubject from RXJS. Currently, I have a setup with 3 components: Inquiry Form Where users enter an ID number to check for summon-related information. This data ...

Bringing out the version information in a React/webpack application: A guide

Looking for a way to display the version of every build in your app? I attempted to follow a tutorial to achieve this, but unfortunately, it didn't work for me. The tutorial I used can be found here: Do you know of any other methods that could help a ...

Unable to adjust the size of a DIV with a button click in Vue3

I am having trouble resizing a DIV block in Vue3. Whenever I click the button, I receive an error message saying "Cannot read properties of undefined (reading 'style')". I know there is an issue with the JS part of the code, but I'm not sure ...

Numeric keypad causing issues with setting minimum and maximum lengths and displaying submit button

I designed a password pin page that resembles a POS NUMPAD for users to enter their password. I am struggling to make the condition specified in the JavaScript function properly. Rule: Hide the submit button if the minimum input is less than 4 characters ...

Loading input field values dynamically in Bootstrap modal

In my Laravel application, I have a Bootstrap modal that I want to populate dynamically with data from the database. The goal is to update the values of the input fields in the modal. I have made progress on this front... Here is what I have in my view fi ...