0

I want to use SceneKit on MacOS to load a Collada file and get scene node properties to use them with my own scene graph.

I can easily access vertices, normals, transformation matrices, material properties and so forth – everything except of the texture file names.

I would expect a texture's file name to be stored in an instance of SCNMaterialProperty Class. From the documentation:

The SCNMaterialProperty class encapsulates a texture and a set of attributes specifying how the texture is applied on the object.

But I can only get an NSImage representing the texture, not the source file name itself.

It must be somewhere - In the inspector of XCode's collada viewer the file name is displayed as well (along with properties from SCNMaterialProperty):

enter image description here

How do i access a texture's file name in a SceneKit object graph?

de.
  • 7,068
  • 3
  • 40
  • 69

1 Answers1

1

There's no API for it. If you're purely interested in it for debugging purposes, it's not too hard to hack at: underlying SCNMaterialProperty is C3DImageRef, which you can retrieve using -[SCNMaterialProperty getC3DImageRef]. Its layout looks something like:

struct __C3DImage {
  void *isa;
  uint32_t junk;
  uint32_t retainCount;
  NSDictionary *entityProperties;  // e.g. contains the kIDKey.  Nothing else for a material property.
  NSURL *path;
  ...
}

So with some casting and offsetting you can grab the path. Be aware the offset changes in 32-bit vs 64-bit due to the size of pointers changing.

All this info can be gleamed from class-dump (and headers can be generated that include the exact structs etc). It's all horribly fragile though, so don't ever ship code that uses it. File a bug report requesting that an API be added to get this info properly.

Wade Tregaskis
  • 1,996
  • 11
  • 15
  • Thanks a lot for your answer. class-dump generates the following output for me: `struct __C3DImage { struct __C3DEntity _field1; struct __CFURL *_field2; struct CGContext *_field3; ... }; ` However, I have problems accessing _field2 (which seems to be the url). `[[mySCNMaterialProperty getC3DImageRef] _field2]` `[mySCNMaterialProperty getC3DImageRef]->_field2` `[mySCNMaterialProperty getC3DImageRef]._field2` all won't work. I'm don't know anything about low-level debugging, could you give a hint or a pointer to some reference? Thx a lot! – de. Dec 01 '12 at 14:18
  • You'll need to cast to the `struct __C3DImage*` (or typedef it to C3DImageRef, though that's probably a less good idea). Unless something else is going on - in what way does it not work? Compiler error? What does the error say? – Wade Tregaskis Dec 01 '12 at 16:55
  • In my code I grab: `struct __C3DImage * a3DimageRef = [scnMaterial.diffuse getC3DImageRef];` I get a compiler warning: `Incompatible pointer types initializing 'struct __C3DImage *' with an expression of type 'id'`. I'm ignoring that, then in my console I do: `(lldb) po a3DimageRef (__C3DImage *) $0 = 0x0000000101678bb0 `. Nice, I seem to have a C3DImage at hands. But if I type: `po a3DimageRef->_field2` I get `(__CFURL *) $2 = 0x0000000000000000 `. – de. Dec 04 '12 at 17:39
  • The compiler warning is harmless, though I'm not sure how to get rid of it. Why the field is nil is a bit of a mystery. I wonder... when you ran class-dump, did you specify an architecture that matches what you're running your app as? It's possible it generated structs that don't match your running architecture. If that's not the issue, then I guess there's additional factors on if and when this dictionary gets created... perhaps different DAE files yield different results? – Wade Tregaskis Dec 05 '12 at 00:28
  • Ok I finally got it! You were right, along my debugging process I messed something up with my target, so that the textures were not copied to the right location in my application. Now that I fixed that, `po a3DimageRef->_field2` returns a nice URL, just like you predicted. Thanks a lot, your really saved my day there! And by the way, I did file a bug report at Apple. – de. Dec 05 '12 at 10:54