Using Three.js: Adjust the UV coordinates of my texture within a specialized ShaderMaterial

Currently, I am working with a plane geometry and developing a CustomShader material for it. This material will require some textures as uniforms and I want these textures to completely cover my plane (similar to the background-size:cover CSS property).

Previously, I was able to achieve this using a utility function when working with textures and a MeshBasicMaterial:

cover( texture, aspect ) {

    var imageAspect = texture.image.width / texture.image.height;

    if ( aspect < imageAspect ) {
        texture.matrix.setUvTransform( 0, 0, aspect / imageAspect, 1, 0, 0.5, 0.5 );

    } else {
        texture.matrix.setUvTransform( 0, 0, 1, imageAspect / aspect, 0, 0.5, 0.5 );

    }

}

However, when using the ShaderMaterial, this "cover" function no longer applies. Do I need to incorporate this functionality into my fragment shader? If so, how can I replicate this behavior?

Below is a snippet of my code:

const vertexShader = `
    precision highp float;
    uniform mat3 uUvTransform;
    varying vec2 vUv;
    void main() {
        vUv = ( uUvTransform * vec3( uv, 1 ) ).xy;
        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`;

const fragmentShader = `
    precision highp float;
    uniform sampler2D uText1;
    varying vec2 vUv;


    void main() {
        vec2 xy = vUv;

        vec4 color = texture2D(uText1,xy);
        gl_FragColor = color;
}`;

Current output can be viewed here:

https://i.sstatic.net/U7Jg7.png

Any insights or suggestions would be greatly appreciated. Thank you.

Answer №1

To implement this feature, you can utilize a personalized uniform like so:

uniform sampler2D uTexture;
uniform vec2 uScale;
varying vec2 uvCoordinates;
void main() {
    vec2 uv = (uvCoordinates - 0.5) * uScale + 0.5;
    gl_FragColor = texture2D(uTexture, uv);
}

Additionally, consider the following logic in JavaScript:

var imageAspect = texture.image.width / texture.image.height;
if ( aspect < imageAspect ) {
    material.uniforms.uScale.value.set(aspect / imageAspect, 1)
} else {
    material.uniforms.uScale.value.set(1, imageAspect / aspect)
}

Answer №2

Three.js utilizes a Matrix3 to handle texture transformations such as

.offset, .repeat, .rotation, .center
. This Matrix3 is passed as a uniform into the vertex shader for processing. The vertex shader performs matrix multiplication and passes the updated UVs as a varying to the fragment shader.

You can incorporate these GLSL code lines into your ShaderMaterial's vertex shader. In most cases, the texture properties will automatically utilize the Matrix3. If not, you have the option to manually recreate the Matrix3 by referencing its implementation in the source code and passing it as a uniform. Without knowledge of your utility function, it's challenging to determine how you are achieving the desired scaling.

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

How to transform a JQuery button into a dropdown menu

For inspiration, consider this JQuery UI Button example: http://jqueryui.com/demos/button/#splitbutton Now, how can you create a dropdown menu when the small button is clicked? My main concern is the way .button() alters the button's actual appearanc ...

Having trouble with your browser freezing up after an AJAX request finishes?

Going through a tough time trying to figure this out for the past two days, but still struggling without any clue. Here's what I've been up to: Firstly, I upload a file using AJAX and instantly start processing it on the backend. $.ajax({ t ...

What's up with this unconventional jQuery formatting? Can someone shed some light on

I recently found a plugin that toggles checkboxes, but unfortunately it's not functioning correctly with the latest version of jQuery so I'm currently working on debugging it. Could someone please provide an explanation for the following code sn ...

Executing PHP script within a Node.js socket server program

I have a JavaScript file running a normal TCP socket using node.js. Before sending a response back to the client, I need to validate the data using some PHP (MySQL) code. Can someone guide me on executing this PHP code inside the JavaScript file? Most of t ...

JavaScript generating HTML code causing malfunctions

I have been attempting to implement the IN Place Editing feature using JQuery. Below is the code snippet editinplace.js $(document).ready(function() { //When div.edit me is clicked, run this function $("div.editme").click(function() { // ...

The implement of the filter function in JavaScript is a powerful tool

Recently, I encountered a challenge on Codewar. Below is my solution, but what piqued my curiosity is why both return e and return arr[i-1] yield the same outcomes. var uniqueInOrder=function(iterable){ let arry = typeof iterable === "string" ? ite ...

How can Vue.js pass an array from a child component to its parent component?

I'm currently developing a contact book app and I have created a modal within a child component that contains a form with several input fields. My goal is to utilize the values entered in the form and add them to the parent component. I have successfu ...

What is the syntax for implementing a nested for loop in JavaScript within this particular scenario?

var entries = [ { "item": "something", "steps": [{ "node": {"name": "test0"}, "status": {"name": "test"}, "time": {"name": "test"} },{ "node": {"name": "test1"}, ...

What are some ways to personalize web notifications?

I am looking for a way to easily send web notifications with custom input and control when they are sent, such as after submitting a form. I want to create a user-friendly interface for non-coders to use. Currently, I am attempting to set up a system wher ...

Having difficulty passing the new state value using props in ReactJS

I am facing an issue with sending state values from parent to child components. Initially, the state value is empty but after making an API call, the state value gets updated. However, the props in my child component are still stuck with the initial empty ...

What is the best way to enable my search function to filter out specific items from a table?

Currently, I have created a table populated with data fetched from a JSON file. Now, my focus is on implementing a search functionality that filters out items based on user input and displays only those table rows matching the search criteria. The code sni ...

What is the best way to save a large quantity of objects to a server using ajax and php?

Imagine a scenario where I have a page containing 100 objects, each around 700 bytes when converted to json format. When it comes to saving these objects to the php based controller, there are several options available to me. Option 1: For each object ( ...

Display endless data within a set window size

I am looking to create a fixed-size window for displaying text from the component <Message/>. If the text is longer, I want it to be scrollable within the fixed window size. See screenshot below: Screenshot export default function AllMessages(){ ...

Looking to Share Your Words on Tumblr?

When it comes to interacting with Tumblr, I have no issues using the GET method. However, as soon as I attempt to use the POST method for my Tumblr blog, an error is thrown: ({"meta":{"status":401,"msg":"Not Authorized"},"response":[]}); Below is the cod ...

What could be the reason the server actions in nextjs 13 are not functioning correctly?

I am currently working on a project to retrieve data from mockapi.io, a mock API. However, I am encountering an issue where the fetched data is not displaying in the browser. There are no visible errors, and the browser window remains blank. Interestingly, ...

Merge arrays with identical names within the same object into one cohesive object containing all elements

I just started using Vue and I'm not entirely sure if it's possible to achieve what I have in mind. Here is the structure I have: { "items":[ { "total":1287, "currency":"USD", "name":"string", "itemID":"", "pro ...

The Service Worker seems to be neglecting to serve the sub-pages at

I've successfully implemented a service worker on my website. The home page loads correctly from the Service Worker cache, and when I visit previously viewed 'posts' while online in Chrome, they load and show as 'from ServiceWorker&apos ...

What is the correct property for accessing and changing the value of a Text node: data or nodeValue?

What is the best option to use? The website suggests using nodeValue, although data shows better compatibility. ...

Utilizing ajax for fetching a data table

I am new to using ajax and have successfully retrieved data from a table. However, I am now trying to pull in an entire data grid but not sure how to achieve this. In my index.php file, I have the following code: <html> <head><title>Aj ...

Seeking a quick conversion method for transforming x or x[] into x[] in a single line of code

Is there a concise TypeScript one-liner that can replace the arrayOrMemberToArray function below? function arrayOrMemberToArray<T>(input: T | T[]): T[] { if(Arrary.isArray(input)) return input return [input] } Trying to cram this logic into a te ...