@deepblend/dsh-blender-provider-local 0.2.14 → 0.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/python/__pycache__/bootstrap.cpython-313.pyc +0 -0
- package/python/__pycache__/bootstrap.cpython-314.pyc +0 -0
- package/python/__pycache__/deepblend_scene.cpython-313.pyc +0 -0
- package/python/__pycache__/deepblend_scene.cpython-314.pyc +0 -0
- package/python/bootstrap.py +11 -0
- package/python/deepblend_scene.py +68 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepblend/dsh-blender-provider-local",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local Blender Provider: the BlenderRuntime Service over ctx.subprocess (batch execution).",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"./package.json": "./package.json"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@deepblend/dsh-blender-contracts": "0.2.
|
|
14
|
+
"@deepblend/dsh-blender-contracts": "0.2.15"
|
|
15
15
|
},
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"repository": {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/python/bootstrap.py
CHANGED
|
@@ -230,6 +230,17 @@ def action_compile_scene(request, options):
|
|
|
230
230
|
# THE RIGS THIS SCENE DECLARES, with their bones. A count alone would say an armature exists;
|
|
231
231
|
# a rig is only useful if the bones are the ones the spec named, so the names travel with it and
|
|
232
232
|
# a test can read them back rather than trust the count.
|
|
233
|
+
# WHICH ENTITIES ARE SKINNED, AND TO WHAT. The vertex groups are the evidence that weights
|
|
234
|
+
# exist at all: an entity bound to an armature with no groups renders as a static object while
|
|
235
|
+
# the file says it is rigged, and the reading is where that difference becomes visible.
|
|
236
|
+
"skinned": [
|
|
237
|
+
{
|
|
238
|
+
"entityId": entity_id,
|
|
239
|
+
"armatureId": entry["armatureId"],
|
|
240
|
+
"vertexGroups": entry["vertexGroups"],
|
|
241
|
+
}
|
|
242
|
+
for entity_id, entry in sorted((report.get("skinned") or {}).items())
|
|
243
|
+
],
|
|
233
244
|
"armatures": [
|
|
234
245
|
{
|
|
235
246
|
"id": armature_id,
|
|
@@ -1375,6 +1375,45 @@ def build_armature(entry, guard):
|
|
|
1375
1375
|
return obj
|
|
1376
1376
|
|
|
1377
1377
|
|
|
1378
|
+
def skin_entity(obj, armature_obj, armature_id, guard):
|
|
1379
|
+
"""Bind a mesh to an armature with Blender's own automatic weights.
|
|
1380
|
+
|
|
1381
|
+
WHY AUTOMATIC WEIGHTS RATHER THAN A WEIGHT TABLE. A per-vertex weight table in the SceneSpec would
|
|
1382
|
+
be a second, hand-written copy of something Blender already computes from the geometry — and the
|
|
1383
|
+
copy would be the one that goes stale, because nothing regenerates it when a generator's parameters
|
|
1384
|
+
change. What the spec states is the RELATIONSHIP ("this entity is skinned to that armature"); the
|
|
1385
|
+
weights are Blender's answer to it.
|
|
1386
|
+
|
|
1387
|
+
Bone heat can fail on a degenerate mesh (Blender reports "failed to find solution for one or more
|
|
1388
|
+
bones"), and that is a WARNING rather than a refusal: the binding still exists and the bones that
|
|
1389
|
+
did solve still deform, so the honest outcome is a scene that mostly works with the failure named.
|
|
1390
|
+
"""
|
|
1391
|
+
for target in bpy.context.selected_objects:
|
|
1392
|
+
target.select_set(False)
|
|
1393
|
+
obj.select_set(True)
|
|
1394
|
+
bpy.context.view_layer.objects.active = armature_obj
|
|
1395
|
+
try:
|
|
1396
|
+
bpy.ops.object.parent_set(type="ARMATURE_AUTO")
|
|
1397
|
+
except Exception as exc:
|
|
1398
|
+
guard.warnings.append({
|
|
1399
|
+
"code": "SKIN_WEIGHTS_FAILED",
|
|
1400
|
+
"message": 'entity "%s" could not be skinned to armature "%s": %s'
|
|
1401
|
+
% (obj.get("deepblend_id"), armature_id, error_text(exc)),
|
|
1402
|
+
})
|
|
1403
|
+
return False
|
|
1404
|
+
finally:
|
|
1405
|
+
obj.select_set(False)
|
|
1406
|
+
|
|
1407
|
+
if len(obj.vertex_groups) == 0:
|
|
1408
|
+
guard.warnings.append({
|
|
1409
|
+
"code": "SKIN_WEIGHTS_EMPTY",
|
|
1410
|
+
"message": 'entity "%s" is bound to armature "%s" but Blender produced no vertex groups, so '
|
|
1411
|
+
"it will not deform" % (obj.get("deepblend_id"), armature_id),
|
|
1412
|
+
})
|
|
1413
|
+
return False
|
|
1414
|
+
return True
|
|
1415
|
+
|
|
1416
|
+
|
|
1378
1417
|
def build_scene(spec, options, guard):
|
|
1379
1418
|
"""Compile a SceneSpec into a live Blender scene.
|
|
1380
1419
|
|
|
@@ -1550,6 +1589,25 @@ def build_scene(spec, options, guard):
|
|
|
1550
1589
|
bpy.context.view_layer.update()
|
|
1551
1590
|
|
|
1552
1591
|
report_progress("compile_done", 90)
|
|
1592
|
+
# SKINNING LAST: it needs both the mesh and the rig, and doing it before either exists would mean
|
|
1593
|
+
# ordering the compile around a step that is about the RELATIONSHIP between them.
|
|
1594
|
+
report_progress("skin_entities", 60)
|
|
1595
|
+
skinned_entities = {}
|
|
1596
|
+
for entity in spec.get("entities") or []:
|
|
1597
|
+
armature_id = entity.get("armatureId")
|
|
1598
|
+
if armature_id is None:
|
|
1599
|
+
continue
|
|
1600
|
+
obj = entity_objects.get(entity["id"])
|
|
1601
|
+
armature_obj = armature_objects.get(armature_id)
|
|
1602
|
+
if obj is None or armature_obj is None:
|
|
1603
|
+
raise ActionError(
|
|
1604
|
+
"SCENE_SPEC_INVALID",
|
|
1605
|
+
'entity "%s" is skinned to armature "%s", which the same SceneSpec does not declare'
|
|
1606
|
+
% (entity["id"], armature_id),
|
|
1607
|
+
)
|
|
1608
|
+
skin_entity(obj, armature_obj, armature_id, guard)
|
|
1609
|
+
skinned_entities[entity["id"]] = entity
|
|
1610
|
+
|
|
1553
1611
|
return {
|
|
1554
1612
|
"objects": describe_objects(),
|
|
1555
1613
|
"actions": actions,
|
|
@@ -1560,6 +1618,16 @@ def build_scene(spec, options, guard):
|
|
|
1560
1618
|
"profileName": profile_name,
|
|
1561
1619
|
"entityObjectNames": {key: value.name for key, value in entity_objects.items()},
|
|
1562
1620
|
"armatureNames": {key: value.name for key, value in armature_objects.items()},
|
|
1621
|
+
"skinned": {
|
|
1622
|
+
key: {
|
|
1623
|
+
"armatureId": entry["armatureId"],
|
|
1624
|
+
# THE GROUPS COME FROM THE OBJECT, not from the spec entry: what the file asked for is
|
|
1625
|
+
# the relationship, and what Blender produced is the weights. Reading the latter back is
|
|
1626
|
+
# the whole point — an entity bound with no groups renders as a static object.
|
|
1627
|
+
"vertexGroups": sorted(group.name for group in entity_objects[key].vertex_groups),
|
|
1628
|
+
}
|
|
1629
|
+
for key, entry in skinned_entities.items()
|
|
1630
|
+
},
|
|
1563
1631
|
"cameraNames": {key: value.name for key, value in cameras.items()},
|
|
1564
1632
|
}
|
|
1565
1633
|
|