{"id":305107,"date":"2020-06-09T21:00:12","date_gmt":"2020-06-09T21:00:12","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=305107"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=305107","title":{"rendered":"\u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u0448\u0435\u0439\u0434\u0435\u0440 \u043c\u0443\u043b\u044c\u0442\u044f\u0448\u043d\u043e\u0439 \u0433\u0440\u0430\u0444\u0438\u043a\u0438 \u0432 OpenGL \u0441\u0432\u043e\u0438\u043c\u0438 \u0440\u0443\u043a\u0430\u043c\u0438"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/505726\/\">\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u044f \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b\u0441\u044f \u0440\u0438\u0441\u0443\u043d\u043a\u0430\u043c\u0438, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0438\u043c\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432, \u0438 \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u043d\u0435\u0447\u0442\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 \u0434\u043b\u044f \u0442\u0440\u0435\u0445\u043c\u0435\u0440\u043d\u043e\u0439 \u0433\u0440\u0430\u0444\u0438\u043a\u0438.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/sv\/qn\/be\/svqnbepps82tnqqwh-stlwsljoa.png\"><br \/>  <i>Suzanne, \u043d\u0435\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0430\u0441\u043a\u043e\u0442 Blender, \u043e\u0442\u0440\u0435\u043d\u0434\u0435\u0440\u0435\u043d\u043d\u044b\u0439 \u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0438\u043c\u0441\u044f \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u043c<br \/>  <\/i><br \/>  \u0412 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0443 \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432 \u0441 \u043f\u043b\u0430\u0432\u043d\u044b\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u043c \u0432\u0435\u0441\u0430 \u043b\u0438\u043d\u0438\u0439 \u043d\u0430 OpenGL, \u0445\u043e\u0442\u044f \u043c\u0435\u0442\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043b\u044e\u0431\u043e\u043c \u0434\u0440\u0443\u0433\u043e\u043c \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u043c API. \u0412\u0441\u0435\u043c \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u2014 \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u043a\u0430\u0442.<br \/>  <a name=\"habracut\"><\/a><br \/>  \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.glfw.org\/\" rel=\"nofollow\">glfw<\/a> \u2014 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u043a\u043d\u0430 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439<\/li>\n<li><a href=\"http:\/\/glew.sourceforge.net\/\" rel=\"nofollow\">glew<\/a> \u2014 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 OpenGL<\/li>\n<li><a href=\"https:\/\/glm.g-truc.net\/0.9.9\/index.html\" rel=\"nofollow\">glm<\/a> \u2014 \u0434\u043b\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0439 \u0438 \u043c\u0430\u0442\u0440\u0438\u0447\u043d\u043e\u0439 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0438<\/li>\n<li><a href=\"https:\/\/www.assimp.org\/\" rel=\"nofollow\">assimp<\/a> \u2014 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043c\u043e\u0434\u0435\u043b\u0438<\/li>\n<\/ul>\n<p>  \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b CMakeLists.txt \u0443 \u043c\u0435\u043d\u044f \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"cmake\">cmake_minimum_required(VERSION 3.17) project(OpenGL_posteffect_tutorial)  find_package(GLEW REQUIRED) find_package(OpenGL REQUIRED) find_package(glfw3 REQUIRED) find_package(glm REQUIRED) find_package(assimp REQUIRED)  add_executable(main main.cpp) target_link_libraries(main GLEW::GLEW OpenGL glfw glm assimp) <\/code><\/pre>\n<p>  \u0412 \u0446\u0435\u043b\u043e\u043c, \u0432\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u2014 \u0438\u0449\u0435\u043c \u043d\u0443\u0436\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c.<\/p>\n<h2>\u0428\u0430\u0433 1. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043e\u043a\u043d\u0430<\/h2>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0430\u0448\u0435 \u043e\u043a\u043d\u043e:<\/p>\n<pre><code class=\"cpp\">#include &lt;GLFW\/glfw3.h&gt; #include &lt;cstdio&gt; #include &lt;functional&gt;  \/\/ \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u0447\u0442\u043e\u0431\u044b \u043e\u043f\u0438\u0441\u0430\u0442\u044c \/\/ \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u0438\u0445 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u044f class InvokeOnDestroy {   std::function&lt;void()&gt; f;  public:   InvokeOnDestroy(std::function&lt;void()&gt; &amp;&amp;fn) : f(fn) {}   ~InvokeOnDestroy() { f(); } };  \/\/ \u0412 \u0446\u0435\u043b\u044f\u0445 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f glfw \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 void myGlfwErrorCallback(int code, const char *description) {   printf(&quot;[GLFW] %d: %s\\n&quot;, code, description);   fflush(stdout); }  \/\/ \u0411\u0443\u0434\u0435\u043c \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044e \u043d\u0430 Escape void myGlfwKeyCallback(GLFWwindow *window, int key, int scancode, int action,                        int mods) {   if (key == GLFW_KEY_ESCAPE &amp;&amp; action == GLFW_PRESS)     glfwSetWindowShouldClose(window, GLFW_TRUE); }  int main() {   if (!glfwInit())     return __LINE__;   InvokeOnDestroy _glfwTerminate(glfwTerminate);   glfwSetErrorCallback(myGlfwErrorCallback);    GLFWwindow *window = glfwCreateWindow(640, 360, &quot;OpenGL Tutorial&quot;, nullptr, nullptr);   glfwSetKeyCallback(window, myGlfwKeyCallback);    \/\/ \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0446\u0438\u043a\u043b   while (!glfwWindowShouldClose(window)) {     glfwPollEvents();     glfwSwapBuffers(window);   }    return 0; }<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ef\/ia\/ja\/efiajahpkuwoazobkh16j6ozjtg.png\"><br \/>  \u0427\u0435\u0440\u043d\u044b\u0439 \u044d\u043a\u0440\u0430\u043d. \u041e\u0436\u0438\u0434\u0430\u0435\u043c\u043e, \u0432\u0435\u0434\u044c \u043c\u044b \u043f\u043e\u043a\u0430 \u043d\u0438\u0447\u0435\u0433\u043e \u0438 \u043d\u0435 \u0440\u0438\u0441\u0443\u0435\u043c  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h2>\u0428\u0430\u0433 2. \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 OpenGL<\/h2>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043c \u0441\u0430\u043c OpenGL:<\/p>\n<pre><code class=\"cpp\">\/\/ GLEW \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0434\u043e GLFW #include &lt;GL\/glew.h&gt; #include &lt;GLFW\/glfw3.h&gt; #include &lt;cstdio&gt; #include &lt;functional&gt;  class InvokeOnDestroy {   std::function&lt;void()&gt; f;  public:   InvokeOnDestroy(std::function&lt;void()&gt; &amp;&amp;fn) : f(fn) {}   ~InvokeOnDestroy() { f(); } };  void myGlfwErrorCallback(int code, const char *description) {   printf(&quot;[GLFW][code=%d] %s\\n&quot;, code, description);   fflush(stdout); }  void myGlfwKeyCallback(GLFWwindow *window, int key, int scancode, int action,                        int mods) {   if (key == GLFW_KEY_ESCAPE &amp;&amp; action == GLFW_PRESS)     glfwSetWindowShouldClose(window, GLFW_TRUE); }  \/\/ \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 \u0441\u0430\u043c\u043e\u0433\u043e OpenGL void GLAPIENTRY myGlDebugCallback(GLenum source, GLenum type, GLuint id,                                   GLenum severity, GLsizei length,                                   const GLchar *message,                                   const void *userParam) {   printf(&quot;[GL][source=0x%X; type=0x%X; id=0x%X; severity=0x%X] %s\\n&quot;, source,          type, id, severity, message); }  int main() {   if (!glfwInit())     return __LINE__;   InvokeOnDestroy _glfwTerminate(glfwTerminate);   glfwSetErrorCallback(myGlfwErrorCallback);    GLFWwindow *window =       glfwCreateWindow(800, 600, &quot;OpenGL Tutorial&quot;, nullptr, nullptr);   glfwSetKeyCallback(window, myGlfwKeyCallback);    \/\/ \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 OpenGL   glfwMakeContextCurrent(window);   if (glewInit() != GLEW_OK)     return __LINE__;    \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043e\u0442\u043b\u0430\u0434\u0447\u0438\u043a\u0430   glEnable(GL_DEBUG_OUTPUT);   glDebugMessageCallback(myGlDebugCallback, nullptr);    \/\/ \u0411\u0443\u0434\u0435\u043c \u0437\u0430\u043a\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u043e\u043a\u043d\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0438\u043d\u0438\u043c \u0446\u0432\u0435\u0442\u043e\u043c   glClearColor(0.0f, 0.0f, 1.0f, 0.0f);   while (!glfwWindowShouldClose(window)) {     glfwPollEvents();     glClear(GL_COLOR_BUFFER_BIT);     glfwSwapBuffers(window);   }    return 0; }<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/u4\/f-\/rm\/u4f-rm4hx3nyvo5ldb1bx6i7ode.png\"><br \/>  \u0422\u0435\u043f\u0435\u0440\u044c \u0444\u043e\u043d \u0441\u0438\u043d\u0438\u0439  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h2>\u0428\u0430\u0433 3. \u041e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430<\/h2>\n<p>  \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043b\u0435\u0433\u043a\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043e\u043a. \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0430\u044f \u0438\u0445 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0446\u0435\u043b\u044c\u044e \u044d\u0442\u043e\u0433\u043e \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430, \u043d\u043e \u0434\u0430\u0436\u0435 \u043f\u0440\u0438 \u043f\u0430\u0434\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0442\u044c \u0440\u0435\u0441\u0443\u0440\u0441\u044b.<\/p>\n<p>  \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u044b\u0435 \u0444\u0430\u0439\u043b\u044b:<\/p>\n<pre><code class=\"cpp\">#include &lt;exception&gt; #include &lt;string&gt; #include &lt;vector&gt;<\/code><\/pre>\n<p>  \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0448\u0435\u0439\u0434\u0435\u0440\u0430:  <\/p>\n<pre><code class=\"cpp\">class Shader {   \/\/ \u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 OpenGL   GLuint id;    \/\/ \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438\u0437 \u0444\u0430\u0439\u043b\u0430   void load(const char *filename) {     FILE *f = fopen(filename, &quot;r&quot;);     \/\/ \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u0443\u0434\u0430\u0447\u0438 \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435     \/\/ \u041a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0448\u0438\u0431\u043e\u043a \u043d\u0435 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0446\u0435\u043b\u0438 \u044d\u0442\u043e\u0433\u043e \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430     \/\/ \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0437\u0434\u0435\u0441\u044c \u0435\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u043d\u0435\u0431\u0440\u0435\u0447\u044c     if (!f)       throw std::exception();     InvokeOnDestroy _fclose([&amp;]() { fclose(f); });      \/\/ \u0427\u0438\u0442\u0430\u0435\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0444\u0430\u0439\u043b\u0430     std::string src;     int c;     while ((c = getc(f)) != EOF)       src.push_back(c);      \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043a\u043e\u0434 \u0448\u0435\u0439\u0434\u0435\u0440\u0430     const GLchar *string = src.data();     const GLint length = src.length();     glShaderSource(id, 1, &amp;string, &amp;length);   }    \/\/ \u041a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f \u0448\u0435\u0439\u0434\u0435\u0440\u0430   void compile() {     glCompileShader(id);     \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438     GLint status;     glGetShaderiv(id, GL_COMPILE_STATUS, &amp;status);     if (!status) {       \/\/ \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u0443\u0434\u0430\u0447\u0438 -- \u0432\u044b\u0432\u0435\u0434\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430       \/\/ \u0438 \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435       GLchar infoLog[2048];       GLsizei length;       glGetShaderInfoLog(id, sizeof(infoLog) \/ sizeof(infoLog[0]), &amp;length,                          infoLog);       fputs(infoLog, stderr);       fflush(stderr);       throw std::exception();     }   }  public:   Shader(GLenum type) : id(glCreateShader(type)) {}   ~Shader() { glDeleteShader(id); }   \/\/ \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043a GLuint,   \/\/ \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 OpenGL   \/\/ \u043f\u0440\u044f\u043c\u043e \u043e\u0442 \u043d\u0430\u0448\u0435\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430   operator GLuint() { return id; }    \/\/ \u0412\u044b\u043d\u0435\u0441\u0435\u043d\u043e \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e,   \/\/ \u0442.\u043a. \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435   \/\/ \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f   void init(const char *filename) {     load(filename);     compile();   } };<\/code><\/pre>\n<p>  \u0422\u0430\u043a\u043e\u0439 \u0436\u0435 \u0434\u043b\u044f \u0448\u0435\u0439\u0434\u0435\u0440\u043d\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b:<\/p>\n<pre><code class=\"cpp\">class ShaderProgram {   \/\/ \u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 OpenGL   GLuint id;    \/\/ \u041a\u043e\u043c\u043f\u043e\u043d\u043e\u0432\u043a\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b   void link() {     glLinkProgram(id);     \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0441\u0442\u044c     GLint status;     glGetProgramiv(id, GL_LINK_STATUS, &amp;status);     if (!status) {       \/\/ \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u0443\u0434\u0430\u0447\u0438 -- \u0432\u044b\u0432\u0435\u0434\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u043e\u0432\u0449\u0438\u043a\u0430       \/\/ \u0438 \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435       GLchar infoLog[2048];       GLsizei length;       glGetProgramInfoLog(id, sizeof(infoLog) \/ sizeof(infoLog[0]), &amp;length,                           infoLog);       fputs(infoLog, stderr);       fflush(stderr);       throw std::exception();     }   }    \/\/ \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b   void validate() {     glValidateProgram(id);     \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0441\u0442\u044c     GLint status;     glGetProgramiv(id, GL_VALIDATE_STATUS, &amp;status);     if (!status) {       \/\/ \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u0443\u0434\u0430\u0447\u0438 -- \u0432\u044b\u0432\u0435\u0434\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u0430       \/\/ \u0438 \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435       GLchar infoLog[2048];       GLsizei length;       glGetProgramInfoLog(id, sizeof(infoLog) \/ sizeof(infoLog[0]), &amp;length,                           infoLog);       fputs(infoLog, stderr);       fflush(stderr);       throw std::exception();     }   }  public:   ShaderProgram() : id(glCreateProgram()) {}   ~ShaderProgram() { glDeleteProgram(id); }   operator GLuint() { return id; }    \/\/ \u0412\u044b\u043d\u0435\u0441\u0435\u043d\u043e \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e,   \/\/ \u0442.\u043a. \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435   \/\/ \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f   void init(const char *vertSrc, const char *fragSrc) {     \/\/ \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u044b\u0439 \u0438 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440\u044b     Shader vert(GL_VERTEX_SHADER);     Shader frag(GL_FRAGMENT_SHADER);     vert.init(vertSrc);     frag.init(fragSrc);     \/\/ \u041f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043c \u0438\u0445 \u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435     glAttachShader(id, vert);     glAttachShader(id, frag);     \/\/ \u0421\u043a\u043e\u043c\u043f\u043e\u043d\u0443\u0435\u043c \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443     link();     validate();   } };<\/code><\/pre>\n<p>  \u0410 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f:<\/p>\n<ul>\n<li>\u0411\u0443\u0444\u0435\u0440\u043e\u0432<\/li>\n<li>\u041c\u0430\u0441\u0441\u0438\u0432\u043e\u0432 \u0432\u0435\u0440\u0448\u0438\u043d<\/li>\n<li>\u0422\u0435\u043a\u0441\u0442\u0443\u0440<\/li>\n<li>\u0424\u0440\u0435\u0439\u043c\u0431\u0443\u0444\u0435\u0440\u043e\u0432<\/li>\n<\/ul>\n<p>  \u0423 \u0432\u0441\u0435\u0445 \u044d\u0442\u0438\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043f\u043e\u0447\u0442\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f\/\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u043c\u0430\u043a\u0440\u043e\u0441\u0430.<\/p>\n<pre><code class=\"cpp\">#define DEFINE_GL_ARRAY_HELPER(name, gen, del)                                 \\   struct name : public std::vector&lt;GLuint&gt; {                                   \\     name(size_t n) : std::vector&lt;GLuint&gt;(n) { gen(n, data()); }                \\     ~name() { del(size(), data()); }                                           \\   }; DEFINE_GL_ARRAY_HELPER(Buffers, glGenBuffers, glDeleteBuffers) DEFINE_GL_ARRAY_HELPER(VertexArrays, glGenVertexArrays, glDeleteVertexArrays) DEFINE_GL_ARRAY_HELPER(Textures, glGenTextures, glDeleteTextures) DEFINE_GL_ARRAY_HELPER(Framebuffers, glGenFramebuffers, glDeleteFramebuffers)<\/code><\/pre>\n<p>  \u0423\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438 \u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 OpenGL \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u043c\u0438 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f.<\/p>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0448\u0435\u0439\u0434\u0435\u0440\u043d\u0443\u044e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443, \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0432\u043e\u0434\u044f\u0449\u0443\u044e \u0432\u0435\u0440\u0448\u0438\u043d\u044b \u0431\u0435\u0437 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0439 \u0431\u0435\u043b\u044b\u043c \u0446\u0432\u0435\u0442\u043e\u043c:<\/p>\n<pre><code class=\"cpp\">ShaderProgram mainProgram; mainProgram.init(&quot;s1.vert&quot;, &quot;s1.frag&quot;);<\/code><\/pre>\n<p>  s1.vert<\/p>\n<pre><code class=\"plaintext\">#version 330 core  in vec3 vertexPosition;  void main() {   gl_Position = vec4(vertexPosition, 1); }<\/code><\/pre>\n<p>  s1.frag<\/p>\n<pre><code class=\"plaintext\">#version 330 core  out vec4 pixelColor;  void main() {   pixelColor = vec4(1); }<\/code><\/pre>\n<p>  \u0417\u0430\u0434\u0430\u0434\u0438\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430:<\/p>\n<pre><code class=\"cpp\">Buffers buffers(1); VertexArrays vertexArrays(1); GLint attribLocation;  glBindVertexArray(vertexArrays[0]); glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); \/\/ \u0417\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0431\u0443\u0444\u0435\u0440 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c\u0438 \u0442\u043e\u0447\u0435\u043a \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 GLfloat vertices[] = {     -0.5f, -0.5f, 0.0f,     -0.5f, 0.5f,  0.0f,     0.5f,  0.0f,  0.0f, }; glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); \/\/ \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0431\u0443\u0444\u0435\u0440 \u043a\u0430\u043a \u0432\u0445\u043e\u0434 \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u0448\u0435\u0439\u0434\u0435\u0440\u0430 attribLocation = glGetAttribLocation(mainProgram, &quot;vertexPosition&quot;); glEnableVertexAttribArray(attribLocation); \/\/ \u0417\u0430\u0434\u0430\u0434\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0440\u0435\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u043d\u0430 \u0432\u0435\u0440\u0448\u0438\u043d\u0443 \u0441 \u043f\u043b\u043e\u0442\u043d\u043e\u0439 \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u043e\u0439 glVertexAttribPointer(attribLocation, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0);<\/code><\/pre>\n<p>  \u0418 \u043d\u0430\u0447\u043d\u0435\u043c \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435:<\/p>\n<pre><code class=\"cpp\">while (!glfwWindowShouldClose(window)) {   glfwPollEvents();    int framebufferWidth, framebufferHeight;   glfwGetFramebufferSize(window, &amp;framebufferWidth, &amp;framebufferHeight);   glViewport(0, 0, framebufferWidth, framebufferHeight);    glClear(GL_COLOR_BUFFER_BIT);   glBindVertexArray(vertexArrays[0]);   glUseProgram(mainProgram);   \/\/ \u041e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a \u0438\u0437 \u043d\u0430\u0447\u0430\u043b\u0430 \u0431\u0443\u0444\u0435\u0440\u0430 \u0438 \u0442\u0440\u0435\u0445 \u0432\u0435\u0440\u0448\u0438\u043d   glDrawArrays(GL_TRIANGLES, 0, 3);   glUseProgram(0);   glBindVertexArray(0);    glfwSwapBuffers(window); }<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ks\/pa\/sb\/kspasbxgncttff39krbbviryebi.png\">  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h2>\u0428\u0430\u0433 4. \u041f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u043a\u0430\u043c\u0435\u0440\u044b<\/h2>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a\u0430\u043c\u0435\u0440\u044b \u0432\u043e\u043a\u0440\u0443\u0433 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430.<\/p>\n<p>  \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0439 \u0444\u0430\u0439\u043b glm \u0434\u043b\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0439 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0438:<\/p>\n<pre><code class=\"cpp\">#include &lt;glm\/glm.hpp&gt;<\/code><\/pre>\n<p>  \u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u043c \u043d\u0430\u0448 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a:<\/p>\n<pre><code class=\"cpp\">GLfloat vertices[] = {     0.0f, 0.0f, 1.0f,     0.0f, 1.0f, 0.0f,     1.0f, 0.0f, 0.0f, };<\/code><\/pre>\n<p>  \u041d\u043e\u0432\u044b\u0439 \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u2014 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0432 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u043a\u0430\u043c\u0435\u0440\u044b \u2014 \u043f\u0440\u043e\u0435\u043a\u0446\u0438\u044f:<\/p>\n<pre><code class=\"plaintext\">#version 330 core  uniform mat4 matModel; uniform mat4 matView; uniform mat4 matProjection; in vec3 vertexPosition;  void main() {   gl_Position = matProjection * matView * matModel * vec4(vertexPosition, 1); }<\/code><\/pre>\n<p>  \u041f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 uniform-\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u0430, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0438\u0445 \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435:<\/p>\n<pre><code class=\"cpp\">GLint ulMatModel = glGetUniformLocation(mainProgram, &quot;matModel&quot;); GLint ulMatView = glGetUniformLocation(mainProgram, &quot;matView&quot;); GLint ulMatProjection = glGetUniformLocation(mainProgram, &quot;matProjection&quot;);<\/code><\/pre>\n<p>  \u041f\u0443\u0441\u0442\u044c \u043a\u0430\u043c\u0435\u0440\u0430 \u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0441\u043e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c\u044e 1\/8 \u0440\u0430\u0434\u0438\u0430\u043d\u0430 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443, \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/ae7\/733\/bf1\/ae7733bf104632e09cb47c3da491cb22.svg\" alt=\"$\\vec{0}$\" data-tex=\"inline\"><\/math> \u0438 \u043e\u0441\u044c \u00ab\u0432\u0432\u0435\u0440\u0445\u00bb \u044d\u0442\u043e Z:<\/p>\n<pre><code class=\"cpp\">float angle = 0.5f * glfwGetTime(); float sin = glm::sin(angle); float cos = glm::cos(angle); glm::vec3 pos(2.5f * sin, 2.5f * cos, 1.5f); glm::vec3 forward = glm::normalize(-pos); glm::vec3 up(0.0f, 0.0f, 1.0f); glm::vec3 right = glm::normalize(glm::cross(forward, up)); up = glm::cross(right, forward);<\/code><\/pre>\n<p>  \u0417\u0434\u0435\u0441\u044c pos \u2014 \u044d\u0442\u043e \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043a\u0430\u043c\u0435\u0440\u044b, \u0430 forward, right \u0438 up \u2014 \u044d\u0442\u043e \u043b\u0435\u0432\u0430\u044f \u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0440\u0442\u043e\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0445 \u0432\u0435\u043a\u0442\u043e\u0440\u043e\u0432, \u0437\u0430\u0434\u0430\u044e\u0449\u0438\u0445 \u0432 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435 \u043a\u0430\u043c\u0435\u0440\u044b \u043e\u0441\u0438 Z (\u043e\u0442 \u043a\u0430\u043c\u0435\u0440\u044b), X (\u0432\u043f\u0440\u0430\u0432\u043e) \u0438 Y (\u0432\u0432\u0435\u0440\u0445) \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e.<\/p>\n<p>  \u041a\u0430\u043c\u0435\u0440\u0430 \u0441\u043c\u043e\u0442\u0440\u0438\u0442 \u0432 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/ae7\/733\/bf1\/ae7733bf104632e09cb47c3da491cb22.svg\" alt=\"$\\vec{0}$\" data-tex=\"inline\"><\/math>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0435\u043a\u0442\u043e\u0440\u0430 pos \u0438 forward \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b.<br \/>  \u0412\u0435\u043a\u0442\u043e\u0440\u0430 forward, up \u0438 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/76c\/06c\/0a4\/76c06c0a4faeafb675ecfc4fb0faa264.svg\" alt=\"$(0,0,1)$\" data-tex=\"inline\"><\/math> \u043b\u0435\u0436\u0430\u0442 \u0432 \u043e\u0434\u043d\u043e\u0439 \u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0435\u043a\u0442\u043e\u0440 right \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f forward \u0438 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/76c\/06c\/0a4\/76c06c0a4faeafb675ecfc4fb0faa264.svg\" alt=\"$(0,0,1)$\" data-tex=\"inline\"><\/math> (\u043c\u0438\u0440\u043e\u0432\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u2014 \u043f\u0440\u0430\u0432\u0430\u044f).<\/p>\n<p>  \u041d\u0443 \u0438 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0432\u0435\u043a\u0442\u043e\u0440 up \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u0430\u043a \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 right \u0438 forward (\u044d\u0442\u0438 \u0432\u0435\u043a\u0442\u043e\u0440\u044b \u0443\u0436\u0435 \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0435 \u0438 \u043e\u0440\u0442\u043e\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0445 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0442\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u043c).<\/p>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0430\u0442\u0440\u0438\u0446\u044b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0439:<\/p>\n<pre><code class=\"cpp\">glm::mat4 matModel(1.0f, 0.0f, 0.0f, 0.0f,                     0.0f, 1.0f, 0.0f, 0.0f,                     0.0f, 0.0f, 1.0f, 0.0f,                     0.0f, 0.0f, 0.0f, 1.0f); <\/code><\/pre>\n<p>  \u041d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u0430\u0442\u0440\u0438\u0446\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u2014 \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u0430\u044f.<\/p>\n<pre><code class=\"cpp\">glm::mat4 matView(right.x, up.x, forward.x, 0.0f,                   right.y, up.y, forward.y, 0.0f,                   right.z, up.z, forward.z, 0.0f,                   0.0f, 0.0f, 0.0f, 1.0f); matView *= glm::mat4(1.0f, 0.0f, 0.0f, 0.0f,                       0.0f, 1.0f, 0.0f, 0.0f,                       0.0f, 0.0f, 1.0f, 0.0f,                       -pos.x, -pos.y, -pos.z, 1.0f);<\/code><\/pre>\n<p>  \u041c\u0430\u0442\u0440\u0438\u0446\u0430 \u0432\u0438\u0434\u0430 \u2014 \u044d\u0442\u043e \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043a\u0430\u043c\u0435\u0440\u044b \u0438 \u043f\u0440\u043e\u0435\u043a\u0446\u0438\u044f \u043d\u0430 \u043e\u0441\u0438 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0432 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435 \u043a\u0430\u043c\u0435\u0440\u044b, \u0442.\u0435.<\/p>\n<p><math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/0af\/c7c\/f55\/0afc7cf55b49b9270b738800351262e4.svg\" alt=\"$M=\\left[\\begin{array}{cccc} R_x &amp; R_y &amp; R_z &amp; 0 \\\\ U_x &amp; U_y &amp; U_z &amp; 0 \\\\ F_x &amp; F_y &amp; F_z &amp; 0 \\\\ 0 &amp; 0 &amp; 0 &amp; 1 \\\\ \\end{array}\\right]\\cdot\\left[\\begin{array}{cccc} 1 &amp; 0 &amp; 0 &amp; -P_x \\\\ 0 &amp; 1 &amp; 0 &amp; -P_y \\\\ 0 &amp; 0 &amp; 1 &amp; -P_z \\\\ 0 &amp; 0 &amp; 0 &amp; 1 \\\\ \\end{array}\\right]$\" data-tex=\"display\"><\/math><\/p>\n<p>  \u0413\u0434\u0435 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/d00\/339\/84c\/d0033984cb17f398d33c3b5684cd6126.svg\" alt=\"$\\vec{F}$\" data-tex=\"inline\"><\/math> \u2014 forward, <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c9c\/64c\/904\/c9c64c904c47589553638a8524b34874.svg\" alt=\"$\\vec{R}$\" data-tex=\"inline\"><\/math> \u2014 right, <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/0a4\/68c\/798\/0a468c79823c9f400d060cba8bc1c129.svg\" alt=\"$\\vec{U}$\" data-tex=\"inline\"><\/math> \u2014 up, <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a64\/ffe\/162\/a64ffe162a83dd7329b7a7dac9ae913f.svg\" alt=\"$\\vec{P}$\" data-tex=\"inline\"><\/math> \u2014 pos.<\/p>\n<p>  \u0421\u0442\u043e\u0438\u0442 \u0443\u0447\u0435\u0441\u0442\u044c, \u0447\u0442\u043e \u0432 glm \u043c\u0430\u0442\u0440\u0438\u0446\u044b \u0437\u0430\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0430\u043c, \u0442.\u0435. \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0438\u0434\u0443\u0442 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435:<\/p>\n<p><math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/4c6\/593\/73d\/4c659373d383ba3d053539c690d13118.svg\" alt=\"$A=\\left[\\begin{array}{cccc} a_1 &amp; a_5 &amp; a_9 &amp; a_{13} \\\\ a_2 &amp; a_6 &amp; a_{10} &amp; a_{14} \\\\ a_3 &amp; a_7 &amp; a_{11} &amp; a_{15} \\\\ a_4 &amp; a_8 &amp; a_{12} &amp; a_{16} \\\\ \\end{array}\\right]$\" data-tex=\"display\"><\/math><\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">float zNear = 0.0625f; float zFar = 32.0f; glm::mat4 matProjection(1.0f, 0.0f, 0.0f, 0.0f,                         0.0f, 1.0f, 0.0f, 0.0f,                         0.0f, 0.0f, (zFar + zNear) \/ (zFar - zNear), 1.0f,                         0.0f, 0.0f, -2.0f * zFar * zNear \/ (zFar - zNear), 0.0f);<\/code><\/pre>\n<p>  \u041d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u0430\u0442\u0440\u0438\u0446\u0430 \u043f\u0440\u043e\u0435\u043a\u0446\u0438\u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442 Z \u0438\u0437 \u043e\u0442\u0440\u0435\u0437\u043a\u0430 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/5a3\/c21\/07a\/5a3c2107ac0cd17f36f76e6ceed6cc63.svg\" alt=\"$[z_1;z_2]$\" data-tex=\"inline\"><\/math> (<math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/dee\/174\/0c6\/dee1740c6084ec2a28c58a370135bba8.svg\" alt=\"$z_1$\" data-tex=\"inline\"><\/math> \u2014 zNear, <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/371\/b15\/55f\/371b1555f4cdf82e5472b2fd5b6c1afc.svg\" alt=\"$z_2$\" data-tex=\"inline\"><\/math> \u2014 zFar) \u0432 \u043e\u0442\u0440\u0435\u0437\u043e\u043a <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c1e\/15e\/6d6\/c1e15e6d6de96c8dd953b7300f1fa06a.svg\" alt=\"$[-1;1]$\" data-tex=\"inline\"><\/math>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u0435\u043b\u0438\u0442 X \u0438 Y \u043d\u0430 Z.<\/p>\n<p>  \u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442: \u0432\u044b\u0432\u043e\u0434 gl_Position \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u0448\u0435\u0439\u0434\u0435\u0440\u0430 \u0434\u043e \u0440\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0435\u043b\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u0432\u043e\u044e \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0443 W, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b X \u0438 Y \u043d\u0430 Z \u043c\u044b \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u043c W \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b Z. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b XYZ \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u044b \u043a\u0443\u0431\u043e\u043c <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/523\/55c\/95a\/52355c95af381194f02bbcb647aac3ee.svg\" alt=\"$[-1;1]^3$\" data-tex=\"inline\"><\/math>, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043d\u043e\u0432\u0430\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430 Z \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u043e\u043f\u0430\u0441\u0442\u044c \u0432 \u044d\u0442\u043e\u0442 \u043a\u0443\u0431. \u0417\u0430\u0434\u0430\u0434\u0438\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u2014 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/dee\/174\/0c6\/dee1740c6084ec2a28c58a370135bba8.svg\" alt=\"$z_1$\" data-tex=\"inline\"><\/math> \u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u2014 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/371\/b15\/55f\/371b1555f4cdf82e5472b2fd5b6c1afc.svg\" alt=\"$z_2$\" data-tex=\"inline\"><\/math> \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0434\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c \u043d\u043e\u0432\u0443\u044e Z \u043a\u0430\u043a \u043b\u0438\u043d\u0435\u0439\u043d\u0443\u044e \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044e Z \u0434\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0438 1 (\u0442.\u0435. W \u0434\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f):  <\/p>\n<p><math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/f2a\/ec3\/610\/f2aec3610a91cb09eff8587a92c0b833.svg\" alt=\"$\\hat{z}=\\frac{az+b}{z}=a+\\frac{b}{z}; z_1\\leq z\\leq z_2; -1\\leq\\hat{z}\\leq 1$\" data-tex=\"display\"><\/math><\/p>\n<p>  \u041f\u0440\u0438 \u044d\u0442\u043e\u043c <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/4ec\/3e2\/363\/4ec3e23638b6073b649999485c251c94.svg\" alt=\"$z$\" data-tex=\"inline\"><\/math> \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0441\u0442\u0430\u0442\u044c\u0441\u044f \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430\u044e\u0449\u0435\u0439, \u0442.\u043a. <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/dee\/174\/0c6\/dee1740c6084ec2a28c58a370135bba8.svg\" alt=\"$z_1$\" data-tex=\"inline\"><\/math> \u2014 \u0431\u043b\u0438\u0436\u043d\u044f\u044f \u0433\u0440\u0430\u043d\u0438\u0446\u0430, \u0430 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/371\/b15\/55f\/371b1555f4cdf82e5472b2fd5b6c1afc.svg\" alt=\"$z_2$\" data-tex=\"inline\"><\/math> \u2014 \u0434\u0430\u043b\u044c\u043d\u044f\u044f. \u041e\u0442\u0441\u044e\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0443\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0439:  <\/p>\n<p><math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/fdd\/125\/691\/fdd12569176d32e8ae956d10b3cdc1b7.svg\" alt=\"$\\left\\{\\begin{array}{ccc} a+\\frac{b}{z_1}&amp;=&amp;-1 \\\\ a+\\frac{b}{z_2}&amp;=&amp;1 \\\\ \\end{array}\\right.$\" data-tex=\"display\"><\/math><\/p>\n<p>  <\/p>\n<p><math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/0f8\/916\/d06\/0f8916d068e14d119d16a3b92ce54108.svg\" alt=\"$\\left\\{\\begin{array}{l} a\\left(z_2-z_1\\right)=z_2+z_1 \\\\ b\\left(\\frac{1}{z_2}-\\frac{1}{z_1}\\right)=2 \\\\ \\end{array}\\right.$\" data-tex=\"display\"><\/math><\/p>\n<p>  <\/p>\n<p><math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a42\/486\/f84\/a42486f84867b36be27fb7dbd4d47354.svg\" alt=\"$a=\\frac{z_2+z_1}{z_2-z_1}$\" data-tex=\"display\"><\/math><\/p>\n<p>  <\/p>\n<p><math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/cba\/fbc\/64c\/cbafbc64c9d86ba61b33cbe8dd7fcf76.svg\" alt=\"$b=\\frac{2z_1z_2}{z_1-z_2}=-2\\frac{z_2z_1}{z_2-z_1}$\" data-tex=\"display\"><\/math><\/p>\n<p>  \u0418 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u0430\u044f \u043c\u0430\u0442\u0440\u0438\u0446\u0430 \u043f\u0440\u043e\u0435\u043a\u0446\u0438\u0438:  <\/p>\n<p><math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/961\/86e\/166\/96186e166c3e28898e52268e64cf6d11.svg\" alt=\"$M=\\left[\\begin{array}{cccc} 1 &amp; 0 &amp; 0 &amp; 0 \\\\ 0 &amp; 1 &amp; 0 &amp; 0 \\\\ 0 &amp; 0 &amp; \\frac{z_2+z_1}{z_2-z_1} &amp; -2\\frac{z_2z_1}{z_2-z_1} \\\\ 0 &amp; 0 &amp; 1 &amp; 0 \\\\ \\end{array}\\right]$\" data-tex=\"display\"><\/math><\/p>\n<p>  \u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043c \u043d\u0430\u0448\u0438 \u043c\u0430\u0442\u0440\u0438\u0446\u044b \u0432 \u0448\u0435\u0439\u0434\u0435\u0440:  <\/p>\n<pre><code class=\"cpp\">glUseProgram(mainProgram); glUniformMatrix4fv(ulMatModel,      1, GL_FALSE, &amp;matModel[0][0]); glUniformMatrix4fv(ulMatView,       1, GL_FALSE, &amp;matView[0][0]); glUniformMatrix4fv(ulMatProjection, 1, GL_FALSE, &amp;matProjection[0][0]); glDrawArrays(GL_TRIANGLES, 0, 3);<\/code><\/pre>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><iframe src=\"https:\/\/www.youtube.com\/embed\/XO0pohW9i4Q?rel=0&amp;showinfo=1&amp;hl=en-US\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen scrolling=\"no\" allow=\"encrypted-media; accelerometer; gyroscope; picture-in-picture\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/w1\/ox\/iq\/w1oxiqrma3zhh3-qy4fp8w6de00.png\"><br \/>  \u041a\u0430\u043a \u0438 \u043e\u0436\u0438\u0434\u0430\u043b\u043e\u0441\u044c, \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0439\u0441\u044f \u0431\u0435\u043b\u044b\u0439 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a. \u041f\u043e\u043a\u0430 \u043d\u0438\u0447\u0435\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0433\u043e.  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h2>\u0428\u0430\u0433 5. \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438<\/h2>\n<p>  \u0417\u0430\u043c\u0435\u043d\u0438\u043c \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a \u043d\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u0443\u044e \u0444\u0438\u0433\u0443\u0440\u0443. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b assimp:<\/p>\n<pre><code class=\"cpp\">#include &lt;assimp\/Importer.hpp&gt; #include &lt;assimp\/postprocess.h&gt; #include &lt;assimp\/scene.h&gt;<\/code><\/pre>\n<p>  \u041f\u043e\u043a\u0430 \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u0443\u0431. \u0415\u0433\u043e OBJ-\u0444\u0430\u0439\u043b \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"plaintext\">v  1  1  1 v  1  1 -1 v  1 -1  1 v  1 -1 -1 v -1  1  1 v -1  1 -1 v -1 -1  1 v -1 -1 -1 f 1 5 7 3 f 4 3 7 8 f 8 7 5 6 f 6 2 4 8 f 2 1 3 4 f 6 5 1 2<\/code><\/pre>\n<p>  \u0417\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0441\u0442\u043e 8 \u0432\u0435\u0440\u0448\u0438\u043d \u043a\u0443\u0431\u0430 \u0438 6 \u0435\u0433\u043e \u0433\u0440\u0430\u043d\u0435\u0439, \u043f\u043e 4 \u0432\u0435\u0440\u0448\u0438\u043d\u044b \u043d\u0430 \u043a\u0430\u0436\u0434\u0443\u044e<\/p>\n<p>  \u0417\u0430\u043c\u0435\u043d\u0438\u043c \u043a\u043e\u0434 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432\u0435\u0440\u0448\u0438\u043d \u0432 \u0431\u0443\u0444\u0435\u0440:<\/p>\n<pre><code class=\"cpp\">\/\/ \u041d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f 2 \u0431\u0443\u0444\u0435\u0440\u0430: \u0434\u043b\u044f \u0432\u0435\u0440\u0448\u0438\u043d \u0438 \u0434\u043b\u044f \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u0432 \u0432\u0435\u0440\u0448\u0438\u043d Buffers buffers(2); VertexArrays vertexArrays(1); GLint attribLocation;  glBindVertexArray(vertexArrays[0]); glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); \/\/ \u0412 \u043e\u0431\u044a\u0435\u043a\u0442\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0435\u0440\u0448\u0438\u043d, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0437\u0430\u043f\u0438\u0448\u0435\u043c \u0435\u0433\u043e \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e GLuint indexCount; {   Assimp::Importer importer;   \/\/ \u0413\u0440\u0430\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0435 \u0432 \u0432\u0438\u0434\u0435 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u043e\u0432,   \/\/ \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043c \u0442\u0440\u0438\u0430\u043d\u0433\u0443\u043b\u044f\u0446\u0438\u044e \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435   const aiScene *scene =       importer.ReadFile(&quot;scene.obj&quot;, aiProcess_Triangulate);   \/\/ \u041f\u043e\u043a\u0430 \u0441\u0447\u0438\u0442\u0430\u0435\u043c, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0441\u0446\u0435\u043d\u0435   const aiMesh *mesh = scene-&gt;mMeshes[0];   glBufferData(GL_ARRAY_BUFFER, mesh-&gt;mNumVertices * 3 * sizeof(GLfloat),                 mesh-&gt;mVertices, GL_STATIC_DRAW);   \/\/ \u041f\u0440\u043e\u0445\u043e\u0434\u0438\u043c \u043f\u043e \u0432\u0441\u0435\u043c \u0433\u0440\u0430\u043d\u044f\u043c \u0438 \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u043c \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0432\u0435\u0440\u0448\u0438\u043d \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u043e\u0432   std::vector&lt;GLuint&gt; indices;   for (int i = 0; i &lt; mesh-&gt;mNumFaces; ++i)     for (int j = 0; j &lt; mesh-&gt;mFaces[i].mNumIndices; ++j)       indices.push_back(mesh-&gt;mFaces[i].mIndices[j]);   \/\/ \u0417\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u0432   indexCount = indices.size();   \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0432 \u0431\u0443\u0444\u0435\u0440   glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(GLuint),                 indices.data(), GL_STATIC_DRAW); } \/\/ \u0417\u0434\u0435\u0441\u044c \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u043d\u0430 \u0432\u0445\u043e\u0434 \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u0448\u0435\u0439\u0434\u0435\u0440\u0430 \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u043f\u043e\u0434\u0430\u044e\u0442\u0441\u044f \/\/ \u0442\u0440\u0435\u0445\u043c\u0435\u0440\u043d\u044b\u0435 \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0432\u0435\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0447\u0438\u0441\u0435\u043b \u043e\u0434\u0438\u043d\u0430\u0440\u043d\u043e\u0439 \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 attribLocation = glGetAttribLocation(mainProgram, &quot;vertexPosition&quot;); glEnableVertexAttribArray(attribLocation); glVertexAttribPointer(attribLocation, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);<\/code><\/pre>\n<p>  \u0418 \u043a\u043e\u0434 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438:<\/p>\n<pre><code class=\"cpp\">\/\/ \u0417\u0430\u043c\u0435\u043d\u044f\u0435\u043c glDrawArrays(GL_TRIANGLES, 0, 3) \u043d\u0430 glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);<\/code><\/pre>\n<p>  \u0410 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u043a\u0430 \u0437\u0430\u043c\u0435\u043d\u0438\u043c \u043d\u0430\u0448 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0439 \u0448\u0435\u0439\u0434\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u0446\u0432\u0435\u0442 \u0442\u043e\u0447\u043a\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043b \u043e\u0442 \u0435\u0435 \u0433\u043b\u0443\u0431\u0438\u043d\u044b:<\/p>\n<pre><code class=\"plaintext\">#version 330 core  out vec4 pixelColor;  void main() {   pixelColor = vec4(vec3(exp(-gl_FragCoord.w)), 1); }<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ga\/ml\/jp\/gamljpnn-eita71rzwgfr0bdqc4.png\"><br \/>  \u0427\u0442\u043e-\u0442\u043e \u0442\u0443\u0442 \u043d\u0435 \u0442\u0430\u043a. \u0412\u0435\u0434\u044c \u0433\u043b\u0443\u0431\u0438\u043d\u0430 \u043d\u0430 \u043f\u043e\u0432\u0435\u0440\u0445\u043d\u043e\u0441\u0442\u0438 \u043a\u0443\u0431\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0439.  <\/div>\n<\/p><\/div>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0433\u043b\u0443\u0431\u0438\u043d\u044b, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u043e \u0432\u0438\u0434\u043d\u043e \u043d\u0435 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0437\u0436\u0435 \u043f\u0438\u043a\u0441\u0435\u043b\u044c, \u0430 \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0439 \u043a \u043a\u0430\u043c\u0435\u0440\u0435:<\/p>\n<pre><code class=\"cpp\">glEnable(GL_DEPTH_TEST);<\/code><\/pre>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u043e\u0447\u0438\u0449\u0430\u0442\u044c \u0431\u0443\u0444\u0435\u0440 \u0433\u043b\u0443\u0431\u0438\u043d\u044b:<\/p>\n<pre><code class=\"cpp\">glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);<\/code><\/pre>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><iframe src=\"https:\/\/www.youtube.com\/embed\/6GEps8Vea-g?rel=0&amp;showinfo=1&amp;hl=en-US\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen scrolling=\"no\" allow=\"encrypted-media; accelerometer; gyroscope; picture-in-picture\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/cn\/5t\/aa\/cn5taaxagthvnjowsuitdtv4gya.png\"><br \/>  \u0412\u043e\u0442 \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0440\u044f\u0434\u043e\u043a  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h2>\u0428\u0430\u0433 6. \u041f\u043e\u0441\u0442\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430<\/h2>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u043f\u043e\u0441\u0442\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0418\u0434\u0435\u044f \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0443, \u0430 \u0437\u0430\u0442\u0435\u043c \u044d\u0442\u0443 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0443 \u043e\u0442\u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u0435\u0449\u0435 \u0440\u0430\u0437. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0435\u0434\u043d\u0438\u0445 \u043f\u0438\u043a\u0441\u0435\u043b\u0435\u0439 \u043f\u0440\u0438 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0435 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b, \u0447\u0442\u043e \u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0433\u043b\u0443\u0431\u0438\u043d\u044b \u043f\u0440\u0438 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0435 \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432.<\/p>\n<p>  \u0421\u0445\u0435\u043c\u0430 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/wu\/da\/ko\/wudakoiylgomx_hgqplieiaesyi.png\"><\/p>\n<p>  \u0417\u0434\u0435\u0441\u044c \u0447\u0435\u0440\u043d\u044b\u043c \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u044d\u043a\u0440\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b, \u0430 \u0441\u0438\u043d\u0438\u043c \u2014 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u043d\u044b\u0435.<\/p>\n<p>  \u041a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0432 \u0447\u0435\u0440\u043d\u044b\u0439 \u043a\u0432\u0430\u0434\u0440\u0430\u0442 \u044d\u043a\u0440\u0430\u043d\u0430 (\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043e\u0442 -1 \u0434\u043e 1) \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0442\u043e\u0447\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0441 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c\u0438 \u043e\u0442 0 \u0434\u043e 1.<\/p>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0431\u0443\u0444\u0435\u0440 \u0438 \u043c\u0430\u0441\u0441\u0438\u0432 \u0432\u0435\u0440\u0448\u0438\u043d \u2014 \u0434\u043b\u044f \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430; \u0434\u0432\u0435 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u2014 \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0446\u0432\u0435\u0442\u0430 \u0438 \u0433\u043b\u0443\u0431\u0438\u043d\u044b; \u0444\u0440\u0435\u0439\u043c\u0431\u0443\u0444\u0435\u0440 \u2014 \u0434\u043b\u044f \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043a\u0443\u0434\u0430 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c.<\/p>\n<pre><code class=\"cpp\">Buffers buffers(3); VertexArrays vertexArrays(2); Textures textures(2); Framebuffers framebuffers(1);<\/code><\/pre>\n<p>  \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430:<\/p>\n<pre><code class=\"cpp\">glBindVertexArray(vertexArrays[1]); glBindBuffer(GL_ARRAY_BUFFER, buffers[2]); GLfloat fillTriangle[] = {     -1.0f, -1.0f, 0.0f, 0.0f, \/\/     3.0f,  -1.0f, 2.0f, 0.0f, \/\/     -1.0f, 3.0f,  0.0f, 2.0f, \/\/ }; glBufferData(GL_ARRAY_BUFFER, sizeof(fillTriangle), fillTriangle,               GL_STATIC_DRAW); attribLocation = glGetAttribLocation(postProgram, &quot;vertexPosition&quot;); glEnableVertexAttribArray(attribLocation); glVertexAttribPointer(attribLocation, 2, GL_FLOAT, GL_FALSE,                       4 * sizeof(GLfloat), 0); attribLocation = glGetAttribLocation(postProgram, &quot;vertexTextureCoords&quot;); glEnableVertexAttribArray(attribLocation); glVertexAttribPointer(attribLocation, 2, GL_FLOAT, GL_FALSE,                       4 * sizeof(GLfloat), (GLvoid *)(2 * sizeof(GLfloat))); <\/code><\/pre>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b:<\/p>\n<pre><code class=\"plaintext\">const int MAX_WIDTH = 2048; const int MAX_HEIGHT = 2048; glBindTexture(GL_TEXTURE_2D, textures[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, MAX_WIDTH, MAX_HEIGHT, 0, GL_RGB,               GL_UNSIGNED_BYTE, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  glBindTexture(GL_TEXTURE_2D, textures[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, MAX_WIDTH, MAX_HEIGHT, 0,               GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(GL_TEXTURE_2D, 0);<\/code><\/pre>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u0432 \u043e\u043a\u043d\u0430, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0438\u0445 \u0441 \u0437\u0430\u043f\u0430\u0441\u043e\u043c \u043f\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0443 (\u0443 \u043c\u0435\u043d\u044f \u043c\u043e\u043d\u0438\u0442\u043e\u0440 1920 \u043d\u0430 1080, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 2048 \u043d\u0430 2048 \u2014 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u044b\u0439 \u0437\u0430\u043f\u0430\u0441), \u0438 \u0431\u0443\u0434\u0435\u043c \u0434\u043e\u043c\u043d\u043e\u0436\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u043d\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043d\u0430 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442  <\/p>\n<p><math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1b2\/148\/1d2\/1b21481d2a6d894f52f57a3465859d09.svg\" alt=\"$\\frac{\\text{\u0448\u0438\u0440\u0438\u043d\u0430 \u0438\u043b\u0438 \u0432\u044b\u0441\u043e\u0442\u0430 \u043e\u043a\u043d\u0430}}{\\text{\u0448\u0438\u0440\u0438\u043d\u0430 \u0438\u043b\u0438 \u0432\u044b\u0441\u043e\u0442\u0430 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b}}$\" data-tex=\"display\"><\/math><\/p>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0440\u0435\u0439\u043c\u0431\u0443\u0444\u0435\u0440:<\/p>\n<pre><code class=\"cpp\">glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[0]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,                         textures[0], 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,                         textures[1], 0); GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0}; glDrawBuffers(sizeof(drawBuffers) \/ sizeof(drawBuffers[0]), drawBuffers); glBindFramebuffer(GL_FRAMEBUFFER, 0);<\/code><\/pre>\n<p>  \u0418 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u043f\u043e\u0441\u0442\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438:<\/p>\n<pre><code class=\"cpp\">ShaderProgram postProgram; postProgram.init(&quot;s2.vert&quot;, &quot;s2.frag&quot;);<\/code><\/pre>\n<p>  s2.vert<\/p>\n<pre><code class=\"plaintext\">#version 330 core  uniform vec2 textureScale; in vec2 vertexPosition; in vec2 vertexTextureCoords; out vec2 textureCoords;  void main() {   gl_Position = vec4(vertexPosition, 0, 1);   textureCoords = textureScale * vertexTextureCoords; }<\/code><\/pre>\n<p>  s2.frag<\/p>\n<pre><code class=\"plaintext\">#version 330 core  uniform sampler2D renderTexture; uniform sampler2D depthTexture; in vec2 textureCoords; out vec4 pixelColor;  void main() {   vec4 baseColor = texture2D(renderTexture, textureCoords);   pixelColor = vec4(baseColor.x, 1 - baseColor.y, baseColor.z, 1); }<\/code><\/pre>\n<p>  \u041a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u043f\u043e\u043a\u0430 \u0441\u0443\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0441\u0442\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0432 \u0438\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0437\u0435\u043b\u0435\u043d\u043e\u0433\u043e \u043a\u0430\u043d\u0430\u043b\u0430.<\/p>\n<p>  \u041f\u0440\u0438\u0446\u0435\u043f\u0438\u043c \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0443 \u0446\u0432\u0435\u0442\u0430 \u0432 \u0441\u043b\u043e\u0442 0, \u0430 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0443 \u0433\u043b\u0443\u0431\u0438\u043d\u044b \u2014 \u0432 \u0441\u043b\u043e\u0442 1.<\/p>\n<pre><code class=\"cpp\">glBindVertexArray(vertexArrays[1]); glUseProgram(postProgram); glUniform1i(glGetUniformLocation(postProgram, &quot;renderTexture&quot;), 0); glUniform1i(glGetUniformLocation(postProgram, &quot;depthTexture&quot;), 1); glUseProgram(0); glBindVertexArray(0);<\/code><\/pre>\n<p>  \u0417\u0430\u043f\u043e\u043c\u043d\u0438\u043c \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0435\u0439 \u0437\u0430 \u043c\u0430\u0441\u0448\u0442\u0430\u0431 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b:<\/p>\n<pre><code class=\"cpp\">GLint ulTextureScale = glGetUniformLocation(postProgram, &quot;textureScale&quot;);<\/code><\/pre>\n<p>  \u041d\u043e\u0432\u044b\u0439 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0446\u0438\u043a\u043b:<\/p>\n<pre><code class=\"cpp\">while (!glfwWindowShouldClose(window)) {   glfwPollEvents();    int framebufferWidth, framebufferHeight;   glfwGetFramebufferSize(window, &amp;framebufferWidth, &amp;framebufferHeight);   glViewport(0, 0, framebufferWidth, framebufferHeight);    \/\/ \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0444\u0440\u0435\u0439\u043c\u0431\u0443\u0444\u0435\u0440   glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[0]);   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   glBindVertexArray(vertexArrays[0]);   glUseProgram(mainProgram);    \/\/ \u0417\u0434\u0435\u0441\u044c \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043f\u043e\u043c\u0435\u043d\u044f\u043b\u043e\u0441\u044c   float angle = 0.5f * glfwGetTime();   float sin = glm::sin(angle);   float cos = glm::cos(angle);   glm::vec3 pos(2.5f * sin, 2.5f * cos, 1.5f);   glm::vec3 forward = glm::normalize(-pos);   glm::vec3 up(0.0f, 0.0f, 1.0f);   glm::vec3 right = glm::normalize(glm::cross(forward, up));   up = glm::normalize(glm::cross(right, forward));   float zNear = 0.0625f;   float zFar = 32.0f;    glm::mat4 matModel(1.0f, 0.0f, 0.0f, 0.0f,                       0.0f, 1.0f, 0.0f, 0.0f,                       0.0f, 0.0f, 1.0f, 0.0f,                       0.0f, 0.0f, 0.0f, 1.0f);   glm::mat4 matView(right.x, up.x, forward.x, 0.0f,                     right.y, up.y, forward.y, 0.0f,                     right.z, up.z, forward.z, 0.0f,                     0.0f, 0.0f, 0.0f, 1.0f);   matView *= glm::mat4(1.0f, 0.0f, 0.0f, 0.0f,                         0.0f, 1.0f, 0.0f, 0.0f,                         0.0f, 0.0f, 1.0f, 0.0f,                         -pos.x, -pos.y, -pos.z, 1.0f);   glm::mat4 matProjection(       (float)framebufferHeight \/ framebufferWidth, 0.0f, 0.0f, 0.0f,       0.0f, 1.0f, 0.0f, 0.0f,       0.0f, 0.0f, (zFar + zNear) \/ (zFar - zNear), 1.0f,       0.0f, 0.0f, -2.0f * zFar * zNear \/ (zFar - zNear), 0.0f);    glUniformMatrix4fv(ulMatModel, 1, GL_FALSE, &amp;matModel[0][0]);   glUniformMatrix4fv(ulMatView, 1, GL_FALSE, &amp;matView[0][0]);   glUniformMatrix4fv(ulMatProjection, 1, GL_FALSE, &amp;matProjection[0][0]);    glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);    \/\/ \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0442\u0440\u0438\u0441\u0443\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0443\u044e\u0441\u044f \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0443   glBindFramebuffer(GL_FRAMEBUFFER, 0);   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   \/\/ \u0412 \u0441\u043b\u043e\u0442\u0435 0 -- \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0446\u0432\u0435\u0442\u0430   glBindTexture(GL_TEXTURE_2D, textures[0]);   \/\/ \u0412 \u0441\u043b\u043e\u0442\u0435 1 -- \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0433\u043b\u0443\u0431\u0438\u043d\u044b   glActiveTexture(GL_TEXTURE1);   glBindTexture(GL_TEXTURE_2D, textures[1]);   glBindVertexArray(vertexArrays[1]);   glUseProgram(postProgram);   \/\/ \u041c\u0430\u0441\u0448\u0442\u0430\u0431 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b   glUniform2f(ulTextureScale,               (GLfloat)framebufferWidth \/ MAX_WIDTH,               (GLfloat)framebufferHeight \/ MAX_HEIGHT);   glDrawArrays(GL_TRIANGLES, 0, 3);   glBindTexture(GL_TEXTURE_2D, 0);   glActiveTexture(GL_TEXTURE0);   glBindTexture(GL_TEXTURE_2D, 0);    glfwSwapBuffers(window); }<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><iframe src=\"https:\/\/www.youtube.com\/embed\/9Cu74CI_b9k?rel=0&amp;showinfo=1&amp;hl=en-US\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen scrolling=\"no\" allow=\"encrypted-media; accelerometer; gyroscope; picture-in-picture\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/r-\/tp\/or\/r-tpormq80a5frthcpis3qlcqdi.png\"><br \/>  \u0417\u0435\u043b\u0435\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b \u0438\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h2>\u0428\u0430\u0433 7. \u041e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432<\/h2>\n<p>  \u0412\u0435\u0440\u043d\u0435\u043c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u043e\u0432 \u0431\u0435\u043b\u044b\u043c \u0446\u0432\u0435\u0442\u043e\u043c, \u0442.\u043a. \u0431\u043e\u043b\u044c\u0448\u0435 \u0438\u0445 \u0446\u0432\u0435\u0442 \u043d\u0430\u043c \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f<\/p>\n<p>  s1.frag<\/p>\n<pre><code class=\"plaintext\">#version 330 core  out vec4 pixelColor;  void main() {   pixelColor = vec4(1); }<\/code><\/pre>\n<p>  \u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u0432\u0441\u0435 \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u044b, \u0438 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u0441\u0430\u043c\u0438\u043c \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u043c \u043f\u043e\u0441\u0442\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<br \/>  s2.frag<\/p>\n<pre><code class=\"plaintext\">#version 330 core  uniform vec2 reverseMaxSize; uniform sampler2D renderTexture; uniform sampler2D depthTexture; in vec2 textureCoords; out vec4 pixelColor;  void main() {   vec4 baseColor = texture2D(renderTexture, textureCoords);   float sum = 0.0f;   float my = texture2D(depthTexture, textureCoords).x;   sum += texture2D(depthTexture, textureCoords + vec2(+1, 0) * reverseMaxSize).x;   sum += texture2D(depthTexture, textureCoords + vec2(-1, 0) * reverseMaxSize).x;   sum += texture2D(depthTexture, textureCoords + vec2(0, +1) * reverseMaxSize).x;   sum += texture2D(depthTexture, textureCoords + vec2(0, -1) * reverseMaxSize).x;   float d = sum \/ my - 4.0f;   pixelColor = baseColor - vec4(1000.0f * d, 100.0f * d, 10.0f * d, 0); }<\/code><\/pre>\n<p>  \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u0433\u043b\u0443\u0431\u0438\u043d\u0443 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u043f\u0438\u043a\u0441\u0435\u043b\u044f \u0438 4 \u0441\u043e\u0441\u0435\u0434\u043d\u0438\u0445, \u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0435\u0435 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0446\u0432\u0435\u0442 \u043f\u0438\u043a\u0441\u0435\u043b\u044f \u043d\u0430 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0435. \u041f\u0440\u0438\u0447\u0435\u043c \u0435\u0441\u043b\u0438 \u043f\u0438\u043a\u0441\u0435\u043b\u044c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430, \u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 d \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0432\u043d\u043e 0: \u0433\u043b\u0443\u0431\u0438\u043d\u0430 \u043b\u0438\u043d\u0435\u0439\u043d\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 X \u0438 Y, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0443\u043c\u043c\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043d\u0430 \u043a\u043e\u043d\u0446\u0430\u0445 \u043e\u0442\u0440\u0435\u0437\u043a\u0430 \u0440\u0430\u0432\u043d\u0430 \u0443\u0434\u0432\u043e\u0435\u043d\u043d\u043e\u0439 \u0441\u0443\u043c\u043c\u0435 \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u043e\u0442\u0440\u0435\u0437\u043a\u0430, \u0438 \u0440\u0430\u0437\u043d\u043e\u0441\u0442\u044c \u044d\u0442\u0438\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0432\u044b\u0434\u0430\u0441\u0442 0. \u041e\u0442\u0440\u0435\u0437\u043a\u043e\u0432 \u0443 \u043d\u0430\u0441 2: <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a19\/49d\/f73\/a1949df734f8233fb48a1917e63dcc01.svg\" alt=\"$-1&lt;\\Delta x&lt;1$\" data-tex=\"inline\"><\/math> \u0438 <math><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/fee\/e6b\/16e\/feee6b16ec9d9ef66313abb9e3a7fea7.svg\" alt=\"$-1&lt;\\Delta y&lt;1$\" data-tex=\"inline\"><\/math>, \u0438 \u043d\u0435 \u043d\u0430 \u0433\u0440\u0430\u043d\u0438\u0446\u0430\u0445 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u0432\u043b\u0438\u044f\u043d\u0438\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u043d\u0438\u0445 \u043d\u0430 d \u0431\u0443\u0434\u0435\u0442 \u043d\u0443\u043b\u0435\u0432\u044b\u043c.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><iframe src=\"https:\/\/www.youtube.com\/embed\/7wAlNar32UY?rel=0&amp;showinfo=1&amp;hl=en-US\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen scrolling=\"no\" allow=\"encrypted-media; accelerometer; gyroscope; picture-in-picture\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/zj\/b5\/vf\/zjb5vfhnk-0sqzt3i6fhru0ghfq.png\">  <\/div>\n<\/p><\/div>\n<p>  \u041a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0433\u0440\u0430\u043d\u0438\u0446 \u043c\u044b \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u0435\u043c 2: \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044e\u044e (\u0446\u0432\u0435\u0442 \u0442\u0435\u043c\u043d\u0435\u0435 \u0431\u0435\u043b\u043e\u0433\u043e, d &gt; 0) \u0438 \u0432\u043d\u0435\u0448\u043d\u044e\u044e (\u0431\u0435\u043b\u0443\u044e, d &lt; 0). \u0414\u0432\u043e\u0439\u043d\u0430\u044f \u0433\u0440\u0430\u043d\u0438\u0446\u0430 \u044d\u0442\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043a\u043b\u0430\u0441\u0441\u043d\u043e, \u0438, \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c, \u043a\u0442\u043e-\u0442\u043e \u0445\u043e\u0447\u0435\u0442 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a\u0438\u043c \u0441\u0442\u0438\u043b\u0435\u043c, \u043d\u043e \u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u043f\u043e\u0439\u0442\u0438 \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<p>  \u0421\u0430\u043c\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u0432\u0437\u044f\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c \u043e\u0442 d. \u0422\u043e\u0433\u0434\u0430 \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c \u0434\u0432\u043e\u0439\u043d\u0443\u044e \u0442\u0435\u043c\u043d\u0443\u044e \u0433\u0440\u0430\u043d\u0438\u0446\u0443:<\/p>\n<pre><code class=\"plaintext\">float d = abs(sum \/ my - 4.0f);<\/code><\/pre>\n<p>  \u0417\u0430\u043e\u0434\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0441\u0432\u0435\u0442\u043b\u043e-\u0441\u0435\u0440\u044b\u0439 \u0444\u043e\u043d, \u0442.\u043a. \u0442\u0435\u043c\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0443\u0440\u044b \u043d\u0430 \u0441\u0438\u043d\u0435\u043c \u0444\u043e\u043d\u0435 \u0443\u0436\u0435 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u0432\u0438\u0434\u043d\u044b:<\/p>\n<pre><code class=\"cpp\">glClearColor(0.875f, 0.875f, 0.875f, 0.0f);<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><iframe src=\"https:\/\/www.youtube.com\/embed\/dZj06bJe6_M?rel=0&amp;showinfo=1&amp;hl=en-US\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen scrolling=\"no\" allow=\"encrypted-media; accelerometer; gyroscope; picture-in-picture\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/jh\/a2\/ba\/jha2bawvoejbfxlrjnx5dl0u5jk.png\">  <\/div>\n<\/p><\/div>\n<p>  \u0417\u0430\u043c\u0435\u043d\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u044c\u043a\u0443 \u043a\u0443\u0431\u0430 \u043d\u0430 \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u043f\u043e\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0435\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 Suzanne \u0438\u0437 Blender, \u0430 \u0437\u0430\u043e\u0434\u043d\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u043c \u0440\u0430\u043a\u0443\u0440\u0441:<\/p>\n<pre><code class=\"cpp\">float angle = 0.125f * glfwGetTime(); float sin = glm::sin(angle); float cos = glm::cos(angle); glm::vec3 pos(2.0f * sin, 2.0f * cos, 0.125f);<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><iframe src=\"https:\/\/www.youtube.com\/embed\/oU8HI9YeH-A?rel=0&amp;showinfo=1&amp;hl=en-US\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen scrolling=\"no\" allow=\"encrypted-media; accelerometer; gyroscope; picture-in-picture\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ac\/kg\/j7\/ackgj7r-saflta_rwqgmbfbvtxs.png\">  <\/div>\n<\/p><\/div>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043b\u0438\u043d\u0438\u0438 \u0442\u043e\u043b\u0449\u0438\u043d\u043e\u0439 \u043d\u0435 2, \u0430 1 \u043f\u0438\u043a\u0441\u0435\u043b\u044c. \u0421\u0430\u043c\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0435, \u0447\u0442\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0432 \u0433\u043e\u043b\u043e\u0432\u0443 \u2014 \u043e\u0442\u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0443 \u0434\u043e \u043f\u043e\u0441\u0442\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432 2 \u0440\u0430\u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u0435\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430:<\/p>\n<pre><code class=\"cpp\">const int MAX_WIDTH = 4096; const int MAX_HEIGHT = 4096;<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[0]); glViewport(0, 0, 2 * framebufferWidth, 2 * framebufferHeight);<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, framebufferWidth, framebufferHeight);<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">glUniform2f(ulTextureScale,             2.0f * framebufferWidth \/ MAX_WIDTH,             2.0f * framebufferHeight \/ MAX_HEIGHT);<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><iframe src=\"https:\/\/www.youtube.com\/embed\/9cXYoZctMqY?rel=0&amp;showinfo=1&amp;hl=en-US\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen scrolling=\"no\" allow=\"encrypted-media; accelerometer; gyroscope; picture-in-picture\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/1h\/xe\/ha\/1hxehatemovs-gu3yocqyawlcyy.png\">  <\/div>\n<\/p><\/div>\n<p>  \u041d\u043e \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0432 4 \u0440\u0430\u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u0440\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u0434\u043e \u043f\u043e\u0441\u0442\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u0434\u0432\u0443\u0445 \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432 (\u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0438 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439):<\/p>\n<pre><code class=\"plaintext\">float d = max(0.0f, sum \/ my - 4.0f);<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><iframe src=\"https:\/\/www.youtube.com\/embed\/An-CAc72RWE?rel=0&amp;showinfo=1&amp;hl=en-US\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen scrolling=\"no\" allow=\"encrypted-media; accelerometer; gyroscope; picture-in-picture\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/oy\/d-\/vj\/oyd-vj2luuw-ygmp5xrvcuvijnq.png\">  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<pre><code class=\"plaintext\">float d = max(0.0f, 4.0f - sum \/ my);<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><iframe src=\"https:\/\/www.youtube.com\/embed\/4khPRIGen5A?rel=0&amp;showinfo=1&amp;hl=en-US\" style=\"border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;\" allowfullscreen scrolling=\"no\" allow=\"encrypted-media; accelerometer; gyroscope; picture-in-picture\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/h1\/7v\/9j\/h17v9jcvyvxwkxi5a4k51ew2rbw.png\">  <\/div>\n<\/p><\/div>\n<p>  \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a \u044d\u0442\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043e\u043d\u0438 \u043d\u0435\u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u0432\u044b\u043f\u0443\u043a\u043b\u044b\u0435 \u0438 \u0432\u043e\u0433\u043d\u0443\u0442\u044b\u0435 \u0433\u0440\u0430\u043d\u0438, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u0438\u0434\u0435\u0442\u044c \u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 Suzanne. \u041d\u043e, \u0442\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435, \u043e\u043d\u0438 \u0432\u044b\u0434\u0430\u044e\u0442 \u043b\u0438\u043d\u0438\u044e \u0442\u043e\u043b\u0449\u0438\u043d\u043e\u0439 1 \u043f\u0438\u043a\u0441\u0435\u043b\u044c \u0431\u0435\u0437 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0443\u0434\u0432\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f.<\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>  \u0412 \u044d\u0442\u043e\u043c \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0435 \u043c\u044b \u043f\u0440\u043e\u0448\u043b\u0438\u0441\u044c \u043f\u043e \u043f\u0443\u0442\u0438 \u043e\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u043a\u043d\u0430 \u0434\u043e \u0448\u0435\u0439\u0434\u0435\u0440\u0430 \u043f\u043e\u0441\u0442\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u0442\u0438\u043b\u0435\u043c. \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u043a\u043e\u043c\u0443-\u043d\u0438\u0431\u0443\u0434\u044c \u0442\u0430\u043a\u0430\u044f \u043f\u043e\u0441\u0442\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439, \u0438 \u043d\u0430\u0439\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435 \u0438\u0433\u0440\u044b \u0438\u043b\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438.<\/p>\n<p>  <a href=\"https:\/\/github.com\/asurkis\/opengl-posteffect-tutorial\" rel=\"nofollow\">\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 GitHub<\/a><\/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\/post\/505726\/\"> https:\/\/habr.com\/ru\/post\/505726\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/505726\/\">\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u044f \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b\u0441\u044f \u0440\u0438\u0441\u0443\u043d\u043a\u0430\u043c\u0438, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0438\u043c\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432, \u0438 \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u043d\u0435\u0447\u0442\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 \u0434\u043b\u044f \u0442\u0440\u0435\u0445\u043c\u0435\u0440\u043d\u043e\u0439 \u0433\u0440\u0430\u0444\u0438\u043a\u0438.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/sv\/qn\/be\/svqnbepps82tnqqwh-stlwsljoa.png\"><br \/>  <i>Suzanne, \u043d\u0435\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0430\u0441\u043a\u043e\u0442 Blender, \u043e\u0442\u0440\u0435\u043d\u0434\u0435\u0440\u0435\u043d\u043d\u044b\u0439 \u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0438\u043c\u0441\u044f \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u043c<br \/>  <\/i><br \/>  \u0412 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0443 \u043a\u043e\u043d\u0442\u0443\u0440\u043e\u0432 \u0441 \u043f\u043b\u0430\u0432\u043d\u044b\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u043c \u0432\u0435\u0441\u0430 \u043b\u0438\u043d\u0438\u0439 \u043d\u0430 OpenGL, \u0445\u043e\u0442\u044f \u043c\u0435\u0442\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043b\u044e\u0431\u043e\u043c \u0434\u0440\u0443\u0433\u043e\u043c \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u043c API. \u0412\u0441\u0435\u043c \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u2014 \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u043a\u0430\u0442.  <\/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-305107","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/305107","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=305107"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/305107\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=305107"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=305107"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=305107"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}