Simply i would like to pre-load contents with a bar or what ever really in my three.js project or JavaScript either way should be fine, im familiar with action-script to do this task but cant seem to manage this in javascript:
Heres the code:
var loader = new THREE.OBJMTLLoader();
loader.load( 'myobject.obj', 'myobject.mtl', function ( object ) {
for(k in object.children){
object.children[k].position.z =-5;
console.log("position Changed");
}
scene.add( object );
console.log("the item is loaded");
I have looked at the loader examples to do with three.js sample files but i really dont follow it to well, is there way to check the file size vs file bytes received and implement it with the above, i have tried but returns under-fine. Jquery is also welcomed
I have similar problem. I have created an Array to preload and store all the objects in there. Passed and returned the currentId, to be able to store them after that. In Objects3DListJson I put the info for the Paths
for (var curobj = 0; curobj < Objects3DListJson.length; curobj++) {
loaderMTL.load(curobj, ObjPath, mtlPath, function (object, currentID) {
var obj3D = new Obj3D(Objects3DListJson[currentID].ObjectName, object)
objects3D.push(obj3D);
}
}
Of course I changed OBJMTLLoader to return the Current ID. I hope this help you on some way.
Related
I have a problem adding a Bounding Box from an object in a different module. Right now, it is working fine as long as I write everything in my main function, but as soon as I create my function in a different file, and import in in the main file, it's not working anymore.
The error code I get :
Uncaught TypeError: Cannot read properties of undefined (reading 'updateWorldMatrix')
at Box3.expandByObject (three.module.js:4934:10)
at Box3.setFromObject (three.module.js:4852:15)
at camCollision (camColliders.js:68:37)
at HTMLDocument.<anonymous> (World.js:355:7)
camColliders.js being the file I'm trying to put the function in, and World.js my main file.
Here is the function :
function camCollision() {
const camBB = new Box3().setFromObject(camSphereDetector);
const boule1BB = new Box3().setFromObject(boule1Obj);
boule1BB.name = 'first';
const boule2BB = new Box3().setFromObject(boule2Obj);
boule2BB.name = 'second';
const boule3BB = new Box3().setFromObject(boule3Obj);
boule3BB.name = 'third';
const boulesBB = [boule1BB, boule2BB, boule3BB];
boulesBB.forEach((bbs) => {
if (bbs.intersectsBox(camBB)) {
console.log('got it');
}
});
}
document.addEventListener('mouseup', () => {
camCollision();
});
When I'm doing this in a separate file, i'm first importing the objects from another file and they are all Mesh.
I believe the problem is that I can't create the Bounding Boxes in a separate file, because it needs to be added to the scene first, and I'm only adding them in the scene in World.js. Yet, the error is leading me to line 68, the variable for 'boule1BB', which is weird because 'camBB' should have the problem first ?
Here is how I'm creating the Box3 (these are just copying some GLTF objects position and size, cause I can't manage to get a Box3 from it) :
const boule1Obj = new Mesh(
new SphereGeometry(2, 32, 16),
new MeshBasicMaterial({ color: 'red', transparent: true, opacity: 0 }),
);
boule1Obj.position.set(10, -3.5, 0);
Then, I would like to know, if I got the problem right : is there a way to create a Box3 in a different js file, from an object that is not added to the scene yet (even if it should when the function is being called) ? With a different way than 'setFromObject' maybe ? Or am I not understanding the real problem.
For a bit of context, the aim is to provide some informations about each model when the user clicks on it, and I'm planning on putting the informations as '.name' for each Mesh corresponding to a model. So I don't want to write all this stuff in the main file, but rather on a separate one.
I hope this is clear enough, and I've given enough content for a solution to be found. I couldn't find anyone else having this problem. If you need anything else, please tell me !
Thanks already for your help !
I believe the problem is that I can't create the Bounding Boxes in a separate file, because it needs to be added to the scene in World.js.
Not so. Since a constructed THREE.Mesh has a shape with extents (from its geometry) and a transform (by default, translated to the origin, with no scaling or rotation), Three.js can and will determine a bounding box from that information as though the mesh were in the scene. I've posted a demo of this on CodePen.
Nor should defining the object in one file and referencing it another make any difference, as long as the object is in scope and initialized at the time it's bound to.
Here, I suspect that you're assigning boule1Obj, boule2Obj, and boule3Obj in World.js. In that case, the imported function is being hoisted before the variables are assigned, and the function is seeingbinding to them as unassignedundefined.
Try changing camCollision() to accept the bouleXObjs as arguments.
function camCollision(...objs) {
const camBB = new Box3().setFromObject(camSphereDetector);
for(let i = 0; i < objs.length; i++) {
const objBB = new Box3().setFromGeometry(objs[i]);
objBB.name = `Bounding Box ${i + 1}`;
if(objBB.intersectsBox(camBB)) {
console.log("Got it!");
}
}
}
And then call it as
document.addEventListener("mouseup", () => {
camCollision(boule1Obj, boule2Obj, boule3Obj);
});
My object separated into 9 files, so I need to load all 9 files: file_1.obj, ..., file_9.obj, merge them all and after that somehow use file.mtl with the result "big" object. How am I suppose to do it?
I thought about this solution:
mainObjGeometry = new THREE.Geometry();
loader.load( 'file_1.obj', function ( object ) {
object.updateMatrix();
mainObjGeometry.merge(object.geometry, object.matrix);
});
...
loader.load( 'file_9.obj', function ( object ) {
object.updateMatrix();
mainObjGeometry.merge(object.geometry, object.matrix);
});
And after that load .mtl file and connect them (even though I don't know how to do it).
But I think that using this technique I can not know the time when all objects are loaded.
How can I solve this problem? And can I connect "mainObjGeometry" and loaded from .mtl "mainObjMaterial"?
You can know the time when all the files load. For example, you have:
loader.load( 'file_9.obj', function ( object ) {
object.updateMatrix();
mainObjGeometry.merge(object.geometry, object.matrix);
});
do this:
var totalModels = 0, loadedModels = 0;
function allLoadedCallback(){...}
loader.load( 'file_9.obj', function ( object ) {
object.updateMatrix();
mainObjGeometry.merge(object.geometry, object.matrix);
loadedModels++
if(loadedModel == totalModels) allLoadedCallback();
});
totalModels++;
The other part of the question i'm not so sure about. Why can't you merge the model before even exporting it. That way at least the exported material would make sense. I'm not too familiar with the merge utility, but I can see you having problems if you are trying to merge the materials without properly loading them first.
Let me explain the whole problem. I was trying to avoid writing this as it could be a long explanation.
I am working with a tool called Lectora. This is an authoring tool which generates HTML pages and SCORM compliant packages to be deployed to the LMS.
When I insert a button in the Lectora, the code that is generated is something like this...
<script>
// some code here...
button63 = new ObjButton('button63', ....);
button63.setImages('images/btn_next_en.png','images/btn_next_en.png','images/btn_next_mouseover_en.png');
button63.build();
button64 = new ObjButton('button64', ....);
button64.setImages('images/btn_back_en.png','images/btn_back_en.png','images/btn_back_mouseover_en.png');
button64.build();
button65897 = new ObjButton('button65897', ....);
button65897.setImages('images/btn_submit_en.png','images/btn_submit_en.png','images/btn_submit_mouseover_en.png');
button65897.build();
// some more code here...
</script>
So I try to write:
<script>
var arr_buttons = [];
for(var i in window)
{
if(window[i] typeof object)
{
if(window[i] != null)
{
if(window[i] instanceof ObjButton)
{
arr_buttons.push(i);
}
}
}
}
alert(arr_buttons.length); // gives me 845 in IE11 and it gives me 44 in IE8
</script>
And when I check the contents of arr_buttons in console or by any other method, I do not find button65897 of any other button object in it. Which makes me think that it is not iterated at all!! This is my problem.
ObjButton is a Lectora created javascript object and I cannot edit it.
Now, I have set the language option in another variable and depending on the variable value for language, I want to get hold of the object 'button65897' and change its images. Now I am finding it difficult to get hold of 'button65897' in IE8.
Isn't there any way to get hold of the object 'button65897' in IE8?
Please excuse the SEO friendly title, but I would like to make the problem I am currently solving as accessible as possible. For those of you who are looking to customise the look and feel of dat.gui, you need to download the source and include it using require.js using the instructions here: https://code.google.com/p/dat-gui/.
And now my question.
I am working on a project that requires building a UI with heavy live integration with Javascript (I'm using three.js) and I have decided to modify dat.gui to create this ui; with a view to soon integrate it with backbone.js as a collection of views.
I wish to switch to use the dat.gui source files to edit the styling
To start, I switched over from the concatenated dat.gui.min.js, to the source using the instructions in the link above. I put the whole source in its own folder within my libraries folder, and placed the main.js file the require.js err... requires within the "src" folder. I did this due to linking dependencies within dat.gui's "GUI.js".
Everything seems to link up properly, and I am using essentially the same code as I did before to create my dat.guis, but I keep getting undefined errors, depending on how I change the gui variable either in my original code or in main.js. My understanding of require.js is VERY limited and I feel it is something integral to how it works (and that it's defiantly one of those oh so simple problems for someone with the know how)
Here's my main.js file located at /libraries/dat-gui/src
(this dir also includes text.js)
//This is main.js for using require.js
require([
'dat/gui/GUI'
], function(GUI) {
// No namespace necessary
var gui = new GUI();
});
and here's the bones of my original dat.gui definition code:
////////////////////////////////////////////////DatGui/////////////////////////////////////////////////////
var stageConfigData = function() {
this.scaleX = params.stageWidth;
this.scaleZ = params.stageDepth;
this.spinTheCamera = false;
this.lightIntensity = 1;
this.lightDistance = 0;
this.lightFrontColour = "#ffb752";
this.lightRearColour = "#3535fa";
this.lockCameraToScene = true;
this.tooltype = 3;
this.objectSelect = 'Man';
this.saveJSON = function(){
saveJSON();
};
};
var stageConfig = new stageConfigData( );
var moveConfig = new moveConfigData( );
///I think the problem is linked to defining this variable:
//var gui = new dat.GUI();//works for the minified version
var gui = new dat.GUI();//for non-concatenated
var fstage = gui.addFolder('Stage');
var fcamera = gui.addFolder('Camera');
var ffhouselts = gui.addFolder('Front of House Lights');
var fRearlts = gui.addFolder('Rear Lights');
var sandl = gui.addFolder('Saving and Loading');
fstage.add( stageConfig, 'scaleX', 1, 100, 5).name('Width of stage').onChange( function(){
stage.scale.x = ( stageConfig.scaleX );
});
fstage.add( stageConfig, 'scaleZ', 1, 100, 5).name('Depth of stage').onChange( function(){
stage.scale.z = ( stageConfig.scaleZ );
});
... //there's more but i think it's irrelevant
and the errors i am getting are either:
Uncaught ReferenceError: dat is not defined
or
Uncaught ReferenceError: GUI is not defined
depending on how I mess with those variables and the bit in main.js under //No namespace necessary. I don't understand how namespaces work as I am quite new to javascript as a whole.
Has anyone any ideas? Again, I'd say this is probably one of those real dunce moments, but I would really appreciate the help nonetheless.
Thanks a lot!
When you use require.js method there will be no global object. But you can create it yourself
require([
'dat/gui/GUI'
], function(GUI) {
window.dat = {
GUI: GUI
};
});
I have file called common.js and it's included in each page of my site using <script />.
It will grow fast as my sites functionality will grow (I hope; I imagine). :)
Lets example I have a jQuery event:
$('#that').click(function() {
one_of_many_functions($(this));
}
For the moment, I have that one_of_many_functions() in common.js.
Is it somehow possible that JavaScript automatically loads file one_of_many_functions.js when such function is called, but it doesn't exist? Like auto-loader. :)
The second option I see is to do something like:
$('#that').click(function() {
include('one_of_many_functions');
one_of_many_functions($(this));
}
That not so automatically, but still - includes wanted file.
Is any of this possible? Thanks in an advice! :)
It is not possible to directly auto-load external javascripts on demand. It is, however, possible to implement a dynamic inclusion mechanism similar to the second route you mentioned.
There are some challenges though. When you "include" a new external script, you aren't going to be able to immediately use the included functionality, you'll have to wait until the script loads. This means that you'll have to fragment your code somewhat, which means that you'll have to make some decisions about what should just be included in the core vs. what can be included on demand.
You'll need to set up a central object that keeps track of which assets are already loaded. Here's a quick mockup of that:
var assets = {
assets: {},
include: function (asset_name, callback) {
if (typeof callback != 'function')
callback = function () { return false; };
if (typeof this.assets[asset_name] != 'undefined' )
return callback();
var html_doc = document.getElementsByTagName('head')[0];
var st = document.createElement('script');
st.setAttribute('language', 'javascript');
st.setAttribute('type', 'text/javascript');
st.setAttribute('src', asset_name);
st.onload = function () { assets._script_loaded(asset_name, callback); };
html_doc.appendChild(st);
},
_script_loaded: function (asset_name, callback) {
this.assets[asset_name] = true;
callback();
}
};
assets.inlude('myfile.js', function () {
/* do stuff that depends on myfile.js */
});
Sure it's possible -- but this can become painful to manage. In order to implement something like this, you're going to have to maintain an index of functions and their corresponding source file. As your project grows, this can be troublesome for a few reasons -- the 2 that stick out in my mind are:
A) You have the added responsibility of maintaining your index object/lookup mechanism so that your scripts know where to look when the function you're calling cannot be found.
B) This is one more thing that can go wrong when debugging your growing project.
I'm sure that someone else will mention this by the time I'm finished writing this, but your time would probably be better spent figuring out how to combine all of your code into a single .js file. The benefits to doing so are well-documented.
I have created something close to that a year ago. In fact, I have found this thread by search if that is something new on the field. You can see what I have created here: https://github.com/thiagomata/CanvasBox/blob/master/src/main/New.js
My project are, almost 100% OOP. So, I used this fact to focus my solution. I create this "Class" with the name "New" what is used to, first load and after instance the objects.
Here a example of someone using it:
var objSquare = New.Square(); // Square is loaded and after that instance is created
objSquare.x = objBox.width / 2;
objSquare.y = objBox.height / 2;
var objSomeExample = New.Stuff("some parameters can be sent too");
In this version I am not using some json with all js file position. The mapping is hardcore as you can see here:
New.prototype.arrMap = {
CanvasBox: "" + window.MAIN_PATH + "CanvasBox",
CanvasBoxBehavior: "" + window.MAIN_PATH + "CanvasBoxBehavior",
CanvasBoxButton: "" + window.MAIN_PATH + "CanvasBoxButton",
// (...)
};
But make this more automatic, using gulp or grunt is something what I am thinking to do, and it is not that hard.
This solution was created to be used into the project. So, the code may need some changes to be able to be used into any project. But may be a start.
Hope this helps.
As I said before, this still is a working progress. But I have created a more independent module what use gulp to keep it updated.
All the magic que be found in this links:
https://github.com/thiagomata/CanvasBox/blob/master/src/coffee/main/Instance.coffee
https://github.com/thiagomata/CanvasBox/blob/master/src/node/scripts.js
https://github.com/thiagomata/CanvasBox/blob/master/gulpfile.js
A special look should be in this lines of the Instance.coffee
###
# Create an instance of the object passing the argument
###
instaceObject = (->
ClassElement = (args) ->
window[args["0"]].apply this, args["1"]
->
ClassElement:: = (window[arguments["0"]])::
objElement = new ClassElement(arguments)
return objElement
)()
This lines allows me to initialize a instance of some object after load its file. As is used in the create method:
create:()->
#load()
return instaceObject(#packageName, arguments)