I'm currently messing around with THREE.js and socket.io to make a little game - I'm wanting to use the OrbitControls extension for THREE.js (i've used it before in a non-TS project) for camera controls.
The problem is that the client can't seem to find it (it compiles fine):
Uncaught TypeError: undefined is not a function
at line:
this.cameraControls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
I'm including in my TS file using:
///<reference path="../typings/threejs/three-orbitcontrols.d.ts"/>
import OrbitControls = require("three-orbitcontrols");
At the bottom of my three-orbitcontrols.d.ts file I have my usual export that I seem to need at the bottom of some typing files:
declare module 'three-orbitcontrols' {
export=THREE.OrbitControls;
}
But i'm not sure if this is the right format, I've tried a few things like directing requirejs to the right file in the config (since the filename is a bit different):
paths: {
"three-orbitcontrols": "three.orbitcontrols"
}
Interestingly, after compiling with Gulp (using AMD), three-orbitcontrols does not appear in the require at the top of the resulting .js file.
My question is: how do you properly include an 'extension' library for a library you already have with TS and requirejs? Is there some form of merge I need to do? Do i need to manually merge the d.ts and js files? (I hope not!)
Thanks!
how do you properly include an 'extension' library for a library you already have with TS and requirejs?
Since you are calling THREE. here : new THREE.OrbitControls. You need to put import OrbitControls = require("three-orbitcontrols"); on THREE so:
import OrbitControls = require("three-orbitcontrols");
THREE.OrbitControls = OrbitControls;
Note: There isn't an idiomatic way of doing this since there isn't an idiomatic way that JavaScript libraries do this. The solution here is specific to your use case and this extension.
Related
I posted a similar thread:
How do you correctly include three.js and gltf.js?
Now that I've looked more into three.js and gltfloader.js, it seems there's a convoluted mix of packages and modules and imports and exports. My goal is to make an .html file, or web app, that will use three.js to put a 3D file over the user's face in the camera. I started off with Jeeliz's face filter repository, and modified it by putting the scripts (that it imported or had for) fully into the .html file. This worked for the cube, but then I realized I needed to use GLTFLoader.js to import a .glb file instead of the cube being over my face.
Now that I've looked into the repositories more, it's less clear how to completely include three.js and gltfloader.js into 1 html file. Every way I've tried (three.min.js and GLTFLoader.js copied into html file, three.js and GLTFLoader.js copied into html file, GLTFLoader.js copied into three.js which is also copied into the html file, and a few other ways) gives me Uncaught Error: GLTFLoader is not defined or Uncaught Error: THREE.GLTFLoader is not a constructor. I'm trying to use it in my main script with this
const loader = new GLTFLoader();
loader.load( '/your-glb-file2.glb', function ( gltf ) {
threeStuffs.faceObject.add( gltf.scene );
} );
but that first line is what is causing the error. Even when I copied the contents of GLTFLoader.js into the contents of three.js (which gave me ~37k lines of code), and copied that mega-script into my html file, it still gave me either of the 2 Uncaught Errors.
I Google'd how to use three.js with no dependencies, but it was going into package.json and npm stuff, even though I'm simply trying to copy three.js into the file itself. I couldn't find any guides on a "standalone" three.js web app, and I figured here is a good place to ask.
I know I can copy three.js into a script in an HTML file, but what I'm asking is how do I get GLTFLoader.js AND three.js into an HTML file and working so I can use
const loader = new GLTFLoader();
to load a glb file into the scene.
I've also tried
import { GLTFLoader } from '/GLTFLoader.js';
at the top of my "demo" script with GLTFLoader.js (from the correct current GitHub repository) in the same directory and it says "Cannot use import statement outside a module"
Thanks in advance!
EDIT:
Now I have tried a few more things, and it's like playing wackamole. At first I realized it's probably best to not combine revisions of three.js so now I've copied three.module.js into the folder and changed <script scr='../../libs/three/r112/three.js> to
<script type="importmap">
{
"imports": {
"THREE": "../../../libs/three/v112/three.js"
}
}
</script>
This got it to stop with some errors, but then it said the helper script is calling THREE and it's not defined. So I put
import * as THREE from 'path/to/three.js'
(of course with the correct path) and then it said the helper script is not defined in main.
I basically turned every script tag into a type="module" and imported three.js into each .js that needed it, and I keep running into errors, and it's becoming clear this is not the best way to set up three.js and gltfloader.js
Any help is appreciated.
When using THREE.SkeletonUtils.clone(object), im seeing that THREE.SkeletonUtils is undefined.
I am refering to this forum (posted in 2019) which suggests using this to clone a 3d model which has skinned animations.
I am importing three.js like this:
import * as THREE from 'https://unpkg.com/three#0.118.3/build/three.module.js';
Do i need to reference this SkeletonUtils separately? My understanding is that this is part of Three.js.
There are a lot of additional modules that are not part of core Three.js, and you need to import them separately. The convention is that if the source file is in the /examples folder, then it's not part of the core library and you'll have to import it separately.
import * as THREE from 'https://unpkg.com/three#0.118.3/build/three.module.js';
import SkeletonUtils from 'https://raw.githubusercontent.com/mrdoob/three.js/master/examples/jsm/utils/SkeletonUtils.js';
// Now you can use it as follows
SkeletonUtils.clone(object);
How do I know if I need to import it separately?
The best way I've found to differentiate between core classes, and add-on classes is by looking at the documentation. For instance:
Look at Vector3, and scroll to the bottom of the page, you'll see Source: src/math/Vector3.js.
Look at SkeletonUtils, scroll to the bottom of the page, and you'll see Source: examples/jsm/utils/SkeletonUtils.js
Since SkeletonUtils is part of the examples folder, it needs to be imported separately.
As I added webpack to my NativeScript iOS app to bundle it in preparation for release, I discovered that the various some-page.minWH600.css "qualifier" files I was using to target different screen resolutions are no longer loading. (See NativeScript docs for supporting multiple screen sizes using qualifiers)
I then refactored a bit to test for small vs medium vs large tablet screens, planning to add a .css file programmatically via...
if (mediumScreen) page.addCssFile(app.minWH600.css);
...but discovered due to the bundling of pages in webpack, page.addCssFile() doesn't work either.
Does anyone have another solution to add css classes to support different screen resolutions that works with webpack?
I can think of the obvious: using many getViewById() calls and adding either NS/js properties and or css styles (or a css class) to each view, but that's laborious and kludgey...
I'd prefer to somehow redefine the relevant css classes on the fly like I was able to before bundling with webpack, but I don't know if that is possible?
To answer my own question, because someone else may have to solve this someday, I came up with two workarounds.
Simply redefining the class using:
if (mediumScreen) page.addCss(".class {font-size:18 }, .class2 {font-size: 14}");
Oddly enough that works, even though page.addCssFile() does not. The disadvantage is that the css presentation is buried in the code and this is less maintainable.
By using the "nativescript-dom" plugin to gather all the views by class and defining a function to add ".classTablet" to all views containing ".class", I was able to keep all the css together in one css file for easier maintenance. I simply added the class for the larger screen size to that file and use:
if (tabletScreen) addSizeClass("welcomeButton","welcomeButtonTabletSize");
which calls the global function:
require("nativescript-dom"); // must install this nativescript plugin
addSizeClass = function(className, newSizeClassname) {
// note page is a global variable and is set in onNavigatedTo
var items = page.getElementsByClassName(className); //getElementsByClassName() is from nativescript-dom plugin
items.forEach((item) => { item.className += " " + newSizeClassname; }); //define and maintain a new size class in app.css
}
Of course, better yet might be configuring NativeScript webpack to be smarter. But I am no webpack configuration guru.
At the moment I need to convert all my IFC files into Collada format to visualise them in Three.js. Is there any IFC Loader in three.js? I could not find anything.
Is there any plan to develop an IFCLoader in the near future?
How difficult it would be to write that?
May be a late answer for this question. Have you seen the BIMserver plugin to get a three.js export of your IFC file? Check it out from here
I haven't encountered a native Javascript parser that can directly read IFC files, however there is a product from Apstex available. It's a Java tool that outputs three.js geometry.
We're using that as a self running web service, so the client sends an IFC file and receives the JSON Three.js geometry (which is then loaded in the viewer).
It might be a bit late, but we have recently released the official IFC Loader for Three.js. It's relatively young and we still have work to do, but it's able to open a lot of IFC files already. Assuming you have an HTML input element in your scene:
import { IFCLoader } from "three/examples/jsm/loaders/IFCLoader";
//Sets up the IFC loading
const ifcLoader = new IFCLoader();
ifcLoader.setWasmPath("wasm/");
const input = document.getElementById("file-input");
input.addEventListener(
"change",
(changed) => {
var ifcURL = URL.createObjectURL(changed.target.files[0]);
console.log(ifcURL);
ifcLoader.load(ifcURL, (ifcModel) => scene.add(ifcModel.mesh));
},
false
);
You can visit the docs to see the full tutorial, see the official example or let us know if you have any question / feedback / want to contribute in the Discord channel.
I tried to import models from the 3D Warehouse, but some models fail to load (error in ColladaLoader.js (line 2808)
Uncaught TypeError: Cannot read property 'input' of null). I experienced this error with a lot of different models from 3D warehouse.
I prepared a fiddle (elcsiga/rep1z1xt/4), it loads the model from a different domain via ajax (CORS violation), however it worked me in Chrome.
A fully working example (fails to load model):
http://projecthost.hu/webview/jsfiddle/metro.html
Exactly same code with the monster model from three.js repository (it works):
http://projecthost.hu/webview/jsfiddle/monster.html
The collada model is available here: projecthost.hu/webview/jsfiddle/metro.dae
First I tried to download it as a .kmz file, unzip and use the .dae file in it directly. Additionally, I tried to download the .skp file, opened it in Sketchup and exported it into .dae format, but got the same error in ColladaLoader.js.
Do these models contain an unsupported geometry, or is it a bug in Collada loader?
Thanks.
The Model don't have any vertices so the Loader cant create a geometry. (maybe I'm wrong)
You created the Model via Google SketchUp right?
https://github.com/mrdoob/three.js/wiki/Using-SketchUp-Models
find
var vertexData = sources[ this.vertices.input['POSITION'].source ].data;
in ColladaLoader.js, replace it with
var vertexData = [];
if (this.vertices && this.vertices.input['POSITION'].source) {
vertexData = sources[ this.vertices.input['POSITION'].source ].data;
}
this can fix my problem by avoiding empty vertices. It may lost some info of dae file, but it won't harm ColladaLoader.js's function.