{"id":269528,"date":"2015-12-03T10:34:02","date_gmt":"2015-12-03T07:34:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=269528"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=269528","title":{"rendered":"2D \u0442\u0435\u043d\u0438 \u043d\u0430 WebGL \u0437\u0430 4 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0448\u0430\u0433\u0430"},"content":{"rendered":"<p>       \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0441\u0432\u043e\u0438\u043c\u0438 \u0440\u0443\u043a\u0430\u043c\u0438, \u0438\u043c\u0435\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u043b\u043e\u043a\u043d\u043e\u0442 \u0438 \u043b\u044e\u0431\u043e\u0439 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440, \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0448\u0435\u0439\u0434\u0435\u0440\u043d\u044b\u0435 2D-\u0442\u0435\u043d\u0438 \u043d\u0430 WebGL. \u0412\u0441\u0435 \u0448\u0430\u0433\u0438 \u043b\u0435\u0436\u0430\u0442 \u043d\u0430 \u0433\u0438\u0442\u0445\u0430\u0431\u0435 \u043a\u0430\u043a \u0432\u0435\u0442\u043a\u0438 \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f git checkout stepN, \u0442\u0430\u043a \u0447\u0442\u043e \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u0436\u0435 \u0442\u0435\u043c, \u043a\u0442\u043e \u043d\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u043a\u043e\u0434\u0438\u0442\u044c.<\/p>\n<p>  \u041a\u0414\u041f\u0412: <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/9f3\/a70\/19a\/9f3a7019ab2e4ddbb41aac47a960f62c.jpg\"\/><br \/>  <a name=\"habracut\"><\/a><br \/>  \u041f\u043e\u0438\u0433\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u0433\u043e\u0442\u043e\u0432\u044b\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e <a href=\"http:\/\/fen1kz.github.io\/dung7\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>  \u0418\u0442\u0430\u043a, \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u043c\u043d\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u0441 2\u0414-\u0442\u0435\u043d\u044f\u043c\u0438 \u043d\u0430 javascript&#8217;\u0435. \u0421 \u043a\u0443\u0447\u0435\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0441\u0432\u0435\u0442\u0430 \u0438 \u043b\u044e\u0431\u044b\u043c\u0438 (\u0447\u0438\u0442\u0430\u0439: \u0440\u0430\u0441\u0442\u0440\u043e\u0432\u044b\u043c\u0438) \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f\u043c\u0438 \u0434\u043b\u044f \u043d\u0438\u0445. \u0420\u0435\u0439\u0442\u0440\u0435\u0439\u0441\u0438\u043d\u0433 \u043d\u0430\u043f\u0443\u0433\u0430\u043b \u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044f\u043c\u0438 \u0441 \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0435\u0439 (\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u0430 \u043d\u0435 \u0443\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0439 \u0432\u044b\u0431\u043e\u0440 \u043f\u0430\u043b \u043d\u0430 WebGL \u0448\u0435\u0439\u0434\u0435\u0440\u044b.<\/p>\n<p>  \u0422\u0417: \u0415\u0441\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u043d\u044b \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f, \u0435\u0441\u0442\u044c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0441\u0432\u0435\u0442\u0430, \u043d\u0430\u0434\u043e \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043d\u0438. <\/p>\n<p>  \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0443\u0434\u0435\u043c pixi.js: \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f, \u0438\u043c\u0435\u0435\u0442 \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0449\u0438\u0439 \u043d\u0435\u043a\u0443\u044e \u0441\u0446\u0435\u043d\u0443 (\u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 PIXI.Container) \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043a\u0435. \u0421\u0446\u0435\u043d\u0430-\u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b, \u0438\u043b\u0438 \u0443\u0436\u0435 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u043f\u0440\u0430\u0439\u0442\u044b\/\u0433\u0440\u0430\u0444\u0438\u043a\u0443 (PIXI.Sprite\/PIXI.Graphics \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e). PIXI.Graphics \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f, \u0421\u043f\u0440\u0430\u0439\u0442\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0443, \u043b\u0438\u0431\u043e \u0442\u043e\u0436\u0435 \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u043d\u043d\u0443\u044e, \u043b\u0438\u0431\u043e \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u0443\u044e \u0438\u0437\u0432\u043d\u0435. \u0422\u0430\u043a\u0436\u0435 \u043a \u0421\u043f\u0440\u0430\u0439\u0442\u0430\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u0424\u0438\u043b\u044c\u0442\u0440\u044b (\u0448\u0435\u0439\u0434\u0435\u0440\u044b). <\/p>\n<p>  \u041f\u0440\u043e \u0424\u0438\u043b\u044c\u0442\u0440\u044b: \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u0437\u0430\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e filters <\/p>\n<pre><code>someGraphicObject.filters = [filter]<\/code><\/pre>\n<p>  \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u044f\u0442 \u043a\u0430\u043a\u0438\u0435-\u043b\u0438\u0431\u043e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u043e\u0439 \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u043b\u043e\u0436\u0438\u0442\u044c \u0448\u0435\u0439\u0434\u0435\u0440. \u0423 \u043d\u0430\u0441 \u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u044b\u0439 \u0444\u0438\u043b\u044c\u0442\u0440, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u0438\u0437 \u0434\u0432\u0443\u0445 \u00ab\u043f\u043e\u0434\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u00bb. \u0422\u0430\u043a\u0430\u044f \u00ab\u0441\u043b\u043e\u0436\u043d\u0430\u044f\u00bb \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043d\u0443\u0436\u043d\u0430 \u0438\u0437-\u0437\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043d\u0435\u0439:<\/p>\n<p>  \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043a\u0430\u0440\u0442\u0443 \u0442\u0435\u043d\u0435\u0439 (\u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0441\u0432\u0435\u0442\u0430), \u043e\u0434\u043d\u043e\u043c\u0435\u0440\u043d\u0443\u044e \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0443 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0449\u0443\u044e \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430, \u0433\u0434\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 X \u0431\u0443\u0434\u0435\u0442 \u0443\u0433\u043b\u043e\u043c, \u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0430\u043b\u044c\u0444\u0430-\u043a\u0430\u043d\u0430\u043b\u0430 \u2014 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0434\u043e \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f. \u041e\u0434\u043d\u0430\u043a\u043e, \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0430\u043a\u0430\u044f \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0441\u0432\u0435\u0442\u0430, \u0434\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u043c\u0435\u0441\u0442\u0430 \u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0435-\u0442\u0430\u043a\u0438 \u0434\u0432\u0443\u043c\u0435\u0440\u043d\u043e\u0439, Y \u0431\u0443\u0434\u0435\u0442 \u043e\u0437\u043d\u0430\u0447\u0430\u0442\u044c \u043d\u043e\u043c\u0435\u0440 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430. <\/p>\n<p>  \u0412\u043e\u043f\u0440\u043e\u0441 \u0434\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f: \u0422\u0435\u043a\u0441\u0442\u0443\u0440\u0430 256\u0445256, \u043f\u0438\u043a\u0441\u0435\u043b\u044c \u0441 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c\u0438 (\u0445 = 64, \u0443 = 8) \u043f\u043e\u043b\u0443\u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u044b\u0439, \u043d\u0430\u0437\u043e\u0432\u0438\u0442\u0435 \u043d\u043e\u043c\u0435\u0440 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0441\u0432\u0435\u0442\u0430, \u0438 \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041e\u0442\u0432\u0435\u0442<\/b><\/p>\n<div class=\"spoiler_text\">\u041d\u043e\u043c\u0435\u0440 \u043d\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u043e\u0441\u044c\u043c\u043e\u0433\u043e (\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043c\u0435\u0436\u0434\u0443 Y \u0438 \u043d\u043e\u043c\u0435\u0440\u043e\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435 \u043f\u0440\u044f\u043c\u0430\u044f), \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u2014 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u043e\u0442 \u043d\u0435\u043a\u043e\u0435\u0433\u043e \u0447\u0438\u0441\u043b\u0430 (\u043e\u043f\u044f\u0442\u044c \u0436\u0435, \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435 \u043f\u0440\u044f\u043c\u0430\u044f), \u0443\u0433\u043e\u043b \u2014 90 \u0433\u0440\u0430\u0434\u0443\u0441\u043e\u0432.  <\/div>\n<\/div>\n<p>  \u041f\u043e\u0442\u043e\u043c, \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438 \u043a\u0430\u0440\u0442\u044b \u0442\u0435\u043d\u0435\u0439 \u0432\u0442\u043e\u0440\u044b\u043c \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u043c \u0440\u0438\u0441\u0443\u0435\u043c \u0441\u0430\u043c\u0438 \u0442\u0435\u043d\u0438 \u0438, \u0437\u0430\u043e\u0434\u043d\u043e, \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0435\u043c \u0432\u0441\u0451 \u0442\u0430\u043c \u0436\u0435.<\/p>\n<p>  \u0418\u0435\u0440\u0430\u0440\u0445\u0438\u044f \u0441 \u0442.\u0437. PIXI \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u043e\u0439:<\/p>\n<pre> \u0421\u0446\u0435\u043d\u0430 (PIXI.Container) |- \u041b\u0430\u043c\u043f\u043e\u0447\u043a\u0438 (\u043f\u0430\u0440\u0430 PIXI.Graphics) |- \u0421\u043f\u0440\u0430\u0439\u0442 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u043d\u044b \u0442\u0435\u043d\u0438 + \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u043d\u044b\u0439 \u0444\u043e\u043d (PIXI.Sprite) |- |- \u0422\u0435\u043a\u0441\u0442\u0443\u0440\u0430 (PIXI.RenderTexture) |- |- \u0424\u0438\u043b\u044c\u0442\u0440 (PIXI.AbstractFilter) <\/pre>\n<p>  \u0418 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e, \u0432\u043d\u0435 \u0441\u0446\u0435\u043d\u044b:<\/p>\n<pre> |- \u0424\u043e\u043d (PIXI.Sprite) |- |- \u0422\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0444\u043e\u043d\u0430 |- \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0434\u043b\u044f \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u0439 (PIXI.Container) |- |- \u0421\u043f\u0440\u0430\u0439\u0442 \u0441 \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f\u043c\u0438 (PIXI.Sprite) |- |- |- \u0422\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0441\u043f\u0440\u0430\u0439\u0442\u0430 <\/pre>\n<p>  \u0417\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u0444\u043e\u043d \u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c \u0432 \u0444\u0438\u043b\u044c\u0442\u0440 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0430\u043c \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u0442\u0441\u044f \u0447\u0442\u043e \u0438 \u043a\u0430\u043a \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c.<br \/>  \u0412\u043e\u0442 \u0438 \u0432\u0441\u044f \u0442\u0435\u043e\u0440\u0438\u044f, \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435:<\/p>\n<h3>\u0428\u0430\u0433 0: \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442<\/h3>\n<p>  \u041b\u0438\u0431\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0435\u0433\u043e <a href=\"https:\/\/github.com\/Fen1kz\/hh-shadows-webglsl.git\">\u043e\u0442\u0441\u044e\u0434\u0430<\/a>, \u0432\u0435\u0442\u043a\u0430 step0.<\/p>\n<p>  \u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f 3 \u0444\u0430\u0439\u043b\u0430:<\/p>\n<ul>\n<li>index.html c\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435\u043c<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;pre&gt; &lt;!DOCTYPE HTML&gt; &lt;html&gt; &lt;head&gt; \t&lt;title&gt;Deferred Example&lt;\/title&gt; \t&lt;meta charset=&quot;UTF-8&quot;&gt; \t&lt;style&gt;&lt;\/style&gt; \t&lt;script src=&quot;js\/pixi.min.js&quot;&gt;&lt;\/script&gt; \t&lt;script src=&quot;js\/script.js&quot;&gt;&lt;\/script&gt; &lt;\/head&gt; &lt;body&gt; &lt;\/body&gt; &lt;\/html&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/li>\n<li>\u041a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u0441 \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f\u043c\u0438 \u2014 \u043b\u044e\u0431\u043e\u0439 PNG \u0441 \u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e\u0441\u0442\u044c\u044e, \u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0432\u043e\u0442 \u0442\u0430\u043a\u0443\u044e.\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/b><\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/0a4\/c73\/c9b\/0a4c73c9b4f2493c88208de1b0a71e10.png\"\/>  <\/div>\n<\/div>\n<p>  <\/li>\n<li>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a href=\"https:\/\/github.com\/pixijs\/pixi.js\">pixi.js<\/a>, \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/raw.githubusercontent.com\/pixijs\/pixi.js\/master\/bin\/pixi.min.js\">\u043e\u0442\u0441\u044e\u0434\u0430<\/a>.  <\/li>\n<\/ul>\n<p>  \u0415\u0449\u0451 \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u0441\u0440\u0430\u0437\u0443 \u0437\u0430\u0432\u0435\u0441\u0442\u0438 \u043b\u044e\u0431\u043e\u0439 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u043f\u0430\u043f\u043a\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<h3>\u0428\u0430\u0433 1: \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0446\u0435\u043d\u0443<\/h3>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u0451 \u0432 \u0444\u0430\u0439\u043b\u0435 js\/script.js. \u041a\u043e\u0434, \u044f \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u043e\u0447\u0435\u0432\u0438\u0434\u0435\u043d \u0434\u0430\u0436\u0435 \u0442\u0435\u043c, \u043a\u0442\u043e \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c \u0441 PIXI:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">js\/script.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code>(function () {    var WIDTH = 640;    var HEIGHT = 480;    var renderer = new PIXI.WebGLRenderer(WIDTH, HEIGHT); \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c PIXI \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440     document.addEventListener(&quot;DOMContentLoaded&quot;, function (event) { \/\/ \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e html \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b\u0441\u044f        document.body.appendChild(renderer.view);         \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b        PIXI.loader            .add('background', 'img\/maze.png')            .once('complete', setup)            .load();    });     function setup() {        \/\/ \u0412\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e, \u043c\u043e\u0436\u043d\u043e \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c.        var lights = []; \/\/ \u041b\u0430\u043c\u043f\u043e\u0447\u043a\u0438        lights[0] = new PIXI.Graphics();        lights[0].beginFill(0xFFFF00);        lights[0].drawCircle(0, 0, 4); \/\/ x, y, radius        lights[1] = new PIXI.Graphics();        lights[1].beginFill(0xFFFF00);        lights[1].drawCircle(0, 0, 4);        lights[1].x = 50;        lights[1].y = 50;        var background = new PIXI.Graphics();        background.beginFill(0x999999);        background.drawRect(0, 0, WIDTH, HEIGHT); \/\/ x, y, width, height         var shadowCastImage = PIXI.Sprite.fromImage('img\/maze.png'); \/\/ \u041e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u044e\u0449\u0430\u044f \u0442\u0435\u043d\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 (\u0447\u0435\u0440\u043d\u044b\u043c)         var shadowCasters = new PIXI.Container(); \/\/ \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0434\u043b\u044f \u0432\u0441\u0435\u0445, \u043a\u0442\u043e \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442 \u0442\u0435\u043d\u044c        shadowCasters.addChild(shadowCastImage); \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u0443\u0434\u0430 \u043d\u0430\u0448\u0443 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443.         var stage = new PIXI.Container();        stage.addChild(background);        stage.addChild(shadowCasters);        stage.addChild(lights[0]);        stage.addChild(lights[1]);         (function animate() {            \/\/ lights[0] \u0431\u0443\u0434\u0435\u0442 \u0431\u0435\u0433\u0430\u0442\u044c \u0437\u0430 \u043c\u044b\u0448\u043a\u043e\u0439.            var pointer = renderer.plugins.interaction.mouse.global;            lights[0].x = pointer.x;            lights[0].y = pointer.y;             \/\/ \u0420\u0435\u043d\u0434\u0435\u0440            renderer.render(stage);                       requestAnimationFrame(animate);        })();    } })(); <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0443\u0436\u0435 \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u0430\u0437\u0443\u043c\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435, \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430, \u0434\u0432\u0435 \u043b\u0430\u043c\u043f\u043e\u0447\u043a\u0438, \u043f\u0440\u0438\u0447\u0435\u043c \u043e\u0434\u043d\u0430 \u0443\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u0430 \u043a \u043c\u044b\u0448\u043a\u0435:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/51d\/9b0\/20b\/51d9b020bf37437aa8f4d4f5efbfd1e7.jpg\"\/><\/p>\n<h3>\u0428\u0430\u0433 2: \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0448\u0435\u0439\u0434\u0435\u0440<\/h3>\n<p>  \u042f \u043d\u0430\u0447\u043d\u0443 \u0441 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0448\u0435\u0439\u0434\u0435\u0440\u0430, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043a\u0440\u0430\u0441\u0438\u0442\u044c \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f \u0432 \u043a\u0440\u0430\u0441\u043d\u044b\u0439, \u0430 \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u2014 \u0432 \u0441\u0435\u0440\u044b\u0439 \u0446\u0432\u0435\u0442.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0424\u0430\u0439\u043b glsl\/smap-shadow-texture.frag:<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code>precision mediump float; \/\/ \u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u0442\u0430\u0432\u0438\u043c \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c  varying vec2 vTextureCoord; \/\/ \u0417\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f (\u043e\u0442 0.0 \u0434\u043e 1.0) \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 \u043f\u0438\u043a\u0441\u0435\u043b\u044f uniform sampler2D uSampler; \/\/ \u0422\u0435\u043a\u0441\u0442\u0443\u0440\u0430, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d \u0448\u0435\u0439\u0434\u0435\u0440.  void main() {     vec4 color = texture2D(uSampler, vTextureCoord); \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0446\u0432\u0435\u0442 \u043f\u0438\u043a\u0441\u0435\u043b\u044f      if (color.a == 0.) { \/\/ \u0435\u0441\u043b\u0438 \u0430\u043b\u044c\u0444\u0430-\u043a\u0430\u043d\u0430\u043b \u043f\u0443\u0441\u0442         gl_FragColor = vec4(.5, .5, .5, 1.); \/\/ \u043a\u0440\u0430\u0441\u0438\u043c \u0432 \u0441\u0435\u0440\u044b\u0439, \u043f\u0443\u0441\u0442\u043e     } else { \/\/ \u0430 \u0435\u0441\u043b\u0438 \u0447\u0435\u0440\u043d\u044b\u0439         gl_FragColor = vec4(1., 0., 0., 1.); \/\/ \u043a\u0440\u0430\u0441\u0438\u043c \u0432 \u043a\u0440\u0430\u0441\u043d\u044b\u0439, \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u0435     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0435\u0433\u043e \u0432 loader&#8217;e:<\/p>\n<pre><code>  PIXI.loader     ...     .add('glslShadowTexture', 'glsl\/smap-shadow-texture.frag')     ... <\/code><\/pre>\n<p>  \u041d\u0435\u043b\u044c\u0437\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0430\u043a \u0432\u0437\u044f\u0442\u044c \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0448\u0435\u0439\u0434\u0435\u0440 \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u044f \u043a \u0441\u0446\u0435\u043d\u0435 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0442\u043e\u0433\u0434\u0430 \u0442\u0435\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u0432\u0435\u0440\u0445 \u0432\u0441\u0435\u0433\u043e, \u0442\u0430\u043a \u0447\u0442\u043e \u044f \u0441\u043e\u0437\u0434\u0430\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u0440\u0430\u0439\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0443 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0444\u043e\u043d \u0438 \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e RenderTexture (\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0430\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 PIXI \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0441\u0435\u0431\u044f \u0436\u0435), \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044e \u043a \u043d\u0435\u043c\u0443 \u043d\u0430\u0448 \u0424\u0438\u043b\u044c\u0442\u0440.<\/p>\n<pre><code>  var lightingRT = new PIXI.RenderTexture(renderer, WIDTH, HEIGHT);   var lightingSprite = new PIXI.Sprite(lightingRT);   var filter = createSMapFilter();   lightingSprite.filters = [filter];   ...   stage.addChild(lightingSprite); <\/code><\/pre>\n<p>  \u041d\u0443 \u0438 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430, \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 animate(): <\/p>\n<pre><code>  lightingRT.render(shadowCasters, null, true); \/\/ (shadowCasters \u043a\u0430\u043a \u043e\u0431\u044a\u0435\u043a\u0442 PIXI, null \u043a\u0430\u043a \u043c\u0430\u0442\u0440\u0438\u0446\u0430 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e), true \u043a\u0430\u043a \u0444\u043b\u0430\u0433 \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b) <\/code><\/pre>\n<p>  \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e createSMapFilter:<\/p>\n<pre><code>  function createSMapFilter() {     var SMapFilter = new PIXI.AbstractFilter(null, PIXI.loader.resources.glslShadowTexture.data, {}); \/\/ (\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0432\u0435\u0440\u0442\u0435\u043a\u0441\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440, \u043d\u0430\u0448 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0439 \u043f\u0438\u043a\u0441\u0435\u043b\u044c\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440, \u043f\u0443\u0441\u0442\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 (uniforms))     return SMapFilter;   } <\/code><\/pre>\n<p>  \u0412\u0441\u0435 \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u043a\u0440\u0430\u0441\u044f\u0442\u0441\u044f \u0432 \u043a\u0440\u0430\u0441\u043d\u044b\u0439 \u0446\u0432\u0435\u0442:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/b71\/414\/40c\/b7141440c87d4917b30ba3368b316640.jpg\"\/><\/p>\n<h3>\u0428\u0430\u0433 3: \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u044b \u0442\u0435\u043d\u0435\u0439<\/h3>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0444\u0438\u043b\u044c\u0442\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445 \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0448\u0435\u0439\u0434\u0435\u0440\u0430 \u0435\u0433\u043e \u043d\u0430\u0434\u043e \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u0432 \u00ab\u043a\u043e\u043c\u0431\u043e-\u0444\u0438\u043b\u044c\u0442\u0440\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432 \u0441\u0435\u0431\u0435 \u0434\u0440\u0443\u0433\u0438\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u044b. \u0414\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u0432\u0430 \u2014 \u043e\u0434\u0438\u043d \u043f\u0443\u0441\u0442\u043e\u0439, \u0432\u044b\u0432\u043e\u0434\u044f\u0449\u0438\u0439 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0443 \u043a\u0430\u043a \u0435\u0441\u0442\u044c \u0438 \u043e\u0434\u0438\u043d \u0434\u043b\u044f \u043a\u0430\u0440\u0442\u044b \u0442\u0435\u043d\u0435\u0439. \u0422\u0430\u043a \u0436\u0435, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u0430\u0440\u0442\u0443 \u0442\u0435\u043d\u0435\u0439 \u0438 \u0435\u0449\u0451 \u043e\u0434\u043d\u0443 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0443, \u043a\u0443\u0434\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 shadowCasters (\u0434\u043b\u044f \u0442\u0435\u0445 \u043a\u0442\u043e \u043f\u043e\u0442\u0435\u0440\u044f\u043b\u0441\u044f \u2014 \u044d\u0442\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441 \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f\u043c\u0438.) \u041f\u043e\u0436\u0430\u043b\u0443\u0439, \u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u00abcreateSMapFilter()\u00bb \u0446\u0435\u043b\u0438\u043a\u043e\u043c:<\/p>\n<pre><code>  function createSMapFilter() {    var CONST_LIGHTS_COUNT = 2;    var SMapFilter = new PIXI.AbstractFilter(null, null, { \/\/ \u0417\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u0448\u0435\u0439\u0434\u0435\u0440\u0430 \u0437\u0434\u0435\u0441\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435\u0442, \u044d\u0442\u043e \u0444\u0438\u043b\u044c\u0442\u0440 &quot;\u043e\u0431\u0435\u0440\u0442\u043a\u0430&quot;        viewResolution: {type: '2fv', value: [WIDTH, HEIGHT]} \/\/ \u041f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432 \u0444\u0438\u043b\u044c\u0442\u0440 \u0440\u0430\u0437\u043c\u0435\u0440\u044b view        , rtSize: {type: '2fv', value: [1024, CONST_LIGHTS_COUNT]} \/\/ \u041f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0440\u0430\u0437\u043c\u0435\u0440\u044b \u043a\u0430\u0440\u0442\u044b \u0442\u0435\u043d\u0435\u0439.        , uAmbient: {type: '4fv', value: [.0, .0, .0, .0]} \/\/ \u0418 \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u0435 &quot;\u043f\u043e \u0434\u0435\u0444\u043e\u043b\u0442\u0443&quot; \u043f\u0443\u0441\u043a\u0430\u0439 \u0431\u0443\u0434\u0435\u0442 \u043d\u043e\u043b\u044c.    });    \/\/ \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0433\u043b\u043e\u0431\u0430\u043b\u043a\u0438 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\/\u0446\u0432\u0435\u0442\u0430 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0441\u0432\u0435\u0442\u0430:    for (var i = 0; i &lt; CONST_LIGHTS_COUNT; ++i) {        SMapFilter.uniforms['uLightPosition[' + i + ']'] = {type: '4fv', value: [0, 0, 256, .3]}; \/\/ \u0445, \u0443, \u0440\u0430\u0437\u043c\u0435\u0440 \u0432 \u043f\u0438\u043a\u0441\u0435\u043b\u044f\u0445 \u0438 &quot;falloff&quot; \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043f\u0430\u0434\u0435\u043d\u0438\u044f \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u043d\u043e\u0441\u0442\u0438        SMapFilter.uniforms['uLightColor[' + i + ']'] = {type: '4fv', value: [1, 1, 1, .3]}; \/\/ r, g, b, \u0438 \u044d\u043c\u0431\u0438\u0435\u043d\u0442 \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0441\u0432\u0435\u0442\u0430.    }     \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 PIXI \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c\u0441\u044f \u043a\u0430\u0440\u0442\u0430 \u0442\u0435\u043d\u0435\u0439    SMapFilter.renderTarget = new PIXI.RenderTarget(        renderer.gl        , SMapFilter.uniforms.rtSize.value[0]        , SMapFilter.uniforms.rtSize.value[1]        , PIXI.SCALE_MODES.LINEAR        , 1);    SMapFilter.renderTarget.transform = new PIXI.Matrix()        .scale(SMapFilter.uniforms.rtSize.value[0] \/ WIDTH            , SMapFilter.uniforms.rtSize.value[1] \/ HEIGHT);     \/\/ \u0422\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f:    SMapFilter.shadowCastersRT = new PIXI.RenderTexture(renderer, WIDTH, HEIGHT);    SMapFilter.uniforms.uShadowCastersTexture = {        type: 'sampler2D',        value: SMapFilter.shadowCastersRT    };    \/\/ \u0418 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430:    SMapFilter.render = function (group) {        SMapFilter.shadowCastersRT.render(group, null, true);    };     \/\/ \u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440, \u043d\u0435 \u0434\u0435\u043b\u0430\u044e\u0449\u0438\u0439 \u043d\u0438\u0447\u0435\u0433\u043e;    SMapFilter.testFilter = new PIXI.AbstractFilter(null, &quot;precision highp float;&quot;        + &quot;varying vec2 vTextureCoord;&quot;        + &quot;uniform sampler2D uSampler;&quot;        + &quot;void main(void) {gl_FragColor = texture2D(uSampler, vTextureCoord);}&quot;);     \/\/ \u0428\u0435\u0439\u0434\u0435\u0440, \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0432 renderTarget \u043a\u0430\u0440\u0442\u0443 \u0442\u0435\u043d\u0435\u0439.    var filterShadowTextureSource = PIXI.loader.resources.glslShadowTexture.data;    \/\/ CONST_LIGHTS_COUNT \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0438 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a uniform.    filterShadowTextureSource = filterShadowTextureSource.replace(\/CONST_LIGHTS_COUNT\/g, CONST_LIGHTS_COUNT);     \/\/ \u0410 \u0442\u0430\u043a\u0436\u0435 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 uniforms, \u044d\u0442\u043e\u0433\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 WebGL (\u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435 \u043d\u0430\u0434\u043e, \u043d\u043e \u043c\u044b \u0436\u0435 \u0434\u043e\u043f\u0438\u0448\u0435\u043c \u0432\u0442\u043e\u0440\u043e\u0439 \u0448\u0435\u0439\u0434\u0435\u0440)    var filterShadowTextureUniforms = Object.keys(SMapFilter.uniforms).reduce(function (c, k) {        c[k] = {            type: SMapFilter.uniforms[k].type            , value: SMapFilter.uniforms[k].value        };        return c;    }, {});    SMapFilter.filterShadowTexture = new PIXI.AbstractFilter(        null        , filterShadowTextureSource        , filterShadowTextureUniforms    );     SMapFilter.applyFilter = function (renderer, input, output) {        SMapFilter.filterShadowTexture.applyFilter(renderer, input, SMapFilter.renderTarget, true);        SMapFilter.testFilter.applyFilter(renderer, SMapFilter.renderTarget, output); \/\/ \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043c\u0435\u043d\u0435\u043d \u043d\u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u0448\u0435\u0439\u0434\u0435\u0440.    };    return SMapFilter; } <\/code><\/pre>\n<p>  \u0421\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e filterShadowTexture \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 input. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043e\u043d \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0447\u0435\u0440\u0435\u0437 uniform uShadowCastersTexture. \u042f \u0441\u0434\u0435\u043b\u0430\u043b \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0437\u0430\u043c\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u0435\u0449\u0451 \u043e\u0434\u043d\u043e\u0439 renderTarget.<\/p>\n<p>  \u0414\u0430\u043b\u044c\u0448\u0435 \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 animate:<\/p>\n<pre><code>  \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c uniforms \u0432 \u0448\u0435\u0439\u0434\u0435\u0440\u0435   filter.uniforms['uLightPosition[0]'].value[0] = lights[0].x;   filter.uniforms['uLightPosition[0]'].value[1] = lights[0].y;   filter.uniforms['uLightPosition[1]'].value[0] = lights[1].x;   filter.uniforms['uLightPosition[1]'].value[1] = lights[1].y;    \/\/ \u0420\u0435\u043d\u0434\u0435\u0440\u0438\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441 \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f\u043c\u0438 \u0432 renderTexture \u0432 \u0444\u0438\u043b\u044c\u0442\u0440\u0435.   filter.render(shadowCasters); <\/code><\/pre>\n<p>  \u0418, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0448\u0435\u0439\u0434\u0435\u0440\u0430:<\/p>\n<pre><code>\/\/ \u0428\u0435\u0439\u0434\u0435\u0440 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u044b \u0442\u0435\u043d\u0435\u0439:  precision mediump float;  \/\/\u041e\u0431\u044a\u044f\u0432\u043b\u044f\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 uniform'\u044b varying vec2 vTextureCoord; \/\/ \u041a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 uniform sampler2D uSampler; \/\/ \u0422\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0430\u043b\u043e\u0436\u0435\u043d \u0444\u0438\u043b\u044c\u0442\u0440 (\u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f)  uniform vec2 viewResolution; \/\/ \u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432\u044c\u044e\u0448\u043a\u0438 uniform vec2 rtSize; \/\/ \u0420\u0430\u0437\u043c\u0435\u0440 renderTarget  uniform vec4 uLightPosition[CONST_LIGHTS_COUNT]; \/\/x,y = \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b, z = \u0440\u0430\u0437\u043c\u0435\u0440 uniform vec4 uLightColor[CONST_LIGHTS_COUNT]; \/\/\u041d\u0430 \u0432\u0441\u044f\u043a\u0438\u0439 \u0441\u043b\u0443\u0447\u0430\u0439  uniform sampler2D uShadowCastersTexture; \/\/ \u041e\u0442\u0441\u044e\u0434\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0431\u0440\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 -- \u0435\u0441\u0442\u044c \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u0435 \u0438\u043b\u0438 \u043d\u0435\u0442.  const float PI = 3.14159265358979; const float STEPS = 256.0; const float THRESHOLD = .01;  void main(void) {     int lightnum = int(floor(vTextureCoord.y * float(CONST_LIGHTS_COUNT))); \/\/ \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043d\u043e\u043c\u0435\u0440 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0441\u0432\u0435\u0442\u0430 \u043f\u043e Y     vec2 lightPosition;     float lightSize;     for (int i = 0; i &lt; CONST_LIGHTS_COUNT; i += 1) { \/\/ \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u0430\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0441\u0432\u0435\u0442\u0430 \u043f\u043e \u0435\u0433\u043e \u043d\u043e\u043c\u0435\u0440\u0443         if (lightnum == i) {             lightPosition = uLightPosition[i].xy \/ viewResolution;             lightSize = uLightPosition[i].z \/ max(viewResolution.x, viewResolution.y);             break;         }     }     float dst = 1.0; \/\/ \u0421\u0447\u0438\u0442\u0430\u0435\u043c \u0447\u0442\u043e \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u0439 \u043d\u0435\u0442     for (float y = 0.0; y &lt; STEPS; y += 1.0) { \/\/ \u0418 \u043c\u0435\u043b\u043a\u0438\u043c\u0438 (\u0441 \u043c\u0435\u043b\u043a\u043e\u0441\u0442\u044c\u044e (y \/ STEPS)) \u0448\u0430\u0433\u0430\u043c\u0438 \u0438\u0434\u0435\u043c \u0432\u043e \u0432\u0441\u0435\u0445 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u0445         float distance = (y \/ STEPS); \/\/ \u0420\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430         float angle = vTextureCoord.x * (2.0 * PI); \/\/ \u0423\u0433\u043e\u043b \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430         \/\/ \u041f\u043e \u043f\u043e\u043b\u044f\u0440\u043d\u044b\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043f\u0438\u043a\u0441\u0435\u043b\u044c \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430         vec2 coord = vec2(cos(angle) * distance, sin(angle) * distance);         coord *= (max(viewResolution.x, viewResolution.y) \/ viewResolution);  \/\/ \u041f\u0440\u043e\u043f\u043e\u0440\u0446\u0438\u0438         coord += lightPosition; \/\/ \u041f\u0440\u0438\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430         coord = clamp(coord, 0., 1.); \/\/ \u041d\u0435 \u0432\u044b\u0445\u043e\u0434\u0438\u043c \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044b \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b         vec4 data = texture2D(uShadowCastersTexture, coord); \/\/ \u041d\u0430\u0445\u043e\u0434\u0438\u043c \u043f\u0438\u043a\u0441\u0435\u043b\u044c         if (data.a &gt; THRESHOLD) { \/\/ \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u0435, \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0430\u0435\u043c \u043f\u043e\u0438\u0441\u043a.             dst = min(dst, distance);             break;         }     }     \/\/ \u0414\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u044f \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u0438\u043a\u0441\u0435\u043b\u044f\u0445, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0435\u0451 \u0432 \u043e\u0442\u0440\u0435\u0437\u043a\u0435 0..1     gl_FragColor = vec4(vec3(0.0), dst \/ lightSize); } <\/code><\/pre>\n<p>  \u041e\u0441\u043e\u0431\u043e \u0442\u0443\u0442 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0447\u0435\u0433\u043e, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u044f \u0434\u043e\u043f\u043e\u043b\u043d\u044e \u0447\u0435\u043c-\u043d\u0438\u0431\u0443\u0434\u044c \u0438\u0437 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445.<\/p>\n<p>  \u0414\u043e\u043b\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0432\u043e\u0442 \u0442\u0430\u043a\u043e\u0435 \u0437\u0430\u0433\u0430\u0434\u043e\u0447\u043d\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u043e\u0434\u043d\u0430\u043a\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a \u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u0430\u0448\u0430 \u043a\u0430\u0440\u0442\u0430 \u0442\u0435\u043d\u0435\u0439, \u0432\u0435\u0434\u044c \u043e\u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u0432 \u0430\u043b\u044c\u0444\u0430 \u043a\u0430\u043d\u0430\u043b\u0435 \u0438 \u043d\u0430\u043b\u043e\u0436\u0435\u043d\u0430 \u043d\u0430 \u0441\u0446\u0435\u043d\u0443.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/6c5\/30c\/a60\/6c530ca6089f4c70b7dbd8be23795aa0.jpg\"\/><\/p>\n<h3>\u0428\u0430\u0433 4: \u041f\u043e \u043a\u0430\u0440\u0442\u0435 \u0442\u0435\u043d\u0435\u0439 \u0441\u0442\u0440\u043e\u0438\u043c \u0442\u0435\u043d\u0438<\/h3>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u0432 \u043f\u0440\u0435\u0434\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443, \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"javascript\">  PIXI.loader       .add('background', 'img\/maze.png')       .add('glslShadowTexture', 'glsl\/smap-shadow-texture.frag')       .add('glslShadowCast', 'glsl\/smap-shadow-cast.frag')       .once('complete', setup)       .load(); <\/code><\/pre>\n<p>  \u0418, \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 createSMapFilter, \u0441\u043d\u043e\u0432\u0430 \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c uniforms, \u043d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u0443\u0436\u0435 \u0434\u043b\u044f \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u0448\u0435\u0439\u0434\u0435\u0440\u0430:<\/p>\n<pre><code>  var filterShadowCastUniforms = Object.keys(SMapFilter.uniforms).reduce(function (c, k) {       c[k] = {           type: SMapFilter.uniforms[k].type           , value: SMapFilter.uniforms[k].value       };       return c;   }, {}); <\/code><\/pre>\n<p>  \u0414\u0430\u043b\u044c\u0448\u0435 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u043a\u0430\u0440\u0442\u0443 \u0442\u0435\u043d\u0435\u0439 (\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0432 renderTarget). \u042f \u043d\u0435 \u043d\u0430\u0448\u0435\u043b \u043a\u0430\u043a \u044d\u0442\u043e\u0433\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0445\u0430\u043a, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0432 renderTarget \u043a\u0430\u043a Texture:<\/p>\n<pre><code>  filterShadowCastUniforms.shadowMapChannel = {       type: 'sampler2D',       value: {           baseTexture: {               hasLoaded: true               , _glTextures: [SMapFilter.renderTarget.texture]           }       }   }; <\/code><\/pre>\n<p>  \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u0430:<\/p>\n<pre><code>  SMapFilter.filterShadowCast = new PIXI.AbstractFilter(       null       , PIXI.loader.resources.glslShadowCast.data.replace(\/CONST_LIGHTS_COUNT\/g, CONST_LIGHTS_COUNT)       , filterShadowCastUniforms   ); <\/code><\/pre>\n<p>  \u0418\u0437\u043c\u0435\u043d\u044f\u0435\u043c applyFilter:<\/p>\n<pre><code>  SMapFilter.applyFilter = function (renderer, input, output) {       SMapFilter.filterShadowTexture.applyFilter(renderer, input, SMapFilter.renderTarget, true);       \/\/SMapFilter.testFilter.applyFilter(renderer, SMapFilter.renderTarget, output); \/\/ \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043c\u0435\u043d\u0435\u043d \u043d\u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u0448\u0435\u0439\u0434\u0435\u0440.       SMapFilter.filterShadowCast.applyFilter(renderer, input, output);   }; <\/code><\/pre>\n<p>  \u0415\u0449\u0451 \u0440\u0430\u0437, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u043b\u0438, \u0447\u0442\u043e \u043a\u0443\u0434\u0430 \u0438\u0434\u0435\u0442:<\/p>\n<p>  input \u2014 \u044d\u0442\u043e \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0432\u0441\u0435\u0439 \u0441\u0446\u0435\u043d\u044b, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043b\u043e\u0436\u0435\u043d\u043e \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u0435;<br \/>  output \u2014 \u043e\u043d\u0430 \u0436\u0435;<br \/>  SMapFilter.renderTarget \u2014 \u044d\u0442\u043e \u043a\u0430\u0440\u0442\u0430 \u0442\u0435\u043d\u0435\u0439.<\/p>\n<p>  \u041f\u0435\u0440\u0432\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 input \u0438 \u043f\u0438\u0448\u0435\u0442 \u043a\u0430\u0440\u0442\u0443 \u0442\u0435\u043d\u0435\u0439 \u0438\u0437 uniform\u2019\u0430, \u0432\u0442\u043e\u0440\u043e\u0439 \u0448\u0435\u0439\u0434\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0438 input \u0438 \u043a\u0430\u0440\u0442\u0443 \u0442\u0435\u043d\u0435\u0439 (\u0432 \u0432\u0438\u0434\u0435 uniform\u2019\u0430).<\/p>\n<p>  \u0412\u0441\u0451, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 glsl\/smal-shadow-cast.frag:<\/p>\n<pre><code>precision mediump float;  uniform sampler2D uSampler; varying vec2 vTextureCoord;  uniform vec2 viewResolution;  uniform sampler2D shadowMapChannel;  uniform vec4 uAmbient; uniform vec4 uLightPosition[CONST_LIGHTS_COUNT]; uniform vec4 uLightColor[CONST_LIGHTS_COUNT];  const float PI = 3.14159265358979;  \/\/ \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f (\u0444\u0443\u043d\u043a\u0446\u0438\u0438) \u0447\u0442\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u044b \u0442\u0435\u043d\u0435\u0439 vec4 takeSample(in sampler2D texture, in vec2 coord, in float light) {    return step(light, texture2D(texture, coord)); }  \/\/ \u0421\u0430\u043c\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u043a\u0430\u0440\u0442\u044b \u0442\u0435\u043d\u0435\u0439 (\u0441\u043e \u0441\u0433\u043b\u0430\u0436\u0438\u0432\u0430\u043d\u0438\u0435\u043c!) vec4 blurFn(in sampler2D texture, in vec2 tc, in float light, in float iBlur) {    float blur = iBlur \/ viewResolution.x;    vec4 sum = vec4(0.0);    sum += takeSample(texture, vec2(tc.x - 5.0*blur, tc.y), light) * 0.022657;    sum += takeSample(texture, vec2(tc.x - 4.0*blur, tc.y), light) * 0.046108;    sum += takeSample(texture, vec2(tc.x - 3.0*blur, tc.y), light) * 0.080127;    sum += takeSample(texture, vec2(tc.x - 2.0*blur, tc.y), light) * 0.118904;    sum += takeSample(texture, vec2(tc.x - 1.0*blur, tc.y), light) * 0.150677;     sum += takeSample(texture, vec2(tc.x, tc.y), light) * 0.163053;     sum += takeSample(texture, vec2(tc.x + 1.0*blur, tc.y), light) * 0.150677;    sum += takeSample(texture, vec2(tc.x + 2.0*blur, tc.y), light) * 0.118904;    sum += takeSample(texture, vec2(tc.x + 3.0*blur, tc.y), light) * 0.080127;    sum += takeSample(texture, vec2(tc.x + 4.0*blur, tc.y), light) * 0.046108;    sum += takeSample(texture, vec2(tc.x + 5.0*blur, tc.y), light) * 0.022657;    return sum; }  \/\/ \u041e\u043a, \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0447\u0430\u0442\u044c: void main() {    \/\/ \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u0435 \u0443 \u043d\u0430\u0441 \u0447\u0435\u0440\u043d\u043e\u0435    vec4 color = vec4(0.0, 0.0, 0.0, 1.0);     \/\/ \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0441\u0432\u0435\u0442\u0430.    float lightLookupHalfStep = (1.0 \/ float(CONST_LIGHTS_COUNT)) * .5;     \/\/ \u0412 \u0446\u0438\u043a\u043b\u0435 \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u0441\u0432\u0435\u0442\u0430    for (int lightNumber = 0; lightNumber &lt; CONST_LIGHTS_COUNT; lightNumber += 1) {        float lightSize = uLightPosition[lightNumber].z \/ max(viewResolution.x, viewResolution.y);        float lightFalloff = min(0.99, uLightPosition[lightNumber].a);        if (lightSize == 0.) {            \/\/ \u0415\u0441\u043b\u0438 \u0440\u0430\u0437\u043c\u0435\u0440 \u043d\u0443\u043b\u0435\u0432\u043e\u0439, \u0442\u043e \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c \u0441\u043c\u044b\u0441\u043b\u0430 \u043d\u0435\u0442.            continue;        }        vec2 lightPosition = uLightPosition[lightNumber].xy \/ viewResolution;        vec4 lightColor = uLightColor[lightNumber];        \/\/ \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0441\u0432\u0435\u0442\u0430        vec3 lightLuminosity = vec3(0.0);         \/\/ \u041a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 Y \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u043d\u0430 \u043a\u0430\u0440\u0442\u0435 \u0442\u0435\u043d\u0435\u0439.        float yCoord = float(lightNumber) \/ float(CONST_LIGHTS_COUNT) + lightLookupHalfStep;         \/\/ \u0412\u0435\u043a\u0442\u043e\u0440 \u043e\u0442 \u0442\u043e\u0447\u043a\u0438 \u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0443 \u0441\u0432\u0435\u0442\u0430        vec2 toLight = vTextureCoord - lightPosition;         \/\/ \u041f\u0440\u043e\u043f\u043e\u0440\u0446\u0438\u0438        toLight \/= (max(viewResolution.x, viewResolution.y) \/ viewResolution);        toLight \/= lightSize;         \/\/ \u0420\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0442 \u0442\u043e\u0447\u043a\u0438 \u0434\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430        float light = length(toLight);        \/\/ \u0423\u0433\u043e\u043b \u043e\u0442 \u0442\u043e\u0447\u043a\u0438 \u0434\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 (\u0434\u043b\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0425)        float angleToPoint = atan(toLight.y, toLight.x);        float angleCoordOnMap = angleToPoint \/ (2.0 * PI);         vec2 samplePoint = vec2(angleCoordOnMap, yCoord);         \/\/ \u0427\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435 \u043e\u0442 \u0441\u0432\u0435\u0442\u0430 -- \u0442\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0440\u0430\u0437\u043c\u044b\u0442\u0438\u044f.        float blur = smoothstep(0., 2., light);         \/\/ \u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0435\u0441\u0442\u044c \u043b\u0438 \u0442\u0435\u043d\u044c \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0438 \u043d\u0430 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u043d\u0430 \u0440\u0430\u0437\u043c\u044b\u0442\u0430 \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0435        float sum = blurFn(shadowMapChannel, samplePoint, light, blur).a;        sum = max(sum, lightColor.a);         lightLuminosity = lightColor.rgb * vec3(sum) * smoothstep(1.0, lightFalloff, light);         \/\/ \u041f\u0440\u0438\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a \u043e\u0431\u0449\u0435\u043c\u0443 \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u044e (\u0432 \u043f\u0438\u043a\u0441\u0435\u043b\u0435):        color.rgb += lightLuminosity;    }     \/\/ \u041e\u0431\u0449\u0435\u0435 \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u0435    color = max(color, uAmbient);     \/\/ \u041f\u0438\u043a\u0441\u0435\u043b\u044c \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0434\u043e \u043e\u0441\u0432\u0435\u0442\u0438\u0442\u044c    vec4 base = texture2D(uSampler, vTextureCoord);     \/\/ \u041e\u0441\u0432\u0435\u0449\u0430\u0435\u043c \u0443\u043c\u043d\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043d\u0430 \u043a\u043e\u0440\u0435\u043d\u044c \u0438\u0437 &quot;\u043e\u0441\u0432\u0435\u0449\u0435\u043d\u043d\u043e\u0441\u0442\u0438&quot; (\u043f\u043e \u043c\u043d\u0435 \u0442\u0430\u043a \u043a\u0440\u0430\u0441\u0438\u0432\u0435\u0435 \u0447\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e)    gl_FragColor = vec4(base.rgb * sqrt(color.rgb), 1.0); } <\/code><\/pre>\n<p>  \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0438 \u0432\u043e\u0442, \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/a6a\/fb8\/506\/a6afb8506c3b45cca273163aa226e072.jpg\"\/><\/p>\n<p>  \u041d\u0443 \u0438\u043b\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u0441\u044f \u043d\u0430 \u0432\u0435\u0442\u043a\u0443 step4. <\/p>\n<p>  \u0412 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0445\u043e\u0447\u0443 \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u043d\u0435 \u0442\u043e \u0447\u0442\u043e \u0445\u043e\u0442\u0435\u043b (\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043a\u0440\u0443\u0442\u044b\u0435 \u0438 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0442\u0435\u043d\u0438, \u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u043b <em>\u0411\u0435\u0441\u0446\u0435\u043d\u043d\u044b\u0439 \u041e\u043f\u044b\u0442<\/em> \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432), \u043e\u0434\u043d\u0430\u043a\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u0435\u043c\u043b\u0438\u043c\u043e \u0438 \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0433\u0434\u0435-\u043d\u0438\u0431\u0443\u0434\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c.       <\/p>\n<div class=\"clear\"><\/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=\"http:\/\/habrahabr.ru\/post\/272233\/\"> http:\/\/habrahabr.ru\/post\/272233\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>       \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0441\u0432\u043e\u0438\u043c\u0438 \u0440\u0443\u043a\u0430\u043c\u0438, \u0438\u043c\u0435\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u043b\u043e\u043a\u043d\u043e\u0442 \u0438 \u043b\u044e\u0431\u043e\u0439 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440, \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0448\u0435\u0439\u0434\u0435\u0440\u043d\u044b\u0435 2D-\u0442\u0435\u043d\u0438 \u043d\u0430 WebGL. \u0412\u0441\u0435 \u0448\u0430\u0433\u0438 \u043b\u0435\u0436\u0430\u0442 \u043d\u0430 \u0433\u0438\u0442\u0445\u0430\u0431\u0435 \u043a\u0430\u043a \u0432\u0435\u0442\u043a\u0438 \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f git checkout stepN, \u0442\u0430\u043a \u0447\u0442\u043e \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u0436\u0435 \u0442\u0435\u043c, \u043a\u0442\u043e \u043d\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u043a\u043e\u0434\u0438\u0442\u044c.<\/p>\n<p>  \u041a\u0414\u041f\u0412: <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/9f3\/a70\/19a\/9f3a7019ab2e4ddbb41aac47a960f62c.jpg\"\/>  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-269528","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/269528","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=269528"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/269528\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=269528"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=269528"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=269528"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}