Utilizing external sources to add texture to 3D models in WebGL

After mastering the art of applying texture to my 3D-models in WebGL using .mtl files (and .obj files), the process works seamlessly when the images are saved on my local computer. Below is an excerpt from my .mtl file showcasing how the texture is applied:

newmtl Earth_MATERIAL
Ns 96.078431
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 1

map_Kd Earth.png

Although everything works smoothly on my local machine, the challenge arises when I aim to publish my simulation and need to reference the image source. I initially tried uploading the image to Dropbox and using the link, but encountered an issue:

...
map_Kd https://dl.dropbox.com/s/t4cm3vzsbx21crc/Earth.png?dl=0

The error message I received when attempting to run this code was:

Error: WebGL warning: texImage2D: Element is write-only, thus cannot be uploaded.

To load the texture and model, I rely on an MTLloader and OBJloader. The following are the loaders I'm utilizing:

MTLloader: link

OBJloader: link

In addition, I make use of the ThreeJS Library:

ThreeJS: link

UPDATE: Thanks to Jave, the problem has been resolved! For those interested, here is the outcome:

Answer №1

The MTLLoader provides a convenient method called setTexturePath that allows you to specify the base path for loading textures. In cases where you are sourcing files from an external location like Dropbox, it may be necessary to also invoke setCrossOrigin(true). Below is a sample implementation demonstrating the use of these methods to load a texture.

Consider the following points:

  • It is common practice to store textures in the same directory as the mtl-file, or in a subdirectory for direct referencing (e.g., Earth.png or textures/Earth.png).
  • When using mipmaps, texture dimensions should be power of two (e.g., 2048 x 1024). Non-compliant images are automatically resized upon loading, so pre-sizing is recommended for efficiency.
  • Your texture is currently sized at 5689 x 2844 pixels, which is quite large. It would be advisable to reduce its size, as some devices may not support textures larger than 2048 x 2048.

const canvas = document.getElementById("canvas");
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, 1, 1, 10);
const renderer = new THREE.WebGLRenderer({ canvas });
const light = new THREE.AmbientLight();
scene.add(light);
camera.position.set(0, 0, 6);

const mesh = new THREE.Mesh(new THREE.SphereBufferGeometry( 1, 32, 32 ));
scene.add(mesh);

function update(){
  scene.rotation.y = 0.001 * performance.now();
  renderer.render(scene, camera);
  requestAnimationFrame(update);
}

update();

//The following code snippet generates a data-url from the div containing the mtl-data. While not essential, it enhances the example's similarity to file loading.
const data = document.getElementById("mtlplaceholder").textContent;
const dataurl = "data:text/plain;base64," + btoa(data);

const loader = new THREE.MTLLoader();

//To load texture files from a different folder than the mtl-file, setTexurePath must be invoked with the appropriate base path. Note that each texture needs to be available at this base url, which may not be the case with shared files from Dropbox.
//The complete URL is  https://dl.dropbox.com/s/t4cm3vzsbx21crc/Earth.png
loader.setTexturePath("https://dl.dropbox.com/s/t4cm3vzsbx21crc/");
//To enable cross-origin loading of textures, use setCrossOrigin(true):
loader.setCrossOrigin(true);
//Finally, load the mtl file (in this case, the "file" corresponds to the created dataurl):
loader.load(dataurl, res => {
  //MTLLoader.load creates a MTLLoader.MaterialCreator. To obtain the actual material, call create with the desired material name.
  //For OBJLoader users, utilize preload before calling objloader.setMaterials.
  const loadedMat = res.create("Earth_MATERIAL");
  //Assign the material to the mesh.
  mesh.material = loadedMat;
}, e => console.log("error", e));
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/53838a2/examples/js/loaders/MTLLoader.js"></script>

<canvas id="canvas" width="400" height="400"></canvas>

<div id="mtlplaceholder" style:"white-space:pre">
newmtl Earth_MATERIAL
Ns 96.078431
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 1

map_Kd Earth.png
</div>

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

Customize the border width and color of a specific column in HighCharts based on dynamic data

I am looking to dynamically change the border width and color of only one column in a basic column chart. Here is an example: var chartingOptions = { chart: { renderTo: 'container', type: 'column' }, xAxis: { categories: [ ...

Eliminate the Div Attribute once the radio button is activated

I'm just starting out with JavaScript and feeling a bit lost. I came across some code that adjusts the attributes of a Div based on a selection from a dropdown list. Now, I want to tweak it so that it works when a radio button is selected instead. Be ...

Dynamic image sources in reusable Gatsby-Image Component

Recently, I have been exploring Gatsby-Image for an upcoming project and have started experimenting with its capabilities. My test project was successful, but now I want to utilize the <Image /> tag from Gatsby in a similar way to a standard <img ...

The art of concealing and compressing JavaScript code

Can modern JavaScript obfuscation and minification tools effectively protect my code from reverse engineering? Which obfuscation platforms are the most reliable in thwarting these attempts? Is it possible that a program could easily deobfuscate the code, ...

I'm not satisfied with the value of the ReactJs state after the change

I am working on creating a calendar app for practice purposes. Currently, I have a current_month state variable set to 1. Additionally, I have a function called IncreaseMonth() that is designed to increment the value of current_month. However, when the va ...

You cannot use the "this" keyword outside of a class body

I am facing an issue with my function, can someone help me? Here is the code: function remove_multi_leg(): void { if (Number($("#search_no_legs").val()) < 2) { return; } const removeId: number = Number($(this).attr("data-number")); const ...

Is it possible to remove Sprites from a three.js scene?

Currently facing an issue where I am trying to update axis labels on a 3D plot by removing the old labels (implemented as sprites) before adding new ones. Unfortunately, I am experiencing difficulties. The previous labels seem to persist in the scene even ...

Combine theme configuration options within Material-UI

I am interested in setting up custom theme rules in Material-UI. My goal is to create both light and dark themes and extend them with some shared settings. My initial idea was to store the common settings for the light and dark themes in a separate variab ...

What could be causing the React-Router-Dom Outlet to not show the component?

I am working on a component that houses four different components. const ProtectedRoute = () => { return ( <> <Header /> <div className='flex h-screen overflow-hidden'> <div className="md:block h ...

To enable RTL in TextField, please note that the JssProvider is only available in "react-jss/src/JssProvider" and not in "react-jss/lib/JssProvider"

Seeking help to convert LTR to RTL in the following code: <TextField id="date" label="EmployeeDate" type="date" onChange= ...

Retrieve data within an object.map() function, returning after the mapping process has been completed

I am currently working with a cardsList object that is retrieved from a fetch() function. As I iterate over the cardsList and make additional requests to get more information for each card, I have encountered a peculiar issue. Despite the mapping process b ...

What is the best way to execute two asynchronous calls sequentially in JavaScript?

When using a common generic function for AJAX calls, the initial request retrieves all data from the server and maintains it within local scope. However, subsequent requests are still hitting the server, even when the data is already available locally. Thi ...

Encountering unexpected fetch requests to JSON files when using getStaticProps/getStaticPaths

My webpage seems to be functioning correctly, however I have noticed that in the console there are 5, 404 errors appearing on fetch requests. It's puzzling where these errors are originating from. Interestingly, these 404 errors only occur in the pro ...

Is there a way to send the image object to the onclick function as it is being assigned?

I apologize if my question is a bit unclear, as I am currently teaching myself how to use javascript. I am working on generating image thumbnails dynamically and would like the ability for users to enlarge the image when they click on the thumbnails. The p ...

Tips for creating a functional null option using the select ng-options feature

While there are a few questions and answers on this topic, I have yet to find a solution that works for my specific case. Imagine having an object like this: $scope.person = {name: 'Peter', category1: null, category2: null}; Another variable r ...

"Utilizing JSON information to create visually appealing graphs and charts

Struggling with syntax and in need of assistance. I have a basic data set that I want to display as a timeline with two filled lines (Time Series with Rangeslider). This is the format of my data set: [{"pm10": 12.1, "pm25": 7.0, "time": "13.08.2018 12:25 ...

Guide to personalizing the ngxDaterangepickerMd calendaring component

I need to customize the daterangepicker library using ngxDaterangepickerMd in order to separate the start date into its own input field from the end date. This way, I can make individual modifications to either the start date or end date without affectin ...

When using Javascript, an error is being thrown when attempting to select a nested element, stating that it is not a function

I am facing a challenge in selecting an element within another element, specifically a button within a form. Typically, I would use jQuery to achieve this as shown below: element = $('#webform-client-form-1812 input[name="op"]'); However, due t ...

I encountered an error when attempting to integrate Node.js with my terminal in the text editor - permission was denied

After installing node.js and npm, I encountered permission issues when trying to run them from my text editor (VSC). I was advised to open the terminal within the text editor, drag and drop the .js files I'm working on, add "node" and hit "enter" to r ...

Utilizing the <webview> functions within Electron: A comprehensive guide

After checking out the documentation for the Electron <webview>, I attempted to use some of the listed methods with no success. In inspecting the properties of the <webview> element, I found that its prototype is labeled as webview (__proto__ : ...