i am trying to learn how to use modules. I thought I would start with the simplest possible but already then I have the problem that it doesn't want to run. I have to overlook something important but I just don't see what.
Including "three.module.js" or executing the script as "module" does not work.
Does anyone have a working example?
I got this example from:
https://threejs.org/examples/webgl_geometry_cube
Why doesn't that work if I do it locally
<script type="module">
import * as THREE from "lib/three.module.js";
var camera, scene, renderer;
var mesh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 400;
scene = new THREE.Scene();
var geometry = new THREE.BoxBufferGeometry( 200, 200, 200 );
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
renderer.render( scene, camera );
}
</script>
Ok i have researched intensively for the last two days. "export / import" only works via http and not with local directories. So you have to set up your own server. The alternative that I am currently using is a bundler. Parcel is not compatible with my tablet but webpack works very well. To do this, I first had to install a terminal. I chose termux. Then I installed node.js (v12.18.3) via termux and then webpack. At first it seemed like a big effort to me, but after you've done it all once, it doesn't seem that bad anymore. Important point! Termux must be configured in the app manager on android in order to have access to the sdcard in the device. By default, access is forbidden and the command line then shows "permission denied" if you want to access the internal memory with "cd /sdcard/".
I created the project normaly with an editor, you don't need the terminal for that. termux is then only required to run webpack with "npx webpack" after going to the project directory in termux.
My first example:
//path-structure
webpack-demo
|
|_page.html
|_webpack.config.js
|_src
|_index.js
|_bar.js
//page.html
<!doctype html>
<html>
<head> </head>
<body>
<div id="message"></div>
<script src="dist/bundle.js"></script>
</body>
</html>
//webpack.config.js
const path = require('path');
module.exports = {
//mode: 'development',
mode: 'production',
entry: './src/index.js',
output: { path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js' }
};
//index.js
import bar from './bar';
bar();
//bar.js
export default function bar() {
document.getElementById("message").innerHTML = "Hello World";
}
Software source:
termux: install from google play
node.js: https://nodejs.org/en/download/package-manager/
webpack: https://webpack.js.org/guides/installation/
now I am satisfied, because now I can write properly structured javascript code 😁
Related
I hope that there are some experienced people on this platform who'd be willing to help me with my three.js problem.
My current problem is this, I can't seem to properly run the three.js library on my localhost, all I get is a white screen.
My files:
My Javascript code:
import * as THREE from 'three.js-master/three.js';
import { OrbitControls } from "three.js-master/examples/OrbitControls.js";
const scene = new THREE.Scene(); //generate scene
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); //generate camera
const renderer = new THREE.WebGLRenderer(); //launch renderer using WebGl
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
const controls = new OrbitControls( camera, renderer.domElement );
const animate = function () {
requestAnimationFrame( animate );
cube.rotation.x += 0.05;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
};
animate();
And my HTML code:
<!DOCTYPE html>
<html>
<head>
<title>EMBÄR</title>
<link src="style.css" type="stylesheet">
</head>
<body>
<script src = "three.js" type="module"></script>
<script src="Main.js" type="module"> </script>
</body>
</html>
Now, this just gives a white screen all the time, but I've managed to use the link:
https://unpkg.com/three/build/three.module.js (instead of three.js-master/three.js) in combination with:
https://cdn.jsdelivr.net/npm/three#0.114/examples/jsm/controls/OrbitControls.js (instead of three.js-master/examples/OrbitControls.js)
to successfully run the script, but this really isn't a solution, since I had to search for days to find these links, and it surely isn't efficient if I want to include more modules besides these.
It'd be awesome if someone knew the answer, but please, don't feel pressured to do a lot of research.
Your HTML should look like so:
<!DOCTYPE html>
<html>
<head>
<title>EMBÄR</title>
<link src="style.css" type="stylesheet">
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims#1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "./three.js-master/build/three.module.js",
"three/addons/": "./three.js-master/examples/jsm/"
}
}
</script>
<script src="Main.js" type="module"> </script>
</head>
<body>
</body>
</html>
In your Main.js file, use the following imports:
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
The imports in your JS should look exactly like the ones from the official examples. The only thing that differs is the import map. In your case, you refer to your locally hosted version of the three.js repo. Keep in mind to always use the module.js version of three.js. Not the UMD build.
You find more information about the setup/installation of three.js in this guide.
I'm having difficulty loading 3D models from a folder on my computer, using a localhost node.js test server, with three.js library.
app.js: (I run it via command line in the project directory using: node app.js command)
var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
var THREE = require('three');
app.get('/', function(req, res) {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
});
http.listen(3000, () => {
console.log('listening on *:3000');
});
Relevant portion of index.html:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Index.html title</title>
</head>
<body>
<script src="/socket.io/socket.io.js"></script>
<script src="//threejs.org/build/three.js"></script>
<script src="//threejs.org/examples/js/loaders/AMFLoader.js"></script>
<script src="//threejs.org/examples/js/controls/OrbitControls.js"></script>
<script>
var socket = io();
var camera, scene, renderer;
init();
function init() {
scene = new THREE.Scene();
scene.add( new THREE.AmbientLight( 0x999999 ) );
camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 500 );
camera.up.set( 0, 0, 1 );
camera.position.set( 0, -9, 6 );
camera.add( new THREE.PointLight( 0xffffff, 0.8 ) );
scene.add( camera );
var grid = new THREE.GridHelper( 25, 1.0, 0xffffff, 0x555555 );
grid.rotateOnAxis( new THREE.Vector3( 1, 0, 0 ), 90 * ( Math.PI/180 ) );
scene.add( grid );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setClearColor( 0x999999 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
/* everything up till here works */
var loader = new THREE.AMFLoader();
loader.load('/models/rook.amf', function ( amfobject ) { //'./models/rook.amf'
scene.add( amfobject );
render();
} );
/* ^^^ this is the part not working */
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render );
controls.target.set( 0, 1.2, 2 );
controls.update();
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
render();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>
My project directory:
The error:
GET http://localhost:3000/models/rook.amf 404 (Not Found)
How can I properly load files with Node and three.js on my simple server test?
Most of the popular 3D formats extensions (.glb, .gltf, .fbx, .dae, .amf, ...) are not standard MIME types, browsers pay a particular care when manipulating these files, attempting to safeguard the user to prevent dangerous behaviors.
So you will need to configure your web server engine to accept these extensions, otherwise you'll receive different HTTP errors downloading them. .amf is not even in this list, so application/octet-stream is the default value for all other cases. An unknown file type should use this type.
If you are using IIS server from an ASP.Net application, add the xml lines below in the </system.webServer> node of your web.config file:
<system.webServer>
...
<staticContent>
<remove fileExtension=".mtl" />
<mimeMap fileExtension=".mtl" mimeType="model/mtl" />
<remove fileExtension=".obj" />
<mimeMap fileExtension=".obj" mimeType="model/obj" />
<remove fileExtension=".glb" />
<mimeMap fileExtension=".glb" mimeType="model/gltf-binary" />
<remove fileExtension=".gltf" />
<mimeMap fileExtension=".gltf" mimeType="model/gltf+json" />
<remove fileExtension=".fbx" />
<mimeMap fileExtension=".fbx" mimeType="application/octet-stream" />
<remove fileExtension=".amf" />
<mimeMap fileExtension=".amf" mimeType="application/octet-stream" />
</staticContent>
</system.webServer>
If you are using an nginx server, add the following lines to the nginx.conf file in the http object:
http {
include /etc/nginx/mime.types;
types {
model/mtl mtl;
model/obj obj;
model/gltf+json gltf;
model/gltf-binary glb;
application/octet-stream fbx;
application/octet-stream amf;
}
...
}
If you are using an Apache server, add the following lines to the mime.types file:
model/mtl mtl
model/obj obj
model/gltf+json gltf
model/gltf-binary glb
application/octet-stream fbx
application/octet-stream amf
For any other web server you can surely find easily how to set the MIME Types configuration.
EDIT: In the case of node, review your file server.js is not including any restriction to these MIME types, most of the popular server.js scripts include limitations for non-standard MIME types
EDIT2: I GOT IT as I suspected it was related to the kind of MIME type AMF is. I have posted the full solution on GitHub
But the important things to change are these ones below.
First, change your app.js to add the MIME type.
const express = require('express');
const app = express();
const path = require('path');
const router = express.Router();
router.get('/', function (req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
//__dirname : It will resolve to your project folder.
});
app.use('/models', express.static('models')) // add this!
app.use('/express', express.static('express')) // add this!
express.static.mime.define({ 'application/octet-stream': ['amf'] })
//add the router
app.use('/', router);
app.listen(process.env.port || 3000);
console.log('Running at Port 3000');
Second, because of the recent changes in Three.js (April 23), the use of AMF loader, requires of jszip module. No need to download it locally, you can consume it by url like the other js files. In my project, index.html is in a /express folder, so my path to amf model is ../models/rock.amf
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Index.html title</title>
</head>
<body>
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/libs/jszip.min.js"></script>
<script src="https://threejs.org/examples/js/loaders/AMFLoader.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script>
var camera, scene, renderer;
init()
function init() {
scene = new THREE.Scene();
scene.add(new THREE.AmbientLight(0x999999));
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 500);
camera.up.set(0, 0, 1);
camera.position.set(0, -9, 6);
camera.add(new THREE.PointLight(0xffffff, 0.8));
scene.add(camera);
var grid = new THREE.GridHelper(25, 1.0, 0xffffff, 0x555555);
grid.rotateOnAxis(new THREE.Vector3(1, 0, 0), 90 * (Math.PI / 180));
scene.add(grid);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setClearColor(0x999999);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
/* NOW IT WORKS!!! */
var loader = new THREE.AMFLoader();
loader.load('../models/rook.amf', function (amfobject) { //'./models/rook.amf'
scene.add(amfobject);
render();
});
/* ^^^ this is the part not working */
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.addEventListener('change', render);
controls.target.set(0, 1.2, 2);
controls.update();
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
function render() {
renderer.render(scene, camera);
}
</script>
</body>
</html>
You got it...
You need to serve the contents of the models folder as static files. Example:
app.use('/models', express.static('models'))
Try to recreate these steps from the code in the question. And you'll succeed too. Maybe there is something else in your real code that is missing in the question. Then you should update it with this info.
I've copied your app.js and index.html.
I've loaded rook.amf from https://threejs.org/examples/models/amf/rook.amf and placed it in the /models. I suppose you did the same
I've added app.use() as others already correctly suggested.
const express = require('express')
const app = express()
const http = require('http').createServer(app)
// const io = require('socket.io')(http) // unrelated
// const THREE = require('three') // unrelated
app.use('/models', express.static('models')) // add this!
app.get('/', function(req, res) { res.sendFile(__dirname + '/index.html') })
// io.on('connection', (socket) => console.log('a user connected')) // unrelated
http.listen(3000, () => console.log('listening on *:3000'))
And I've been able to download rook.amf with AMFLoader. No idea how you've managed to get the error THREE.AMFLoader: Error loading AMF - no AMF document found. you've mentioned in comments.
But then I get THREE.AMFLoader: jszip missing and file is compressed.
Please note the warning in the console
THREE.AMFLoader: As part of the transition to ES6 Modules, the files in 'examples/js' were deprecated in May 2020 (r117) and will be deleted in December 2020 (r124). You can find more information about developing using ES6 Modules in https://threejs.org/docs/#manual/en/introduction/Installation.
Maybe you should try to mimic this updated example https://threejs.org/examples/webgl_loader_amf.html which I, kind of, did...
I've downloaded jszip.module.min.js from the aforementioned example. And placed it in the /models too, just for simplicity. And added to the index.html as
<script type="module">
import { JSZip } from "./models/jszip.module.min.js"
window.JSZip = JSZip
</script>
...
<!-- I also had to add type="module" to the "main" script
so it would be executed after window.JSZip = JSZip -->
<script type="module">
var socket = io();
...
But you don't need this part if you'll use the updated version of example with es6 modules or if you'll download non-es6 version of jszip
Now I can see the rook on the screen!
So I decided to see if I could import a DirectX Model and found this XLoader. However I can't seem to initialize it at all. Now, I am the kind of guy who likes to link directly to the library so that whenever there is an update I don't have to re-download and re-upload. My test code looks like this:
<html>
<body>
<script src="https://threejs.org/build/three.js"></script>
<script type="module" src="https://threejs.org/examples/jsm/loaders/XLoader.js"></script>
<script>
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.001, 10000 );
var manager = new THREE.LoadingManager();
var Texloader = new THREE.TextureLoader();
var loader = new THREE.XLoader(manager, Texloader);
loader.load(['FrigateHull.x'], function (object) {
console.log(object);
},function (xhr) {
if (xhr.lengthComputable) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log(Math.round(percentComplete, 2) + '% downloaded');
}},
function (xhr) {
console.log(xhr);
});
</script>
</body>
</html>
The error I am getting from this setup is this:
TypeError: THREE.XLoader is not a constructor
I have also tried the import method as described in the examples but still same error. I have also downloaded the git to the server and tried linking to that, but it said something about global is undefined.
What am I missing, or is there another DirectX Model Loader out there I could try?
Should be like this:
<script src="https://threejs.org/build/three.js"></script>
<script type="module">
import { XLoader } from "https://threejs.org/examples/jsm/loaders/XLoader.js";
// ....
var loader = new XLoader(manager, Texloader);
// ....
</script>
Although the TypeError: THREE.XLoader is not a constructor exception is resolved, there are still other problems.
Let's look at the source code of XLoader.js:
import {
AnimationClip,
AnimationMixer,
Bone,
BufferGeometry,
FileLoader,
Float32BufferAttribute,
FrontSide,
Loader,
LoaderUtils,
Matrix4,
Mesh,
MeshPhongMaterial,
Quaternion,
Skeleton,
SkinnedMesh,
TextureLoader,
Uint16BufferAttribute,
Vector2,
Vector3
} from "../../../build/three.module.js";
// ...
We don't have ../../../build/three.module.js code.
It is recommended that you clone the repository of three.js, and then npm install → npm start to start the project, instead of viewing it directly in the browser, which involves a lot of import and export of modules depends on front-end construction tools.
So I'm trying to load a GLTF file and I am receiving this error:
I don't know why it can't locate and open the file. Do I have to set up a local server?
I looked up other examples online and this one includes a DRACOLoader. Admittedly, I don't know what this is for and was wondering if I need to implement this in order for it to load.
Here is my code:
<html>
<head>
<meta charset="utf-8">
<title>Website first attempt</title>
<style>
body { margin: 0;
background: linear-gradient(to bottom, #33ccff 0%, #ffffff 20%);}
canvas { display: block; }
</style>
</head>
<body>
<!-- <script type = "module" src="build/myScript.js"></script>-->
<script type = "module">
import * as THREE from '../build/three.module.js';
import { GLTFLoader } from '../build/GLTFLoader.js';
let scene, camera, renderer, hlight;
function init () {
//scene
scene = new THREE.Scene();
//camera
camera = new THREE.PerspectiveCamera(40, window.innerWidth/ window.innerHeight, 1, 5000);
//light
hlight = new THREE.AmbientLight (0x404040, 100);
scene.add(hlight);
//render
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setClearColor( 0x000000, 0 );
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
//3d
let loader = new GLTFLoader();
loader.load('assets/londonmap.gltf', function(gltf){
scene.add(gltf.scene);
})
}
function onWindowResize () {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', onWindowResize, false);
function animate () {
requestAnimationFrame(animate);
render();
}
function render() {
renderer.render( scene, camera );
}
init ();
animate();
</script>
</body>
</html>
DracoLoader is only necessary if the glTF asset was compressed with the same-named compression algorithm.
A HTTP 404 means that it was not possible to load the file (in your case assets/londonmap.gltf) from the given path. So you have to make sure that the asset is actually present in the respective directory.
And yes, it's highly recommended to work with a local web server. Especially to avoid any security related browser issues. The project actually provides a small guide about this topic: How to run things locally.
If I run the script, the console displays me "THREE.OrbitControls is not a constructor".
What did I wrong? I used the same code from a manual.
var controls;
controls = new THREE.OrbitControls( camera );
controls.addEventListener( 'change', render );
var render = function () {
requestAnimationFrame( render );
renderer.render(scene, camera);
//Hier wird die Größe des Fensters manipuliert!
renderer.setSize(window.innerWidth - 20, window.innerHeight - 20);
};
var animate = function () {
requestAnimationFrame( animate );
controls.update();
};
var geometry1 = new THREE.BoxGeometry( 10, 10, 10);
var material = new THREE.MeshPhongMaterial( {specular: "#fdfb57", color: "#d8d613", emissive: "#6b6a0d", side: THREE.DoubleSide} );
var box = new THREE.Mesh(geometry1, material);
scene.add(box);
camera.position.z = 50;
render();
animate();
You must explicitly include OrbitControls in your application. For example:
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims#1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three/build/three.module.js",
"three/addons/": "https://unpkg.com/three/examples/jsm/"
}
}
</script>
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
Also, read the comments in the three.js OrbitControls example carefully so you understand when to use
controls.addEventListener( 'change', render ); // add this only if there is no animation loop (requestAnimationFrame)
and when to use
controls.update(); // required if controls.enableDamping = true, or if controls.autoRotate = true
https://github.com/mrdoob/three.js/blob/dev/examples/misc_controls_orbit.html
three.js r.147
I had the same issue with a webpack build of the three library
var THREE = require('three')
THREE.OrbitControls === undefined // true
Solution, install a 3rd party orbit control
npm install three-orbit-controls
details here: https://github.com/mattdesl/three-orbit-controls
then change the above code fragment to
var THREE = require('three')
var OrbitControls = require('three-orbit-controls')(THREE)
OrbitControls === undefined // false
ok, not the best example, but when applied in place of THREE.OrbitControls, it works just fine ;)
https://github.com/nicolaspanel/three-orbitcontrols-ts :
npm install --save three-orbitcontrols-ts
import { OrbitControls } from 'three-orbitcontrols-ts'
orbitcontrols should be installed separately in angular, this issue bothers me for several days.
I have a same problem too, it's because you put in wrong line.
you need to put it under of this line
document.body.appendChild( renderer.domElement );
then you add orbit controls
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', posUpdate );
controls.update();
if it wasn't work, add the script file download here
<script src="OrbitControls.js"></script>
I faced similar issue and after lot of research, the below thing worked
In your HTML the order matters when adding OrbitControls as it needs certain things from Three.js.
It should be
<script src="../build/three.min.js"></script>
<script src="js/controls/OrbitControls.js"></script>