Utilize a map image as a texture on a plane within a personalized shader in THREE.js

I'm currently facing an issue where I need to load two images as textures, blend between them in the fragment shader, and apply the resulting color to a plane. However, I am struggling to even display a single texture properly.

My process for creating the plane and loading images is outlined below:

const planeGeometry = new THREE.PlaneBufferGeometry(imageSize * screenRatio, imageSize);

loader.load(
    "textures/IMG_6831.jpeg",
    (image) => {
        texture1 = new THREE.MeshBasicMaterial({ map: image });
        //texture1 = new THREE.Texture({ image: image });
    }
)

While using MeshBasicMaterial directly on Mesh presented the image correctly on the plane, trying to achieve the same effect with a custom shader only yields a black color:

const uniforms = {
    texture1: { type: "sampler2D", value: texture1 },
    texture2: { type: "sampler2D", value: texture2 }
};

const planeMaterial = new THREE.ShaderMaterial({
    uniforms: uniforms,
    fragmentShader: fragmentShader(),
    vertexShader: vertexShader()
});

const plane = new THREE.Mesh(planeGeometry, planeMaterial);
scene.add(plane);

The shaders implemented are:

const vertexShader = () => {
    return `
        varying vec2 vUv; 

        void main() {
            vUv = uv; 

            vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
            gl_Position = projectionMatrix * modelViewPosition; 
        }
    `;
}

const fragmentShader = () => {
    return `
        uniform sampler2D texture1; 
        uniform sampler2D texture2; 
        varying vec2 vUv;

        void main() {
            vec4 color1 = texture2D(texture1, vUv);
            vec4 color2 = texture2D(texture2, vUv);
            //vec4 fColor = mix(color1, color2, vUv.y);
            //fColor.a = 1.0;
            gl_FragColor = color1;
        }
    `;
}

Some attempts made to resolve this issue include:

  • Verifying visibility of the plane by shading it with a simple color
  • Ensuring UV coordinates are passed to the shader by visualizing them as color
  • Ensuring that both texture1 and texture2 are defined before passing them to the shader
  • Experimenting with using THREE.Texture instead of THREE.MeshBasicMaterial
  • Altering the uniform type in JS
    texture1: { type: "t", value: texture1 },

Based on my analysis, the issue might lie in how the texture is being passed as a uniform to the shader. There could be errors relating to data types along the way. Any insights or assistance would be greatly appreciated!

Answer №1

If loader is an instance of TextureLoader, it will provide you with a texture.

loader.load(
    "textures/IMG_6831.jpeg",
    (texture) => {
        texture1 = texture;
    }
)

On the other hand, while it's not a bug, the type attribute is no longer used for uniforms in three.js.

const planeGeometry = new THREE.PlaneBufferGeometry(1, 1);
const loader = new THREE.TextureLoader();
let texture1;
loader.load(
    "https://i.imgur.com/KjUybBD.png",
    (texture) => {
        texture1 = texture;
        start();
    }
);

const vertexShader = () => {
    return `
        varying vec2 vUv; 

        void main() {
            vUv = uv; 

            vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
            gl_Position = projectionMatrix * modelViewPosition; 
        }
    `;
}

const fragmentShader = () => {
    return `
        uniform sampler2D texture1; 
        uniform sampler2D texture2; 
        varying vec2 vUv;

        void main() {
            vec4 color1 = texture2D(texture1, vUv);
            vec4 color2 = texture2D(texture2, vUv);
            //vec4 fColor = mix(color1, color2, vUv.y);
            //fColor.a = 1.0;
            gl_FragColor = color1;
        }
    `;
}

function start() {
  const renderer = new THREE.WebGLRenderer();
  document.body.appendChild(renderer.domElement);
  const scene = new THREE.Scene();
  
  const camera = new THREE.Camera();
  
  const uniforms = {
      texture1: { value: texture1 },
      texture2: { value: texture1 },
  };

  const planeMaterial = new THREE.ShaderMaterial({
      uniforms: uniforms,
      fragmentShader: fragmentShader(),
      vertexShader: vertexShader()
  });

  const plane = new THREE.Mesh(planeGeometry, planeMaterial);
  scene.add(plane);

  renderer.render(scene, camera);
}
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="681c001a0d0d2858465959594658">[email protected]</a>/build/three.min.js"></script>

In addition, TextureLoader will give back a texture. If you are rendering continuously in a requestAnimationFrame loop, you can use this approach:

const planeGeometry = new THREE.PlaneBufferGeometry(1, 1);
const loader = new THREE.TextureLoader();
const texture1 = loader.load("https://i.imgur.com/KjUybBD.png");
const texture2 = loader.load("https://i.imgur.com/UKBsvV0.jpg");

const vertexShader = () => {
    return `
        varying vec2 vUv; 

        void main() {
            vUv = uv; 

            vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
            gl_Position = projectionMatrix * modelViewPosition; 
        }
    `;
}

const fragmentShader = () => {
    return `
        uniform sampler2D texture1; 
        uniform sampler2D texture2; 
        varying vec2 vUv;

        void main() {
            vec4 color1 = texture2D(texture1, vUv);
            vec4 color2 = texture2D(texture2, vUv);
            gl_FragColor = mix(color1, color2, vUv.y);
        }
    `;
}

const renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();

const camera = new THREE.Camera();

const uniforms = {
    texture1: { value: texture1 },
    texture2: { value: texture2 },
};

const planeMaterial = new THREE.ShaderMaterial({
    uniforms: uniforms,
    fragmentShader: fragmentShader(),
    vertexShader: vertexShader()
});

const plane = new THREE.Mesh(planeGeometry, planeMaterial);
scene.add(plane);

function render() {
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
requestAnimationFrame(render);
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0c78647e69694c3c223d3d3d223c">[email protected]</a>/build/three.min.js"></script>

The textures might initially appear blank, but three.js will update them once the images have finished loading.

You may find more current tutorials that interest you at this link.

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

Setting Up AdminLTE Using Bower

Recently, I decided to incorporate the Admin LTE Template into my Laravel project. I diligently followed the guidelines outlined here As soon as I entered the command: bower install admin-lte The installation process seemed to start, but then the ...

Making changes to HTML on a webpage using jQuery's AJAX with synchronous requests

Seeking assistance to resolve an issue, I am currently stuck and have invested a significant amount of time. The situation at hand involves submitting a form using the traditional post method. However, prior to submitting the form, I am utilizing the jQue ...

Google Maps GeoCoding consistently relies on the language settings of the browser in use

I have implemented the Google AJAX API loader to retrieve information in German by loading the maps API using this code: google.load("maps", "2", {language : "de"}); Despite trying variations such as deu, ger, de, de_DE, and ...

"Utilize the await/async and promise functions to pause and wait for a code to

I am facing an issue with using await/async in conjunction with Promise.all to retrieve arrays and proceed with the code. However, when I introduce a delay in the code, it seems like it's not functioning as expected. Below is my code snippet: asyn ...

Stopping a function that is currently running on a website using Javascript

I have a script on my website that triggers a rain feature when a user clicks on a button. However, I am struggling to figure out how to allow the user to deactivate this feature. I've tried various methods such as using break, return, and timeouts, b ...

Guide on Linking a Variable to $scope in Angular 2

Struggling to find up-to-date Angular 2 syntax is a challenge. So, how can we properly connect variables (whether simple or objects) in Angular now that the concept of controller $scope has evolved? import {Component} from '@angular/core' @Comp ...

Creating a jQuery AJAX data object that contains numerous values for a single key

My goal is to make an ajax call with multiple values in the same key within the data object. var data = { foo: "bar", foo: "baz" } $.ajax({ url: http://example.com/APIlocation, data: data, success: function (results) { console.log(res ...

Angular Controller encounters issue with event handler functionality ceasing

One of my Angular controllers has the following line. The event handler works when the initial page loads, but it stops working when navigating to a different item with the same controller and template. document.getElementById('item-details-v ...

The Discord.js error message popped up, stating that it was unable to access the property 'then' since it was undefined

I'm currently working on implementing a mute command for my discord bot, but I'm encountering an error that says; TypeError: Cannot read property 'then' of undefined I am unsure of what is causing this issue and would greatly apprecia ...

Tips for utilizing Angular Js to redirect a webpage

Can someone help me figure out how to redirect to another page using Angular Js? I've searched through various questions here but haven't found a successful answer. This is the code I'm currently working with: var app = angular.module(&ap ...

Tips for continuously randomizing colors in p5.js

I recently began exploring p5.js and I have a query regarding color randomization. Currently, it seems that the color only changes randomly when I restart the code. Is there a way to trigger this randomization every time the mouse is clicked? Below is the ...

Combining Jquery with Objects and Strings

Having a bit of trouble with a small issue that I can't seem to figure out. Let me explain... So, I'm creating an input like this... var input = $('<input/>'); When I append it like this, everything works fine: $(this).append( ...

Using Lodash to Substitute a Value in an Array of Objects

Looking to update the values in an array of objects, specifically the created_at field with months like 'jan', 'Feb', etc.? One way is to loop through using map as demonstrated below. However, I'm curious if there's a more co ...

Advantages and disadvantages of distinct methods for looping through HTML elements

My JS code generates HTML elements that are structured like this: <div id="container"> <div id="block_1" class="blocks"></div> <div id="block_2" class="blocks"></div> <div id="block_3" class="blocks"></di ...

What is the best way to send a variable using $.post in a JavaScript script?

My jQuery and Javascript code below is responsible for handling the ajax request: else { $.post("http://www.example.com", {email: val}, function(response){ finishAjax('email', response); }); } joi ...

Chat box custom scrollbar always positioned at the bottom

I have a personalized chat box where I included overflow-y for scrolling functionality. However, every time I input a message in the text box, it displays at the top of the scrollbar window. Is there a way to automatically show the most recent message I ...

Every time I try to access Heroku, I encounter an issue with Strapi and the H10 error code

Upon opening Heroku and running the command "heroku logs --tail", my app encountered a crash and I can't seem to locate my Strapi application in Heroku. 2020-05-04T19:05:38.602418+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GE ...

Having trouble uploading Node.js and Mongoose to Heroku due to error codes H12 and H15? Need help troubleshooting and resolving this issue?

Attempting to deploy my Node, mongoose, express app on Heroku for the first time has been a challenge. The application is a simple blog with a login system. Despite extensive research and effort, I am struggling to successfully host it. Below is the error ...

What is the proper way to define the type for a functional React component by using object destructuring on props?

As I continue to learn TypeScript and work on declaring advanced types, I am faced with converting my CRA project to TypeScript. Within this project, I have a component that closely resembles examples from react-router-dom, but I have not come across any T ...

Error: The function styles$1.makeStyles is not defined

Currently, I am experimenting with rollup for bundling. However, when I run the code, I encounter the following problem: https://i.stack.imgur.com/8xLT3.png import { makeStyles } from '@material-ui/styles'; const styles = makeStyles({ subHead ...