Esate.ru
Esate.ru Уроки Программирование 3D Уроки OpenGL + C#Визуализация графика функции в С# и OpenGL.

Уроки OpenGL + C#

Выполняя главы последовательно, вы ознакомитесь с основами синтаксиса C#, увидите, как просто создавать оконные приложения с помощью .net, познакомитесь с библиотекой Tao, которая обеспечивает поддержку OpenGl в среде .NET, изучите основы 2D визуализации, работу как с примитивами, так и принцип загрузки и построения сложных 3D моделей , экспортированных из 3D редакторов.

5.4 Визуализация графика функции. (Рисование графиков в C#, OpenGL).

Создание визуализации анимированного графика функции на С# и OpenGL

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

Это будет реализовано следующим образом: по графику двигается красная точка, принимающая значения y для заданного x в нашем графике (по всей видимой области). Помимо этого возле курсора будут визуализироваться его координаты (рис. 1).
Уроки OpenGL + C#: Визуализация анимированного графика функции Рисунок 1. Визуализация анимированного графика функции.
Создайте основу приложения так, как это было описано в главе 4.4. Только не добавляйте кнопки «Визуализировать» и «Закрыть», ограничьтесь элементом SimpleOpenGLControl.

Окно должно иметь форму, как показано на рисунке 1.

Добавьте в проект таймер, назовите его (параметр name в свойствах таймера) PointInGrap и установите в его свойствах интервал 30 миллисекунд. После этого щелкните по нему дважды, чтобы создалась функция PointInGrap_Tick, отвечающая за обработку события ontimer.

Теперь, когда основа приложения создана, мы перейдем к исходному коду. Он будет основан на 7 функциях, которые мы сейчас рассмотрим, но сначала перед кодом функции-конструктора класса добавьте инициализацию следующих переменных:

/*http://esate.ru, Anvi*/


// размеры окна 
double ScreenW, ScreenH; 

// отношения сторон окна визуализации 
// для корректного перевода координат мыши в координаты, 
// принятые в программе 

private float devX; 
private float devY; 

// массив, который будет хранить значения x,y точек графика 
private float[,] GrapValuesArray; 
// количество элементов в массиве 
private int elements_count = 0; 

// флаг, означающий, что массив с значениями координат графика пока еще не заполнен 
private bool not_calculate = true; 

// номер ячейки массива, из которой будут взяты координаты для красной точки 
// для визуализации текущего кадра 
private int pointPosition = 0; 

// вспомогательные переменные для построения линий от курсора мыши к координатным осям 
float lineX, lineY; 

// текущение координаты курсора мыши 
float Mcoord_X = 0, Mcoord_Y = 0; 



Перед каждой переменной закомментировано ее назначение, так что вопросов возникнуть не должно.
Теперь вернемся к нашим 7 функциям.

Первая функция – это обработчик события загрузки формы Form1_Load. Здесь при загрузке приложения будет произведена инициализация OpenGL для последующей визуализации.

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

/*http://esate.ru, Anvi*/

private void Form1_Load(object sender, EventArgs e) 
{ 

  // инициализация библиотеки glut 
  Glut.glutInit(); 
  // инициализация режима экрана 
  Glut.glutInitDisplayMode(Glut.GLUT_RGB | Glut.GLUT_DOUBLE); 

  // установка цвета очистки экрана (RGBA) 
  Gl.glClearColor(255, 255, 255, 1); 

  // установка порта вывода 
  Gl.glViewport(0, 0, AnT.Width, AnT.Height); 

  // активация проекционной матрицы 
  Gl.glMatrixMode(Gl.GL_PROJECTION); 
  // очистка матрицы 
  Gl.glLoadIdentity(); 

  // определение параметров настройки проекции в зависимости от размеров сторон элемента AnT. 
  if ((float)AnT.Width <= (float)AnT.Height) 
  { 
    ScreenW = 30.0; 
    ScreenH = 30.0 * (float)AnT.Height / (float)AnT.Width; 
    Glu.gluOrtho2D(0.0, ScreenW, 0.0, ScreenH);
  } 
  else 
  {
    ScreenW = 30.0 * (float)AnT.Width / (float)AnT.Height; 
    ScreenH = 30.0; 
    Glu.gluOrtho2D(0.0, 30.0 * (float)AnT.Width / (float)AnT.Height, 0.0, 30.0);
  } 

  // сохранение коэффициентов, которые нам необходимы для перевода координат указателя в оконной системе в координаты, 
  // принятые в нашей OpenGL сцене 
  devX = (float)ScreenW / (float)AnT.Width; 
  devY = (float)ScreenH / (float)AnT.Height; 

  // установка объектно-видовой матрицы 
  Gl.glMatrixMode(Gl.GL_MODELVIEW); 

  // старт счетчика, отвечающего за вызов функции визуализации сцены 
  PointInGrap.Start();

} 



Как видите, почти ничего не изменилось. Теперь обратимся к функции PointInGrap_Tick. Эта функция вызывается с задержкой в 30 миллисекунд.

В ней мы ведем отсчет того, из какого элемента массива с координатами графика мы сейчас возьмем координаты, которые используем для рисования красной точки.
Отсюда так же вызывается функция Draw, отвечающая за визуализацию.

Код этой функции:

/*http://esate.ru, Anvi*/


// функция обработчик события таймера 
private void PointInGrap_Tick(object sender, EventArgs e) 
{ 

  // если мы дошли до последнего элемента массива 
  if (pointPosition == elements_count-1) 
    pointPosition = 0; // переходим к начальному элементу 

  // функция визуализации 
  Draw(); 

  // переход к следующему элементу массива 
  pointPosition++;

} 



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

Начтем с функции AnT_MouseMove. Эта функция добавляется созданием события MouseMove для элемента SimpleOpnGLControl (AnT). Событие создается аналогично тому, как мы его создавали в главе 2.2. Только в данном случае мы переходим к свойствам элемента AnT и уже в них переходим во вкладку Event и добавляем событие MouseMove.

В данной функции мы производим сохранение текущих координат мыши, чтобы в будущем использовать их при визуализации графика, а также производим вычисление размеров линий, которые будут по нормалям соединять координаты указателя мыши с координатными осями (две красные линии на рисунке 1).

Код этой функции выглядит следующим образом:

/*http://esate.ru, Anvi*/


// обработка движения мыши над элементом AnT 
private void AnT_MouseMove(object sender, MouseEventArgs e) 
{ 

// сохраняем координаты мыши 
Mcoord_X = e.X; 
Mcoord_Y = e.Y; 

// вычисляем параметры для будущей дорисовки линий от указателя мыши к координатным осям. 
lineX = devX * e.X; 
lineY = (float)(ScreenH - devY * e.Y);

} 



Теперь рассмотрим функцию, которая будет осуществлять визуализацию текстовых строк. Эта функция устанавливает координаты вывода растровых символов в соответствии с координатами, переданными в параметрах x и y, а затем в цикле перебирает все символы из указанной в параметре строки текста. Каждый из символов визуализируется с помощью функции. В этой функции указывается шрифт для вывода и переменная типа char для визуализации.

Код функции выглядит следующим образом:

/*http://esate.ru, Anvi*/


// функция визуализации текста 
private void PrintText2D(float x, float y, string text) 
{ 

  // устанавливаем позицию вывода растровых символов 
  // в переданных координатах x и y. 
  Gl.glRasterPos2f(x, y); 

  // в цикле foreach перебираем значения из массива text, 
  // который содержит значение строки для визуализации 
  foreach (char char_for_draw in text) 
  { 
    // символ C визуализируем с помощью функции glutBitmapCharacter, используя шрифт GLUT_BITMAP_9_BY_15. 
    Glut.glutBitmapCharacter(Glut.GLUT_BITMAP_9_BY_15, char_for_draw);
  }

} 



Следующая функция, которой мы коснемся - это функция, вычисляющая координаты для построения графика. В ней инициализируется массив координат и производится вычисление всех координат графика в зависимости от указанного диапазона значений x и шага приращения этих значений.

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

Код этой функции с подробными комментариями:

/*http://esate.ru, Anvi*/

// функция, производящая вычисления координат графика 
// и заносящая их в массив GrapValuesArray 
private void functionCalculation() 
{ 

  // определение локальных переменных X и Y 
  float x = 0, y = 0; 

  // инициализация массива, который будет хранить значение 300 точек, 
  // из которых будет состоять график 

  GrapValuesArray = new float[300, 2]; 

  // счетчик элементов массива 
  elements_count = 0; 

  // вычисления всех значений y для x, принадлежащего промежутку от -15 до 15 с шагом в 0.01f 
  for (x = -15; x < 15; x += 0.1f) 
  { 
    // вычисление y для текущего x 
    // по формуле y = (float)Math.Sin(x)*3 + 1; 
    // эта строка задает формулу, описывающую график функции для нашего уравнения y = f(x). 
    y = (float)Math.Sin(x)*3 + 1; 

    // запись координаты x 
    GrapValuesArray[elements_count, 0] = x; 
    // запись координаты y 
    GrapValuesArray[elements_count, 1] = y; 
    // подсчет элементов 
    elements_count++;

  } 

  // изменяем флаг, сигнализировавший о том, что координаты графика не вычислены 
  not_calculate = false;

} 


Функция, выполняющая визуализацию графика

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

В этой функции сначала будет проверен флаг, сигнализирующий о том, что координаты графика вычислены и занесены в массив (переменная not_calculate). В том случае, если флаг указывает, что просчета значений еще не было, вызывается функция, которая посчитает значения координат точек графика и заполнит ими массив.

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

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

Исходный код данной функции:

/*http://esate.ru, Anvi*/

// визуализация графика 
private void DrawDiagram() 
{ 

  // проверка флага, сигнализирующего о том, что координаты графика вычислены 
  if (not_calculate) 
  { 
    // если нет, то вызываем функцию вычисления координат графика 
    functionCalculation();
  } 

  // стартуем отрисовку в режиме визуализации точек 
  // объединяемых в линии (GL_LINE_STRIP) 
  Gl.glBegin(Gl.GL_LINE_STRIP); 

  // рисуем начальную точку 
  Gl.glVertex2d(GrapValuesArray[0, 0], GrapValuesArray[0, 1]); 

  // проходим по массиву с координатами вычисленных точек 
  for (int ax = 1; ax < elements_count; ax+=2) 
  { 
    // передаем в OpenGL информацию о вершине, участвующей в построении линий 
    Gl.glVertex2d(GrapValuesArray[ax, 0], GrapValuesArray[ax, 1]);
  } 

  // завершаем режим рисования 
  Gl.glEnd(); 

  // устанавливаем размер точек, равный 5 пикселям 
  Gl.glPointSize(5); 
  // устанавливаем текущим цветом - красный цвет 
  Gl.glColor3f(255, 0, 0); 
  // активируем режим вывода точек (GL_POINTS) 
  Gl.glBegin(Gl.GL_POINTS); 
  // выводим красную точку, используя ту ячейку массива, до которой мы дошли (вычисляется в функции обработчике событий таймера) 
  Gl.glVertex2d(GrapValuesArray[pointPosition, 0], GrapValuesArray[pointPosition, 1]); 
  // завершаем режим рисования 
  Gl.glEnd(); 
  // устанавливаем размер точек равный единице 
  Gl.glPointSize(1);

} 



И теперь нам осталось просмотреть последнюю функцию – функцию Draw.

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

Код этой функции выглядит следующим образом:

/*http://esate.ru, Anvi*/

// функция, управляющая визуализацией сцены 
private void Draw() 
{ 

  // очистка буфера цвета и буфера глубины 
  Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT); 

  // очищение текущей матрицы 
  Gl.glLoadIdentity(); 

  // установка черного цвета 
  Gl.glColor3f(0, 0, 0); 

  // помещаем состояние матрицы в стек матриц 
  Gl.glPushMatrix(); 

  // выполняем перемещение в пространстве по осям X и Y 
  Gl.glTranslated(15, 15, 0); 

  // активируем режим рисования (Указанные далее точки будут выводиться как точки GL_POINTS) 
  Gl.glBegin(Gl.GL_POINTS); 

  // с помощью прохода вдумя циклами, создаем сетку из точек 
  for (int ax = -15; ax < 15; ax++) 
  {
    for (int bx = -15; bx < 15; bx++) 
    { 
      // вывод точки 
      Gl.glVertex2d(ax, bx);
    } 
  } 

  // завершение режима рисования примитивов 
  Gl.glEnd(); 

  // активируем режим рисования, каждые 2 последовательно вызванные команды glVertex 
  // объединяются в линии 
  Gl.glBegin(Gl.GL_LINES); 

  // далее мы рисуем координатные оси и стрелки на их концах 
  Gl.glVertex2d(0, -15); 
  Gl.glVertex2d(0, 15); 

  Gl.glVertex2d(-15, 0); 
  Gl.glVertex2d(15, 0); 

  // вертикальная стрелка 
  Gl.glVertex2d(0, 15); 
  Gl.glVertex2d(0.1, 14.5); 
  Gl.glVertex2d(0, 15); 
  Gl.glVertex2d(-0.1, 14.5); 

  // горизонтальная трелка 
  Gl.glVertex2d(15, 0); 
  Gl.glVertex2d(14.5, 0.1); 
  Gl.glVertex2d(15, 0); 
  Gl.glVertex2d(14.5, -0.1); 

  // завершаем режим рисования 
  Gl.glEnd(); 

  // выводим подписи осей "x" и "y" 
  PrintText2D(15.5f, 0, "x"); 
  PrintText2D(0.5f, 14.5f, "y"); 

  // вызываем функцию рисования графика 
  DrawDiagram(); 

  // возвращаем матрицу из стека 
  Gl.glPopMatrix(); 

  // выводим текст со значением координат возле курсора 
  PrintText2D(devX * Mcoord_X + 0.2f, (float)ScreenH - devY * Mcoord_Y + 0.4f, "[ x: " + (devX * Mcoord_X - 15).ToString() + " ; y: " + ((float)ScreenH - devY * Mcoord_Y - 15).ToString() + "]"); 

  // устанавливаем красный цвет 
  Gl.glColor3f(255, 0, 0); 

  // включаем режим рисования линий, для того чтобы нарисовать 
  // линии от курсора мыши к координатным осям 
  Gl.glBegin(Gl.GL_LINES); 

  Gl.glVertex2d(lineX, 15); 
  Gl.glVertex2d(lineX, lineY); 
  Gl.glVertex2d(15, lineY); 
  Gl.glVertex2d(lineX, lineY); 

  Gl.glEnd(); 

  // дожидаемся завершения визуализации кадра 
  Gl.glFlush(); 

  // сигнал для обновление элемента реализующего визуализацию. 
  AnT.Invalidate();

} 



Как видите, в этой функции тоже нет ничего сложного, необходимо только разобраться с координатным методом построения примитивов. Если какой-либо кусок кода остается непонятным, достаточно изменить параметры в коде и посмотреть на изменения, чтобы потом сделать вывод о его работе.
P.S.:
Не забудьте инициализировать компонент SimpleOpenGLControl в конструкторе формы, аналогично тому, как это делалось в предыдущих уроках:
/*http://esate.ru, Anvi*/


public Form1() 
{ 
  InitializeComponent(); 
  AnT.InitializeContexts();
} 


Прикрепленные к статье файлы:

Скачать файлы, актуальные для этой статьи:


Источник: Esate.ru
08 Января 2010


Комментарии (из ветки форума)


Мне нравится0
Уважаемый автор! На данном примере как сместить центр координат в (-14:-14)? Никак не могу разобраться!
Мне нравится0
Цитата
afonya пишет:
Уважаемый автор! На данном примере как сместить центр координат в (-14:-14)? Никак не могу разобраться!
Привет.

Весь проект сделан так, что центр смещен в середину экрана. Вам нужно скорректировать все координаты: начального сдвига отрисовки сцены, координатных осей, стрелок к ним и прочему.
Т.е. начиная с:

Код
// выполняем перемещение в пространстве по осям X и Y 
Gl.glTranslated(1, 1, 0);
 
вместо glTranslated(15,15,0), как было изначально.
затем стеку точек отрисовать надо с учетом того, что сместились всего на 1 по каждой оси:

Код
// с помощью прохода двумя циклами, создаем сетку из точек 
            for (int ax = -1; ax < 29; ax++)
            {
                for (int bx = -1; bx < 29; bx++)
                {
                    // вывод точки 
                    Gl.glVertex2d(ax, bx);
                }
            }
 
Координатные оси, подписи к ним, элементы стрелок
Код
// далее мы рисуем координатные оси и стрелки на их концах 
            Gl.glVertex2d(0, -11);
            Gl.glVertex2d(0, 29);

            Gl.glVertex2d(-1, 0);
            Gl.glVertex2d(29, 0);

            // вертикальная стрелка 
            Gl.glVertex2d(0, 29);
            Gl.glVertex2d(0.1, 28.5);
            Gl.glVertex2d(0, 29);
            Gl.glVertex2d(-0.1, 28.5);

            // горизонтальная трелка 
            Gl.glVertex2d(29, 0);
            Gl.glVertex2d(28.5, 0.1);
            Gl.glVertex2d(29, 0);
            Gl.glVertex2d(28.5, -0.1);

            // завершаем режим рисования 
            Gl.glEnd();

            // выводим подписи осей "x" и "y" 
            PrintText2D(29.5f, 0, "x");
            PrintText2D(0.5f, 28.5f, "y");
 
ну и прочие мелочи:

Код
// выводим текст со значением координат возле курсора 
PrintText2D(devX * Mcoord_X + 0.2f, (float)ScreenH - devY * Mcoord_Y + 0.4f, "[ x: " + (devX * Mcoord_X - 1).ToString() + " ; y: " + ((float)ScreenH - devY * Mcoord_Y - 1).ToString() + "]");
 
Gl.glVertex2d(lineX, 1);
Gl.glVertex2d(lineX, lineY);
Gl.glVertex2d(1, lineY);
Gl.glVertex2d(lineX, lineY);
в самой функции рисования графика не забудьте поправить координаты. на выходе получаем что-то вроде:
new-graphic.png (26.36 КБ)
Мне нравится0
Прикрепил оригинальный код урока к статье 8)
Мне нравится0
Здравствуйте, на одной системе координат как можно построить три графика функции точно так же как на вашем примере?
Мне нравится0
У меня при помещении в дочернее окно MDI какая то непонятная вещь - когда запускаешь вторую вкладку, берешь её за рамку для перетаскивания на 1 окошке рисуются каляки от окошка при перемещении
не пойму как с этим бороться?


Код
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

// для работы с библиотекой OpenGL 
using Tao.OpenGl;
// для работы с библиотекой FreeGLUT 
using Tao.FreeGlut;
// для работы с элементом управления SimpleOpenGLControl 
using Tao.Platform.Windows; 

namespace GraphRed2010
{
    public partial class MDIChildren1 : Form
    {
        private bool MDIChildren1_Active = false; //активно ли окно
      
        // размеры окна 
        double ScreenW, ScreenH;

        // отношения сторон окна визуализации 
        // для корректного перевода координат мыши в координаты, 
        // принятые в программе 

        private float devX;
        private float devY;

        // массив, который будет хранить значения x,y точек графика 
        private float[,] GrapValuesArray;
        // количество элементов в массиве 
        private int elements_count = 0;

        // флаг, означающий, что массив с значениями координат графика пока еще не заполнен 
        private bool not_calculate = true;

        // номер ячейки массива, из которой будут взяты координаты для красной точки 
        // для визуализации текущего кадра 
        private int pointPosition = 0;

        // вспомогательные переменные для построения линий от курсора мыши к координатным осям 
        float lineX, lineY;

        // текущение координаты курсора мыши 
        float Mcoord_X = 0, Mcoord_Y = 0; 

        public MDIChildren1()
        {
            InitializeComponent();
            AnT.InitializeContexts();        
        }

        private void MDIChildren1_Load(object sender, EventArgs e)
        {
            // инициализация библиотеки glut 
           /* Glut.glutInit();
            // инициализация режима экрана 
            Glut.glutInitDisplayMode(Glut.GLUT_RGB | Glut.GLUT_DOUBLE);*/

            // установка цвета очистки экрана (RGBA) 
            Gl.glClearColor(255, 255, 255, 1);

            // установка порта вывода 
            Gl.glViewport(0, 0, AnT.Width, AnT.Height);

            // активация проекционной матрицы 
            Gl.glMatrixMode(Gl.GL_PROJECTION);
            // очистка матрицы 
            Gl.glLoadIdentity();

            // определение параметров настройки проекции в зависимости от размеров сторон элемента AnT. 
            if ((float)AnT.Width <= (float)AnT.Height)
            {
                ScreenW = 30.0;
                ScreenH = 30.0 * (float)AnT.Height / (float)AnT.Width;
                Glu.gluOrtho2D(0.0, ScreenW, 0.0, ScreenH);
            }
            else
            {
                ScreenW = 30.0 * (float)AnT.Width / (float)AnT.Height;
                ScreenH = 30.0;
                Glu.gluOrtho2D(0.0, 30.0 * (float)AnT.Width / (float)AnT.Height, 0.0, 30.0);
            }

            // сохранение коэффициентов, которые нам необходимы для перевода координат указателя в оконной системе в координаты, 
            // принятые в нашей OpenGL сцене 
            devX = (float)ScreenW / (float)AnT.Width;
            devY = (float)ScreenH / (float)AnT.Height;

            // установка объектно-видовой матрицы 
            Gl.glMatrixMode(Gl.GL_MODELVIEW);

            // старт счетчика, отвечающего за вызов функции визуализации сцены 
            /*PointInGrap.Start();
            */
            // функция визуализации 
            Draw();
            // сигнал для обновление элемента реализующего визуализацию. 
            AnT.Invalidate();

            MDIChildren1_Active = true; //окно активно
        }

        private void MDIChildren1_Resize(object sender, EventArgs e)
        {
            //this.Text = "4356436"; 
            // сигнал для обновление элемента реализующего визуализацию. 
            AnT.Invalidate();
        }

        private void PointInGrap_Tick(object sender, EventArgs e)
        {
            // если мы дошли до последнего элемента массива 
            if (pointPosition == elements_count - 1)
                pointPosition = 0; // переходим к начальному элементу 

            /*// функция визуализации 
            Draw();*/
            DrawDiagram();
            // переход к следующему элементу массива 
            pointPosition++;
        }
        
        private void AnT_MouseMove(object sender, MouseEventArgs e)
        {
            // сохраняем координаты мыши 
            Mcoord_X = e.X;
            Mcoord_Y = e.Y;

            // вычисляем параметры для будущей дорисовки линий от указателя мыши к координатным осям. 
            lineX = devX * e.X;
            lineY = (float)(ScreenH - devY * e.Y);

            if (MDIChildren1_Active == true)
            {
                // функция визуализации 
                Draw();
                /*// сигнал для обновление элемента реализующего визуализацию. 
                AnT.Invalidate();*/
            }
        }

        // функция визуализации текста 
        private void PrintText2D(float x, float y, string text)
        {

            // устанавливаем позицию вывода растровых символов 
            // в переданных координатах x и y. 
            Gl.glRasterPos2f(x, y);

            // в цикле foreach перебираем значения из массива text, 
            // который содержит значение строки для визуализации 
            foreach (char char_for_draw in text)
            {
                // символ C визуализируем с помощью функции glutBitmapCharacter, используя шрифт GLUT_BITMAP_9_BY_15. 
                Glut.glutBitmapCharacter(Glut.GLUT_BITMAP_9_BY_15, char_for_draw);
            }

        }

        // функция, производящая вычисления координат графика 
        // и заносящая их в массив GrapValuesArray 
        private void functionCalculation()
        {

            // определение локальных переменных X и Y 
            float x = 0, y = 0;

            // инициализация массива, который будет хранить значение 300 точек, 
            // из которых будет состоять график 

            GrapValuesArray = new float[300, 2];

            // счетчик элементов массива 
            elements_count = 0;

            // вычисления всех значений y для x, принадлежащего промежутку от -15 до 15 с шагом в 0.01f 
            for (x = -15; x < 15; x += 0.1f)
            {
                // вычисление y для текущего x 
                // по формуле y = (float)Math.Sin(x)*3 + 1; 
                // эта строка задает формулу, описывающую график функции для нашего уравнения y = f(x). 
                y = (float)Math.Sin(x) * 3 + 1;

                // запись координаты x 
                GrapValuesArray[elements_count, 0] = x;
                // запись координаты y 
                GrapValuesArray[elements_count, 1] = y;
                // подсчет элементов 
                elements_count++;

            }

            // изменяем флаг, сигнализировавший о том, что координаты графика не вычислены 
            not_calculate = false;

        }

        // визуализация графика 
        private void DrawDiagram()
        {

            // проверка флага, сигнализирующего о том, что координаты графика вычислены 
            if (not_calculate)
            {
                // если нет, то вызываем функцию вычисления координат графика 
                functionCalculation();
            }

            // стартуем отрисовку в режиме визуализации точек 
            // объединяемых в линии (GL_LINE_STRIP) 
            Gl.glBegin(Gl.GL_LINE_STRIP);

            // рисуем начальную точку 
            Gl.glVertex2d(GrapValuesArray[0, 0], GrapValuesArray[0, 1]);

            // проходим по массиву с координатами вычисленных точек 
            for (int ax = 1; ax < elements_count; ax += 2)
            {
                // передаем в OpenGL информацию о вершине, участвующей в построении линий 
                Gl.glVertex2d(GrapValuesArray[ax, 0], GrapValuesArray[ax, 1]);
            }

            // завершаем режим рисования 
            Gl.glEnd();

            // устанавливаем размер точек, равный 5 пикселям 
            Gl.glPointSize(5);
            // устанавливаем текущим цветом - красный цвет 
            Gl.glColor3f(255, 0, 0);
            // активируем режим вывода точек (GL_POINTS) 
            Gl.glBegin(Gl.GL_POINTS);
            // выводим красную точку, используя ту ячейку массива, до которой мы дошли (вычисляется в функции обработчике событий таймера) 
            Gl.glVertex2d(GrapValuesArray[pointPosition, 0], GrapValuesArray[pointPosition, 1]);
            // завершаем режим рисования 
            Gl.glEnd();
            // устанавливаем размер точек равный единице 
            Gl.glPointSize(1);

            // возвращаем матрицу из стека 
            Gl.glPopMatrix();

            // дожидаемся завершения визуализации кадра 
            Gl.glFlush();

            // сигнал для обновление элемента реализующего визуализацию. 
            AnT.Invalidate();
        }

        // функция, управляющая визуализацией сцены 
        private void Draw()
        {

            // очистка буфера цвета и буфера глубины 
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);

            // очищение текущей матрицы 
            Gl.glLoadIdentity();

            // установка черного цвета 
            Gl.glColor3f(0, 0, 0);

            // помещаем состояние матрицы в стек матриц 
            Gl.glPushMatrix();

            // выполняем перемещение в пространстве по осям X и Y 
            Gl.glTranslated(15, 15, 0);

            // активируем режим рисования (Указанные далее точки будут выводиться как точки GL_POINTS) 
            Gl.glBegin(Gl.GL_POINTS);

            // с помощью прохода вдумя циклами, создаем сетку из точек 
            for (int ax = -15; ax < 15; ax++)
            {
                for (int bx = -15; bx < 15; bx++)
                {
                    // вывод точки 
                    Gl.glVertex2d(ax, bx);
                }
            }

            // завершение режима рисования примитивов 
            Gl.glEnd();

            // активируем режим рисования, каждые 2 последовательно вызванные команды glVertex 
            // объединяются в линии 
            Gl.glBegin(Gl.GL_LINES);

            // далее мы рисуем координатные оси и стрелки на их концах 
            Gl.glVertex2d(0, -15);
            Gl.glVertex2d(0, 15);

            Gl.glVertex2d(-15, 0);
            Gl.glVertex2d(15, 0);

            // вертикальная стрелка 
            Gl.glVertex2d(0, 15);
            Gl.glVertex2d(0.1, 14.5);
            Gl.glVertex2d(0, 15);
            Gl.glVertex2d(-0.1, 14.5);

            // горизонтальная трелка 
            Gl.glVertex2d(15, 0);
            Gl.glVertex2d(14.5, 0.1);
            Gl.glVertex2d(15, 0);
            Gl.glVertex2d(14.5, -0.1);

            // завершаем режим рисования 
            Gl.glEnd();

            // выводим подписи осей "x" и "y" 
            PrintText2D(15.5f, 0, "x");
            PrintText2D(0.5f, 14.5f, "y");

            // вызываем функцию рисования графика 
            DrawDiagram();

            // возвращаем матрицу из стека 
            Gl.glPopMatrix();

            // выводим текст со значением координат возле курсора 
            PrintText2D(devX * Mcoord_X + 0.2f, (float)ScreenH - devY * Mcoord_Y + 0.4f, "[ x: " + (devX * Mcoord_X - 15).ToString() + " ; y: " + ((float)ScreenH - devY * Mcoord_Y - 15).ToString() + "]");
            
            // устанавливаем красный цвет 
            Gl.glColor3f(255, 0, 0);

            // включаем режим рисования линий, для того чтобы нарисовать 
            // линии от курсора мыши к координатным осям 
            Gl.glBegin(Gl.GL_LINES);

            Gl.glVertex2d(lineX, 15);
            Gl.glVertex2d(lineX, lineY);
            Gl.glVertex2d(15, lineY);
            Gl.glVertex2d(lineX, lineY);

            Gl.glEnd();

            // дожидаемся завершения визуализации кадра 
            Gl.glFlush();

            // сигнал для обновление элемента реализующего визуализацию. 
            AnT.Invalidate();
        }

        private void MDIChildren1_Deactivate(object sender, EventArgs e)
        {
            MDIChildren1_Active = false; //окно неактивно при деактивации
        }

        private void MDIChildren1_Activated(object sender, EventArgs e)
        {
            MDIChildren1_Active = true; //окно активно при активации формы
        }
    }
}
 
Каляки )).jpg (141.88 КБ)
Мне нравится0
Цитата
У меня при помещении в дочернее окно MDI какая то непонятная вещь - когда запускаешь вторую вкладку, берешь её за рамку для перетаскивания на 1 окошке рисуются каляки от окошка при перемещении
не пойму как с этим бороться?
Да, с ходу не знаю что предположить.

Артефакты на неактивном окне, видимо от края активного угла. Мне кажется это особенности визуализации окон наложившиеся на компонент визуализации TAO.

А если перерисовывать 1 раз (даже без вычислений) неактивное окно по окончанию перемещения активного? Возможно это единственный вариант.
Мне нравится0
Цитата
Anvi пишет:
А если перерисовывать 1 раз (даже без вычислений) неактивное окно по окончанию перемещения активного? Возможно это единственный вариант.
не совсем понял чем это поможет ведь рисуется крокозябры в процессе движения окна а не "по окончанию"

хорошим вариантом было бы останавливать любую отрисовку на окне при пропадании активности на нем но как это сделать? да еще и чтоб не пропадало последнее нарисованное?
есть ли в АнТе какаянибудь функция "остановки" ? ))
"// завершаем режим рисования Gl.glEnd();" тут не поможет?
Мне нравится0
Цитата
releyshic пишет:
хорошим вариантом было бы останавливать любую отрисовку на окне при пропадании активности на нем но как это сделать? да еще и чтоб не пропадало последнее нарисованное?
есть ли в АнТе какаянибудь функция "остановки" ? ))
"// завершаем режим рисованияGl.glEnd();" тут не поможет?
а может получится проверять в условном операторе не активно ли какоето еще окно при текущей отрисовке здесь помимо
Код
MDIChildren1_Active == true

Код
 private void AnT_MouseMove(object sender, MouseEventArgs e)
     {
      // сохраняем координаты мыши 
      Mcoord_X = e.X;
      Mcoord_Y = e.Y;
      // вычисляем параметры для будущей дорисовки линий от указателя мыши к координатным осям. 
      lineX = devX * e.X;
      lineY = (float)(ScreenH - devY * e.Y);

      if (MDIChildren1_Active == true)
      {
          // функция визуализации 
          Draw();
          /*// сигнал для обновление элемента реализующего визуализацию. 
          AnT.Invalidate();*/
      }
     }
но вот как проверить на активность все открытые дочерние окна ?
Мне нравится0
Нужно смотреть весь проект и экспериментировать.

Мне кажется что артефакты можно убрать только перерисовкой окна, на котором они появились, и что они не связаны с тем, как реализован рендер в приложении.
Но это все надо опытным путем делать.
Мне нравится0
Цитата
Anvi пишет:
ужно смотреть весь проект и экспериментировать.

Мне кажется что артефакты можно убрать только перерисовкой окна, на котором они появились, и что они не связаны с тем, как реализован рендер в приложении.
Но это все надо опытным путем делать.
ниужели надо всегда всё перерисовывать полностью? и что никак нельзя например сделать постоянный фон (кроме картинки конечно)? или есть слои какието? можно ли как то сохранить текущий вид во чтото (для быстрого использования конечно)?
Мне нравится0
Цитата
releyshic написал:
ниужели надо всегда всё перерисовывать полностью? и что никак нельзя например сделать постоянный фон (кроме картинки конечно)? или есть слои какието? можно ли как то сохранить текущий вид во чтото (для быстрого использования конечно)?
я уже написал выше: мне кажется, что дело в особенностях наложений окон и их перерисовки. Судя по скриншотам на не активном окне артефакты.
Значит как минимум нужно проверить, будет ли повторяться проблема на компьютерах с другими видеокартами (точно помню, что как-то мне попадались скриншоты с сильными артефактами на окне с визуализацией, и проблема была в видеокарте и драйверах ноутбука).

Ну а дальше да, сначала проверить - поможет ли вообще перерисовка неактивного окна от этих артефактов.

А потом уже думать над тем, как выходить из ситуации - либо перерисовка от доп. события, либо еще какие-нибудь варианты.

Обратите внимание на glReadPixels / glDrawPixels, но это не самый быстрый способ.


Оставить сообщение:

Авторизируйтесь или Зарегистрируйтесь
чтобы оставлять комментарии.

OpenGL

OpenGL

OpenGL (Open Graphics Library — открытая графическая библиотека, графический API) — спецификация, определяющая независимый от языка программирования платформонезависимый программный интерфейс для написания приложений, использующих двумерную и трёхмерную компьютерную графику.

Регистрация

Регистрируясь, вы принимаете правила сайта. Если вы не получили код подтв. регистрации - не забудьте проверить папку спам.
Логин*
Email*
Пароль*
Подтверждение пароля*
 
Логин*
Код*
 

Восстановление пароля

Пожалуйста, заполните поля, после чего вы получите код подтверждения на ваш E-mail. Если код не пришел в течении нескольких минут - проверьте папку спам.
Логин

или Email
 
Логин*
Код подтверждения*
Новый пароль*
Подтверждение пароля*
 

Авторизация

Пожалуйста, авторизуйтесь, для входа на сайт с помощью соц. сети:
  • Используйте вашу учетную запись на Facebook.com для входа на сайт.
  • Используйте вашу учетную запись VKontakte для входа на сайт.
  • Используйте вашу учетную запись Google для входа на сайт.

или с помощью аккаунта на сайте:

Логин
Пароль