No functional change, just splitting them to two separate headers and
two separate tests. These will eventually become public SceneTools
APIs... once I figure out better naming.
Similar to sceneconverter's --profile option, measuring import and
conversion time. This also means that sceneconverter's --profile now
includes image import time, which wasn't done before.
Not really important right now as the SceneData from these are used only
in internal deprecated APIs, but at least it might speed up the
children2D() / children3D() queries. Mainly done so I don't forget to do
this later when these APIs are published in the SceneTools library.
What's not done is the rather complex logic in the single-function
conversion utility, where a field could retain the implicit/ordered
flags in *some* scenarios. There's too many corner cases so better be
conservative and don't preserve anything rather than mark something as
ordered while it's no longer the case. The corner cases are hopefully
all checled for (and XFAIL'd) in the test.
Currently used by the per-object access APIs to make the lookup
constant- or logarithmic-time instead of linear, available for use by
external data consumers as well.
Now it's a field and its corresponding object mapping, instead of
field and "objects":
- Goes better with the concept that there's not really any materialized
"object" anywhere, just fields mapped to them.
- No more weird singular/plural difference between field() and
objects(), it's field() and mapping() now.
- The objectCount() that actually wasn't really object count is now a
mappingBound(), an upper bound for object IDs contained in the object
mapping views. Which is quite self-explanatory without having to
mention every time that the range may be sparse.
This got originally added as some sort of a kludge to make it easy to go
to the parent transformation, assuming Parent and Transformation share
the same object mapping:
parentTransformation = transformations[parents[i]]
But after some ACTUAL REAL WORLD use, I realized that there's often a
set of objects that have a Parent defined, and then another, completely
disjoint, set of objects that have a transformation (for example certain
nodes having no transformation at all because it's an identity). And so
this parent indirection is not only useless, but in fact an additional
complication. Let's say we make a map of the transformations, where
transformationMap[i] is a transformation for object i:
transformationMap = {}
for j in range(len(transformations)):
transformationMap[transformationObject[j]] = transformation[j]
Then, with *no* assumptions about shared object mapping, the indirection
would cause parent transformation retrieval to look like this:
parentTransformation = transformationMap[parentObjects[parents[i]]
While *without* the indirection, it'd be just
parentTransformation = transformationMap[parents[i]]
Because that way one can query a field with *AsArray() and iterate
through it in a single expression. This also resolves the pending issue
where it was more than annoying to fetch object mapping for TRS fields
when only a subset of the fields is available.
To become the central piece of an upcoming SceneTools library, now I
need it just to implement duplication of objects that have more than one
mesh/light/camera/... assignment.
Reason is that Assimp custom material attribute names are also prefixed
with $ and other weird characters, which could lead to them appearing
before $LayerName, causing a layer to falsely appear unnamed. A space,
instead, is before all printable characters so it's guaranteed to be
always first.
Some things you just don't realize at first. Fortunately the binary
layout isn't pinned yet for the serialization format so this change is
mostly fine.
Turns out glTF doesn't actually put metalness into R and roughness into
G, even though the naming suggests that. This was done originally, but
then they changed that in order to be compatible with UE4 and allow for
a more efficient storage of an occlusion map.
Because this feels extremely arbitrary, the docs have added rationale
for each of the packing variants, and I'm also renaming the packed
attribute and checks to imply the red channel isn't used.
This is a bit huge because of all the new overloads that take a
MaterialLayer instead of a string, but all that is just boring
boilerplate. Additionally this:
* exposes glTF clear coat parameters (which, interestingly enough,
reuse existing attributes and don't introduce any new)
* provides a convenience wrapper in PbrClearCoatMaterialData
* and a convenience base for material layer wrappers that redirect
all APIs with implicit layer argument to desired layer instead of the
base material
Well, "basic". Practically mirrors glTF PBR materials:
- builtin metallic/roughness
- the KHR_materials_pbrSpecularGlossiness extension
- extra normal/occlusion/emission maps
- exposes the implicit metallic/roughness and specular/glossiness
packing, but also allows separate maps with arbitrary packings as
well as two-channel normal maps (instead of three-channel)
- provides convenience checks for the most common packing schemes
including MSFT_packing_normalRoughnessMetallic and the three variants
of MSFT_packing_occlusionRoughnessMetallic
- teaches PhongMaterialData to recognize packed specular/glossiness
maps as well
Next up is exposing at least one layer extension, and then I'm done
here.
With API analogous to the (relatively) new AnimationData -- with one
buffer containing all index data and one buffer containing all vertex
data, both meant to be uploaded as-is to the GPU.
This will eventually replace MeshData2D and MeshData3D, backwards
compatibility and wiring up to other APIs will be done in follow-up
commits.