Merge remote-tracking branch 'origin/develop' into feature/event_driven_updates
@@ -0,0 +1,8 @@
|
||||
About
|
||||
=====
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:name: toc-about
|
||||
|
||||
introduction
|
||||
@@ -7,4 +7,4 @@ A film is an idea carved along the whole production process by many different pe
|
||||
|
||||
Nowadays it's a known fact that real-time rendering technologies allows to speedup traditional linear production by reducing drastically the iteration time across different steps. All majors industrial CG solutions are moving toward real-time horizons to bring innovative interactive workflows. But this is a microscopic, per-task/solution vision of real-time rendering benefits for the animation production. What if we step-back, get a macroscopic picture of an animation movie pipeline and ask ourself how real-time could change our global workflow ? Could-it bring better ways of working together by giving more visibility between departments during the whole production ?
|
||||
|
||||
The multi-user addon is an attempt to experiment real-time parallelisation between different production stage. By replicating blender data blocks over the networks, it allows different artists to collaborate on a same scene in real-time.
|
||||
The multi-user addon is an attempt to experiment real-time parallelism between different production stage. By replicating blender data blocks over the networks, it allows different artists to collaborate on a same scene in real-time.
|
||||
@@ -72,7 +72,7 @@ html_theme_options = {
|
||||
# 'analytics_id': '',
|
||||
# 'sticky_navigation': True # Set to False to disable the sticky nav while scrolling.
|
||||
# 'logo_only': True, # if we have a html_logo below, this shows /only/ the logo with no title text
|
||||
#'collapse_navigation': False, # Collapse navigation (False makes it tree-like)
|
||||
'collapse_navigation': False, # Collapse navigation (False makes it tree-like)
|
||||
# 'display_version': True, # Display the docs version
|
||||
# 'navigation_depth': 4, # Depth of the headers shown in the navigation bar
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
@@ -0,0 +1,9 @@
|
||||
Getting started
|
||||
===============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:name: toc-getting-started
|
||||
|
||||
install
|
||||
quickstart
|
||||
@@ -34,15 +34,22 @@ Documentation is organized into the following sections:
|
||||
:caption: About
|
||||
:name: sec-about
|
||||
|
||||
introduction
|
||||
about/introduction
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Getting started
|
||||
:name: sec-learn
|
||||
|
||||
install
|
||||
quickstart
|
||||
getting_started/install
|
||||
getting_started/quickstart
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Tutorials
|
||||
:name: sec-tutorials
|
||||
|
||||
tutorials/hosting_guide
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
================
|
||||
Advanced hosting
|
||||
================
|
||||
|
||||
This tutorial aims to guide you to host a collaborative Session on internet.
|
||||
|
||||
.. note::
|
||||
This tutorial will change soon with the new dedicated server.
|
||||
|
||||
|
||||
The multi-user network architecture is based on a clients-server model. The communication protocol use four ports to communicate with client:
|
||||
|
||||
* Commands: command transmission (such as **snapshots**, **change_rights**, etc.)
|
||||
* Subscriber: pull data
|
||||
* Publisher: push data
|
||||
* TTL (time to leave): used to ping each clients
|
||||
|
||||
.. warning::
|
||||
Until now, those communications are not encrypted but are planned to be in a mid-term future (`Status <https://gitlab.com/slumber/multi-user/issues/62>`_).
|
||||
|
||||
To know which ports will be used, you just have to read the port in your preference.
|
||||
|
||||
.. image:: img/hosting_guide_port.png
|
||||
:align: center
|
||||
:alt: Port
|
||||
|
||||
In the picture below we have setup our port to **5555** so it will be:
|
||||
|
||||
* Commands: 5555 (**5555** +0)
|
||||
* Subscriber: 5556 (**5555** +1)
|
||||
* Publisher: 5557 (**5555** +2)
|
||||
* TTL: 5558 (**5555** +3)
|
||||
|
||||
Now that we know which port are needed to communicate we need to allow other computer to communicate with our one.
|
||||
By default your router shall block those ports. In order grant server access to people from internet you have multiple options:
|
||||
|
||||
1. Simple: use a third party software like `HAMACHI <https://vpn.net/>`_ (Free until 5 users) or `ZEROTIER <https://www.zerotier.com/download/>`_ to handle network sharing.
|
||||
|
||||
2. Harder: Setup a VPN server and allow distant user to connect to your VPN.
|
||||
|
||||
3. **Not secure** but simple: Setup port forwarding for each ports (for example 5555,5556,5557 and 5558 in our case). You can follow this `guide <https://www.wikihow.com/Set-Up-Port-Forwarding-on-a-Router>`_ for example.
|
||||
|
||||
Once you have setup the network, you can run **HOST** in order to start the server. Then other users could join your session in the regular way.
|
||||
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,8 @@
|
||||
Tutorials
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:name: toc-tutorial
|
||||
|
||||
hosting_guide
|
||||
@@ -30,7 +30,7 @@ class BlImage(BlDatablock):
|
||||
bl_id = "images"
|
||||
bl_class = bpy.types.Image
|
||||
bl_delay_refresh = 0
|
||||
bl_delay_apply = 0
|
||||
bl_delay_apply = 1
|
||||
bl_automatic_push = False
|
||||
bl_icon = 'IMAGE_DATA'
|
||||
|
||||
@@ -54,18 +54,26 @@ class BlImage(BlDatablock):
|
||||
|
||||
image.source = 'FILE'
|
||||
image.filepath = img_path
|
||||
image.colorspace_settings.name = data["colorspace_settings"]["name"]
|
||||
|
||||
|
||||
def dump_implementation(self, data, pointer=None):
|
||||
assert(pointer)
|
||||
data = {}
|
||||
data['pixels'] = dump_image(pointer)
|
||||
utils.dump_datablock_attibutes(pointer, [], 2, data)
|
||||
data = utils.dump_datablock_attibutes(
|
||||
pointer,
|
||||
["name", 'size', 'height', 'alpha', 'float_buffer', 'filepath', 'source'],
|
||||
2,
|
||||
data)
|
||||
dumper = utils.dump_anything.Dumper()
|
||||
dumper.depth = 2
|
||||
dumper.include_filter = [
|
||||
"name",
|
||||
'size',
|
||||
'height',
|
||||
'alpha',
|
||||
'float_buffer',
|
||||
'filepath',
|
||||
'source',
|
||||
'colorspace_settings']
|
||||
data.update(dumper.dump(pointer))
|
||||
|
||||
return data
|
||||
|
||||
def diff(self):
|
||||
|
||||
@@ -235,6 +235,9 @@ class BlObject(BlDatablock):
|
||||
'rotation_mode',
|
||||
'location',
|
||||
'scale',
|
||||
'custom_shape',
|
||||
'use_custom_shape_bone_size',
|
||||
'custom_shape_scale',
|
||||
group_index,
|
||||
rotation
|
||||
]
|
||||
|
||||
@@ -101,7 +101,9 @@ class DynamicRightSelectTimer(Timer):
|
||||
|
||||
if self._user:
|
||||
current_selection = utils.get_selected_objects(
|
||||
bpy.context.scene)
|
||||
bpy.context.scene,
|
||||
bpy.data.window_managers['WinMan'].windows[0].view_layer
|
||||
)
|
||||
if current_selection != self._last_selection:
|
||||
if self._right_strategy == RP_COMMON:
|
||||
obj_common = [
|
||||
|
||||
@@ -48,12 +48,6 @@ def module_can_be_imported(name):
|
||||
return False
|
||||
|
||||
|
||||
def get_package_install_directory():
|
||||
for path in sys.path:
|
||||
if os.path.basename(path) in ("dist-packages", "site-packages"):
|
||||
return path
|
||||
|
||||
|
||||
def install_pip():
|
||||
# pip can not necessarily be imported into Blender after this
|
||||
get_pip_path = Path(__file__).parent / "libs" / "get-pip.py"
|
||||
@@ -61,10 +55,8 @@ def install_pip():
|
||||
|
||||
|
||||
def install_package(name):
|
||||
target = get_package_install_directory()
|
||||
|
||||
subprocess.run([str(PYTHON_PATH), "-m", "pip", "install",
|
||||
name, '--target', target], cwd=SUBPROCESS_DIR)
|
||||
name], cwd=SUBPROCESS_DIR)
|
||||
|
||||
def check_dir(dir):
|
||||
if not os.path.exists(dir):
|
||||
|
||||
@@ -104,8 +104,8 @@ def get_armature_edition_context(armature):
|
||||
return override
|
||||
|
||||
|
||||
def get_selected_objects(scene):
|
||||
return [obj.uuid for obj in scene.objects if obj.select_get()]
|
||||
def get_selected_objects(scene, active_view_layer):
|
||||
return [obj.uuid for obj in scene.objects if obj.select_get(view_layer=active_view_layer)]
|
||||
|
||||
|
||||
def load_dict(src_dict, target):
|
||||
|
||||