Rendering an .OBJ as a 3D interactive display

  • Thread starter Thread starter DaveC426913
  • Start date Start date
  • Tags Tags
    3d
AI Thread Summary
A project is underway to render a 3D critter from an .OBJ file using Blender and Three.js. The initial steps involve applying color and rendering the model in a browser, allowing for interactive 3D rotation. Three.js is identified as the primary tool for this task, with the need to set up a local server to avoid CORS errors when loading JavaScript modules. Node.js is suggested as a simpler alternative to traditional servers like WAMP, enabling the use of the 'serve' package for local development.Challenges include loading the .MTL file for textures alongside the .OBJ file, with references to outdated examples causing compatibility issues. The latest Three.js documentation is recommended for accurate implementation. The user has successfully reduced the model's file size significantly, improving load times, but still faces difficulties in applying colors from Blender to the final render. The process involves creating and applying materials to achieve the desired visual results. Incremental learning and troubleshooting are key themes in this project.
DaveC426913
Gold Member
Messages
23,830
Reaction score
7,816
TL;DR Summary
What tools do I use to make one of those renderings (in a browser) that you can rotate with your mouse? I have the .OBJ and Blender 10.
Welp. I've been given a challenge to help out with a project. I have no budget, no knowledge-holders and not much knowledge, but I'll see how far I can get.

I am about to receive an .OBJ file of a critter. I have some experience in Blender, building and shaping and stuff (not a super complex, fluid object like a creature but see my creation, attached - designed, built and 3D printed by me, which I am quite proud of), but I have yet to crack the seal on actually applying colour or even rendering in colour (as opposed to the default uniform grey). So that'll be step one.

The next step is to output the critter in a format that is usable by whatever applet (do they still have Java applets?) so that it can be rendered (presumably in a browser) so that a user can rotate it in 3D with their mouse. I'm nore sure how the kids do that these days.
 

Attachments

  • scimitar1.jpg
    scimitar1.jpg
    32.8 KB · Views: 25
Computer science news on Phys.org
DaveC426913 said:
TL;DR Summary: What tools do I use to make one of those renderings (in a browser) that you can rotate with your mouse? I have the .OBJ and Blender 10.
The most widely used is Three.js which has an addon which can load .obj files directly: https://threejs.org/docs/#examples/en/loaders/OBJLoader.

DaveC426913 said:
(do they still have Java applets?)
No.

DaveC426913 said:
I'm nore sure how the kids do that these days.
Three.js.
 
  • Informative
  • Like
Likes jack action, DaveC426913 and BvU
OK. I've downloaded and unpacked three.js.

It explicitly assumes I'm either running a build tool, or using a local server with a CDN and import maps.

I really just want a proof of concept. If I can see the file using an index.html, a link to the .js files and a reference to the .obj file I'll be happy. But I don't think that's going to happen.

Ugh. Seriously don't want to spin up a whole dev environment. This is why left front-end dev in the first place. It's all environment and config stuff, and no coding.

I stole this code from stack overflow as a way to start, but of course it dies on line 1 of the js code because OBJLoader doesn't exist.

[ unable to post CODE block ]

Do I need to also run this in a local server like WAMP or something?
 
DaveC426913 said:
I really just want a proof of concept. If I can see the file using an index.html, a link to the .js files and a reference to the .obj file I'll be happy. But I don't think that's going to happen.
Yes it can, use the example code here:
https://github.com/mrdoob/three.js/blob/master/examples/webgl_loader_obj.html

DaveC426913 said:
Do I need to also run this in a local server like WAMP or something?
Yes, you can't load javascript modules from a file:// origin so you will need an HTTP server. Easier and more robust than WAMP on Windows is to install Node.js and then you can just do npx serve in the relevant directory.
 
pbuk said:
install Node.js
Ugh. One of the reasons I got out of dev.

But I'll do that. Thanks.

You're saying don't need a server like WAMP if I use node.js? I.e. node.js acts as a server?
 
DaveC426913 said:
You're saying don't need a server like WAMP if I use node.js?
Correct.

DaveC426913 said:
I.e. node.js acts as a server?
Not quite: Node.js provides the mid-level routines to listen on a port and parse an incoming HTTP request, you need a script like serve to create a response that will work with modern browsers (e.g. serving the right Content-Type and cors headers). Typing npx serve into a terminal runs the npx executable which downloads the serve package from https://registry.npmjs.org into memory and runs it.

DaveC426913 said:
Ugh. One of the reasons I got out of dev.
I'll guess that rather than Node.js itself this was more due to the build tools that were prevalent in the JS ecosystem at the time - and I agree with you: gulp, grunt etc. were hideous.

Things are much better now: check out vite.
 
Last edited:
I can see the code you posted in an image at https://www.physicsforums.com/threads/cannot-type-etc-hosts-without-the-spaces.1045236/post-6796951

That code won't work - you can't load three that way (any more, I think you could with earlier versions which did expose a THREE global). You need to follow the instructions at https://threejs.org/docs/#manual/en/introduction/Installation: either Option 1 (which you will find easier in the long run if you can overcome your fear of build tools, and is certainly easier if you want to be able to run your script without an internet connection) or Option 2, which is set up to use a CDN but could I suppose be adapted to use an offline download of the whole bundle including addons, noting that this is undocumented and unsupported and probably requires a deeper understanding of how browsers implement CORS for JavaScript modules than I believe you want to delve into.

If you don't like Option 1 because you don't understand what is going on 'under the hood', follow the more explicit tutorial at https://threejs-journey.com/lessons/first-threejs-project
 
Ultimately, I'm going to need to show this to someone as a "poof of concept" (because demos are built on magic), which means uploading it to my webhost. It seems my webhost does support node.js.

Why have I agreed to do something I hate?

And it's not going to get better. I know if I produce a working demo, the client will say "Great. You're now the smartest person we know. Can you get this running on our Mac, running a virtual machine, with XP, in Swahili? Tomorrow?"
 
DaveC426913 said:
Ultimately, I'm going to need to show this to someone as a "poof of concept" (because demos are built on magic), which means uploading it to my webhost. It seems my webhost does support node.js.
No, you don't need your webhost to support node.js, you simply need to upload the html and javascript files. I simply suggested Node.js as an easier way to get a development web server running on a local machine, all it is doing is serving static files. Your web host uses (probably) Apache to serve static files, you just need to upload them to the right directory.

If you are following Option 1: build using vite build and upload the build directory.
If you are following Option 2: just upload a html file containing an importmap pointing to the CDN:

1739240835296.png


(you need to substitute a version number in the import map above, something like
Code:
{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/three@0.173.0/build/three.module.js",
    "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.173.0/examples/jsm/"
    }
}

DaveC426913 said:
Can you get this running on our Mac, running a virtual machine, with XP, in Swahili? Tomorrow?"
The answer is "Tomorrow? No, it is already done. Simply point the Mac's browser at the web server. Oh and this will also work on an iPad, Android phone, Raspberry Pi...."
 
Last edited:
  • #10
  • Love
  • Like
Likes BvU and DaveC426913
  • #11
  • #12
Not really sure how the pieces fit together. I
  • installed node in its default directory.
  • downloaded @pbuk's index.html to a local folder
  • pointed it at my .obj file.
  • pointed the OBJLoader to one I found in an example subfolder of the three-js-master folder
  • I didn't find any file called OrbitControls.js anywhere. There is no /controls/ folder. So I commeted that line out.
  • launched index.html
index.html throws a CORS error
I tried opening a terminal and running node index.html which, of course, fails.

I'm not really sure what I'm doing.


This is where I get stumped. There are an uncountable number of ways of configuring and using node and modules, and none of the examples match any others so the jigsaw puzzle pieces don't fit together. Even the Intro to node.js has absolutely nothing to do with what I'm doing. I don't see what I would gain by blindly going down a rabbit hole.

*sigh* guess I've got some tutorials to review.
 
Last edited:
  • #13
Jesoosi Christoosi! It's working!

https://www.davesbrain.ca/3d-three/index.html

Now all I have to do is figure out how to alter the lighting and add some colour...



Lighting
I added a light (otherwise it renders pitch black). I tried altering the light - turning it from the default 1000W down to 200W but it appears to have made no difference in final rendering - still that burned out white.

Colouring
I gave it a different colour (a deep blue) using "texture paint", just to see if the colour would render. It did not. Still stark white. Maybe texture paint is the wrong tool to export to .obj.

I think I need to break the object down somehow, before I can colour particular bits of it. It's a .OBJ, which means it has to be imported into Blender as a single object, not multiple components. I can only select the entire object (the orange outline). There is only 'Object Mode' available - there is no 'Edit Mode'. Maybe something to do with UV editing?

Bit by bit ...
 
  • #14
It looks like what I need to do is load the .MTL file along with the obj.

Here is an example of loading the .MTL:
https://stackoverflow.com/questions/35246590/how-to-add-a-mtl-texture-to-an-obj-in-three-js
I adapted the code as best I could but it was not compatible.

This is my attempt to dovetail @pbuk 's code with the example:

It dies on line 107 with "THREE.MTLLoader is not a constructor".

Here is my co ... ***SIGH*** Here is a screen grab of my code:

1739678054166.png

1739678084654.png

1739678122028.png


I'm trying a few alternate implementations I'm finding online. Problem is, Unless they list ALL their code, the samples are not compatible (since there are as many ways to implement a .js module as there are developers).
 
Last edited:
  • #15
DaveC426913 said:
Jesoosi Christoosi! It's working!

https://www.davesbrain.ca/3d-three/index.html

Excellent!

DaveC426913 said:
It looks like what I need to do is load the .MTL file along with the obj.

Probably.

DaveC426913 said:
Here is an example of loading the .MTL:

https://stackoverflow.com/questions/35246590/how-to-add-a-mtl-texture-to-an-obj-in-three-js
I adapted the code as best I could but it was not compatible.

That example is nearly 10 years old so it is not surprising it is not compatible. The best source of examples is the current documentation maintained by the Three.js developers themselves at https://github.com/mrdoob/three.js/tree/dev/examples: for OBJ+MTL you want https://github.com/mrdoob/three.js/blob/dev/examples/webgl_loader_obj_mtl.html. I'm going to copy the relevent code from that page here - as long as you post just the code, as javascript, rather than HTML you should find that it it posts OK.

JavaScript:
import * as THREE from 'three';

import { MTLLoader } from 'three/addons/loaders/MTLLoader.js';
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

let camera, scene, renderer;

init();

function init() {

  camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 20 );
  camera.position.z = 2.5;

  // scene

  scene = new THREE.Scene();

  const ambientLight = new THREE.AmbientLight( 0xffffff );
  scene.add( ambientLight );

  const pointLight = new THREE.PointLight( 0xffffff, 15 );
  camera.add( pointLight );
  scene.add( camera );

  // model

  const onProgress = function ( xhr ) {

    if ( xhr.lengthComputable ) {

      const percentComplete = xhr.loaded / xhr.total * 100;
      console.log( percentComplete.toFixed( 2 ) + '% downloaded' );

    }

  };

  new MTLLoader()
    .setPath( 'models/obj/male02/' )
    .load( 'male02.mtl', function ( materials ) {

      materials.preload();

      new OBJLoader()
        .setMaterials( materials )
        .setPath( 'models/obj/male02/' )
        .load( 'male02.obj', function ( object ) {

          object.position.y = - 0.95;
          object.scale.setScalar( 0.01 );
          scene.add( object );

        }, onProgress );

    } );

  //

  renderer = new THREE.WebGLRenderer( { antialias: true } );
  renderer.setPixelRatio( window.devicePixelRatio );
  renderer.setSize( window.innerWidth, window.innerHeight );
  renderer.setAnimationLoop( animate );
  document.body.appendChild( renderer.domElement );

  //

  const controls = new OrbitControls( camera, renderer.domElement );
  controls.minDistance = 2;
  controls.maxDistance = 5;

  //

  window.addEventListener( 'resize', onWindowResize );

}

function onWindowResize() {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize( window.innerWidth, window.innerHeight );

}

//

function animate() {

  renderer.render( scene, camera );

}

DaveC426913 said:
It dies on line 107 with "THREE.MTLLoader is not a constructor".

Yes, addons are no longer handled in this way. If you look at line 27 of your code
JavaScript:
import { MTLLoader } from 'three/addons/loaders/MTLLoader.js';

you can see that line 107 should simply be

JavaScript:
const mtlLoader = new MTLLoader(); // Don't use var, it is 2025.

DaveC426913 said:
index.html throws a CORS error

Yes, that is because the new way of loading modules does not work from a file:// origin, it must be from a file served over http(s).

DaveC426913 said:
I tried opening a terminal and running node index.html which, of course, fails.

It's a shame you didn't try
Code:
npx serve .
like I suggested: that would have started up a web server on http://localhost:3000 which would have rendered your index.html file.

DaveC426913 said:
Even the Intro to node.js has absolutely nothing to do with what I'm doing.

No, you don't need to know anything about Node.js for any of this.
 
  • #16
I've been incrementally improving both the HTML configuration and the .obj itself.

Decimating it from 325Mb down to 16Mb (95%) sure has helped the load time - which went from 25s+ to < 1s.

https://www.davesbrain.ca/3d-three/decimate/index-decimate-0.05.html
1739903252547.png


I have only one thing to do now - I have to colour parts of it for labelling. Currently, painting parts of it works fine in Blender, but does not translate to the final render. I think I have to create a material, colour the material and apply that for it to show up in the final render. Incremental learning steps...

Thanks for all your assistance, @pbuk !
 

Similar threads

Replies
1
Views
2K
Replies
7
Views
3K
Replies
9
Views
3K
Back
Top