"I need assistance with loading a shader from an external file using THREE.FileLoader. Can you

Can someone help me with loading shaders from an external file in Three.js? The shader works fine when placed within a <script> tag, but I'm encountering issues when trying to load it externally. Here's what I'm doing:

var loader = new THREE.FileLoader();
loader.load('shader.vert',function ( data ) {vShader =  data;},);
loader.load('shader.frag',function ( data ) {fShader =  data;},);

Later on, I use the shaders like this:

var material = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: vShader,
    fragmentShader: fShader,

});

The problem arises when I reload the page and get errors stating that the shaders are not defined. Strangely, when I check vShader in the console, it displays the correct value. However, during debugging (with a breakpoint inside the init() function), vShader is shown as undefined.

Could someone please explain my mistake?

Here is the snippet of the entire code:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">

    <script src="https://threejs.org/build/three.min.js"></script>

</head>
<body>
<div class="WebGL-output" id="WebGL-output"></div>
<script id="vertexShader" type="x-shader/x-vertex" src="shader.vert">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec3 color;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(color,1.);
}
</script>

<script>
var renderer,uniforms,vShader,fShader,camera,scene;
var loader = new THREE.FileLoader();
init();
animate();
function init(){
renderer = new THREE.WebGLRenderer
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('WebGL-output').appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 5000;
scene = new THREE.Scene();

//******* DO NOT WORK
loader.load('plaid.frag',function ( data ) {fShader =  data;},);
loader.load('plaid.vert',function ( data ) {vShader =  data;},);
// ****** WORK
//fShader = document.getElementById('fragmentShader').text;
//vShader = document.getElementById('vertexShader').text;

// **************************
uniforms = {
    "color" : {
        type : "c",
        //value :new THREE.Color(0xf0f0f0)
        value :new THREE.Color(0x00ff00)
    },
};


var material = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: vShader,
    fragmentShader: fShader,
});

// Create circles and add to scene.
var geometry = new THREE.CircleGeometry(100, 50);
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

var light = new THREE.AmbientLight(0x000000); // soft white light
scene.add(light);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
</script>
</body>
</html>

Answer №1

I have decided to convert my init function into an async function for improved performance:

async function initialize() {

    let fragmentShader = await (await fetch('simple.frag')).text();

    console.log(fragmentShader);

    // Additional initialization code goes here

}
initialize();

Answer №2

One common mistake that developers make is assuming that loading files in browsers is synchronous. Here is an example:

loader.load('plaid.frag',function ( data ) {fShader =  data;},);
loader.load('plaid.vert',function ( data ) {vShader =  data;},);

The functions that set fShader and vShader will not be called immediately, but rather after some time when the files have finished downloading.

However, further down in the code, there is an attempt to use both fShader and vShader right away, even though they haven't finished downloading yet:

var material = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: vShader,
    fragmentShader: fShader,
});

If you want to load external files successfully, you need to structure your code to wait for them to finish downloading. Here is one way to do it:

var renderer,uniforms,vShader,fShader,camera,scene;
var loader = new THREE.FileLoader();
init();

function init() {
  renderer = new THREE.WebGLRenderer
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.getElementById('WebGL-output').appendChild(renderer.domElement);
  camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.z = 5000;
  scene = new THREE.Scene();

  var numFilesLeft = 2;
  
  function runMoreIfDone() {
     --numFilesLeft;
     if (numFilesLeft === 0) {
       more();
     }
  }

  loader.load('plaid.frag',function ( data ) {fShader =  data; runMoreIfDone(); },);
  loader.load('plaid.vert',function ( data ) {vShader =  data; runMoreIfDone(); },);

}

function more() {

  uniforms = {
      "color" : {
          type : "c",
          value :new THREE.Color(0x00ff00)
      },
  };

  var material = new THREE.ShaderMaterial({
      uniforms: uniforms,
      vertexShader: vShader,
      fragmentShader: fShader,
  });

  // Create circles and add to scene.
  var geometry = new THREE.CircleGeometry(100, 50);
  mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  var light = new THREE.AmbientLight(0x000000); 
  scene.add(light);
  
  animate();
}

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

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

Navigating the world of gtag and google_tag_manager: untangling

Tracking custom events in my react application using Google Analytics has been successful. Initially, I followed a helpful document recommending the use of the gtag method over the ga method for logging calls. The implementation through Google Tag Manager ...

What is the best way to retrieve data and handle error messages using the fetch API in Node.js?

I am attempting to utilize Node's 18 fetch API to send requests to a REST server. Below is the code snippet: const get = () => { let response = await fetch("10.0.0.12/test", { method: "GET", }); console.log(&quo ...

Click a button to show or hide text

I am attempting to create a button that will toggle text visibility from hidden using 'none' to visible using 'block'. I have tried the following code but unfortunately, it did not yield the desired outcome. <p id='demo' s ...

utilizing dropzone.js to pass an index and invoke a function

While everything seems to be functioning correctly, there is a notable issue that I am facing. When I upload an image to my Dropzone instance, I want the file name of that image to be added to the cards array under imageInfo. The challenge lies in figurin ...

Why is it necessary to include both the preserveDrawingBuffer and autoClear properties in the renderer?

Even if the `autoClear` setting is disabled, the renderer will still clear its output because the default value of the `preserveDrawingBuffer` property is set to false. These two properties, `autoClear` and `preserveDrawingBuffer`, both determine whether ...

What is the best way to compare two date strings with the format dd/mm/yyyy using JavaScript?

When attempting to compare a "Date" type of data with an "Any" type of data, the comparison is not functioning as expected. The date is retrieved in the following code: var today = new Date(); var dd = String(today.getDate()).padStart(2, '0'); v ...

Angular4 and jQuery working together for effective navigation and pagination

Trying to implement pagination in angular 4 and jQuery, but encountering an issue where clicking on the next button causes it to skip through multiple pages at once (2, then 3, then 5)... Component code: addClass(x) { $(".page-item").click(function () ...

What exactly does a module's scope entail in browsers and Node.js environments?

Can someone clarify the scope of a module in different environments like browsers and Node? I'm particularly interested in whether a module-level variable is initialized once for the entire application or multiple times. Is each import creating a new ...

Exploring the Safari browser with Polymer 2.0

Looking for some help with a question I have... I've been experimenting with the new Polymer 2.0 preview on Safari, but it doesn't seem to be working correctly. I'm using a simple code (just my-element) in the index.htm file, loading the pol ...

Accessing the next and previous elements using jQuery

Aug: <input type="text" value="100000" name="targetMonth_8" id="targetMonth_8" class="targetMonth" disabled> Sep: <input type="text" value="100000" name="targetMonth_9" id="targetMonth_9" class="targetMonth" disabled> Oct: <input type="text" ...

Perform an Ajax request with JQuery in an HTML document and transfer the response to a different HTML page

This is my first attempt at using AJAX and jQuery to retrieve data from another HTML page. Below is the code I have written: Here is my JavaScript code: <script type="text/javascript> $(document).ready(function() { $('#submit').click( ...

Tips for traversing through individual elements within an array present in the request payload

Looking to extract specific values from an array in req.body. I want to loop through and retrieve data like quantity_1 and quantity_2 separately. How can I achieve this? Here is a snippet of my array from req.body: { quantity_1: '9', item_n ...

Tips for creating emissiveMap lighting exclusively in dimly lit spaces using three.js

Using three.js, I am able to render the earth with textures and add an emissive texture for city lights. However, I am facing a problem where even the light areas of the earth emit city lights. For example: https://i.sstatic.net/hZ1Cr.png Is there a way ...

numerous cross-origin requests

Imagine a scenario where a page originating from A needs to make a GET request to a page originating from B, which in turn needs to make a GET request to a page originating from C. The goal is to retrieve the result from C to B and from B to A using callba ...

Unable to navigate through bootstrap dropdown items using keyboard shortcuts

I am currently working on a bootstrap dropdown menu that is filled with time zone details. Everything seems to be in order as the dropdown gets populated correctly. However, when I click on it and try to select an item by pressing a key on the keyboard (fo ...

Utilize an asynchronous method to upload files to Google Cloud Storage in a loop

I am new to using Javascript and have been working on a loop to upload images to Google Cloud Storage. While the image uploads correctly with this code, I'm facing an issue where the path (URL) is not being saved in the database AFTER the upload. I a ...

What is the best way to add a new element with specified text to a group of chosen HTML elements?

Here is some HTML code that selects specific elements: let array = jQuery.makeArray($(".dersprg tr td:nth-child(6)")); The selected elements contain table header text and some irrelevant data. While I can interpret the irrelevant data using if statements ...

Including a variable in an array within a function

I'm encountering an issue with inserting a variable into my array. Below is the code snippet: var data = new Array(); google.load("feeds", "1"); function initialize() { var feed = new google.feeds.Feed("http://www.ntvmsnbc.com/id/24927681/device/r ...

Experience the thrill of downshifting polygon GLSL particles with THREE.JS

Jaume Sanchez created an incredible experiment that you can explore here or view the code on GitHub here. If you set the scales to be 1.0 for X, Y, and Z, you'll notice that each particle transforms into a box, resembling three square polygons. http ...

Inquire about Javascript appendChild Function

As I dive into learning JavaScript, I encountered an issue with my code. I have created a button that, when clicked, should append some text to all paragraphs on my page. However, for some reason, it's not working as expected. Here's my code: &l ...