如何在OpenGL的即时模式下永久绘制事物?

时间:2019-07-12 13:32:19

标签: c++ opengl

从本质上来说,我在创建路径跟踪器时遇到了一个小问题。

在我的项目中,我有一个对象,该对象通过while循环中完成的更新功能不断有机地移动。我使用即时模式并将玩家表示为一个正方形,我想这样做,以便每次更新时都将对象绘制在其当前位置,但也要让它绘制其先前的位置,以便向路径蚀刻点对象在移动。我很确定我们可以通过正常绘制位置来实现此目的,但是在while循环中在此实例之后不清除所有内容,但是我不知道如何执行此操作。

编辑:对于需要这些代码的人,一定要了解该代码尤其不符合该问题,并且我做了大量的概括(例如将粒子称为对象),因此该问题的基本要点是可以理解的:

#include "PerlinNoise.hpp"
#include "Particle.hpp"

#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <cmath>
#include <vector>

using namespace siv;

float map(float oValue, float oMin, float oMax, float nMin, float nMax)
{
  float oRange = (oMax - oMin);
  float nRange = (nMax - nMin);
  return(((oValue - oMin) * nRange)/oRange) + nMin;
}

void drawRectangle(float x, float y, float xr, float yr, float R, float G, float B)
{
  glBegin(GL_QUADS);
  glColor3f(R,G,B);
  glVertex2f(x,y);
  glVertex2f(x+xr,y);
  glVertex2f(x+xr,y+yr);
  glVertex2f(x,y+yr);
  glEnd();
}

void drawLine(float x, float y, float xr, float yr, float rotation)
{
  float radius = sqrt(xr*xr + yr*yr);
  float a0 = asin(yr/radius);
  float tangle = a0+rotation;
  //std::cout<<tangle*180/M_PI<<std::endl;
  glBegin(GL_LINES);
  glColor3f(.1,.1,.1);
  glVertex2f(x,y);
  glVertex2f(x + sin(tangle)*radius,y + cos(tangle)*radius);
  glEnd();
}


int main()
{
  float inc = 0.1;
  int scl   = 20;
  int cols,rows;

  Particle particles[100000];

  //V2D flowfield[cols*rows];

  GLFWwindow* window;
  if (!glfwInit())
    return 1;
  int width  = 800;
  int height = 800;
  window = glfwCreateWindow(width, height, "Window", NULL, NULL);
  cols = floor(width/scl);
  rows = floor(height/scl);
  V2D flowfield[cols*rows];
  float zoff = 0;
  if (!window) {
    glfwTerminate();
    return 1;
  }
  glfwMakeContextCurrent(window);
  if(glewInit()!=GLEW_OK)
    std::cout<<"Error"<<std::endl;
  glEnable(GL_DEPTH_TEST);
  glMatrixMode(GL_PROJECTION);
  glfwGetFramebufferSize(window, &width, &height);
  glOrtho(0, width*(width/height), height, 0, -2, 2);
  PerlinNoise png = PerlinNoise(1);
  while(!glfwWindowShouldClose(window)) {
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glClearColor(0.11, 0.14, 0.17, 1);
    float yoff = 0;
    for(int y = 0; y < rows; y++)
    {
      float xoff = 0;
      for(int x = 0; x < cols; x++)
      {
        double noise = map(png.noise((double)xoff, (double)yoff, (double)zoff),-1,1,0,1);
        double angle = noise * 8 *M_PI;
        //std::cout<<angle/(2*M_PI)<<std::endl;
        int index = x + y * cols;
        V2D v = V2D(cos(angle), sin(angle));
        v.normalize();
        v = V2D(v.x*5,v.y*5);
        flowfield[index] = v;
        //drawLine(x*scl, y*scl, scl, 0, atan2(v.x, v.y));
        //drawRectangle(x*scl,y*scl,scl,scl,noise,noise,noise);

        xoff += inc;
      }
      yoff += inc;
      zoff += 0.0001;
    }
    for(int i = 0; i < 100000; i++)
    {
      particles[i].follow(flowfield);
      particles[i].update();
      particles[i].show();
    }
    glfwSwapBuffers(window);
    glfwPollEvents();
  }
  glfwTerminate();
}

1 个答案:

答案 0 :(得分:3)

直接在窗口上绘制时(无论是否具有双缓冲,都没有影响),您不得假设其内容在绘制之间是持久的。哎呀,严格来说,内容可能会在抽签中途甚至完成之前就损坏;当然,在实践中这不太可能发生,并且考虑到现代合成图形系统,实际上已将其消除。

您的应用程序尖叫到绘制到中间帧缓冲区对象。无论发生什么情况,FBO均保证保留其内容;您也可以随时在FBO的后备缓冲区中添加更多图形。

OpenGL官方Wiki在https://www.khronos.org/opengl/wiki/Framebuffer_Object上描述了FBO

很久以前,我编写了一个简单的代码示例(使用许多过时的旧版OpenGL);绘图是遗留的,但是FBO的部分已经像10年前一样完成了:https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/minimalfbo/minimalfbo.c(我使用渲染到纹理来实现;渲染到renderbuffer和缓冲区blit到主帧缓冲区也对您有用)。