Как получить динамически созданный glb из бэкенда django для отображения в three.js

У меня есть приложение, которое принимает пользовательский ввод и создает 3D-модель из этого ввода в скрипте python. Теперь я хочу визуализировать этот 3D-объект с помощью three.js.

Моя проблема в том, что я не могу получить данные из бэкенда в three.js GLTFLoader в правильном формате. Данные glb генерируются с помощью trimesh. Я уверен, что 3D-модель создана правильно, потому что я могу вывести ее в файл и открыть в Blender. Загрузка статических ресурсов в формате glb через three.js также работает. Но поскольку контент создается динамически, я не хочу сохранять его на стороне сервера, если только пользователь не решит его сохранить.

Мой текущий подход заключается в том, чтобы попытаться включить 3D-модель в содержимое представления шаблона. В документации по three.js говорится, что данные glb могут быть разобраны из js BufferArray. Но похоже, что в js данные считываются как двоичная строка: "b'......'"

Виды.py:

class PreviewView(TemplateView):
template_name = 'editor/preview.html'
context_object_name = 'preview_generated'

def get_preview(self, request):
    from editor.tools.gltf import GLTFConverter
    raw_lines = json.loads(request.POST.get('vertex_sets'))
    if type(raw_lines[0]) is list:
        lines = [np.pad(np.array(line).reshape((-1,2)),[(0,0),(0,1)], mode='constant') for line in raw_lines]
    else:
        lines = [np.pad(np.array(raw_lines).reshape((-1,2)),[(0,0),(0,1)], mode='constant')]
    preview = get_preview(lines)
    request.session["preview"] = preview
    converter = GLTFConverter(preview.mesh)
    scene = converter.get_scene("preview")
    return scene


def get_context_data(self, **kwargs):
    context  =  super().get_context_data(**kwargs)
    return context

def post(self, request, *args, **kwargs):
    context = self.get_context_data()
    preview = self.get_preview(request)
    context['preview'] = preview
    return self.render_to_response(context)

Предварительный просмотр.html:

<script src="{% static 'editor/js/three.js' %}"></script>
<script src="{% static 'editor/js/OrbitControls.js' %}"></script>
<script src="{% static 'editor/js/OBJLoader.js' %}"></script>
<script src="{% static 'editor/js/OBJExporter.js' %}"></script>
<script src="{% static 'editor/js/ColladaLoader.js' %}"></script>
<script src="{% static 'editor/js/GLTFLoader.js' %}"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"> </script>

 <!-- load the static resources for the editor main.js  -->
{% with mannequin_path="editor/models/xyz.gltf" %}
<script>
  var mannequin_path = "{{ mannequin_path }}";
  var mannequin_url="{% static mannequin_path %}";
  var material_url="{% static 'editor/textures/abstract-art-attractive-1122400.jpg' %}";
  var csrf = "{{ csrf_token }}"
</script>
{% endwith %}
<script src="{% static 'editor/js/main.js' %}"></script>

{% if preview %}
  <script>
  var preview = "{{ preview|safe }}";
  let loader = new THREE.GLTFLoader();
  loader.parse( preview, '', function ( gltf ) {
      const model = gltf.scene;
      model.traverse((o) => {
        if (o.isMesh) {
          o.material = generic_material;
        }
      });
      garment = model;
      scene.add( model );
    },
    function( gltf ) {
        console.log("no");
    }
  );
</script>
{% endif %}

В браузере я получаю сообщение об ошибке: "Uncaught SyntaxError: Unexpected identifier (at (index):66:82)"

Строка, о которой идет речь, гласит:

var preview = "b'glTF\x02\x00\x00\x00\x18\xc1\x00\x00\x0c\x03\x00\x00JSON{"scene":0,"scenes":[{"nodes":[0]}],"asset":{"version":"2.0","generator":"https://github. com/mikedh/trimesh"},"accessors":[{"componentType":5125,"type":"SCALAR","bufferView":0,"count":8664,"max":[1163],"min":[0]},{"componentType":5126,"type":"VEC3","byteOffset":0,"bufferView":1,"count":1164,"max":[0. 17265082895755768,1.5097070932388306,0.12908484041690826],"min":[-0. 3401854634284973,1.0074307918548584,-0. 24667978286743164]}],"meshes":[{"name":"geometry_0","extras":{"processed":true},"primitives":[{"attributes":{"POSITION":1},"indices":0,"mode":4}]}],"nodes":[{"name":"preview","children": [1]},{"name":"geometry_0","mesh":0}],"buffers":[{"byteLength":48624}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":34656},{"buffer":0,"byteOffset":34656,"byteLength":13968}]} \xf0\xbd\x00\x00BIN\x00\x00\x00\x00\x00\x14\x00\x00\x00\x15\x00\ [... эта часть удалена ...] e\xce\x12\xa3?\xb6M\x85\xbd'";

Я пробовал до сих пор:

  • для преобразования в json (ошибка python: невозможно преобразовать объект в json)
  • для декодирования двоичной строки в python (ошибка python: невозможно декодировать из-за того, что некоторые символы не соответствуют utf-8)
  • установить content_type всего представления в "model/gltf-binary" (сгенерирован файл, который браузер загрузил)

Кто-нибудь делал это раньше? Могу ли я указать content_type только одной контекстной переменной, а не всего представления? Или есть другой способ отправить динамические ресурсы пользователю, не сохраняя их в базе данных и не обслуживая файл через url?

Вернуться на верх