Three.js - possible to use JSON to declare objects? - json

I'm trying to decide on the best Javascript 3D library for my project.
I like Three.js a bit more than Scene.js, but the coding style of Scene.js seems more efficient, because I need to create about 100 objects on the fly, and this would mean declaring hundreds of variables with Three.js.
In Three.js it seems that for each different object you need to define variables and add them to the scene, like this :
var renderer = new THREE.WebGLRenderer();
var camera =
new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR);
var scene = new THREE.Scene();
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(
50,
16,
16),
sphereMaterial);
scene.add(sphere);
while in Scene.js, objects are created in a JSON-like structure, like this :
var scene = SceneJS.createScene({
nodes:[
{
type:"material",
color: { r: 0.3, g: 0.3, b: 1.0 },
nodes:[
{
type: "rotate",
id: "myRotate",
y: 1.0,
angle: 0,
nodes: [
{
type:"geometry",
source:{
type:"teapot"
}
}
]
}
]
}
]
});
Now my question is, if it's possible to use a more JSON-like coding style with Three.js as well?
I already found out about THREE.JSONLoader, but since Three.js doesn't have very good documentation, I find it very hard to discover if this would be right for me. It seems to be more aimed at converted models from 3D-software, but I really need to build the objects myself.

Yes you can use JSON to define geometries in Three.js. You can parse JSON directly like this (untested, but at least the idea is there):
var json = { .... }; // your JSON geometry, not as string but already parsed object
var loader = new THREE.JSONLoader();
var result = loader.parse(json, texturePath);
var mesh = new THREE.Mesh(result.geometry, result.materials);
This can be used to define only geometries (and materials).
I agree that the documentation is sparse. Fortunately all Three.js JSON formats are pretty much human readable. You can check existing example models or take a look at https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3.1 for geometry JSON format to use with JSONLoader.
For complex scene hierarchies (multiple geometries, lights etc) you can use the apparently undocumented ObjectLoader JSON format pretty much in a similar fashion as the JSONLoader format. For checking out the ObjectLoader JSON format, I suggest reading the source at src/loaders/ObjectLoader.js and/or generating sample files using http://threejs.org/editor/ (File->Export Scene / Object)

You could take a look at GLGE's 'Quick Notation': http://www.glge.org/ (I've not looked deeply into that BTW, so I'm not sure if it fits your needs).
If you use SceneJS, be sure first that its features cover your requirements, because it has a narrower feature set than THREE.js, being intended more for high detail visualisation rather than for a wide range of rendering effects.
If I were you though, I would jump in and write your own open source JSON layer for THREE.js, starting with what you need. I'm sure you would get contributors filling in the rest soon enough.

Related

How can I a texture to a json model exported from Blender to Three.js?

In this case, I create two spheres in the scene. One is a SphereGeometry of Three.js(the left one), the other is a json model from Blender(the right one).
Both of them use the same material and it does work. As follows:
var material = new THREE.MeshPhongMaterial({
color: 0xffffff
});
var material = new THREE.MeshPhongMaterial({
color: 0xffffff,
wireframe: true
});
I try to add a texture to both of them.
However, the mapping effect does not work on the surface of the json model(the right one).
var material = new THREE.MeshPhongMaterial({
map: texture,
});
How can I solve this problem?
Here are my Demo and source code.
Check the UVs option in the Blender Three.js exporter:
I got the answer.
I have to unwrap a UV sphere in Blender first.
Just like this video.
How To Unwrap A UV Sphere In Blender
After this step, the json file has complete information of the UVs array and mapping effect does work.

no materials applied and missing faces when exporting from blender to three.js

I'm trying to export a jet I made in blender to three.js. the model shows up properly, but it's missing some faces and no materials are applied even though they are clearly present in json. Here's how it looks in blender:
And here's how it looks in browser:
As you can see, most of the canopy is missing, parts of the fuselage and inlets as well. No materials are applied to any part and the coloring comes only from ambient light. Here's how it's called:
var x29;
function createFighter() {
var loader = new THREE.JSONLoader();
loader.load('x29.json', function(geometry, materials) {
x29 = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials));
x29.castShadow = true;
x29.receiveShadow = true;
scene.add(x29);
});
}
No combination of changes in the exporter, triangulating the model or anything else produced any results. What am I doing wrong?
Turns out three will recognize, but won't apply materials created in cycles. blender render will. Faces were missing because of flipped normals, as #Radio pointed out.

AS#3 changing material Textures

I cant seem to find a solution, anyways basically im trying to add a new dynamic texture to a 3D model using Away3d engine with flash
var myImage:BitmapData = new BitmapData(256, 256, true,0xFFFFFFFF);
// i cant seem to reference this to my 3D model in the example: Myevent(enter frame):
myModel.material = new TextureMaterial(new BitmapTexture(myImage))
I have tried different things along the above method, i have checked the away3d docs and cant find something similar for my current situation:
Im using the latest Away3d lib, and flash player 11...all my models works and load with there original embedded materialtTextures, im just trying to change them to a bitmap or texture that i have dynamically created
Take a look here:
https://github.com/away3d/away3d-tutorials-fp11/blob/master/tutorials/materials/basic_shading/src/Basic_Shading.as
They use Away3D’s Cast utility class to create BitmapTexture objects and they also add a bunch of different texture maps - hopefully this helps
** EDIT --- This Tutorial Does Work **
Added
public bmt:BtiMapTexture;
....
private function initMaterials():void {
this.bmt = new BitmapTexture(new BitmapData(256,256, true, 0x222277FF));
sphereMaterial = new TextureMaterial(Cast.bitmapTexture(this.bmt));
sphereMaterial.specularMap = Cast.bitmapTexture(this.bmt);
sphereMaterial.lightPicker = lightPicker;
}
And I got a nice blue sphere
My solution is:
var mesh:Mesh = 'the mesh for changing'
for each (var item:SubMesh in mesh.subMeshes) {
item.material = null;
}
mesh.material = new ColorMaterial(0xFF00FF);

How to clone an object without knowing the exact type in AIR for iOS

I am writing an iOS game in Flash and I need a way to clone polymorphic objects.
I have BaseClass, SubClass1, SubClass2 (and so on...) and I need a clone() method in BaseClass, that will create a copy of the current object, without a conditional such as
var obj:BaseClass;
if(this is SubClass1) {
obj = new SubClass1();
}else if(this is SubClass2) {
obj = new SubClass2();
}else...
I need a way to create an object and create the exact bytes (yes, a shallow copy is enough for my purpose) of the object. I've looked at:
AS3 - Clone an object
As3 Copy object
http://actionscripthowto.com/how-to-clone-objects-in-as3/
But none seem to work. Probably not available in AIR 3.3 for iOS SDK. (they compile, but the code doesn't work in my case)
Is there any other way, or did anybody achieve to clone an object in AIR for iOS?
Thanks,
Can.
Bit-by-bit cloning cannot be done with ActionScript, unless your class only contains primitive values (i.e. a simple data structure). That's what the ByteArray approach you've linked to in this question's answer is used for - but when you're dealing with complex types, especially display objects, you'll soon come to the limits (as, I gather, you have already realized).
So this more or less leaves you with two options:
Create a new object and copy all of its fields and properties.
This is the way to go if you're going to need behavior and field values, and you didn't use any drawing methods (i.e., you can not copy vector graphics this way). Creating a new class instance without knowing its exact type can be done in a generalized way using reflections, getQualifiedClassName() and getDefinitionByName() will help you there, and if you need more than just the name, describeType(). This does have limits, too, though:private fields will not be available (they don't appear in the information provided by describeType()), and in order to not run into performance problems, you will have to use some sort of cacheing. Luckily, as3commons-reflect has already solved this, so implementing the rest of what you need for a fully functional shallow copy mechanism is not too complex.
Create a new instance like this:
var newObject:* = new Type.forInstance( myObject ).clazz();
Then iterate over all accessors, variables and dynamic properties and assign the old instance's values.
I have implemented a method like this myself, for an open source framework I am working on. You can download or fork it at github. There isn't any documentation yet, but its use is as simple as writing:
var myCopy:* = shallowCopy( myObject );
I also have a copy() method there, which creates a true deep copy. This, however, has not been tested with anything but data structures (albeit large ones), so use at your own risk ;)
Create a bitmap copy.
If you do have vector graphics in place, this is often easier than recreating an image: Simply draw the content of the object's graphics to a new Bitmap.
function bitmapCopy( source:Sprite ):Bitmap {
source.cacheAsBitmap = true;
var bitmapData:BitmapData = new BitmapData( source.width, source.height, true, 0xFFFFFF );
bitmapData.draw( source, new Matrix(), null, null, null, true );
return new Bitmap( bitmapData, PixelSnapping.AUTO, true );
}
You need to create an abstract clone method in the base class and implement it for each subclass. In the specific implementations, you would copy all of the properties of the object to the new one.
public class BaseClass {
public function clone():BaseClass
{
// throw an error so you quickly see the places where you forgot to override it
throw new Error("clone() should be overridden in subclasses!");
return null;
}
}
public class Subclass1 extends BaseClass {
public override function clone():BaseClass
{
var copy:Subclass1 = new Subclass1();
copy.prop1 = prop1;
copy.prop2 = prop2;
// .. etc
return copy;
}
}
If you wanted to create a generic default implementation of clone, you could use describeType to access the properties and copy them over:
public function clone():BaseClass
{
var defn:XML = describeType(this);
var clsName:String = defn.#name;
var cls:Class = getDefinitionByName(clsName) as Class;
var inst:* = new cls();
for each(var prop:String in (defn.variable + defn.accessor.(#access == 'readwrite')).#name )
{
inst[prop] = this[prop];
}
return inst;
}
The main issue with this is that the describeType XML can get quite large - especially if you are dealing with objects that extend DisplayObject. That could use a lot of memory and be slow on iOS.

Actionscript 3 - Import SVG file

Does anyone know of any libraries or tools for importing an SVG file into actionscript on the fly? I need to be able to import an SVG file into flash and convert it to a movieclip or preferably a flat 3d object. The end goal here is to implement a vector file with Augmented reality.
A great library for this can be downloaded here: http://code.google.com/p/as3svgrendererlib/
It is easy to implement and reliable. Note that there are two ways to implement the code. I prefer the following because it gives you more control:
private function loadSVG(url:String):void {
ProcessExecutor.instance.initialize(stage);
ProcessExecutor.instance.percentFrameProcessingTime = 0.9;
loader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.addEventListener(Event.COMPLETE, svgLoaded, false, 0, true);
try {
loader.load(new URLRequest(url));
} catch (error:Error) {
trace(error);
}
}
private function svgLoaded(e:Event):void {
var svgString:String = loader.data as String;
var svgDocument:SVGDocument = new SVGDocument();
svgDocument.parse(svgString);
this.addChild(svgDocument);
}
The other way is shorter and might be the way to go when you only have to load a small SVG or just a few.
public function loadSVG(url:String) {
ProcessExecutor.instance.initialize(stage);
ProcessExecutor.instance.percentFrameProcessingTime = 0.9;
var svgDocument:SVGDocument = new SVGDocument();
svgDocument.load(url);
addChild(svgDocument);
}
Two important notes:
1. I could not seem to be able to capture the width or height of the SVGs and the parent Sprite had a width and height of 0 after loading the SVG. I solved this by making all the SVGs the same size before loading them into AS3. After that I knew the dimensions I used the ScaleX and scaleY to resize the loaded SVGs.
2. The stage has to exist before you can use this code. adding the following code will make sure you won't run into problems:yourDisplayClass.addEventListener(Event.ADDED_TO_STAGE, loadYourSVGs);
Now how you convert this to a flat 3D object depends on your 3D Library. I have worked with Away3D where you can use bitmapmaterial on your Sprite3D. The Sprite3D class would be the object to use. I hope your 3D Library supports the use of MovieClips so that you can add them to your 3D Object. Else you will have to use to extract the bitmapMaterial from the movie clip as i have done in the following example:
public function movieClipToBitmapMaterial(mc:MovieClip):BitmapMaterial {
var bmData:BitmapData = new BitmapData(mc.width, mc.height, true, 0xFFFFFF);
bmData.draw(displayObject);
return new BitmapMaterial(bmData);
}
Your input in the above function will be the movieclip onto wich you have loaded your SVG.
I am not sure of this but I think that by using this function you will loose the ability to scale as much as you like without loosing quality.
I hope my input was of some help!
Good luck
PS: don't forget to add the SWC from the link to your project and to check out the provided examples. Please note as well the excellent comment of shaunhusain on your original question. You might not have to use 3D Library.
Salam,
It is very easy:
Open the "name.svg" file in illustartror.
Save it as "name.ai"
Import it into the stage in flash, that is all.