Как получить динамически созданный 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?