I can't seem to instantiate THREEjs objects using the threejs npm build and browserify.
var THREE = require("three-js");
var camera = new THREE.PerspectiveCamera( 75, 1, 20, 2250 );
This throws an error
bundle.js:24 Uncaught TypeError: THREE.PerspectiveCamera is not a constructor
I can see that the constructor exists in bundle.js
THREE.PerspectiveCamera = function ( fov, aspect, near, far ) {
THREE.Camera.call( this );
this.type = 'PerspectiveCamera';
this.fov = fov !== undefined ? fov : 50;
this.zoom = 1;
this.near = near !== undefined ? near : 0.1;
this.far = far !== undefined ? far : 2000;
this.focus = 10;
this.aspect = aspect !== undefined ? aspect : 1;
this.view = null;
this.filmGauge = 35; // width of the film (default in millimeters)
this.filmOffset = 0; // horizontal film offset (same unit as gauge)
this.updateProjectionMatrix();
};
As I am porting this code from a working build I suspect that I may be doing something wrong with Browserify.
npm Threejs build version 79
The problem was not constructing the three-js object correctly. From https://www.npmjs.com/package/three-js
var THREE = require("three-js")();
The extra brackets were missing from my example.
FYI: To get addons working use this structure
var oc = require("three-js/addons/OrbitControls");
var anotherAddon = require("three-js/addons/anotherAddon");
var THREE = require('three-js')([oc,anotherAddon]);
Related
I am trying to replace a cube mesh with a car mesh using .obj and .mtl files (using three.js)
But every everytime I got this error:
Uncaught TypeError: e.OBJMTLLoader is not a constructor
I made sure to include the library () and there is no typo.
This is how I load the mesh model:
var loader = new THREE.OBJMTLLoader();
loader.load('./toycar.obj', './toycar.mtl',
function (object) {
toycar = object;
toycar.rotateX(-12); //toycar.rotateZ(-10.99);
toycar.rotateY(4.718);
scene.add(toycar);
});
and this is how I use it to move the model on the y axis:
if (toycar != undefined){
toycar.position.y = disp * 0.07; // z for rightLeft, y for upDown
var relativeCameraOffset = new THREE.Vector3(5, 0, 0); // change camera offset
var cameraOffset = relativeCameraOffset.applyMatrix4(toycar.matrixWorld);
camera.position.x = cameraOffset.x;
camera.position.y = cameraOffset.y;
camera.position.z = cameraOffset.z;
camera.lookAt(toycar.position);
}
At this point, I am not sure what caused this error to happen.
THREE.OBJMTLLoader does not exist in the repository. There is only OBJLoader and MTLLoader. The latter one is only required if you want to load materials, too.
I suggest you study webgl_loader_obj_mtl to show how both are used. Typical code looks like so:
new MTLLoader().load( 'materials.mtl', function ( materials ) {
materials.preload();
new OBJLoader()
.setMaterials( materials )
.load( 'object.obj', function ( object ) {
scene.add( object );
} );
} );
I´m trying to load some STL files using Three.js. The models are loaded correctly, but there are too many triangles that I would like to merge/smooth.
I had successfully applied smooth loading terrains in other 3D formats, but I can´t do it with the BufferGeometry that results from loading an STL file with the STLLoader.
_
var material = new THREE.MeshLambertMaterial( { ... } );
var path = "./models/budah.stl";
var loader = new THREE.STLLoader();
loader.load( path, function ( object ) {
object.computeBoundingBox();
object.computeBoundingSphere();
object.computeFaceNormals();
object.computeVertexNormals();
object.normalizeNormals();
object.center();
// Apply smooth
var modifier = new THREE.SubdivisionModifier( 1);
var smooth = smooth = object.clone();
smooth.mergeVertices();
smooth.computeFaceNormals();
smooth.computeVertexNormals();
modifier.modify( smooth );
scene.add( smooth );
});
This is what I tried, it throws an error: Uncaught TypeError: smooth.mergeVertices is not a function
If I comment the "mergeVertices()" line, what I get is a different error: Uncaught TypeError: Cannot read property 'length' of undefined in SubdivisionsModifier, line 156.
It seems that the sample codes I´m trying are outdated (this is happenning a lot recently due to the massive changes in the Three.JS library). Or maybe I´m forgetting something. The fact is that the vertices seems to be null..?
Thanks in advance!
It seems I was looking in the wrong direction: smoothing the triangles has nothing to do with the SubdivisionsModifier... What I needed was easier than that, just compute the vertex BEFORE applying the material, so it can use SmoothShading instead of FlatShading (did I got it right?).
The problem here was that the BufferGeometry returned by the STLLoader has not calculated vertices/vertex, so I had to do it manually. After that, apply mergeVertices() just before computeVertexNormals() and voilà! The triangles dissappear and everything is smooth:
var material = new THREE.MeshLambertMaterial( { ... } );
var path = "./models/budah.stl";
var loader = new THREE.STLLoader();
loader.load( path, function ( object ) {
object.computeBoundingBox();
object.computeVertexNormals();
object.center();
///////////////////////////////////////////////////////////////
var attrib = object.getAttribute('position');
if(attrib === undefined) {
throw new Error('a given BufferGeometry object must have a position attribute.');
}
var positions = attrib.array;
var vertices = [];
for(var i = 0, n = positions.length; i < n; i += 3) {
var x = positions[i];
var y = positions[i + 1];
var z = positions[i + 2];
vertices.push(new THREE.Vector3(x, y, z));
}
var faces = [];
for(var i = 0, n = vertices.length; i < n; i += 3) {
faces.push(new THREE.Face3(i, i + 1, i + 2));
}
var geometry = new THREE.Geometry();
geometry.vertices = vertices;
geometry.faces = faces;
geometry.computeFaceNormals();
geometry.mergeVertices()
geometry.computeVertexNormals();
///////////////////////////////////////////////////////////////
var mesh = new THREE.Mesh(geometry, material);
scene.add( mesh );
});
Than, you can convert it back to BufferGeometry, because it's more GPU/CPU efficient for more complex models:
var geometry = new THREE.Geometry();
geometry.vertices = vertices;
geometry.faces = faces;
geometry.computeFaceNormals();
geometry.mergeVertices();
geometry.computeVertexNormals();
var buffer_g = new THREE.BufferGeometry();
buffer_g.fromGeometry(geometry);
var mesh = new THREE.Mesh(buffer_g, material);
scene.add( mesh )
Happened this issue for me while loading an obj file. If you have a 3d software like 3dsmax:
Open the obj file,
Go to polygons selection mode and select all polygons.
Under the Surface properties panel, click 'Auto Smooth' button.
Export the model back to obj format
Now you won't have to call the functions geometry.mergeVertices() and geometry.computeVertexNormals();. Just load the obj and add to the scene, mesh will be smooth.
EDIT:
My obj files had meshphongmaterial by default and on changing the shading property to value 2 the mesh became smooth.
child.material.shading = 2
STL does not support vertex index.
That is reason it has duplicated vertex of all triangles.
Each vertex has its normal as triangle normal.
As a result, at same position( multiple very closed vertices), there is multiple normal value.
This leads to non-smooth surface of geometry when using Normal for lighting calculation.
I have been trying out Three.js lately and i used the exporter addon for Blender to test out making models in blender and exporting so i can use them in a three.js program.
I included the add-on to blender, and using just the basic cube model of blender, exported it to .json as the exporter says. Then i imported the model into my three.js using this as a guide
but that gave me an error:
Uncaught TypeError: Cannot read property 'length' of undefined.
Ive already searched online and tried a few different approaches(like including a materials in the function call of the loader) but nothing seems to work.
I also checked stackoverflow for answers but so far nothing seems solved. If anyone would clarify what im doing wrong I would be very grateful.
The code for my three.js program:
var WIDTH = 1000,
HEIGHT = 1000;
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000;
var radius = 50,
segments = 16,
rings = 16;
var sphereMaterial =
new THREE.MeshLambertMaterial(
{
color: 0xCCCCCC
});
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(
radius,
segments,
rings),
sphereMaterial);
var pointLight =
new THREE.PointLight(0x660000);
var $container = $('#container');
var renderer = new THREE.WebGLRenderer();
var camera =
new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR);
var scene = new THREE.Scene();
var loader = new THREE.JSONLoader(); // init the loader util
scene.add(camera);
pointLight.position.x = 10;
pointLight.position.y = 50;
pointLight.position.z = 130;
scene.add(pointLight);
camera.position.z = 300;
renderer.setSize(WIDTH, HEIGHT);
$container.append(renderer.domElement);
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
loader.load('test.json', function (geometry, materials) {
var material = new THREE.MeshFaceMaterial(materials);
var object = new THREE.Mesh(geometry, material);
scene.add(object);
});
(function animloop() {
requestAnimFrame(animloop);
renderer.render(scene, camera);
})();
When you export, change the Type from buffergeometry to Geometry (Blender 2.76)
In my experience so far with the exporter, you have to be very careful which boxes you tick!
This length error is usually because you are either not exporting the vertexes, or exporting the scene rather the object.
I have the same issue with the new exporter.
If select SCENE then I usually get "Cannot read property 'length' of undefined"
If I select only the object and the materials and vertices. It usually just seems to get stuck forever.
UPDATE
Check this response to this issue!
Threejs blender exporter exports in wrong format
As roadkill stated earlier, exporting as Geometry instead of BufferedGeometry works.
Also note that loading JSON model loading is handled asyncronously (the callback is only called only when the operation is completed, the rest of your code keeps running). The model won't exist for the first frame or two, so check that your model exists before doing any operations with it inside the animation loop.
I am creating a "Space Invaders" game in AS3. Got everything working now, but keep ketting a #1009 error and i'm looking at it for quite a time now and i just don't see the problem. Some extra eyes could help out I think!
This is what the debugger says:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at testbestandkopie_fla::MainTimeline/winGame()[testbestandkopie_fla.MainTimeline::frame1:352]
at testbestandkopie_fla::MainTimeline/enemyHitTest()[testbestandkopie_fla.MainTimeline::frame1:338]
at testbestandkopie_fla::MainTimeline/onTick()[testbestandkopie_fla.MainTimeline::frame1:117]
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
Below I will paste the code that has to do with the error:
1: Creating the AS Linkage names:
//Sound FX-------------------------------------------------------------------------
var startFX:Sound = new startGameSound();
var laserFX:Sound = new laserSound();
var explosionFX:Sound = new explosionSound();
var musicFX:Sound = new backgroundMusic();
var loseFX:Sound = new endGameSound();
var winFX:Sound = new winGameSound();
var SfxTransform = new SoundTransform();
var myChannelMisc:SoundChannel = new SoundChannel();
var myChannelMusic:SoundChannel = new SoundChannel();
var myChannelWin:SoundChannel = new SoundChannel();
var myChannelLose:SoundChannel = new SoundChannel();
//---------------------------------------------------------------------------------
2: [Line 117] The AS line 117 is the highlighted one:
//Handlers Functions---------------------------------------------------------------
function onTick(e:TimerEvent) { //A continuous run of some functions below.
moveCharacter();
moveEnemyField();
playerCollisionDetectWall();
enemyCollisionDetectWall();
enemyCollisionDetectWallBottom();
moveLasers();
enemyHitTest(); <---- line 117
}
3: [Line 338] The function enemyHitTest(); where it starts the winGame(); function:
function enemyHitTest() {
//For each of the three enemys
for (var i:int = 0; i < enemyArray.length; i++) {
//the each of the six lasers
for (var j:int = 0; j < 6; j++) {
//don't consider lasers that aren't in play:
if (laserArray[j].y > SpelerMC.y) continue;
if (enemyArray[i].visible && enemyArray[i].hitTestObject(laserArray[j])) {
score += 10;
myChannelMisc = explosionFX.play();
SfxTransform.volume = 0.3;
myChannelMisc.soundTransform = SfxTransform;
scoreTxt.text = score.toString();
trace("Invader nummer " + i + " neergeschoten!");
enemyArray[i].visible = false;
//Now we remove the laser when hitting.
laserArray[j].x = j * 70 + 100;
laserArray[j].y = 895;
}
else if(score == 660) {
//If you reach a score of 660 (66 enemy's x 10 = 660) you win the game.
winGame(); <---- Line 338
}
}
}
}
4: [Line 352] Where the winGame(); function run's after getting 660 points at the enemyHit.
function winGame() {
winScreen.visible = true;
gameTimer.stop();
//Stop the music.
myChannelMusic.stop();
//Start the "You Win" music.
myChannelWin = winFX.play();
SfxTransform.volume = 0.02;
myChannelWin.soundTransform = SfxTransform; <---- line 352
}
So as you can see, it run's through these functions. I've already checked if something is wrong with my file in the Library, but the AS Linkage name is exactly the same as the var I defined above. Maybe a few extra eyes can see what's going wrong here, and explain me why..
Thanks in advance!
As per the livedocs :
winFX.play() method may return null if you have no sound card or if you run out of available sound channels. The maximum number of sound channels available at once is 32.
Check if either of the issues above is applicable to you....
As Mark said, the class winGameSound is the culprit here. The call winFX.play() returns a null, not a sound channel. So you can not apply a sound transform to the null object.
The only info one can currently get is that the class inherits Sound class & returns null with play() call.
I am loading a set of thumbnail images from an array [hard coded] into a movieclip symbol on the stage. I have two arrays with the thumbnail and the full size image having the same index number. In many examples, "event.currentTarget.contentLoaderInfo.url" returns the full path to the image selected. i just want the index number.
Adobe does not make is easy to figure out what other properties are available to me from the contentLoaderInfo. Is 'SelectedIndex' or something like that available?
Where does an inspiring AS programmer find the contentLoaderInfo properties and or methods available? Is url the only thing that us usable here?
Is there a better approach?
Thanks in advance.
Edit:
var thumbnails:Array = ["tn_2010OpenHouse_00.jpg","tn_2010OpenHouse_01.jpg"];
var images:Array = ["2010OpenHouse_00.jpg","2010OpenHouse_01.jpg"];
var thumbX:Number = 10;
var thumbY:Number = 623;
var loader:Loader = new Loader();
loader.load(new URLRequest("images/" + images[0]));
addChild(loader);
loadThumbs();
function loadThumbs():void
{
var thumbLoader:Loader;
var container:Sprite = new Sprite();
container.width = 100;
addChild(container);
container.buttonMode = true;
for (var i:uint = 0; i < thumbnails.length; i++)
{
thumbLoader = new Loader();
thumbLoader.load(new URLRequest("images/" + thumbnails[i]));
thumbLoader.x = thumbX;
thumbLoader.y = thumbY;
thumbX += 100;
container.addChild(thumbLoader);
thumbLoader.addEventListener(MouseEvent.CLICK, thumbClicked);
container.width += 100;
addChild(thumbLoader);
}
stop();
}
function thumbClicked(ev:MouseEvent):void
{
//weltraumpirat's example
var index:int = thumbnails.indexOf ( ev.target.contentLoaderInfo.url );
trace("Index= "+ index);
//trying a different approach as well
index = thumbnails.indexOf ( ev.currentTarget.contentLoaderInfo.url );
trace("Index= "+ index);
loader.load(new URLRequest("images/" + images[index]));
}
Output:
Index= -1
Index= -1
Error #2044: Unhandled IOErrorEvent:. text=Error #2035: URL Not Found.
The contentLoaderInfo property returns a LoaderInfo class. You can view its properties here:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/LoaderInfo.html
You can use array.indexOf() to return an object's index. Since I don't know the rest of your code, here's an approximate example:
function thumbClicked (ev:MouseEvent) : void {
var index:int = thumbnails.indexOf ( ev.target.contentLoaderInfo.url );
loader.load ( new URLRequest (fullSizeImages[index]) ) ;
}
Edit:
Since I didn't know the exact code you were using, I assumed you store the entire path to the picture in your array. In your code, you prepend "images/", so the code should be:
function thumbClicked (ev:MouseEvent) : void {
var index:int = thumbnails.indexOf ( ev.target.contentLoaderInfo.url.substring (7));
// 7 is the length of "images/", so substring returns only the filename part.
loader.load ( new URLRequest (fullSizeImages[index]) ) ;
}