OpenGL вложенные трафареты - PullRequest
7 голосов
/ 27 октября 2019

Я хочу, чтобы вложенные трафареты работали в OpenGL. Теперь я называю их масками.

Таким образом, буфер трафарета очищен для всех нулей. Я делаю свою первую маску, серую область.

enter image description here

Теперь это должны быть все 1 в буфере трафарета, и обычное рисование не разрешенопроисходит за пределами этой маски.

Теперь я создаю вторую маску, которая является дочерней по отношению к первой: она обновит буфер трафарета, только если область находится внутри области предыдущей маски:

enter image description here

То же самое, если мы создадим другую дочернюю маску, мы увеличим ее, только если она будет внутри родительской маски.

enter image description here

Теперь, если мы закончим последнюю маску (зеленую), мы можем уменьшить значения, где они равны глубине маски.

Хорошо, это идея, но я застрял на том, чтобы заставить это работать несколько недель (не полный рабочий день ...).

Либо маскировка не работает, либо она не работаеткак и ожидалось. Здесь я предоставляю код, который имеет для меня наибольшее значение.

Я использую обработку, которую можно скачать здесь https://processing.org/ (скачать и запустить, просто так).

PGL pgl;


Rect current_rect;


void setup() {
  size(600, 600, P3D);
  noStroke();

  // will have a depth of 0, equal to the stencil buffer after a clear
  current_rect = make_rect(null, 0, 0, width, height);
}

class Rect {
  float x;
  float y;
  float w;
  float h;
  ArrayList<Rect> children = new ArrayList<Rect>();
  Rect parent;
  int mask_depth;
}

Rect make_rect(Rect parent, float x, float y, float w, float h) {
  Rect r = new Rect();
  r.x = x;
  r.y = y;
  r.w = w;
  r.h = h;
  if (parent != null) {
    r.parent = parent;
    r.mask_depth = parent.mask_depth + 1;
    parent.children.add(r);
  }
  return r;
}



void draw() {

  if (frameCount == 2) noLoop();

  println();

  pgl = beginPGL();

  pgl.enable(PGL.STENCIL_TEST);
  pgl.clear(PGL.STENCIL_BUFFER_BIT);

  background(150, 80, 70);

  begin_mask(100, 100, 400, 400);

  fill(150);
  rect(100, 100, 400, 400);
  // SHOULD NOT FALL OUTSIDE OF THE MASK!
  debug_text(" A ");

  // disabled for now cause the above begin_mask
  // goes already wrong
  if (false) {
    begin_mask(50, 150, 500, 100); // B
    fill(100);
    rect(50, 150, 500, 100);
    debug_text(" B ");

    if (true) {
      begin_mask(200, 50, 100, 500); // C
      fill(50);
      rect(200, 50, 100, 500);
      debug_text(" C ");
      end_mask(); // C
    }


    end_mask(); // B

    // why is the one from above (C) on this one?
    // disable this one to see what I mean
    if (true) {
      begin_mask(50, 350, 500, 100); // D
      fill(75);
      rect(50, 350, 500, 100);
      fill(255);
      debug_text(" D ");
      end_mask(); // D
    }
  }

  end_mask(); // A


  flush();

  endPGL();
}




void begin_mask(float x, float y, float w, float h) {
  current_rect = make_rect(current_rect, x, y, w, h);

  flush();
  pgl.colorMask(false, false, false, false);
  pgl.depthMask(false);
  pgl.stencilOp(PGL.KEEP, PGL.KEEP, PGL.INCR);
  println("increment stencil when stencil is equal to: "+current_rect.parent.mask_depth);
  pgl.stencilFunc(PGL.EQUAL, current_rect.parent.mask_depth, 0xFF);

  // write to stencil buffer
  noStroke();
  fill(0);
  rect(x, y, w, h);
  flush();

  enable_normal_draw_mode();
}



void enable_normal_draw_mode() {
  pgl.stencilMask(0x00);
  println("normal write when stencil depth is: "+(current_rect.mask_depth));
  pgl.stencilFunc(PGL.GEQUAL, current_rect.mask_depth, 0xff);
  pgl.stencilOp(PGL.KEEP, PGL.KEEP, PGL.KEEP);
  pgl.colorMask(true, true, true, true);
  pgl.depthMask(true);
  flush();

  println("enable_normal_draw_mode "+current_rect.mask_depth);
}



void end_mask() {
  // decrement stencil mask as if we never existed
  pgl.stencilMask(0xff);
  pgl.stencilFunc(PGL.GEQUAL, current_rect.mask_depth, 0xff);
  pgl.stencilOp(PGL.KEEP, PGL.KEEP, PGL.DECR);
  pgl.colorMask(false, false, false, false);
  pgl.depthMask(false);
  noStroke();
  fill(0);
  rect(current_rect.x, current_rect.y, current_rect.w, current_rect.h);
  flush();

  current_rect = current_rect.parent;

  enable_normal_draw_mode();
}






void debug_text(String s) {
  fill(255);
  text(xxx(s), 0, 0);
}

String xxx(String to_repeat) {
  String result = "";
  String line = "";
  for (int x = 0; x < 50; x++) {
    line += to_repeat;
  }
  for (int y = 0; y < 50; y++) {
    result += line + "\n";
  }
  return result;
}
...