{"id":475920,"date":"2026-04-14T14:17:13","date_gmt":"2026-04-14T14:17:13","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=475920"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=475920","title":{"rendered":"WebGPU, \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 Orillusion \u0438 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u044b: \u043a\u0430\u043a \u044f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b 4D \u0422\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/00b\/7dc\/2e9\/00b7dc2e9da891569262e4fe22998568.png\" alt=\"orillusion \u0422\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u044b\" title=\"orillusion \u0422\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u044b\" width=\"1918\" height=\"931\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/00b\/7dc\/2e9\/00b7dc2e9da891569262e4fe22998568.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/00b\/7dc\/2e9\/00b7dc2e9da891569262e4fe22998568.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>orillusion \u0422\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u044b<\/figcaption><\/div>\n<\/figure>\n<p>WebGPU \u2014  \u044d\u0442\u043e \u043d\u043e\u0432\u044b\u0439 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c \u0432\u0438\u0434\u0435\u043e\u043a\u0430\u0440\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u0443\u0436\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043b\u0435\u0442 \u0445\u043e\u0447\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u0432\u043e\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435. \u0414\u0432\u0430 \u0433\u043e\u0434\u0430, \u0434\u0430\u0436\u0435 \u0441 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u043c\u0438 \u0444\u043b\u0430\u0433\u0430\u043c\u0438, \u0443 \u043c\u0435\u043d\u044f \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u043e\u0441\u044c \u0441 \u043c\u043e\u0435\u0439 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u0432\u0438\u0434\u0435\u043e\u043a\u0430\u0440\u0442\u043e\u0439 \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 WebGL, WebGPU \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u0441 \u043d\u0443\u043b\u044f \u043f\u043e\u0434 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 GPU, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043d\u0430\u0434 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f\u043c\u0438, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 compute-\u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432 \u0438 \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445.<\/p>\n<p>\u041d\u043e \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u044d\u0442\u0430 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0438\u0437 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 webGPU \u0443\u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0432 Chrome, Edge \u0438 Firefox (\u043f\u043e\u0434 \u0444\u043b\u0430\u0433\u043e\u043c). \u0412\u0441\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0443 \u043c\u0435\u043d\u044f \u043d\u0430 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435 \u0438 \u044f \u0440\u0435\u0448\u0438\u043b \u0433\u043b\u0443\u0431\u0436\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u044d\u0442\u043e\u0439 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0435\u0439.<\/p>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u0447\u0442\u043e \u0442\u043e \u044f \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435, \u043a\u0430\u043a\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u0443\u0436\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u041d\u0438\u0436\u0435 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f.<\/p>\n<h4>\u0421\u0440\u0430\u0432\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437 WebGPU\/WebGL \u0434\u0432\u0438\u0436\u043a\u043e\u0432<\/h4>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0425\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0430<\/p>\n<\/th>\n<th>\n<p align=\"left\">Orillusion<\/p>\n<\/th>\n<th>\n<p align=\"left\">Three.js<\/p>\n<\/th>\n<th>\n<p align=\"left\">Babylon.js<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>\u0411\u0430\u0437\u043e\u0432\u0430\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">WebGPU (\u043d\u0430\u0442\u0438\u0432\u043d\u0430\u044f)<\/p>\n<\/td>\n<td>\n<p align=\"left\">WebGL\/WebGPU<\/p>\n<\/td>\n<td>\n<p align=\"left\">WebGL\/WebGPU<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">ECS<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041e\u041e\u041f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041e\u041e\u041f<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 WebGPU<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u2705 \u041f\u043e\u043b\u043d\u0430\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u26a0\ufe0f \u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u2705 \u0421\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u0430\u044f<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>Compute Shaders<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u2705 \u041d\u0430\u0442\u0438\u0432\u043d\u0430\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u26a0\ufe0f \u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u0430\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u2705 \u0425\u043e\u0440\u043e\u0448\u0430\u044f<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>\u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041e\u0447\u0435\u043d\u044c \u0432\u044b\u0441\u043e\u043a\u0430\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0412\u044b\u0441\u043e\u043a\u0430\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0412\u044b\u0441\u043e\u043a\u0430\u044f<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>\u041f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0434\u0430<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0412\u044b\u0441\u043e\u043a\u0438\u0439<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0438\u0437\u043a\u0438\u0439<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0421\u0440\u0435\u0434\u043d\u0438\u0439<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0420\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0430\u044f\u0441\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041e\u0442\u043b\u0438\u0447\u043d\u0430\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0425\u043e\u0440\u043e\u0448\u0430\u044f<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>\u0421\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041e\u0433\u0440\u043e\u043c\u043d\u043e\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0411\u043e\u043b\u044c\u0448\u043e\u0435<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043f\u043b\u044e\u0441\u044b, \u043e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Three.js \u0438 Babylon.js \u044f \u0432\u0441\u0435 \u0442\u0430\u043a\u0438 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f \u043d\u0430 <strong>Orillusion, <\/strong>\u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0434\u0432\u0438\u0436\u043e\u043a, \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 WebGPU. \u041e\u043d \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u0441 \u043d\u0443\u043b\u044f \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u043d\u043e\u0432\u044b\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 API.<\/p>\n<h4>\u041f\u043e\u0447\u0435\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442<\/h4>\n<p>\u0418\u0437\u0443\u0447\u0438\u0432 <a href=\"https:\/\/www.orillusion.com\/en\/guide\/\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e Orillusion<\/a>, \u044f \u0437\u0430\u043c\u0435\u0442\u0438\u043b, \u0447\u0442\u043e \u043c\u043d\u0435 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432. \u042f \u043d\u0430\u0448\u0435\u043b \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432, \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u0430 \u043f\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043d\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u044b\u0439\/\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440 \u0441 \u043d\u0443\u043b\u044f \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0435\u0433\u043e \u043a \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0443, \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0435\u0442. \u0422\u043e, \u0447\u0442\u043e \u043d\u0430\u0448\u0435\u043b \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043f\u0440\u043e <a href=\"https:\/\/www.orillusion.com\/en\/guide\/advanced\/shader\/shader_unlit.html\" rel=\"noopener noreferrer nofollow\">Unlit Material<\/a>, \u0434\u0430\u0451\u0442 \u043e\u0431\u0449\u0435\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c, \u043d\u043e \u043d\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430. \u041d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0441 \u043a\u0430\u043a\u0438\u043c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0448\u0435\u0439\u0434\u0435\u0440\u044b, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0438 \u0438 \u043a\u0430\u043a \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c compute-\u0448\u0435\u0439\u0434\u0435\u0440\u044b.<\/p>\n<p>\u042f \u0440\u0435\u0448\u0438\u043b \u044d\u0442\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c. \u041c\u043e\u044f \u0446\u0435\u043b\u044c \u0431\u044b\u043b\u0430 \u2014 <strong>\u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0441 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u043c\u0438 \u0448\u0435\u0439\u0434\u0435\u0440\u0430\u043c\u0438 \u0441 \u043d\u0443\u043b\u044f<\/strong> \u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0438\u0437\u043d\u0443\u0442\u0440\u0438. \u041f\u043b\u0430\u043d \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439:<\/p>\n<ul>\n<li>\n<p>\u041f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u044b \u0438 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0445 \u0441 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0435\u0439<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c\u0438 \u0438 uniform-\u0431\u0443\u0444\u0435\u0440\u0430\u043c\u0438<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c compute-\u0448\u0435\u0439\u0434\u0435\u0440\u044b \u0434\u043b\u044f GPU-\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439<\/p>\n<\/li>\n<li>\n<p><strong>\u0420\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u043e\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0438\u043d\u0433\u0430<\/strong> \u2014 \u043a\u0430\u043a \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 (\u043f\u043e\u0437\u0438\u0446\u0438\u0438, \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f) \u0437\u0430 \u043e\u0434\u0438\u043d draw call<\/p>\n<\/li>\n<\/ul>\n<p>\u041c\u043e\u0435\u0439 \u0446\u0435\u043b\u044c\u044e \u0441\u0442\u0430\u043b\u043e \u043f\u0440\u043e\u0439\u0442\u0438 \u0432\u0435\u0441\u044c \u043f\u0443\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u044b \u0441 \u043d\u0443\u043b\u044f, \u0447\u0442\u043e\u0431\u044b \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432 \u0441\u0432\u043e\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435.<\/p>\n<h4>\u041c\u0438\u043d\u0443\u0441\u044b, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u044f \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f<\/h4>\n<ol>\n<li>\n<p><strong>\u041c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e<\/strong> \u2014 \u043d\u0430\u0439\u0442\u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0441\u043b\u043e\u0436\u043d\u0435\u0435, \u0447\u0435\u043c \u0434\u043b\u044f Three.js.<\/p>\n<\/li>\n<li>\n<p><strong>\u0420\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0430\u044f\u0441\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/strong> \u2014 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0435\u0449\u0451 \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b. <strong>\u041f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u0442.<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u0412\u044b\u0441\u043e\u043a\u0438\u0439 \u043f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0434\u0430<\/strong> \u2014 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f WebGPU \u0438 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0439.<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u043e \u043d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u044d\u0442\u043e, <strong>\u043d\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 Compute Shaders, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 ECS \u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043b\u0435\u0433\u0430\u0441\u0438-\u043a\u043e\u0434\u0430 WebGL<\/strong> \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0438\u043b\u0438 \u043c\u0438\u043d\u0443\u0441\u044b.<\/p>\n<h3>\u041f\u0440\u043e\u0435\u043a\u0442: 4D \u0422\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442 \u043d\u0430 WebGPU<\/h3>\n<p>\u042f \u0441\u043e\u0437\u0434\u0430\u043b <strong>\u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u0443\u044e 3D-\u0441\u0446\u0435\u043d\u0443 \u0441 \u043f\u044f\u0442\u044c\u044e \u0442\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u0430\u043c\u0438 (4D-\u0433\u0438\u043f\u0435\u0440\u043a\u0443\u0431\u0430\u043c\u0438)<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 \u0447\u0435\u0442\u044b\u0440\u0451\u0445\u043c\u0435\u0440\u043d\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c:<\/p>\n<ul>\n<li>\n<p>WebGPU (\u0447\u0435\u0440\u0435\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 Orillusion)<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u044b\u0445\/\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0445 \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432 \u043d\u0430 WGSL<\/p>\n<\/li>\n<li>\n<p>Compute-\u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432 \u0434\u043b\u044f GPU-\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439<\/p>\n<\/li>\n<\/ul>\n<h3>\u042d\u0442\u0430\u043f 1: \u041f\u0435\u0440\u0432\u044b\u0439 \u043a\u0443\u0431 \u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043a\u0443\u0431 \u0441 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u043c \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u043c. \u0418 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438.<\/p>\n<h4>\u041e\u0448\u0438\u0431\u043a\u0430 1: \u041d\u0435\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0438<\/h4>\n<p>\u0428\u0435\u0439\u0434\u0435\u0440 \u043e\u0436\u0438\u0434\u0430\u043b \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044f \u043d\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0430. \u0412 Orillusion \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043d\u0443\u0436\u043d\u043e \u044f\u0432\u043d\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <code>setAttribute()<\/code>.<\/p>\n<h4>\u041e\u0448\u0438\u0431\u043a\u0430 2: \u0424\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c 4 \u0441\u043b\u043e\u0442\u0430<\/h4>\n<pre><code>Color target has no corresponding fragment stage output<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u0432 Orillusion \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440 <strong>\u043e\u0431\u044f\u0437\u0430\u043d<\/strong> \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e \u0432\u0441\u0435 4 render target \u0441\u043b\u043e\u0442\u0430:<\/p>\n<pre><code>struct FragmentOutput {    @location(0) color: vec4&lt;f32&gt;,      \/\/ \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0446\u0432\u0435\u0442    @location(1) dummy1: vec4&lt;f32&gt;,     \/\/ \u041f\u0443\u0441\u0442\u044b\u0448\u043a\u0430    @location(2) dummy2: vec4&lt;f32&gt;,     \/\/ \u041f\u0443\u0441\u0442\u044b\u0448\u043a\u0430    @location(3) dummy3: vec4&lt;f32&gt;,     \/\/ \u041f\u0443\u0441\u0442\u044b\u0448\u043a\u0430}@fragmentfn main(@location(0) v_color: vec4&lt;f32&gt;) -&gt; FragmentOutput {    var output: FragmentOutput;    output.color = v_color;    output.dummy1 = vec4&lt;f32&gt;(0.0);    output.dummy2 = vec4&lt;f32&gt;(0.0);    output.dummy3 = vec4&lt;f32&gt;(0.0);    return output;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u042d\u0442\u0430\u043f 2: \u0413\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044f \u0442\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u0430<\/h3>\n<p>\u0422\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442 \u0438\u043c\u0435\u0435\u0442 <strong>16 \u0432\u0435\u0440\u0448\u0438\u043d<\/strong> \u0432 4D-\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435 (\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b x, y, z, w) \u0438 <strong>32 \u0440\u0435\u0431\u0440\u0430<\/strong>:<\/p>\n<pre><code class=\"javascript\">const vertices4D = [    [-1,-1,-1,-1], [ 1,-1,-1,-1], [ 1,-1, 1,-1], [-1,-1, 1,-1],    [-1, 1,-1,-1], [ 1, 1,-1,-1], [ 1, 1, 1,-1], [-1, 1, 1,-1],    [-1,-1,-1, 1], [ 1,-1,-1, 1], [ 1,-1, 1, 1], [-1,-1, 1, 1],    [-1, 1,-1, 1], [ 1, 1,-1, 1], [ 1, 1, 1, 1], [-1, 1, 1, 1]];<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u042d\u0442\u0430\u043f 3: \u0410\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0447\u0435\u0440\u0435\u0437 ComponentBase<\/h3>\n<p>\u0414\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043c\u0435\u0442\u043e\u0434 <code><strong>onUpdate()<\/strong><\/code> \u0438\u0437 <code>ComponentBase<\/code>:<\/p>\n<pre><code class=\"javascript\">class TesseractComponent extends ComponentBase {    onUpdate() {        \/\/ \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0434\u0440 \u0434\u0432\u0438\u0436\u043a\u043e\u043c        this.updateRotation();    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u042d\u0442\u0430\u043f 4: 4D-\u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0432 \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u043e\u043c \u0448\u0435\u0439\u0434\u0435\u0440\u0435<\/h3>\n<p>\u0412 4D \u043e\u0431\u044a\u0435\u043a\u0442 \u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 <strong>\u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u0438<\/strong> (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, XW). \u0424\u043e\u0440\u043c\u0443\u043b\u0430:<\/p>\n<pre><code>x' = x\u00b7cos(\u03b1) \u2014 w\u00b7sin(\u03b1)w' = x\u00b7sin(\u03b1) + w\u00b7cos(\u03b1)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u0448\u0435\u0439\u0434\u0435\u0440\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0432 \u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u044f\u0445 XW, YW, ZW:<\/p>\n<pre><code>fn rotate4D(p: vec4&lt;f32&gt;, data: TransformData) -&gt; vec4&lt;f32&gt; {    var pos = p;        let cosXW = cos(data.angleXW);    let sinXW = sin(data.angleXW);    let x1 = pos.x * cosXW - pos.w * sinXW;    let w1 = pos.x * sinXW + pos.w * cosXW;    pos.x = x1;    pos.w = w1;        \/\/ \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u043b\u044f YW \u0438 ZW...        return pos;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u041f\u0440\u043e\u0435\u043a\u0446\u0438\u044f 4D \u2192 3D<\/h4>\n<pre><code>fn project4D(pos4D: vec4&lt;f32&gt;, data: TransformData) -&gt; vec3&lt;f32&gt; {    let perspective = data.perspectiveDistance \/                       (data.perspectiveDistance + pos4D.w * 0.4);    return vec3&lt;f32&gt;(        pos4D.x * perspective,        pos4D.y * perspective,        pos4D.z * perspective    );}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u042d\u0442\u0430\u043f 5: Compute-\u0448\u0435\u0439\u0434\u0435\u0440 \u0434\u043b\u044f GPU-\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439<\/h3>\n<h4>\u0417\u0430\u0447\u0435\u043c \u043d\u0443\u0436\u0435\u043d Compute Shader?<\/h4>\n<p>\u0423\u0433\u043b\u044b \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0434\u0440. \u0412\u043c\u0435\u0441\u0442\u043e CPU-\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e GPU \u0447\u0442\u043e \u0431\u044b \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043f\u043e\u043a\u0438\u0434\u0430\u043b\u0438 \u0432\u0438\u0434\u0435\u043e\u043f\u0430\u043c\u044f\u0442\u044c.<\/p>\n<h4>\u0412\u0430\u0436\u043d\u043e! \u0412\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445<\/h4>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0432 <code>StorageGPUBuffer<\/code> \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u043a\u0440\u0430\u0442\u043d\u043e\u0439 <strong>16 \u0431\u0430\u0439\u0442\u0430\u043c<\/strong>:<\/p>\n<pre><code>struct TransformData {    time: f32,    angleXW: f32,    angleYW: f32,    angleZW: f32,    angleXY: f32,    angleXZ: f32,    angleYZ: f32,    perspectiveDistance: f32,    scale: f32,    _pad1: f32,   \/\/ \u043f\u0430\u0434\u0434\u0438\u043d\u0433\u0438 \u0434\u043e 48 \u0431\u0430\u0439\u0442    _pad2: f32,    _pad3: f32,}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u041a\u043e\u0434 compute-\u0448\u0435\u0439\u0434\u0435\u0440\u0430<\/h4>\n<pre><code>@group(0) @binding(0) var&lt;storage, read_write&gt; transform: TransformData;@group(0) @binding(1) var&lt;uniform&gt; deltaTime: f32;@compute @workgroup_size(1, 1, 1)fn CsMain(@builtin(global_invocation_id) id: vec3&lt;u32&gt;) {    var data = transform;    data.time = data.time + deltaTime;        data.angleXW = data.time * 0.8;    data.angleYW = data.time * 0.6;    data.angleZW = data.time * 0.4;        data.perspectiveDistance = 3.5 + sin(data.time * 0.8) * 1.5;        transform = data;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/h4>\n<pre><code class=\"javascript\">onUpdate() {    const dt = 0.016 * this.speedMultiplier;    this.deltaBuffer.setFloat(0, dt);    this.deltaBuffer.apply();        const commandEncoder = webGPUContext.device.createCommandEncoder();    const computePass = commandEncoder.beginComputePass();    this.computeShader.compute(computePass);    computePass.end();    webGPUContext.device.queue.submit([commandEncoder.finish()]);}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u042d\u0442\u0430\u043f 6: \u0418\u043d\u0441\u0442\u0430\u043d\u0441\u0438\u043d\u0433<\/h3>\n<p>\u041e\u0434\u043d\u0430 \u0438\u0437 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0441\u0442\u0430\u043b\u0430 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c <strong>5 \u0442\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u043e\u0432<\/strong> \u043d\u0430 \u043e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438, \u043a\u0430\u0436\u0434\u044b\u0439 \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0435\u0439 \u0438 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c\u044e \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f, \u043d\u043e \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u0430\u0442\u0440\u0430\u0442\u0430\u043c\u0438.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0438\u043d\u0433. \u041e\u043d  \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c <code>instance_index<\/code> \u0432 \u0448\u0435\u0439\u0434\u0435\u0440\u0435:<\/p>\n<pre><code>@builtin(instance_index) instanceIndex: u32<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u0432\u0438\u0436\u043e\u043a \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u0442 \u043c\u0430\u0442\u0440\u0438\u0446\u044b \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 <code>models.matrix[instanceIndex]<\/code>. \u041c\u043d\u0435 \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e:<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0442\u044c 5 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 <code>Object3D<\/code> \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u044f\u043c\u0438 \u043d\u0430 \u043e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>TesseractComponent<\/code> \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0439 <code>speedMultiplier<\/code><\/p>\n<\/li>\n<li>\n<p>\u0412 \u0448\u0435\u0439\u0434\u0435\u0440\u0435 \u0443\u043c\u043d\u043e\u0436\u0438\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0432\u0435\u0440\u0448\u0438\u043d\u044b \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u043c\u0430\u0442\u0440\u0438\u0446\u0443:<\/p>\n<\/li>\n<\/ol>\n<pre><code>let worldPos = models.matrix[instanceIndex] * vec4&lt;f32&gt;(scaledPos, 1.0);output.position = globalUniform.projMat * globalUniform.viewMat * worldPos;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0432\u0441\u0435 5 \u0442\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u043e\u0432 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u044e\u0442\u0441\u044f <strong>\u0437\u0430 \u043e\u0434\u0438\u043d draw call<\/strong>, \u0447\u0442\u043e \u0434\u0430\u0451\u0442 \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u0439 \u0432\u044b\u0438\u0433\u0440\u044b\u0448 \u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0438 \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043e\u043f\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432.<\/p>\n<h3>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/h3>\n<p>\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0446\u0435\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 <strong>5 \u0442\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u043e\u0432<\/strong> \u043d\u0430 \u043e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0434\u0438\u0443\u0441\u043e\u043c 12 \u0435\u0434\u0438\u043d\u0438\u0446. \u041a\u0430\u0436\u0434\u044b\u0439 \u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c\u044e (0.5x, 1.0x, 1.5x, 2.0x, 1.2x).<\/p>\n<h3>\u0412\u044b\u0432\u043e\u0434\u044b<\/h3>\n<ol>\n<li>\n<p><strong>WebGPU \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438.<\/strong> Compute Shaders \u0440\u0430\u0437\u0433\u0440\u0443\u0436\u0430\u044e\u0442 CPU \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>Orillusion \u2014 \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u0432\u044b\u0431\u043e\u0440 \u0434\u043b\u044f \u044d\u043d\u0442\u0443\u0437\u0438\u0430\u0441\u0442\u043e\u0432.<\/strong> \u0421\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435, \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043d\u0435\u043f\u043e\u043b\u043d\u0430\u044f, \u043d\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 ECS \u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 WebGPU \u0441\u0442\u043e\u044f\u0442 \u0442\u043e\u0433\u043e. \u041f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0441\u043b\u043e\u0436\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p><strong>\u041a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u044b \u0432 orillusion \u2014 \u044d\u0442\u043e \u0441\u0442\u0440\u0430\u0448\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043d\u0430\u0447\u0430\u043b\u0435.<\/strong> \u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u2014 \u043f\u043e\u043d\u044f\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432, \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u043c \u0432\u044b\u0445\u043e\u0434\u0430\u043c.<\/p>\n<\/li>\n<li>\n<p><strong>\u0418\u043d\u0441\u0442\u0430\u043d\u0441\u0438\u043d\u0433 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u201c\u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438\u201d.<\/strong> Orillusion \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 <code>models.matrix[instance_index]<\/code>, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>instanceIndex<\/code> \u0432 \u0448\u0435\u0439\u0434\u0435\u0440\u0435.<\/p>\n<\/li>\n<\/ol>\n<hr\/>\n<p><strong>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u0430\u043c\u0438:<\/strong> \u043a\u043e\u0434 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 WebGPU (Chrome 113+, Edge 113+, Firefox Nightly). \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435: \u043c\u044b\u0448\u044c<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434 <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">&lt;!DOCTYPE html&gt;&lt;html lang=\"ru\"&gt;&lt;head&gt;  &lt;meta charset=\"UTF-8\"&gt;  &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\"&gt;  &lt;title&gt;Gaia Star Map - 4D \u0422\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442 | WebGPU&lt;\/title&gt;  &lt;style&gt;    * {      margin: 0;      padding: 0;      box-sizing: border-box;    }    html, body {      width: 100%;      height: 100%;      overflow: hidden;      margin: 0;      padding: 0;    }    body {      font-family: 'Segoe UI', 'Monaco', 'Menlo', 'Consolas', monospace;      background: #000;      position: fixed;      top: 0;      left: 0;      right: 0;      bottom: 0;    }    #canvas {      position: fixed;      top: 0;      left: 0;      width: 100vw;      height: 100vh;      display: block;      outline: none;      z-index: 1;      pointer-events: auto;    }        @keyframes pulse {      0%, 100% { opacity: 0.3; }      50% { opacity: 1; }    }  &lt;\/style&gt;&lt;\/head&gt;&lt;body&gt;&lt;canvas id=\"canvas\"&gt;&lt;\/canvas&gt;&lt;script type=\"importmap\"&gt;  {      \"imports\": {          \"@orillusion\/core\": \"https:\/\/unpkg.com\/@orillusion\/core@0.8.5-dev.9\/dist\/orillusion.es.js\"      }  }&lt;\/script&gt;&lt;script type=\"module\"&gt;  import {    Engine3D,    Scene3D,    Camera3D,    Object3D,    Vector3,    View3D,    AtmosphericComponent,    DirectLight,    HoverCameraController,    GeometryBase,    BoundingBox,    ShaderLib,    RenderShaderPass,    Shader,    Material,    PassType,    BlendMode,    GPUCompareFunction,    GPUCullMode,    UniformGPUBuffer,    StorageGPUBuffer,    ComponentBase,    ComputeShader,    MeshRenderer,    webGPUContext  } from '@orillusion\/core';    const vertices4D = [    [-1, -1, -1, -1], [ 1, -1, -1, -1], [ 1, -1,  1, -1], [-1, -1,  1, -1],    [-1,  1, -1, -1], [ 1,  1, -1, -1], [ 1,  1,  1, -1], [-1,  1,  1, -1],    [-1, -1, -1,  1], [ 1, -1, -1,  1], [ 1, -1,  1,  1], [-1, -1,  1,  1],    [-1,  1, -1,  1], [ 1,  1, -1,  1], [ 1,  1,  1,  1], [-1,  1,  1,  1]  ];  const edges = [    [0,1], [1,2], [2,3], [3,0], [4,5], [5,6], [6,7], [7,4],    [0,4], [1,5], [2,6], [3,7], [8,9], [9,10], [10,11], [11,8],    [12,13], [13,14], [14,15], [15,12], [8,12], [9,13], [10,14], [11,15],    [0,8], [1,9], [2,10], [3,11], [4,12], [5,13], [6,14], [7,15]  ];    class TesseractGeometry extends GeometryBase {    constructor() {      super();      const positions = [];      const wCoords = [];      const colors = [];      const indices = [];      let idx = 0;      for (let i = 0; i &lt; edges.length; i++) {        const v1 = vertices4D[edges[i][0]];        const v2 = vertices4D[edges[i][1]];        positions.push(v1[0], v1[1], v1[2]);        positions.push(v2[0], v2[1], v2[2]);        wCoords.push(v1[3], v2[3]);        const hue = i \/ edges.length;        colors.push(0.5 + 0.5 * Math.sin(hue * Math.PI * 2), 0.3, 0.7, 1.0);        colors.push(0.3, 0.5 + 0.5 * Math.sin(hue * Math.PI * 2), 0.7, 1.0);        indices.push(idx, idx + 1);        idx += 2;      }      this.setAttribute('a_position', new Float32Array(positions));      this.setAttribute('a_wCoord', new Float32Array(wCoords));      this.setAttribute('a_color', new Float32Array(colors));      this.setIndices(new Uint16Array(indices));      const subGeo = this.addSubGeometry({        indexStart: 0,        indexCount: indices.length,        vertexStart: 0,        vertexCount: idx,        firstStart: 0,        index: 0,        topology: 1      });      if (subGeo) {        subGeo.lodLevels = [{          indexStart: 0,          indexCount: indices.length,          vertexStart: 0,          vertexCount: idx,          firstStart: 0,          index: 0,          topology: 1        }];      }      const bounds = new BoundingBox();      bounds.min.set(-2.5, -2.5, -2.5);      bounds.max.set(2.5, 2.5, 2.5);      this.bounds = bounds;      this.name = 'TesseractGeometry';    }  }    const VS_NAME = 'tesseract_final_vs';  const FS_NAME = 'tesseract_final_fs';  const COMPUTE_NAME = 'tesseract_final_compute';  const vsCode = `            #include \"GlobalUniform\"            #include \"WorldMatrixUniform\"                        struct TransformData {                time: f32,                angleXW: f32,                angleYW: f32,                angleZW: f32,                angleXY: f32,                angleXZ: f32,                angleYZ: f32,                perspectiveDistance: f32,                scale: f32,                _pad1: f32,                _pad2: f32,                _pad3: f32,            }                        @group(1) @binding(0) var&lt;storage, read&gt; transformData: TransformData;                        struct VertexOutput {                @builtin(position) position: vec4&lt;f32&gt;,                @location(0) v_color: vec4&lt;f32&gt;,            }                        fn rotate4D(p: vec4&lt;f32&gt;, data: TransformData) -&gt; vec4&lt;f32&gt; {                var pos = p;                                let cosXW = cos(data.angleXW);                let sinXW = sin(data.angleXW);                let x1 = pos.x * cosXW - pos.w * sinXW;                let w1 = pos.x * sinXW + pos.w * cosXW;                pos.x = x1;                pos.w = w1;                                let cosYW = cos(data.angleYW);                let sinYW = sin(data.angleYW);                let y1 = pos.y * cosYW - pos.w * sinYW;                let w2 = pos.y * sinYW + pos.w * cosYW;                pos.y = y1;                pos.w = w2;                                let cosZW = cos(data.angleZW);                let sinZW = sin(data.angleZW);                let z1 = pos.z * cosZW - pos.w * sinZW;                let w3 = pos.z * sinZW + pos.w * cosZW;                pos.z = z1;                pos.w = w3;                                return pos;            }                        fn project4D(pos4D: vec4&lt;f32&gt;, data: TransformData) -&gt; vec3&lt;f32&gt; {                let perspective = data.perspectiveDistance \/ (data.perspectiveDistance + pos4D.w * 0.4);                return vec3&lt;f32&gt;(pos4D.x * perspective, pos4D.y * perspective, pos4D.z * perspective);            }                        @vertex            fn main(                @builtin(instance_index) instanceIndex: u32,                @location(0) a_position: vec3&lt;f32&gt;,                @location(1) a_wCoord: f32,                @location(2) a_color: vec4&lt;f32&gt;            ) -&gt; VertexOutput {                var output: VertexOutput;                                let pos4D = vec4&lt;f32&gt;(a_position.x, a_position.y, a_position.z, a_wCoord);                let rotated4D = rotate4D(pos4D, transformData);                let pos3D = project4D(rotated4D, transformData);                let scaledPos = pos3D * transformData.scale;                                let worldPos = models.matrix[instanceIndex] * vec4&lt;f32&gt;(scaledPos, 1.0);                output.position = globalUniform.projMat * globalUniform.viewMat * worldPos;                                let brightness = 0.6 + 0.4 * sin(transformData.time * 3.0 + rotated4D.w * 5.0);                output.v_color = vec4&lt;f32&gt;(                    a_color.r * brightness,                    a_color.g * brightness,                    a_color.b * brightness,                    1.0                );                                return output;            }        `;  const fsCode = `            struct FragmentOutput {                @location(0) color: vec4&lt;f32&gt;,                @location(1) dummy1: vec4&lt;f32&gt;,                @location(2) dummy2: vec4&lt;f32&gt;,                @location(3) dummy3: vec4&lt;f32&gt;,            }                        @fragment            fn main(                @location(0) v_color: vec4&lt;f32&gt;            ) -&gt; FragmentOutput {                var output: FragmentOutput;                output.color = v_color;                output.dummy1 = vec4&lt;f32&gt;(0.0);                output.dummy2 = vec4&lt;f32&gt;(0.0);                output.dummy3 = vec4&lt;f32&gt;(0.0);                return output;            }        `;  const computeCode = `            struct TransformData {                time: f32,                angleXW: f32,                angleYW: f32,                angleZW: f32,                angleXY: f32,                angleXZ: f32,                angleYZ: f32,                perspectiveDistance: f32,                scale: f32,                _pad1: f32,                _pad2: f32,                _pad3: f32,            }                        @group(0) @binding(0) var&lt;storage, read_write&gt; transform: TransformData;            @group(0) @binding(1) var&lt;uniform&gt; deltaTime: f32;                        @compute @workgroup_size(1, 1, 1)            fn CsMain(@builtin(global_invocation_id) id: vec3&lt;u32&gt;) {                var data = transform;                data.time = data.time + deltaTime;                                data.angleXW = data.time * 0.8;                data.angleYW = data.time * 0.6;                data.angleZW = data.time * 0.4;                data.angleXY = data.time * 0.5;                data.angleXZ = data.time * 0.7;                data.angleYZ = data.time * 0.3;                                data.perspectiveDistance = 3.5 + sin(data.time * 0.8) * 1.5;                data.scale = 1.0;                                transform = data;            }        `;  \/\/ ============================================================================  \/\/ \u041a\u041e\u041c\u041f\u041e\u041d\u0415\u041d\u0422 \u0422\u0415\u0421\u0421\u0415\u0420\u0410\u041a\u0422\u0410  \/\/ ============================================================================  class TesseractComponent extends ComponentBase {    constructor() {      super();      this.geometry = null;      this.transformBuffer = null;      this.deltaBuffer = null;      this.computeShader = null;      this.speedMultiplier = 1.0;    }    start() {      this.geometry = new TesseractGeometry();      this.transformBuffer = new StorageGPUBuffer(12 * 4);      const initialData = new Float32Array(12);      initialData[0] = 0;      initialData[1] = 0;      initialData[2] = 0;      initialData[3] = 0;      initialData[4] = 0;      initialData[5] = 0;      initialData[6] = 0;      initialData[7] = 4.0;      initialData[8] = 1.0;      initialData[9] = 0;      initialData[10] = 0;      initialData[11] = 0;      this.transformBuffer.outFloat32Array = initialData;      this.transformBuffer.apply();      this.deltaBuffer = new UniformGPUBuffer(4);      const renderPass = new RenderShaderPass(VS_NAME, FS_NAME);      renderPass.passType = PassType.COLOR;      renderPass.blendMode = BlendMode.NORMAL;      renderPass.depthWriteEnabled = true;      renderPass.depthCompare = GPUCompareFunction.less;      renderPass.cullMode = GPUCullMode.none;      renderPass.topology = 'line-list';      renderPass.setStorageBuffer('transformData', this.transformBuffer);      const shader = new Shader();      shader.addRenderPass(renderPass);      const material = new Material();      material.shader = shader;      const renderer = this.object3D.addComponent(MeshRenderer);      renderer.geometry = this.geometry;      renderer.material = material;      this.computeShader = new ComputeShader(computeCode);      this.computeShader.setStorageBuffer('transform', this.transformBuffer);      this.computeShader.setUniformBuffer('deltaTime', this.deltaBuffer);      this.computeShader.workerSizeX = 1;      this.computeShader.workerSizeY = 1;      this.computeShader.workerSizeZ = 1;    }    onUpdate() {      if (!this.computeShader || !this.deltaBuffer) return;      const dt = 0.016 * this.speedMultiplier;      this.deltaBuffer.setFloat(0, dt);      this.deltaBuffer.apply();      const commandEncoder = webGPUContext.device.createCommandEncoder();      const computePass = commandEncoder.beginComputePass();      this.computeShader.compute(computePass);      computePass.end();      webGPUContext.device.queue.submit([commandEncoder.finish()]);    }    destroy(force) {      if (this.transformBuffer) this.transformBuffer.destroy();      if (this.deltaBuffer) this.deltaBuffer.destroy();      if (this.computeShader) this.computeShader.destroy();      super.destroy(force);    }  }    function getCirclePosition(radius, angleDeg, yOffset = 0) {    const angleRad = angleDeg * Math.PI \/ 180;    return new Vector3(            Math.cos(angleRad) * radius,            yOffset,            Math.sin(angleRad) * radius    );  }    let frameCount = 0;  let lastTime = performance.now();  async function init() {    console.log('\ud83d\ude80 \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Engine3D...');    \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c canvas \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0440\u0430\u0437\u043c\u0435\u0440\u044b \u043d\u0430 100%    const canvas = document.getElementById('canvas');    canvas.style.width = '100vw';    canvas.style.height = '100vh';    canvas.width = window.innerWidth;    canvas.height = window.innerHeight;    await Engine3D.init({      canvasConfig: {        canvas: canvas,        devicePixelRatio: window.devicePixelRatio      }    });    console.log('\u2705 Engine3D \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d');    \/\/ \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432    ShaderLib.register(VS_NAME, vsCode);    ShaderLib.register(FS_NAME, fsCode);    ShaderLib.register(COMPUTE_NAME, computeCode);    console.log('\u2705 \u0428\u0435\u0439\u0434\u0435\u0440\u044b \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u044b');    \/\/ \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0446\u0435\u043d\u044b    const scene = new Scene3D();    scene.name = 'TesseractScene';    \/\/ \u041a\u0430\u043c\u0435\u0440\u0430    const cameraObj = new Object3D();    cameraObj.name = 'Camera';    const camera = cameraObj.addComponent(Camera3D);    camera.perspective(60, Engine3D.aspect, 0.1, 1000);    cameraObj.transform.localPosition = new Vector3(0, 5, 18);    cameraObj.transform.lookAt(new Vector3(0, 0, 0), new Vector3(0, 1, 0));    scene.addChild(cameraObj);    const controller = cameraObj.addComponent(HoverCameraController);    controller.setCamera(0, -15, 18);    scene.addComponent(AtmosphericComponent).sunY = 0.6;    const light = new Object3D();    light.addComponent(DirectLight);    scene.addChild(light);    const radius = 12;    const angles = [0, 72, 144, 216, 288];    const speeds = [0.5, 1.0, 1.5, 2.0, 1.2];    const scales = [0.8, 1.0, 1.2, 0.9, 1.1];    console.log('\ud83d\udd27 \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 5 \u0442\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u043e\u0432...');    angles.forEach((angle, index) =&gt; {      const position = getCirclePosition(radius, angle, 0);      const container = new Object3D();      container.name = `Tesseract_${index}`;      container.transform.localPosition = position;      container.transform.localScale = new Vector3(scales[index], scales[index], scales[index]);      const comp = container.addComponent(TesseractComponent);      comp.speedMultiplier = speeds[index];      scene.addChild(container);      console.log(`   \u2022 \u0418\u043d\u0441\u0442\u0430\u043d\u0441 ${index}: \u0443\u0433\u043e\u043b ${angle}\u00b0, \u043f\u043e\u0437\u0438\u0446\u0438\u044f (${position.x.toFixed(1)}, ${position.z.toFixed(1)}), \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c ${speeds[index]}x`);    });    \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0441\u0447\u0451\u0442\u0447\u0438\u043a \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432    const objCountElem = document.getElementById('objectCount');    if (objCountElem) objCountElem.textContent = `\u041e\u0431\u044a\u0435\u043a\u0442\u043e\u0432: ${angles.length}`;    const view = new View3D();    view.scene = scene;    view.camera = camera;    Engine3D.startRenderView(view);    window.addEventListener('resize', () =&gt; {      const canvas = document.getElementById('canvas');      canvas.width = window.innerWidth;      canvas.height = window.innerHeight;      camera.aspect = Engine3D.aspect;      camera.perspective(60, Engine3D.aspect, 0.1, 1000);    });    function updateFPS() {      const now = performance.now();      const delta = now - lastTime;      if (delta &gt;= 1000) {        const fps = Math.round((frameCount * 1000) \/ delta);        const fpsElement = document.getElementById('fps');        if (fpsElement) fpsElement.textContent = `FPS: ${fps}`;        frameCount = 0;        lastTime = now;      }      frameCount++;      requestAnimationFrame(updateFPS);    }    lastTime = performance.now();    requestAnimationFrame(updateFPS);    console.log('\u2705 \u0422\u0415\u0421\u0421\u0415\u0420\u0410\u041a\u0422\u042b \u0421\u041e\u0417\u0414\u0410\u041d\u042b!');    console.log('   \u2022 5 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043d\u0430 \u043e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438');    console.log('   \u2022 4D \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 Compute Shader');    console.log('   \u2022 \u0420\u0430\u0437\u043d\u044b\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f');  }  init().catch(console.error);&lt;\/script&gt;&lt;\/body&gt;&lt;\/html&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1023432\/\">https:\/\/habr.com\/ru\/articles\/1023432\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>orillusion \u0422\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u044bWebGPU \u2014  \u044d\u0442\u043e \u043d\u043e\u0432\u044b\u0439 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c \u0432\u0438\u0434\u0435\u043e\u043a\u0430\u0440\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u0443\u0436\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043b\u0435\u0442 \u0445\u043e\u0447\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u0432\u043e\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435. \u0414\u0432\u0430 \u0433\u043e\u0434\u0430, \u0434\u0430\u0436\u0435 \u0441 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u043c\u0438 \u0444\u043b\u0430\u0433\u0430\u043c\u0438, \u0443 \u043c\u0435\u043d\u044f \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u043e\u0441\u044c \u0441 \u043c\u043e\u0435\u0439 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u0432\u0438\u0434\u0435\u043e\u043a\u0430\u0440\u0442\u043e\u0439 \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 WebGL, WebGPU \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u0441 \u043d\u0443\u043b\u044f \u043f\u043e\u0434 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 GPU, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043d\u0430\u0434 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f\u043c\u0438, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 compute-\u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432 \u0438 \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445.\u041d\u043e \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u044d\u0442\u0430 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0438\u0437 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 webGPU \u0443\u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0432 Chrome, Edge \u0438 Firefox (\u043f\u043e\u0434 \u0444\u043b\u0430\u0433\u043e\u043c). \u0412\u0441\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0443 \u043c\u0435\u043d\u044f \u043d\u0430 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435 \u0438 \u044f \u0440\u0435\u0448\u0438\u043b \u0433\u043b\u0443\u0431\u0436\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u044d\u0442\u043e\u0439 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0435\u0439.\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u0447\u0442\u043e \u0442\u043e \u044f \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435, \u043a\u0430\u043a\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u0443\u0436\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u041d\u0438\u0436\u0435 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f.\u0421\u0440\u0430\u0432\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437 WebGPU\/WebGL \u0434\u0432\u0438\u0436\u043a\u043e\u0432\u0425\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0430OrillusionThree.jsBabylon.js\u0411\u0430\u0437\u043e\u0432\u0430\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044fWebGPU (\u043d\u0430\u0442\u0438\u0432\u043d\u0430\u044f)WebGL\/WebGPUWebGL\/WebGPU\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430ECS\u041e\u041e\u041f\u041e\u041e\u041f\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 WebGPU\u2705 \u041f\u043e\u043b\u043d\u0430\u044f\u26a0\ufe0f \u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f\u2705 \u0421\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u0430\u044fCompute Shaders\u2705 \u041d\u0430\u0442\u0438\u0432\u043d\u0430\u044f\u26a0\ufe0f \u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u0430\u044f\u2705 \u0425\u043e\u0440\u043e\u0448\u0430\u044f\u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u041e\u0447\u0435\u043d\u044c \u0432\u044b\u0441\u043e\u043a\u0430\u044f\u0412\u044b\u0441\u043e\u043a\u0430\u044f\u0412\u044b\u0441\u043e\u043a\u0430\u044f\u041f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0434\u0430\u0412\u044b\u0441\u043e\u043a\u0438\u0439\u041d\u0438\u0437\u043a\u0438\u0439\u0421\u0440\u0435\u0434\u043d\u0438\u0439\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0420\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0430\u044f\u0441\u044f\u041e\u0442\u043b\u0438\u0447\u043d\u0430\u044f\u0425\u043e\u0440\u043e\u0448\u0430\u044f\u0421\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e\u041c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0435\u041e\u0433\u0440\u043e\u043c\u043d\u043e\u0435\u0411\u043e\u043b\u044c\u0448\u043e\u0435\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043f\u043b\u044e\u0441\u044b, \u043e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Three.js \u0438 Babylon.js \u044f \u0432\u0441\u0435 \u0442\u0430\u043a\u0438 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f \u043d\u0430 Orillusion, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0434\u0432\u0438\u0436\u043e\u043a, \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 WebGPU. \u041e\u043d \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u0441 \u043d\u0443\u043b\u044f \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u043d\u043e\u0432\u044b\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 API.\u041f\u043e\u0447\u0435\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442\u0418\u0437\u0443\u0447\u0438\u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e Orillusion, \u044f \u0437\u0430\u043c\u0435\u0442\u0438\u043b, \u0447\u0442\u043e \u043c\u043d\u0435 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432. \u042f \u043d\u0430\u0448\u0435\u043b \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432, \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u0430 \u043f\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043d\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u044b\u0439\/\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440 \u0441 \u043d\u0443\u043b\u044f \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0435\u0433\u043e \u043a \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0443, \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0435\u0442. \u0422\u043e, \u0447\u0442\u043e \u043d\u0430\u0448\u0435\u043b \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043f\u0440\u043e Unlit Material, \u0434\u0430\u0451\u0442 \u043e\u0431\u0449\u0435\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c, \u043d\u043e \u043d\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430. \u041d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0441 \u043a\u0430\u043a\u0438\u043c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0448\u0435\u0439\u0434\u0435\u0440\u044b, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0438 \u0438 \u043a\u0430\u043a \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c compute-\u0448\u0435\u0439\u0434\u0435\u0440\u044b.\u042f \u0440\u0435\u0448\u0438\u043b \u044d\u0442\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c. \u041c\u043e\u044f \u0446\u0435\u043b\u044c \u0431\u044b\u043b\u0430 \u2014 \u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0441 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u043c\u0438 \u0448\u0435\u0439\u0434\u0435\u0440\u0430\u043c\u0438 \u0441 \u043d\u0443\u043b\u044f \u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0438\u0437\u043d\u0443\u0442\u0440\u0438. \u041f\u043b\u0430\u043d \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439:\u041f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u044b \u0438 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0445 \u0441 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0435\u0439\u041d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c\u0438 \u0438 uniform-\u0431\u0443\u0444\u0435\u0440\u0430\u043c\u0438\u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c compute-\u0448\u0435\u0439\u0434\u0435\u0440\u044b \u0434\u043b\u044f GPU-\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439\u0420\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u043e\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0438\u043d\u0433\u0430 \u2014 \u043a\u0430\u043a \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 (\u043f\u043e\u0437\u0438\u0446\u0438\u0438, \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f) \u0437\u0430 \u043e\u0434\u0438\u043d draw call\u041c\u043e\u0435\u0439 \u0446\u0435\u043b\u044c\u044e \u0441\u0442\u0430\u043b\u043e \u043f\u0440\u043e\u0439\u0442\u0438 \u0432\u0435\u0441\u044c \u043f\u0443\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u044b \u0441 \u043d\u0443\u043b\u044f, \u0447\u0442\u043e\u0431\u044b \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432 \u0441\u0432\u043e\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435.\u041c\u0438\u043d\u0443\u0441\u044b, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u044f \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f\u041c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e \u2014 \u043d\u0430\u0439\u0442\u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0441\u043b\u043e\u0436\u043d\u0435\u0435, \u0447\u0435\u043c \u0434\u043b\u044f Three.js.\u0420\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0430\u044f\u0441\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u2014 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0435\u0449\u0451 \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b. \u041f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u0442.\u0412\u044b\u0441\u043e\u043a\u0438\u0439 \u043f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0434\u0430 \u2014 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f WebGPU \u0438 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0439.\u041d\u043e \u043d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u044d\u0442\u043e, \u043d\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 Compute Shaders, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 ECS \u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043b\u0435\u0433\u0430\u0441\u0438-\u043a\u043e\u0434\u0430 WebGL \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0438\u043b\u0438 \u043c\u0438\u043d\u0443\u0441\u044b.\u041f\u0440\u043e\u0435\u043a\u0442: 4D \u0422\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442 \u043d\u0430 WebGPU\u042f \u0441\u043e\u0437\u0434\u0430\u043b \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u0443\u044e 3D-\u0441\u0446\u0435\u043d\u0443 \u0441 \u043f\u044f\u0442\u044c\u044e \u0442\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u0430\u043c\u0438 (4D-\u0433\u0438\u043f\u0435\u0440\u043a\u0443\u0431\u0430\u043c\u0438), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 \u0447\u0435\u0442\u044b\u0440\u0451\u0445\u043c\u0435\u0440\u043d\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c:WebGPU (\u0447\u0435\u0440\u0435\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 Orillusion)\u041a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u044b\u0445\/\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0445 \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432 \u043d\u0430 WGSLCompute-\u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432 \u0434\u043b\u044f GPU-\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439\u042d\u0442\u0430\u043f 1: \u041f\u0435\u0440\u0432\u044b\u0439 \u043a\u0443\u0431 \u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043a\u0443\u0431 \u0441 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u043c \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u043c. \u0418 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438.\u041e\u0448\u0438\u0431\u043a\u0430 1: \u041d\u0435\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0438\u0428\u0435\u0439\u0434\u0435\u0440 \u043e\u0436\u0438\u0434\u0430\u043b \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044f \u043d\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0430. \u0412 Orillusion \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043d\u0443\u0436\u043d\u043e \u044f\u0432\u043d\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 setAttribute().\u041e\u0448\u0438\u0431\u043a\u0430 2: \u0424\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c 4 \u0441\u043b\u043e\u0442\u0430Color target has no corresponding fragment stage output\u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u0432 Orillusion \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440 \u043e\u0431\u044f\u0437\u0430\u043d \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e \u0432\u0441\u0435 4 render target \u0441\u043b\u043e\u0442\u0430:struct FragmentOutput {    @location(0) color: vec4&lt;f32&gt;,      \/\/ \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0446\u0432\u0435\u0442    @location(1) dummy1: vec4&lt;f32&gt;,     \/\/ \u041f\u0443\u0441\u0442\u044b\u0448\u043a\u0430    @location(2) dummy2: vec4&lt;f32&gt;,     \/\/ \u041f\u0443\u0441\u0442\u044b\u0448\u043a\u0430    @location(3) dummy3: vec4&lt;f32&gt;,     \/\/ \u041f\u0443\u0441\u0442\u044b\u0448\u043a\u0430}@fragmentfn main(@location(0) v_color: vec4&lt;f32&gt;) -&gt; FragmentOutput {    var output: FragmentOutput;    output.color = v_color;    output.dummy1 = vec4&lt;f32&gt;(0.0);    output.dummy2 = vec4&lt;f32&gt;(0.0);    output.dummy3 = vec4&lt;f32&gt;(0.0);    return output;}\u042d\u0442\u0430\u043f 2: \u0413\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044f \u0442\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u0430\u0422\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442 \u0438\u043c\u0435\u0435\u0442 16 \u0432\u0435\u0440\u0448\u0438\u043d \u0432 4D-\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435 (\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b x, y, z, w) \u0438 32 \u0440\u0435\u0431\u0440\u0430:const vertices4D = [    [-1,-1,-1,-1], [ 1,-1,-1,-1], [ 1,-1, 1,-1], [-1,-1, 1,-1],    [-1, 1,-1,-1], [ 1, 1,-1,-1], [ 1, 1, 1,-1], [-1, 1, 1,-1],    [-1,-1,-1, 1], [ 1,-1,-1, 1], [ 1,-1, 1, 1], [-1,-1, 1, 1],    [-1, 1,-1, 1], [ 1, 1,-1, 1], [ 1, 1, 1, 1], [-1, 1, 1, 1]];\u042d\u0442\u0430\u043f 3: \u0410\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0447\u0435\u0440\u0435\u0437 ComponentBase\u0414\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043c\u0435\u0442\u043e\u0434 onUpdate() \u0438\u0437 ComponentBase:class TesseractComponent extends ComponentBase {    onUpdate() {        \/\/ \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0434\u0440 \u0434\u0432\u0438\u0436\u043a\u043e\u043c        this.updateRotation();    }}\u042d\u0442\u0430\u043f 4: 4D-\u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0432 \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u043e\u043c \u0448\u0435\u0439\u0434\u0435\u0440\u0435\u0412 4D \u043e\u0431\u044a\u0435\u043a\u0442 \u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, XW). \u0424\u043e\u0440\u043c\u0443\u043b\u0430:x&#8217; = x\u00b7cos(\u03b1) \u2014 w\u00b7sin(\u03b1)w&#8217; = x\u00b7sin(\u03b1) + w\u00b7cos(\u03b1)\u0412 \u0448\u0435\u0439\u0434\u0435\u0440\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0432 \u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u044f\u0445 XW, YW, ZW:fn rotate4D(p: vec4&lt;f32&gt;, data: TransformData) -&gt; vec4&lt;f32&gt; {    var pos = p;        let cosXW = cos(data.angleXW);    let sinXW = sin(data.angleXW);    let x1 = pos.x * cosXW &#8212; pos.w * sinXW;    let w1 = pos.x * sinXW + pos.w * cosXW;    pos.x = x1;    pos.w = w1;        \/\/ \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u043b\u044f YW \u0438 ZW&#8230;        return pos;}\u041f\u0440\u043e\u0435\u043a\u0446\u0438\u044f 4D \u2192 3Dfn project4D(pos4D: vec4&lt;f32&gt;, data: TransformData) -&gt; vec3&lt;f32&gt; {    let perspective = data.perspectiveDistance \/                       (data.perspectiveDistance + pos4D.w * 0.4);    return vec3&lt;f32&gt;(        pos4D.x * perspective,        pos4D.y * perspective,        pos4D.z * perspective    );}\u042d\u0442\u0430\u043f 5: Compute-\u0448\u0435\u0439\u0434\u0435\u0440 \u0434\u043b\u044f GPU-\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439\u0417\u0430\u0447\u0435\u043c \u043d\u0443\u0436\u0435\u043d Compute Shader?\u0423\u0433\u043b\u044b \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0430\u0434\u0440. \u0412\u043c\u0435\u0441\u0442\u043e CPU-\u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e GPU \u0447\u0442\u043e \u0431\u044b \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043f\u043e\u043a\u0438\u0434\u0430\u043b\u0438 \u0432\u0438\u0434\u0435\u043e\u043f\u0430\u043c\u044f\u0442\u044c.\u0412\u0430\u0436\u043d\u043e! \u0412\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0432 StorageGPUBuffer \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u043a\u0440\u0430\u0442\u043d\u043e\u0439 16 \u0431\u0430\u0439\u0442\u0430\u043c:struct TransformData {    time: f32,    angleXW: f32,    angleYW: f32,    angleZW: f32,    angleXY: f32,    angleXZ: f32,    angleYZ: f32,    perspectiveDistance: f32,    scale: f32,    _pad1: f32,   \/\/ \u043f\u0430\u0434\u0434\u0438\u043d\u0433\u0438 \u0434\u043e 48 \u0431\u0430\u0439\u0442    _pad2: f32,    _pad3: f32,}\u041a\u043e\u0434 compute-\u0448\u0435\u0439\u0434\u0435\u0440\u0430@group(0) @binding(0) var&lt;storage, read_write&gt; transform: TransformData;@group(0) @binding(1) var&lt;uniform&gt; deltaTime: f32;@compute @workgroup_size(1, 1, 1)fn CsMain(@builtin(global_invocation_id) id: vec3&lt;u32&gt;) {    var data = transform;    data.time = data.time + deltaTime;        data.angleXW = data.time * 0.8;    data.angleYW = data.time * 0.6;    data.angleZW = data.time * 0.4;        data.perspectiveDistance = 3.5 + sin(data.time * 0.8) * 1.5;        transform = data;}\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442onUpdate() {    const dt = 0.016 * this.speedMultiplier;    this.deltaBuffer.setFloat(0, dt);    this.deltaBuffer.apply();        const commandEncoder = webGPUContext.device.createCommandEncoder();    const computePass = commandEncoder.beginComputePass();    this.computeShader.compute(computePass);    computePass.end();    webGPUContext.device.queue.submit([commandEncoder.finish()]);}\u042d\u0442\u0430\u043f 6: \u0418\u043d\u0441\u0442\u0430\u043d\u0441\u0438\u043d\u0433\u041e\u0434\u043d\u0430 \u0438\u0437 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0441\u0442\u0430\u043b\u0430 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c 5 \u0442\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u043e\u0432 \u043d\u0430 \u043e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438, \u043a\u0430\u0436\u0434\u044b\u0439 \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0435\u0439 \u0438 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c\u044e \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f, \u043d\u043e \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u0430\u0442\u0440\u0430\u0442\u0430\u043c\u0438.\u0414\u043b\u044f \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0438\u043d\u0433. \u041e\u043d  \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c instance_index \u0432 \u0448\u0435\u0439\u0434\u0435\u0440\u0435:@builtin(instance_index) instanceIndex: u32\u0414\u0432\u0438\u0436\u043e\u043a \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u0442 \u043c\u0430\u0442\u0440\u0438\u0446\u044b \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 models.matrix[instanceIndex]. \u041c\u043d\u0435 \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e:\u0421\u043e\u0437\u0434\u0430\u0442\u044c 5 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 Object3D \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u044f\u043c\u0438 \u043d\u0430 \u043e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 TesseractComponent \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0439 speedMultiplier\u0412 \u0448\u0435\u0439\u0434\u0435\u0440\u0435 \u0443\u043c\u043d\u043e\u0436\u0438\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0432\u0435\u0440\u0448\u0438\u043d\u044b \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u043c\u0430\u0442\u0440\u0438\u0446\u0443:let worldPos = models.matrix[instanceIndex] * vec4&lt;f32&gt;(scaledPos, 1.0);output.position = globalUniform.projMat * globalUniform.viewMat * worldPos;\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0432\u0441\u0435 5 \u0442\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u043e\u0432 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0437\u0430 \u043e\u0434\u0438\u043d draw call, \u0447\u0442\u043e \u0434\u0430\u0451\u0442 \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u0439 \u0432\u044b\u0438\u0433\u0440\u044b\u0448 \u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0438 \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043e\u043f\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432.\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0446\u0435\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 5 \u0442\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442\u043e\u0432 \u043d\u0430 \u043e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0434\u0438\u0443\u0441\u043e\u043c 12 \u0435\u0434\u0438\u043d\u0438\u0446. \u041a\u0430\u0436\u0434\u044b\u0439 \u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c\u044e (0.5x, 1.0x, 1.5x, 2.0x, 1.2x).\u0412\u044b\u0432\u043e\u0434\u044bWebGPU \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438. Compute Shaders \u0440\u0430\u0437\u0433\u0440\u0443\u0436\u0430\u044e\u0442 CPU \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b.Orillusion \u2014 \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u0432\u044b\u0431\u043e\u0440 \u0434\u043b\u044f \u044d\u043d\u0442\u0443\u0437\u0438\u0430\u0441\u0442\u043e\u0432. \u0421\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435, \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043d\u0435\u043f\u043e\u043b\u043d\u0430\u044f, \u043d\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 ECS \u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 WebGPU \u0441\u0442\u043e\u044f\u0442 \u0442\u043e\u0433\u043e. \u041f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0441\u043b\u043e\u0436\u043d\u043e.\u041a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u044b \u0432 orillusion \u2014 \u044d\u0442\u043e \u0441\u0442\u0440\u0430\u0448\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043d\u0430\u0447\u0430\u043b\u0435. \u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u2014 \u043f\u043e\u043d\u044f\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432, \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u043c \u0432\u044b\u0445\u043e\u0434\u0430\u043c.\u0418\u043d\u0441\u0442\u0430\u043d\u0441\u0438\u043d\u0433 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u201c\u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438\u201d. Orillusion \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 models.matrix[instance_index], \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c instanceIndex \u0432 \u0448\u0435\u0439\u0434\u0435\u0440\u0435.\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u0430\u043c\u0438: \u043a\u043e\u0434 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 WebGPU (Chrome 113+, Edge 113+, Firefox Nightly). \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435: \u043c\u044b\u0448\u044c\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434 &lt;!DOCTYPE html&gt;&lt;html lang=&#187;ru&#187;&gt;&lt;head&gt;  &lt;meta charset=&#187;UTF-8&#8243;&gt;  &lt;meta name=&#187;viewport&#187; content=&#187;width=device-width, initial-scale=1.0, user-scalable=no&#187;&gt;  &lt;title&gt;Gaia Star Map &#8212; 4D \u0422\u0435\u0441\u0441\u0435\u0440\u0430\u043a\u0442 | WebGPU&lt;\/title&gt;  &lt;style&gt;    * {      margin: 0;      padding: 0;      box-sizing: border-box;    }    html, body {      width: 100%;      height: 100%;      overflow: hidden;      margin: 0;      padding: 0;    }    body {      font-family: &#8216;Segoe UI&#8217;, &#8216;Monaco&#8217;, &#8216;Menlo&#8217;, &#8216;Consolas&#8217;, monospace;      background: #000;      position:&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-475920","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/475920","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=475920"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/475920\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=475920"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=475920"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=475920"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}