More versatile communication from blender to JS
14 March 2017 00:05
We're trying hard to set up a team workflow from blender to JS. Blender users shall be able to "tag" or otherwise parametrize objects, materials, nodes etc.
Our own viewer shall pick them up and trigger functionalities accordingly.
So far we're using these methods:
- Object meta tags (e.g. comma separated list in "Categories")
- Calling JS from logical nodes and using callbacks with variables
- Object / material / texture names
- Post processing the JSON file (unstable due to undefined/undocumented scheme)
Use case examples:
1.
Object rotation instead of camera rotation.
For a versatile viewer this means: Tagging of the "main object".
Solution so far: The main objects' name has to be "main".
2.
Change diffuse color for certain objects. Group objects by color group, so for example the web user can choose "front: yellow, rear: green".
Solution so far: Grouping by meta tags (color_1, color_2 etc).
3.
Assign different areas where web users can place a logo.
Solution so far: Naming convention for materials and textures. API Viewer collects all MESH objects/ materials/textures, searches for specially named ones and caches the results for later use via textures.change_image. Our viewer framework then reveals a method "place image i at position number n".
From the point of view of "separation of concerns" this is not very clean, neither is it stable or easily debuggable.
Are there any other methods that could be used to hand data from the blender domain down to the API?
Our own viewer shall pick them up and trigger functionalities accordingly.
So far we're using these methods:
- Object meta tags (e.g. comma separated list in "Categories")
- Calling JS from logical nodes and using callbacks with variables
- Object / material / texture names
- Post processing the JSON file (unstable due to undefined/undocumented scheme)
Use case examples:
1.
Object rotation instead of camera rotation.
For a versatile viewer this means: Tagging of the "main object".
Solution so far: The main objects' name has to be "main".
2.
Change diffuse color for certain objects. Group objects by color group, so for example the web user can choose "front: yellow, rear: green".
Solution so far: Grouping by meta tags (color_1, color_2 etc).
3.
Assign different areas where web users can place a logo.
Solution so far: Naming convention for materials and textures. API Viewer collects all MESH objects/ materials/textures, searches for specially named ones and caches the results for later use via textures.change_image. Our viewer framework then reveals a method "place image i at position number n".
From the point of view of "separation of concerns" this is not very clean, neither is it stable or easily debuggable.
Are there any other methods that could be used to hand data from the blender domain down to the API?
15 March 2017 19:27
Hi Phil! It's a very important question. This is about having some additional metadata for your custom application. Using metatags and naming conventions is not very convenient. Post processing JSON files is an evil thing, because as you said the format isn't documented and isn't intended to use in this way. Also, it tends to change over time, so no one can guarantee that your code will work after update.
But there is the good news: in the latest (17.02) release we've made a little step toward the customization of the export output. It is possible to access some custom properties via the blend4web API. These properties should be coded in a custom script and then bound with the blend4web add-on. This functionality is still in development, so you can not do a lot here. As for now the best approach is to write your own add-on which defines additional properties in the interface for objects, materials and so on. This add-on should perform collecting of the needed metadata and should store it in a special property called "b4w_custom_prop" on a scene before the export.
Here's the small example:
The main idea is to create a custom operator (CustomExport - in the example), which checks if the blend4web add-on is active and if so - performs the corresponding actions: obtains custom metadata and stores it in the scene.b4w_custom_prop property. After that this operator calls json export from the blend4web addon via "bpy.ops.export_scene.b4w_json("INVOKE_DEFAULT")". Blend4web knows about the "b4w_custom_prop" property and writes it into the JSON file. So, instead of the direct blend4web export you can use this operator to have your custom data included into the json.
The written metadata - is the data of your own format collected somehow (for example: by iterating through the all objects/materials/textures). As it's your custom add-on you can create a custom interface for convenient usage, for example, a dedicated checkbox for those "main object", which you mentioned. So, you can form the metadata object, which contains these settings, and store it as a JSON string.
This special property will be available for reading via the get_custom_prop method:
However, this approach is still requires a big amount of work for a developer, but we're planning to improve and simplify it in the future.
But there is the good news: in the latest (17.02) release we've made a little step toward the customization of the export output. It is possible to access some custom properties via the blend4web API. These properties should be coded in a custom script and then bound with the blend4web add-on. This functionality is still in development, so you can not do a lot here. As for now the best approach is to write your own add-on which defines additional properties in the interface for objects, materials and so on. This add-on should perform collecting of the needed metadata and should store it in a special property called "b4w_custom_prop" on a scene before the export.
Here's the small example:
bl_info = {
"name": "My Custom Addon",
"author": "I'm",
"version": (1, 0, 0),
"blender": (2, 78, 0),
"description": "My Custom Addon",
"category": "Development"
}
import bpy
import json
class CustomExport(bpy.types.Operator):
bl_idname = "export_scene.my_custom_export"
bl_label = "MY CUSTOM EXPORT"
def execute(self, context):
for addon in bpy.context.user_preferences.addons:
if addon.module == "blend4web":
store_metadata()
bpy.ops.export_scene.b4w_json("INVOKE_DEFAULT")
return {"FINISHED"}
self.report({"ERROR"}, "Blend4Web addon not found.")
return {"CANCELLED"}
def store_metadata():
metadata = {}
# obtain metadata somehow
for scene in getattr(bpy.data, "scenes"):
scene.b4w_custom_prop = json.dumps(metadata)
def register():
bpy.utils.register_module(__name__)
bpy.types.Scene.b4w_custom_prop = bpy.props.StringProperty(
name = "Custom Metadata",
description = "Custom Metadata",
default = "",
options = set()
)
def unregister():
bpy.utils.unregister_module(__name__)
del bpy.types.Scene.b4w_custom_prop
The main idea is to create a custom operator (CustomExport - in the example), which checks if the blend4web add-on is active and if so - performs the corresponding actions: obtains custom metadata and stores it in the scene.b4w_custom_prop property. After that this operator calls json export from the blend4web addon via "bpy.ops.export_scene.b4w_json("INVOKE_DEFAULT")". Blend4web knows about the "b4w_custom_prop" property and writes it into the JSON file. So, instead of the direct blend4web export you can use this operator to have your custom data included into the json.
The written metadata - is the data of your own format collected somehow (for example: by iterating through the all objects/materials/textures). As it's your custom add-on you can create a custom interface for convenient usage, for example, a dedicated checkbox for those "main object", which you mentioned. So, you can form the metadata object, which contains these settings, and store it as a JSON string.
This special property will be available for reading via the get_custom_prop method:
var data = JSON.parse(m_scenes.get_custom_prop())
However, this approach is still requires a big amount of work for a developer, but we're planning to improve and simplify it in the future.
17 March 2017 00:55