Создание графических моделей с помощью Open Graphics Library

Устранение эффекта ступенчатости

Разбить на страницы
Показывать лекцию целиком

Цель лекции: Изучить команды работы с буфером аккумулятора и метод "джиттеринга" (дрожания), используемого для устранения эффекта ступенчатости изображения OpenGL.

Примеры на C# (WinForms) и Object Pascal (Delphi)

Пример № 11.1 Пример демонстрирует устранение эффекта ступенчатости с помощью "джиттеринга".

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

Одним из вариантов получения эффекта сглаживания изображения сцены является использование буфера накопления. Иногда такой способ называют эффектом дрожания или "джитеринг" (от английского слова jitter). Суть этого способа заключается в том, что перед отображением сцены её прорисовывают в буфере накопления несколько раз с небольшим смещением в каждом случае. За счет этого результирующее изображение получается несколько размытым и переход цветов на границе объектов получается более плавным. Это позволяет уменьшить эффекты ступенчатости и резких переходов цветов.

Качество сглаживания обычно пропорционально количеству прорисовок сцены. При выборе координат смещения сцены относительно исходного положения обычно используют набор массивов, значения которых позволяют получить наилучший эффект сглаживания сцены при заданном количестве прорисовок сцены.

Ниже приведено содержание класса Jitter на C#, который содержит реализацию методов, используемых для реализации эффекта сглаживания. В классе так же объявлены массивы различного размера, которые содержат смещения, которые используются для получения эффекта сглаживания.

class Jitter
{
  public struct PointPloat
  {
    public float X;
    public float Y;
  }
  public static PointPloat[] j2 = new PointPloat[2]
  { 
    new PointPloat{X=  0.246490f,Y=  0.249999f}, 
    new PointPloat{X=  0.246490f,Y=  0.249999f}
  };
  public static PointPloat[] j3 = new PointPloat[3]
  {
    new PointPloat{X= -0.373411f, Y= -0.250550f},
    new PointPloat{X=  0.256263f, Y=  0.368119f},
    new PointPloat{X=  0.117148f, Y= -0.117570f}
  };
  public static PointPloat[] j4 = new PointPloat[4]
  {        
    new PointPloat{X= -0.208147f, Y=  0.353730f}, 
    new PointPloat{X=  0.203849f, Y= -0.353780f},
    new PointPloat{X= -0.292626f, Y= -0.149945f}, 
    new PointPloat{X=  0.296924f, Y=  0.149994f}
  };
  public static PointPloat[] j8 = new PointPloat[8]
  {
    new PointPloat{X= -0.334818f, Y=  0.435331f}, 
    new PointPloat{X=  0.286438f, Y= -0.393495f},
    new PointPloat{X=  0.459462f, Y=  0.141540f}, 
    new PointPloat{X= -0.414498f, Y= -0.192829f},
    new PointPloat{X= -0.183790f, Y=  0.082102f}, 
    new PointPloat{X= -0.079263f, Y= -0.317383f},
    new PointPloat{X=  0.102254f, Y=  0.299133f}, 
    new PointPloat{X=  0.164216f, Y= -0.054399f}
  };
  public static void AccFrustum(double left, double right, 
    double bottom, double top, 
    double anear, double afar, double pdx, double pdy)
  {
    double xwsize, ywsize, dx, dy;
    int[] viewport = new int[4];
    GL.GetInteger(GetPName.Viewport, viewport);
    xwsize = right - left;
    ywsize = top - bottom;
    dx = -(pdx * xwsize / viewport[2]);
    dy = -(pdy * ywsize / viewport[3]);
    GL.MatrixMode(MatrixMode.Projection);
    GL.LoadIdentity();
    GL.Frustum (left + dx, right + dx, bottom + dy, top + dy, anear, afar);
    GL.MatrixMode(MatrixMode.Modelview);
  }
  public static void AccOrtho(double left, double right, 
    double bottom, double top, 
    double anear, double afar, double pdx, double pdy)
  {
    double xwsize, ywsize, dx, dy;
    int[] viewport = new int[4];
    GL.GetInteger(GetPName.Viewport,  viewport);
    xwsize = right - left;
    ywsize = top - bottom;
    dx = -(pdx*xwsize/viewport[2]);
    dy = -(pdy*ywsize/viewport[3]);
    GL.MatrixMode(MatrixMode.Projection);
    GL.LoadIdentity();
    GL.Ortho(left + dx, right + dx, bottom + dy, top + dy, anear, afar);
    GL.MatrixMode(MatrixMode.Modelview);
  }
}

Ниже приведено содержание модуля на Object Pascal, который содержит процедуры, выполняющие операции аналогичные классу ).

unit Jitter;
interface
uses  OpenGL;
Type
  TGLPointFloat = record
    x,y: GLFloat;
  End;
const
  j2: array[0..1] of TGLPointFloat =  
    ((x:  0.246490; y:  0.249999), (x: -0.246490; y: -0.249999));
  j3: array[0..2] of TGLPointFloat = 
    ((x: -0.373411; y: -0.250550), (x:  0.256263; y:  0.368119),            
     (x:  0.117148; y: -0.117570));
  j4: array[0..3] of TGLPointFloat =
    ((x: -0.208147; y:  0.353730), (x:  0.203849; y: -0.353780),
     (x: -0.292626; y: -0.149945), (x:  0.296924; y:  0.149994));
  j8: array[0..7] of TGLPointFloat =
     ((x: -0.334818; y:  0.435331), (x:  0.286438; y: -0.393495),
      (x:  0.459462; y:  0.141540), (x: -0.414498; y: -0.192829),
      (x: -0.183790; y:  0.082102), (x: -0.079263; y: -0.317383),
      (x:  0.102254; y:  0.299133), (x:  0.164216; y: -0.054399));
procedure AccFrustum(left,right,bottom,top: GLdouble; anear,afar,pdx,pdy: GLdouble);
procedure AccOrtho(left, right, bottom, top: GLdouble; anear, afar, pdx, pdy: GLdouble);
Implementation
procedure AccFrustum(left, right, bottom, top: GLdouble; anear, afar, pdx, pdy: GLdouble);
var
  xwsize, ywsize: GLdouble;
  dx, dy: GLdouble;
  viewport: array[0..3] of GLint;
begin
  glGetIntegerv (GL_VIEWPORT, @viewport);
  xwsize := right - left;
  ywsize := top - bottom;
  dx := -(pdx*xwsize/viewport[2]);
  dy := -(pdy*ywsize/viewport[3]);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum (left + dx, right + dx, bottom + dy, top + dy, anear, afar);
  glMatrixMode(GL_MODELVIEW);
end;
procedure AccOrtho(left, right, bottom, top: GLdouble; anear, afar, pdx, pdy: GLdouble);
var
  xwsize, ywsize  : GLdouble;
  dx, dy: GLdouble;
  viewport: array[0..3] of GLint;
begin
  glGetIntegerv (GL_VIEWPORT, @viewport);
  xwsize := right - left;
  ywsize := top - bottom;
  dx := -(pdx*xwsize/viewport[2]);
  dy := -(pdy*ywsize/viewport[3]);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(left + dx, right + dx, bottom + dy, top + dy, anear, afar);
  glMatrixMode(GL_MODELVIEW);
end;
end.

Для управления буфером аккумулятора используется команда Accum.

C#:
  void Accum(AccumOp op, float value);
Object Pascal:
  procedure glAccum (op: GLenum; value: GLfloat);

Аргумент .

Возможные значения параметра op команды Accum
Описание значения параметраЗначение параметра
Библиотека OpenTK, C#Object Pascal
Считывает каждый пиксель из буфера цвета, умножает каждую составляющую цвета пиксела (RGBA) на значение value и добавляет результаты в буфер аккумуляции.AccumOp.AccumGL_ACCUM
Pаботает так же как и параметр AccumOp.Accum/GL_ACCUM за тем исключением, что результирующие значения заменяют уже хранимые в буфере, а не добавляются к ним.AccumOp.LoadGL_LOAD
Умножает величины из буфера аккумуляции на значение параметра value и помещает результат в цветовой буфер, выбранный для записи.AccumOp.ReturnGL_RETURN
Просто добавляют или умножают значения каждого пикселя в буфере аккумуляции на величину value. Для AccumOp.Mult/GL_MULT значение value усекается до диапазона [-1.0, 1.0]. Для AccumOp.Add/GL_ADD усечение не производитсяAccumOp.Add и AccumOp.MultGL_ADD и GL_MULT

В листинге 11.3 приведен фрагмент программы с использованием метода AccOrtho класса Jitter для формирования ортографической проекции сцены на языке программирования C#.

void DrawObjects()
{
  // формирование изображения
  GL.Enable(EnableCap.Lighting);
  GL.Enable(EnableCap.Light0);
  sphere(0.5, 20, 20);
  GL.Disable(EnableCap.Lighting);
  // завершение формирования изображения
}
void DrawScene(Jitter.PointPloat[] j)
{
  GL.Clear(ClearBufferMask.AccumBufferBit);
  for (int i = 0; i< j.Length-1; ++i)
  {
    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
    Jitter.AccOrtho(-1, 1, -1, 1, -1, 1, j[i].X, j[i].Y);
    DrawObjects();
    GL.Accum(AccumOp.Accum, 1.0f/j.Length);
  }
  GL.Accum(AccumOp.Return, 1.0f);
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
  // очистка буферов цвета и глубины
  GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
  // поворот изображения
  GL.LoadIdentity();
  GL.Rotate(AngleX, 1.0, 0.0, 0.0);
  GL.Rotate(AngleY, 0.0, 1.0, 0.0);
  GL.Rotate(AngleZ, 0.0, 0.0, 1.0);
  DrawScene(Jitter.j8);
  GL.Flush();
  GL.Finish();
  glControl1.SwapBuffers();
}

В методе DrawScene вызывается метод DrawObjects, который должен формировать отображаемые объекты в видимой области сцены.

В листинге 11.4 приведен фрагмент программы с использованием процедуры AccOrtho для формирования ортографической проекции сцены на языке программирования Object Pascal.

procedure TForm1.DrawScene(j: array of TGLPointFloat);
var
  i: Integer;
begin
  glClear(GL_ACCUM_BUFFER_BIT);
  for I := 0 to High(j) do
  begin
    glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
    AccOrtho(-2, 2, -2, 2, -2, 2, j[i].x, j[i].y);
    DrawObjects;
    glAccum(GL_ACCUM, 1.0/(High(j)+1));
  end;
  glAccum (GL_RETURN, 1.0);
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
  // очистка буфера цвета
  glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);  glLoadIdentity;
  // этот фрагмент нужен для придания трёхмерности
  glRotatef(AngleX, 1.0, 0.0, 0.0);
  glRotatef(AngleY, 0.0, 1.0, 0.0);
  glRotatef(AngleZ, 0.0, 0.0, 1.0);
  DrawScene(j8);
  glFlush;
  glFinish;
  SwapBuffers(DC);
end;
procedure TForm1.DrawObjects;
begin
  // формирование изображения
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  sphere(0.5, 20, 20);
  glDisable(GL_LIGHTING);
  // завершение формирования изображения
end;

Краткие итоги

Несмотря на то, что у примитивов есть ряд параметров, которые позволяют изменять визуальное качество изображения, но они не позволяют устанить эффект ступенчатости в изображении объектов сцены.

Для решения этой проблемы обычно применяется эффект "джиттеринга", для реализации которого используется буфер аккумулятора.

Изображение сцены формируется несколько раз с уменьшенной интенсивностью составляющих цвета в буфере аккумулятора и с некоторым смещением относительно реального положения объектов сцены. Результат "накапливается" в буфере аккумулятора и затем копируется в отображаемый буфер.

Для работы с буфером аккумурятора используется команда Accum.

Страницы:

Цель лекции: Изучить команды работы с буфером аккумулятора и метод "джиттеринга" (дрожания), используемого для устранения эффекта ступенчатости изображения OpenGL.

Примеры на C# (WinForms) и Object Pascal (Delphi)

Пример № 11.1 Пример демонстрирует устранение эффекта ступенчатости с помощью "джиттеринга".

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

Одним из вариантов получения эффекта сглаживания изображения сцены является использование буфера накопления. Иногда такой способ называют эффектом дрожания или "джитеринг" (от английского слова jitter). Суть этого способа заключается в том, что перед отображением сцены её прорисовывают в буфере накопления несколько раз с небольшим смещением в каждом случае. За счет этого результирующее изображение получается несколько размытым и переход цветов на границе объектов получается более плавным. Это позволяет уменьшить эффекты ступенчатости и резких переходов цветов.

Качество сглаживания обычно пропорционально количеству прорисовок сцены. При выборе координат смещения сцены относительно исходного положения обычно используют набор массивов, значения которых позволяют получить наилучший эффект сглаживания сцены при заданном количестве прорисовок сцены.

Ниже приведено содержание класса Jitter на C#, который содержит реализацию методов, используемых для реализации эффекта сглаживания. В классе так же объявлены массивы различного размера, которые содержат смещения, которые используются для получения эффекта сглаживания.

class Jitter
{
  public struct PointPloat
  {
    public float X;
    public float Y;
  }
  public static PointPloat[] j2 = new PointPloat[2]
  { 
    new PointPloat{X=  0.246490f,Y=  0.249999f}, 
    new PointPloat{X=  0.246490f,Y=  0.249999f}
  };
  public static PointPloat[] j3 = new PointPloat[3]
  {
    new PointPloat{X= -0.373411f, Y= -0.250550f},
    new PointPloat{X=  0.256263f, Y=  0.368119f},
    new PointPloat{X=  0.117148f, Y= -0.117570f}
  };
  public static PointPloat[] j4 = new PointPloat[4]
  {        
    new PointPloat{X= -0.208147f, Y=  0.353730f}, 
    new PointPloat{X=  0.203849f, Y= -0.353780f},
    new PointPloat{X= -0.292626f, Y= -0.149945f}, 
    new PointPloat{X=  0.296924f, Y=  0.149994f}
  };
  public static PointPloat[] j8 = new PointPloat[8]
  {
    new PointPloat{X= -0.334818f, Y=  0.435331f}, 
    new PointPloat{X=  0.286438f, Y= -0.393495f},
    new PointPloat{X=  0.459462f, Y=  0.141540f}, 
    new PointPloat{X= -0.414498f, Y= -0.192829f},
    new PointPloat{X= -0.183790f, Y=  0.082102f}, 
    new PointPloat{X= -0.079263f, Y= -0.317383f},
    new PointPloat{X=  0.102254f, Y=  0.299133f}, 
    new PointPloat{X=  0.164216f, Y= -0.054399f}
  };
  public static void AccFrustum(double left, double right, 
    double bottom, double top, 
    double anear, double afar, double pdx, double pdy)
  {
    double xwsize, ywsize, dx, dy;
    int[] viewport = new int[4];
    GL.GetInteger(GetPName.Viewport, viewport);
    xwsize = right - left;
    ywsize = top - bottom;
    dx = -(pdx * xwsize / viewport[2]);
    dy = -(pdy * ywsize / viewport[3]);
    GL.MatrixMode(MatrixMode.Projection);
    GL.LoadIdentity();
    GL.Frustum (left + dx, right + dx, bottom + dy, top + dy, anear, afar);
    GL.MatrixMode(MatrixMode.Modelview);
  }
  public static void AccOrtho(double left, double right, 
    double bottom, double top, 
    double anear, double afar, double pdx, double pdy)
  {
    double xwsize, ywsize, dx, dy;
    int[] viewport = new int[4];
    GL.GetInteger(GetPName.Viewport,  viewport);
    xwsize = right - left;
    ywsize = top - bottom;
    dx = -(pdx*xwsize/viewport[2]);
    dy = -(pdy*ywsize/viewport[3]);
    GL.MatrixMode(MatrixMode.Projection);
    GL.LoadIdentity();
    GL.Ortho(left + dx, right + dx, bottom + dy, top + dy, anear, afar);
    GL.MatrixMode(MatrixMode.Modelview);
  }
}

Ниже приведено содержание модуля на Object Pascal, который содержит процедуры, выполняющие операции аналогичные классу ).

unit Jitter;
interface
uses  OpenGL;
Type
  TGLPointFloat = record
    x,y: GLFloat;
  End;
const
  j2: array[0..1] of TGLPointFloat =  
    ((x:  0.246490; y:  0.249999), (x: -0.246490; y: -0.249999));
  j3: array[0..2] of TGLPointFloat = 
    ((x: -0.373411; y: -0.250550), (x:  0.256263; y:  0.368119),            
     (x:  0.117148; y: -0.117570));
  j4: array[0..3] of TGLPointFloat =
    ((x: -0.208147; y:  0.353730), (x:  0.203849; y: -0.353780),
     (x: -0.292626; y: -0.149945), (x:  0.296924; y:  0.149994));
  j8: array[0..7] of TGLPointFloat =
     ((x: -0.334818; y:  0.435331), (x:  0.286438; y: -0.393495),
      (x:  0.459462; y:  0.141540), (x: -0.414498; y: -0.192829),
      (x: -0.183790; y:  0.082102), (x: -0.079263; y: -0.317383),
      (x:  0.102254; y:  0.299133), (x:  0.164216; y: -0.054399));
procedure AccFrustum(left,right,bottom,top: GLdouble; anear,afar,pdx,pdy: GLdouble);
procedure AccOrtho(left, right, bottom, top: GLdouble; anear, afar, pdx, pdy: GLdouble);
Implementation
procedure AccFrustum(left, right, bottom, top: GLdouble; anear, afar, pdx, pdy: GLdouble);
var
  xwsize, ywsize: GLdouble;
  dx, dy: GLdouble;
  viewport: array[0..3] of GLint;
begin
  glGetIntegerv (GL_VIEWPORT, @viewport);
  xwsize := right - left;
  ywsize := top - bottom;
  dx := -(pdx*xwsize/viewport[2]);
  dy := -(pdy*ywsize/viewport[3]);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum (left + dx, right + dx, bottom + dy, top + dy, anear, afar);
  glMatrixMode(GL_MODELVIEW);
end;
procedure AccOrtho(left, right, bottom, top: GLdouble; anear, afar, pdx, pdy: GLdouble);
var
  xwsize, ywsize  : GLdouble;
  dx, dy: GLdouble;
  viewport: array[0..3] of GLint;
begin
  glGetIntegerv (GL_VIEWPORT, @viewport);
  xwsize := right - left;
  ywsize := top - bottom;
  dx := -(pdx*xwsize/viewport[2]);
  dy := -(pdy*ywsize/viewport[3]);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(left + dx, right + dx, bottom + dy, top + dy, anear, afar);
  glMatrixMode(GL_MODELVIEW);
end;
end.

Для управления буфером аккумулятора используется команда Accum.

C#:
  void Accum(AccumOp op, float value);
Object Pascal:
  procedure glAccum (op: GLenum; value: GLfloat);

Аргумент .

Возможные значения параметра op команды Accum
Описание значения параметраЗначение параметра
Библиотека OpenTK, C#Object Pascal
Считывает каждый пиксель из буфера цвета, умножает каждую составляющую цвета пиксела (RGBA) на значение value и добавляет результаты в буфер аккумуляции.AccumOp.AccumGL_ACCUM
Pаботает так же как и параметр AccumOp.Accum/GL_ACCUM за тем исключением, что результирующие значения заменяют уже хранимые в буфере, а не добавляются к ним.AccumOp.LoadGL_LOAD
Умножает величины из буфера аккумуляции на значение параметра value и помещает результат в цветовой буфер, выбранный для записи.AccumOp.ReturnGL_RETURN
Просто добавляют или умножают значения каждого пикселя в буфере аккумуляции на величину value. Для AccumOp.Mult/GL_MULT значение value усекается до диапазона [-1.0, 1.0]. Для AccumOp.Add/GL_ADD усечение не производитсяAccumOp.Add и AccumOp.MultGL_ADD и GL_MULT

В листинге 11.3 приведен фрагмент программы с использованием метода AccOrtho класса Jitter для формирования ортографической проекции сцены на языке программирования C#.

void DrawObjects()
{
  // формирование изображения
  GL.Enable(EnableCap.Lighting);
  GL.Enable(EnableCap.Light0);
  sphere(0.5, 20, 20);
  GL.Disable(EnableCap.Lighting);
  // завершение формирования изображения
}
void DrawScene(Jitter.PointPloat[] j)
{
  GL.Clear(ClearBufferMask.AccumBufferBit);
  for (int i = 0; i< j.Length-1; ++i)
  {
    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
    Jitter.AccOrtho(-1, 1, -1, 1, -1, 1, j[i].X, j[i].Y);
    DrawObjects();
    GL.Accum(AccumOp.Accum, 1.0f/j.Length);
  }
  GL.Accum(AccumOp.Return, 1.0f);
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
  // очистка буферов цвета и глубины
  GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
  // поворот изображения
  GL.LoadIdentity();
  GL.Rotate(AngleX, 1.0, 0.0, 0.0);
  GL.Rotate(AngleY, 0.0, 1.0, 0.0);
  GL.Rotate(AngleZ, 0.0, 0.0, 1.0);
  DrawScene(Jitter.j8);
  GL.Flush();
  GL.Finish();
  glControl1.SwapBuffers();
}

В методе DrawScene вызывается метод DrawObjects, который должен формировать отображаемые объекты в видимой области сцены.

В листинге 11.4 приведен фрагмент программы с использованием процедуры AccOrtho для формирования ортографической проекции сцены на языке программирования Object Pascal.

procedure TForm1.DrawScene(j: array of TGLPointFloat);
var
  i: Integer;
begin
  glClear(GL_ACCUM_BUFFER_BIT);
  for I := 0 to High(j) do
  begin
    glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
    AccOrtho(-2, 2, -2, 2, -2, 2, j[i].x, j[i].y);
    DrawObjects;
    glAccum(GL_ACCUM, 1.0/(High(j)+1));
  end;
  glAccum (GL_RETURN, 1.0);
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
  // очистка буфера цвета
  glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);  glLoadIdentity;
  // этот фрагмент нужен для придания трёхмерности
  glRotatef(AngleX, 1.0, 0.0, 0.0);
  glRotatef(AngleY, 0.0, 1.0, 0.0);
  glRotatef(AngleZ, 0.0, 0.0, 1.0);
  DrawScene(j8);
  glFlush;
  glFinish;
  SwapBuffers(DC);
end;
procedure TForm1.DrawObjects;
begin
  // формирование изображения
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  sphere(0.5, 20, 20);
  glDisable(GL_LIGHTING);
  // завершение формирования изображения
end;

Краткие итоги

Несмотря на то, что у примитивов есть ряд параметров, которые позволяют изменять визуальное качество изображения, но они не позволяют устанить эффект ступенчатости в изображении объектов сцены.

Для решения этой проблемы обычно применяется эффект "джиттеринга", для реализации которого используется буфер аккумулятора.

Изображение сцены формируется несколько раз с уменьшенной интенсивностью составляющих цвета в буфере аккумулятора и с некоторым смещением относительно реального положения объектов сцены. Результат "накапливается" в буфере аккумулятора и затем копируется в отображаемый буфер.

Для работы с буфером аккумурятора используется команда Accum.

Вернуться к учебному плану