It seems that most 3D authoring applications use Z as the 'Up' axis. While SceneKit uses Y as the 'Up' axis. SceneKit allows you to load scenes as Collada .DAE files. When loading a Scene via either:
SCNScene(named: String?, inDirectory: String?, options: [NSObject : AnyObject]?)
or
SCNSceneSource(URL url: NSURL!, options: [NSObject : AnyObject]!)
You can specify options including SCNSceneSourceConvertToYUpKey and SCNSceneSourceConvertUnitsToMetersKey.
Setting these accordingly, I expected the various nodes to be transformed and scaled when I added them to my own scene constructed from Nodes in the loaded scene. But these options appear to have no effect.
let myScene = SCNScene(named: "Scene.dae", inDirectory: nil, options: [SCNSceneSourceConvertToYUpKey:true, SCNSceneSourceConvertUnitsToMetersKey:25.4])
Have I misunderstood the meaning of these option parameters?
SceneKit does not directly load DAE (or ABC) files on iOS -- it loads scenes from a private Apple format, which Xcode automatically converts to when you include scene files in your project. Part of this conversion is the option to transform the up axis.
I don't believe that option is exposed when you simply include the DAE file as a bundle resource. (That might be a good bug to file.) However, it's a good idea to use the new SceneKit Asset Catalog feature instead, anyway -- put your DAE files and whatever external resources (textures) into a folder with a .scnassets extension, and Xcode will process them together to optimize for the target device when you build. Then, when you select that folder in the Xcode navigator, you'll get an editor for scene building options:
All the boxes there are good to check. :) (Since the first one doesn't come with an explanation: interleaving means organizing the vertex data for a geometry so you get better GPU-memory locality for fewer cache misses during vertex processing, which is important for performance on embedded devices.)
Hm, I don't see anything about units in there, though. Might be another good bug to file.
There's another option, too -- all SceneKit objects implement the NSSecureCoding protocol, so you can load and preprocess your scene on OS X, then use NSKeyedArchiver to write it out. Include the resulting file in your iOS project as a bundle resource, and Xcode won't preprocess it (it's already as compressed and optimized as it can get) -- and if you name it with an .scn extension, you can use all the SCNScene and SCNSceneSource methods for loading it just like you would a (preprocessed) DAE file.
Related
What is the significance of the andy.obj file in the ARCore Sample?
Let's say if we replace the andy.png with a new image, how can we generate .obj file for the new image?
The OBJ file describes the geometry, the png file the texture to "stretch" over this 3D object. You have to use a 3D modelling program like Blender to create a new model.
This is how you export OBJ files in Blender: https://blender.stackexchange.com/questions/121/how-do-i-export-a-model-to-obj-format
The sample code only can handle the simplest OBJ models that only have 1 texture file.
Fo those complicated OBJ models, they usually come with a MTL file that refers to several different texture files. To be able to handle that ,you need some extra work on the existing code. Please check the code I implement for this case if you are interested #https://github.com/JohnLXiang/arcore-sandbox . Specifially ,you can take a look at ObjectRenderer.createOnGlThread().
To export a texture as image in Blender do the following:
Select your object and enter in edit mode. Select all vertices/faces (press 'a'). Then start the UV Mapping, press 'u'. And Select one of the options of the UVMapping. You must test the best option for your model. I'm not sure which UV Mapping mapping option the ARCore uses.
Then go to the UV/Image Editor:
Export UV Layout at the menu, and save your image.
For creating a new .obj model for your AR app you need to use 3D authoring software like Autodesk Maya, Autodesk 3dsMax, Blender, SideFx Houdini, Cinema 4D, etc. These applications can help you create a high quality polygonal model with corresponding .mtl texture file.
But you should know that Sceneform supports 3D assets not only in OBJ format (where animations aren't supported) but also in FBX (with animations) and in glTF (animations not supported).
.obj
.fbx
.glTF
Sceneform's ASCII and Binary Asset Definitions are also welcome:
.sfa
.sfb
Supported material files (aka textures for your 3D assets) have the following extensions: MTL, BIN, PNG, JPG and native Sceneform's SFM.
.mtl
.bin
.png
.jpg
.sfm
Hope this helps.
Despite reading through much of Apple's docs and reading through their forums and watching their WWDC videos, I seem to have missed the steps required to utilise the texture packing and performance of Sprite Kit for making many large-ish Sprites.
Imagine 100 different sprite images, for 100 different sprites. If each image is 256x256 pixels, they're going to take up more than one SpriteSheet at 2048x2048. And let's imagine that's the limit, rather than 4096x4096, just so it's understood that more than one spritesheet is going to be required.
There might be as many as 20 different sprites on screen at any given time. So performance is a consideration.
How to import these images and then create these sprites in the manner SpriteKit intends for its texture packing and performance considerations of in game use?
Just a specific link to Apple recommended absolute steps will be fine. I must have just skimmed right over it.
Apple's new docs go this far:
Which completely fails to convey:
Import folder, or images?
Import to WHERE within the project?
Load and reference them, how?
So let me see if I can reasonably answer your question. Please keep in mind that while I have used SpriteKit, I'm not a big fan of it. And when I did use it, I did not use any of the tools Apple provided (eg. SKTextureAtlas, sks files, etc). Nevertheless, this should still be applicable. Best practices as per Apple? I have no idea.
Question: Import folder, or images?
If you use Xcode's means of generating atlases, you Add Files... to your project a folder named XYZ.atlas, where XYZ will be the texture name. This folder contains all of your textures which will be in the atlas.
Question: Import to WHERE within the project?
Just has to be in your project. But you should have some organization Group hierarchy in your project file.
Question: Load and reference them, how?
An example of loading would be something like (yeah, I know boo, Obj-C):
self.myTextureAtlas = [SKTextureAtlas atlasNamed:#"MyTexture"];
Inevitably, you will want access to the actual textures and you'll need to do something like:
self.tex0 = [self.myTextureAtlas textureNamed:#"tex0"];
A good tutorial is here: https://www.raywenderlich.com/45152/sprite-kit-tutorial-animations-and-texture-atlases
Here is also a screenshot that shows the .atlas folder. It also shows a couple of tool generated atlas files.
So here you can see I have 2 Groups which are references to folder MyTexture.atlas and ProgressBar.atlas. In game, they will be called MyTexture and ProgressBar.
I have also included, just as an example the same atlases, but pre-built. You would not have both in your project, I only used it to show what including a pre-built would loo like. I generated them using TexturePacker. I'll get into why this may be a better option later on. TexturePacker also can create SpriteKit atlases instead of the atlas PNG.
In reality, an atlas is really just a texture with sub-textures are associated with it. The sub-textures are X/Y/W/H sections of the texture. The actual memory for the texture is "held" by the atlas. Understanding what an atlas is is a useful thing, because it allows you to think through how you would support it if you had to implement it yourself. Or enhance it.
Now let's go over how you would use this altogether to do something useful.And for this you're going to need a texture manager (aka TextureManager), sprite manager (aka SpriteManager) and a manifest of some sort.
The manifest is really some form of association between "sprite name" to atlas:sub texture pair. For example:
{
"progressbar": {
"atlas": "ProgressBar",
"subtexture": progressbarbacking"
},
"progressbarfillr": {
"atlas": "ProgressBar",
"subtexture": progressbarfillr"
}
}
In this case it is some JSON, but you can have whatever format you want. When I build my games, I have a build assets phase which generates all my textures and from that, builds a manifest. This manifest tells me not only what textures exist, but is used later on to find the correct association of a "sprite name" to the actual atlas and sub texture. "sprite name" is just some name you have associated meaning. It could be "zombie" for example.
You use a TextureManager as your asynchronous loader. In addition, it is your inventory manager of all your textures. As an inventory manager, it will prevent you from double loading textures and also give you the correct reference to textures/atlases when requested (if they exist).
You would use the SpriteManager to create a new SKSpriteNode using the data from the manifest. For example:
SKSpriteNode *progressBar = [[SpriteManager sharedInstance] createSprite:#"progressbar"];
Here I've made it a singleton. Use whatever implementation you want. If you hate singletons, that is fine, this is just an example. You'll note that it returns a SKSpriteNode. I see a lot of people making subclasses from SKSpriteNodes. I never do this. To me, the graphic component is always a "has a". However, if you are doing an "is a", you can still do this. You just need to feed in the class you need. I'm considering the way of handling that out of scope for this question.
Now if you look at the manifest, you'll notice that progressbar is associated with an atlas named ProgressBar and a sub texture named progressbarbacking. To get the texture you need, you'd have some implementation code in SpriteManager like:
// NOTE the literal names would be variables which contained the unpacked association from progressbar
// literal strings are used to make the idea easier to follow
SKTextureAtlas *atlas = [[TextureMaanger sharedInstance] findAtlasNamed:#"ProgressBar"];
//Error check of course
SKTexture *tex = [atlas textureNamed:#"progressbarbacking"];
// Error check of course
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithTexture:tex];
Or perhaps you would just have a call:
SKTexture *tex = [[TextureManager] sharedInstance] texNamed:#"progressbarbacking" atlas:#"ProgressBar"];
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithTexture:tex];
And there you have it. A means to get sprites from atlases.
Best practices as per Apple? Dunno, but it is along the lines of what I do.
Some people will complain that there will be dictionaries involved and some of this will be "slow". And yes, there is a penalty for this. And reality, I don't use a dictionary for this either, but it is easier to get the idea across as the dictionary. Also keep in mind that I consider the usage of this to occur during loading phases and very little during game play, if at all. One of the tricks to performant games is pre-loading all or as much of the data you need prior to actual game play.
Oh, going to why I pre-build the atlases. So part of your question was organization of textures to atlas. And that is why. I like to see the generated atlas and understand what the size is and what is in it. Additionally it makes downloadable atlases easier.
As an optimization, you would want to try and put textures in which are all drawn relatively the same time. For example, it would make sense to have all HUD items in the same atlas versus mixing HUD with background.
i want to write a ModelViewer to load many models in my Scene.
so how can i create GLMaterialLibrary in run time and assign it to FreeForms Objects in RunTime?
and i want to know how can i find the name of submodel's texture.
TanX for Help.
First of all, you do not need to create GlMaterialLibrary at run time as you can use single instance of GLMaterialLibriary for all scene GLFreeForms and dynamicaly link it to a new freeform. A TFreeForm or TActor can automatically setup the materials and load the textures from a 3DS files. You must first add a material library component to a form (which will store the materials, once the 3DS is loaded), then link the FreeForm to this material library and set
UseMeshMaterials := true;
After doing this, when loading the 3DS mesh, the importer will add new materials to the material library (using the names defined in the 3DS file), which you can later alter if you so wish.
Be aware that the image formats must be supported, for instance if your textures are JPeg files, you must add "JPeg" to your uses. And least but not last: GLScene comes with a very good pack of demos that you can check for refference. ..\Demos\materials\ folder contains everything what you need.
I'm relatively new to programming and currently trying to learn more about three.js, a JavaScript 3D library. Many things are relatively easy to understand, but I an having a hard time saving an geometry and its material.
I have build a simple cube and an image is projected on to it whenever a picture is loaded.
like this:
$('#picture')[0].onload = function() {
var texture = new THREE.Texture(this,null);
texture.needsUpdate = true;
cube.material = new THREE.MeshBasicMaterial( { map: texture } );
render();
}
My goal is to save the cube and its material. Ideally I would like to save it directly as a .dae file since another program in which i would like to import my cube only takes .dae files.
However, i can not find a collada exporter for THREE.js. Therefore, I searched for other exporters which can produce a file format I can open in e.g. Blender or MeshLab and save as .dae from there. Unfortunately, I have not been able to save both geometry and material/picture with these exporters:
GeometryExporter.js, OBJExporter.js, SceneExporter.js
I also looked into the combination of OBJ and MTL. I did find the OBJMTLLoader.js, however I lack the knowledge to rewrite the OBJMTLLoader.js in to a OBJMTLExporter.js
Can anyone help me find a way to get from a cube and its (picture) material in THREE.js to a .dae file?
For a very simple use case such as this, you could write the DAE manually, or even simpler, modify existing DAE on the fly. It's just XML if you change the file extension.
Create the simple cube with material in Blender, export it to DAE, and use it as a template. Simple DAE files are not very hard to read with text editor, you could find the relevant parts and just search & replace those parts in javascript (texture reference, material properties and UVs maybe).
This might not be exactly what you are looking for, but could work. Not many formats have proper support for materials, and I doubt you have much success finding a working, fully featured Three.js exporter for such a thing (not sure though).
In XNA, how do I load in a texture or mesh from a file without using the content pipeline?
The .FromFile method will not work on xbox or zune. You have two choices:
Just use the content pipeline ... on xbox or zune (if you care about them), you can't have user-supplied content anyways, so it doesn't matter if you only use the content pipeline.
Write code to load the texture (using .SetData), or of course to parse the model file and load the appropriate vertexbuffers, etc.
For anyone interested in loading a model from a file check out this tutorial:
http://creators.xna.com/en-us/sample/winforms_series2
This is a windows only Way to load a texture without loading it through the pipeline, As Cory stated above, all content must be compiled before loading it on the Xbox, and Zune.
Texture2D texture = Texture2D.FromFile(GraphicsDeviceManager.GraphicsDevice, #Location of your Texture Here.png);
I believe Texture2D.FromFile(); is what you are looking for.
It does not look like you can do this with a Model though.
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.texture2d.fromfile.aspx
If you really want to load an Xna Xna.Framework.Graphics.Model on PC without the content pipeline (eg for user generated content), there is a way. I used SlimDX to load an X file, and avoid the parsing code, the some reflection tricks to instantiate the Model (it is sealed and has a private constructor so wasn't meant to be extended or customised). See here: http://contenttracker.codeplex.com/SourceControl/changeset/view/20704#346981