Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Программирование игр, графики и искусственного интеллекта > Тесселяция полигонов


Автор: inkognitum 9.9.2008, 19:47
Добрый день.

Помогите с примером тесселяция полигонов, пробую пробую... ничего не выходит.
пользуюсь библиотекой - Tao, на С#, все примеры в инете на C++.

Самый простой пример который отображает всю процедуры рисования сложного полигона.

Заранее спасибо.

Автор: Rickert 10.9.2008, 03:46
inkognitum, у OpenGL есть стандартные функции по тесселяции - см. MSDN glTes*
Лично у меня был частный случай с вырезание в плоскости дырки, которая представлялась выпулкым полигоном - алгоритм писал сам.
Так же на algolist'е есть алгоритмы вычитания.

Автор: inkognitum 10.9.2008, 07:30
Цитата(Rickert @ 10.9.2008,  03:46)
inkognitum, у OpenGL есть стандартные функции по тесселяции - см. MSDN glTes*
Лично у меня был частный случай с вырезание в плоскости дырки, которая представлялась выпулкым полигоном - алгоритм писал сам.
Так же на algolist'е есть алгоритмы вычитания.

Да, я знаю в библиотеке Glu, только я не могу понять как ее использовать.
Накомпал кучу коду с примерами на С++, на С# перевести не получается.

Автор: Rpahut 10.9.2008, 17:50
Код

// псевдокод
GLUTesselator *t = gluNewTess(); // создаем новый объект тесселяции

gluTessProperty(t, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); // тут возможны другие варианты
gluTessProperty(t, GLU_TESS_BOUNDARY_ONLY, GL_FALSE); // закрашивать полигон
gluTessProperty(t, GLU_TESS_TOLERANCE, 0); // по умолчанию здесь и так 0; вопще польза от этого свойства мне кажется сомнительной

// регистрируем зов-в-зад-функции =)
gluTessCallback(t, GLU_TESS_BEGIN, glBegin); // эта-чтоб глу мог начать отрисовку простого полигона
gluTessCallback(t, GLU_TESS_END, glEnd);  // эта-чтоб глу мог закончить отрисовку простого полигона
gluTessCallback(t, GLU_TESS_VERTEX,glVertex3dv); // эта - чтоб он мог передать координаты вершины

gluTessBeginPolygon(t, 0); // начинаем тесселяцию
gluTessBeginContour(t); // начинаем описание очередного кривого полигона
    gluTessVertex(t, coordsd3, 0); // вызываем по разу для каждой вершины полигона (обрисовываем контур)
gluTessEndContour(t); // сообщаем глу, что контур закончен
gluTessEndPolygon(t, 0); // сообщаем, что ввод данных закончен
// теперь глу обрабатывает данные и вызывает каллбэк-функции(т.е. в нашем случае вызывает glBegin, потом нес-ко раз glVertex, потом glEnd, пока не отобразится весь полигон)

gluDeleteTess(t); // если он больше не нужен


ЗЫ с шарпом не знаком, звиняй уж

Автор: inkognitum 11.9.2008, 07:58
Цитата

Код

// псевдокод
GLUTesselator *t = gluNewTess(); // создаем новый объект тесселяции

gluTessProperty(t, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); // тут возможны другие варианты
gluTessProperty(t, GLU_TESS_BOUNDARY_ONLY, GL_FALSE); // закрашивать полигон
gluTessProperty(t, GLU_TESS_TOLERANCE, 0); // по умолчанию здесь и так 0; вопще польза от этого свойства мне кажется сомнительной

// регистрируем зов-в-зад-функции =)
gluTessCallback(t, GLU_TESS_BEGIN, glBegin); // эта-чтоб глу мог начать отрисовку простого полигона
gluTessCallback(t, GLU_TESS_END, glEnd);  // эта-чтоб глу мог закончить отрисовку простого полигона
gluTessCallback(t, GLU_TESS_VERTEX,glVertex3dv); // эта - чтоб он мог передать координаты вершины

gluTessBeginPolygon(t, 0); // начинаем тесселяцию
gluTessBeginContour(t); // начинаем описание очередного кривого полигона
    gluTessVertex(t, coordsd3, 0); // вызываем по разу для каждой вершины полигона (обрисовываем контур)
gluTessEndContour(t); // сообщаем глу, что контур закончен
gluTessEndPolygon(t, 0); // сообщаем, что ввод данных закончен
// теперь глу обрабатывает данные и вызывает каллбэк-функции(т.е. в нашем случае вызывает glBegin, потом нес-ко раз glVertex, потом glEnd, пока не отобразится весь полигон)

gluDeleteTess(t); // если он больше не нужен



ЗЫ с шарпом не знаком, звиняй уж
Спасибо. 
Я так и делал все, в честности у меня ругается на след. строку кода.

Код

Glu.GLUtesselator t = Glu.gluNewTess();
Glu.gluTessProperty(t, Glu.GLU_TESS_WINDING_RULE, Glu.GLU_TESS_WINDING_ODD); 
Glu.gluTessProperty(t, Glu.GLU_TESS_BOUNDARY_ONLY, Gl.GL_FALSE);
Glu.gluTessProperty(t, Glu.GLU_TESS_TOLERANCE, 0);

// регистрируем зов-в-зад-функции =)

Glu.gluTessCallback(t, Glu.GLU_TESS_BEGIN, Gl.glBegin);   
/* 
ОШИБКА - Error    1    The call is ambiguous between the following methods or 
properties: 'Tao.OpenGl.Glu.gluTessCallback(Tao.OpenGl.Glu.GLUtesselator, int, 
Tao.OpenGl.Glu.TessErrorCallback)' and 'Tao.OpenGl.Glu.gluTessCallback(
Tao.OpenGl.Glu.GLUtesselator, int, Tao.OpenGl.Glu.TessBeginCallback)'
*/

Glu.gluTessCallback(t, Glu.GLU_TESS_END, Gl.glEnd);
Glu.gluTessCallback(t, Glu.GLU_TESS_VERTEX, Gl.glVertex3dv);

Glu.gluTessBeginPolygon(t, new byte[] { 0 });
Glu.gluTessBeginContour(t);
Glu.gluTessVertex(t, coordsd3, new byte[] { 0 });
Glu.gluTessEndContour(t);
Glu.gluTessEndPolygon(t);

Glu.gluDeleteTess(t);


И вопрос как забивать координаты - coordsd3?? у меня показывает тип - double[]
и как в одномерный массив забить координаты точки? подрят чтоль Х и Y, если честно недопонимаю этот момент.

Добавлено @ 08:06
Вопрос с ошибкой снялся. Вопрос с double[] остался smile

Код

Glu.gluTessCallback(t, Glu.GLU_TESS_BEGIN, new Glu.TessBeginCallback(Gl.glBegin));
Glu.gluTessCallback(t, Glu.GLU_TESS_END, new Glu.TessEndCallback(Gl.glEnd));
Glu.gluTessCallback(t, Glu.GLU_TESS_VERTEX, Gl.glVertex3dv);



Автор: Rpahut 11.9.2008, 21:51
coordsd3 я от балды вбивал - лень было рисовать цикл и инициализацию массива. Конечно там массив из трех double передается - x, y, z подряд. Нужно передать координаты всех вершин, соотв. вызываем gluTessVertex по разу для каждой из них.


Автор: inkognitum 12.9.2008, 07:49
Цитата(Rpahut @ 11.9.2008,  21:51)
coordsd3 я от балды вбивал - лень было рисовать цикл и инициализацию массива. Конечно там массив из трех double передается - x, y, z подряд. Нужно передать координаты всех вершин, соотв. вызываем gluTessVertex по разу для каждой из них.

Добрый день.

Чет у меня ничего не рисует.
делаю вот так.

Код

        public void ClearControl()
        {
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);

            Gl.glViewport(0, 0, this.Width, this.Height);
            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();
            Glu.gluOrtho2D(0, this.Width, 0, this.Height);
        }

        public void DrawPolygon(Pen pen, PointF[] pt)
        {
            // псевдокод

            Gl.glColor3ub(255,255,255);

            Glu.GLUtesselator t = Glu.gluNewTess(); // создаем новый объект тесселяции

            Glu.gluTessProperty(t, Glu.GLU_TESS_WINDING_RULE, Glu.GLU_TESS_WINDING_ODD); // тут возможны другие варианты
            Glu.gluTessProperty(t, Glu.GLU_TESS_BOUNDARY_ONLY, Gl.GL_FALSE); // закрашивать полигон
            Glu.gluTessProperty(t, Glu.GLU_TESS_TOLERANCE, 0); // по умолчанию здесь и так 0; вопще польза от этого свойства мне кажется сомнительной

            // регистрируем зов-в-зад-функции =)
            Glu.gluTessCallback(t, Glu.GLU_TESS_BEGIN, new Glu.TessBeginCallback(Gl.glBegin)); // эта-чтоб глу мог начать отрисовку простого полигона
            Glu.gluTessCallback(t, Glu.GLU_TESS_END, new Glu.TessEndCallback(Gl.glEnd));  // эта-чтоб глу мог закончить отрисовку простого полигона
            Glu.gluTessCallback(t, Glu.GLU_TESS_VERTEX, Gl.glVertex2dv); // эта - чтоб он мог передать координаты вершины

            Glu.gluTessBeginPolygon(t, new byte[] { 0 }); // начинаем тесселяцию
            Glu.gluTessBeginContour(t); // начинаем описание очередного кривого полигона

            foreach (PointF ptI in pt)
            {
                double[] dbPoint = new double[2];
                dbPoint[0] = ptI.X;
                dbPoint[1] = this.Height - ptI.Y;
                //dbPoint[2] = 0;
                Glu.gluTessVertex(t, dbPoint, new byte[] { 0 }); // вызываем по разу для каждой вершины полигона (обрисовываем контур)
            }

            Glu.gluTessEndContour(t); // сообщаем глу, что контур закончен
            Glu.gluTessEndPolygon(t); // сообщаем, что ввод данных закончен
            // теперь глу обрабатывает данные и вызывает каллбэк-функции(т.е. в нашем случае вызывает glBegin, потом нес-ко раз glVertex, потом glEnd, пока не отобразится весь полигон)

            Glu.gluDeleteTess(t); // если он больше не нужен

        }


ошибок нет, но и не рисует ничего. (((

Автор: Rpahut 12.9.2008, 09:31
А почему
Код

//dbPoint[2] = 0;

? ГЛУ читает три координаты все равно, так что даже если Z=0, он должен указываться.
Это раз.
Два - если не рисует - значит ошибки есть)
Три.
Добавь следующие ф-ции:
Код

void CALLBACK MyBegin(GLenum mode) {
    glBegin(mode);
}

void CALLBACK MyEnd(void) {
    glEnd();
}

void CALLBACK MyVertex3dv(const GLdouble *v) {
    glVertex3dv(v);
}

, зарегистрируй их вместо старых каллбэков. Поставь в каждую брейкпоинт и посмотри, выполняются ли они.Если вызываются - знач полигон рисуется, но не там или не так, как ты ожидаешь. Если нет, ну, тогда я где-то накосячил  smile 
ЗЫ На счет нужно ли писать CALLBACK не уверен - может скомпилируется и без них, может не скомпилируется с ними.

Автор: inkognitum 12.9.2008, 11:29
Цитата(Rpahut @ 12.9.2008,  09:31)
А почему
Код

//dbPoint[2] = 0;

? ГЛУ читает три координаты все равно, так что даже если Z=0, он должен указываться.
Это раз.
Два - если не рисует - значит ошибки есть)
Три.
Добавь следующие ф-ции:
Код

void CALLBACK MyBegin(GLenum mode) {
    glBegin(mode);
}

void CALLBACK MyEnd(void) {
    glEnd();
}

void CALLBACK MyVertex3dv(const GLdouble *v) {
    glVertex3dv(v);
}

, зарегистрируй их вместо старых каллбэков. Поставь в каждую брейкпоинт и посмотри, выполняются ли они.Если вызываются - знач полигон рисуется, но не там или не так, как ты ожидаешь. Если нет, ну, тогда я где-то накосячил  smile 
ЗЫ На счет нужно ли писать CALLBACK не уверен - может скомпилируется и без них, может не скомпилируется с ними.

Чет странно.

Поставил точку останова на функцию:

Код

void MyVertex3dv(double[] v)
{
      Gl.glVertex3dv(v);
}


он туда заходит рочно столько раз сколько моих точек в полигоне, но почему то переменная V пустая )

Еще интересней )

меняю функцию на:
Код

Glu.gluTessVertex(t, dbPoint, dbPoint);


то в функции MyVirtex в переменное V только 1 объект который равен Х, я проверяю мою переменную dbPoint там все 3 координат.

Автор: Rpahut 12.9.2008, 23:11
Цитата

меняю функцию на:
Цитата

Glu.gluTessVertex(t, dbPoint, dbPoint);


Так правильнее. Мой косяк. smile 

Цитата

в переменное V только 1 объект который равен Х

Скорее всего дебаггер просто показывает тебе только первый элемент - он не знает что их там три.
Раз вызываются каллбэки, значит openGL получает координаты вершин. Я бы вставил перед тесселяцией код, выводящий на экран треугольник или линию( smile ), чтобы убедиться что то что мы рисуем отобразится на экране.

Код

double dbPoint[numVert][3]; // numVert - кол-во вершин
for(int i=0; i<numVert; i++) {
                dbPoint[i][0] = pt[i].X;
                dbPoint[i][1] = this.Height - pt[i].Y;
                dbPoint[i][2] = .0;
                Glu.gluTessVertex(t, dbPoint[i], dbPoint[i]);
}

Вот таким макаром у меня работает однозначно.


Автор: inkognitum 13.9.2008, 12:30
Мне уже смешно )))

ничего не выходит. Сроки поджимают (((

Я кое что переписал и доработал, стал он полигоны выводить но опять же не сложные а простые.

сделал так:

Код

private void MyVertex3dv(System.IntPtr vertexData)
        {
            double[] v = new double[3];
            System.Runtime.InteropServices.Marshal.Copy(vertexData, v, 0, 3);
            Gl.glVertex3dv(v);
        }


потом немного дописал функцию:

Код

lu.GLUtesselator t = Glu.gluNewTess(); // создаем новый объект тесселяции

            Glu.gluTessProperty(t, Glu.GLU_TESS_WINDING_RULE, Glu.GLU_TESS_WINDING_ODD); // тут возможны другие варианты
            Glu.gluTessProperty(t, Glu.GLU_TESS_BOUNDARY_ONLY, Gl.GL_FALSE); // закрашивать полигон
            
            // регистрируем зов-в-зад-функции =)
            Glu.gluTessCallback(t, Glu.GLU_TESS_BEGIN, new Glu.TessBeginCallback(MyBegin)); // эта-чтоб глу мог начать отрисовку простого полигона
            Glu.gluTessCallback(t, Glu.GLU_TESS_END, new Glu.TessEndCallback(MyEnd));  // эта-чтоб глу мог закончить отрисовку простого полигона
            Glu.gluTessCallback(t, Glu.GLU_TESS_VERTEX, new Glu.TessVertexCallback(MyVertex3dv)); // эта - чтоб он мог передать координаты вершины

       
            Glu.gluTessNormal(t, 0, 0, 1);

            Glu.gluTessBeginPolygon(t, IntPtr.Zero); // начинаем тесселяцию
            Glu.gluTessBeginContour(t); // начинаем описание очередного кривого полигона

            for (int i = 0; i <= pt.Length - 1; i++)
            {
                double[] dbPoint = new double[3];
                dbPoint[0] = pt[i].X;
                dbPoint[1] = this.Height - pt[i].Y;
                dbPoint[2] = 0;
                Glu.gluTessVertex(t, dbPoint, dbPoint); // вызываем по разу для каждой вершины полигона (обрисовываем контур)
            }
            Glu.gluTessEndContour(t); // сообщаем глу, что контур закончен
            Glu.gluTessEndPolygon(t); // сообщаем, что ввод данных закончен
            // теперь глу обрабатывает данные и вызывает каллбэк-функции
            //(т.е. в нашем случае вызывает glBegin, потом нес-ко раз glVertex, потом glEnd, пока не отобразится весь полигон)
            Glu.gluDeleteTess(t); // если он больше не нужен



рисует но простые.

кстати нашел вот что:
https://dappleproject.geosoft.com/browser/dapple/PluginSDK/PolygonFeature.cs?rev=333

там кое что поддчеркнул но всерано не работает. что то странно (( голова уже болит.

Автор: Rpahut 13.9.2008, 14:48
Цитата

Я кое что переписал и доработал, стал он полигоны выводить но опять же не сложные а простые

Поподробнее?
И какой формы полигоны у тебя? 

Неплохо бы для GLU_TESS_ERROR тоже сделать каллбэк и посмотреть на что глу жалуется.
Еще меня смущает double[] dbPoint = new double[3]; Вроде работать должно, но выглядит странно. Попробуй как в моем предыдущем посте нарисовано - создать один большой массив, в него затолкать все координаты, и уже из него передавать в gluTessVertex. И - наверное С++ и С# тут не сильно отличаются - если есть new, то должен быть и delete.

И вобще - может там не в тесселяции проблема?

Автор: inkognitum 13.9.2008, 19:27
Цитата(Rpahut @ 13.9.2008,  14:48)
Цитата

Я кое что переписал и доработал, стал он полигоны выводить но опять же не сложные а простые

Поподробнее?
И какой формы полигоны у тебя? 

Неплохо бы для GLU_TESS_ERROR тоже сделать каллбэк и посмотреть на что глу жалуется.
Еще меня смущает double[] dbPoint = new double[3]; Вроде работать должно, но выглядит странно. Попробуй как в моем предыдущем посте нарисовано - создать один большой массив, в него затолкать все координаты, и уже из него передавать в gluTessVertex. И - наверное С++ и С# тут не сильно отличаются - если есть new, то должен быть и delete.

И вобще - может там не в тесселяции проблема?

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

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

Или я ошибаюсь?

Спасибо, за активную помощь, сам бы я не разобрался во всем )))
мог бы дать репутации дал бы.. но не могу (( 

Автор: Rpahut 13.9.2008, 20:50
Цитата

он не может обрисовать полигоны у которых линии пересекаются


Может. Копай в сторону GLU_TESS_COMBINE

Автор: inkognitum 14.9.2008, 11:26
Цитата(Rpahut @ 13.9.2008,  20:50)
Копай в сторону GLU_TESS_COMBINE

Добрый день.

Делаю так:
Код

Glu.gluTessCallback(t, Glu.GLU_TESS_COMBINE,  new Glu.TessCombineCallback1(MyCombine));


сама функция:

Код

private static void MyCombine(double[] coordinates, double[] vertexData, float[] weight, double[] dataOut)
        //private static void MyCombine(double[] coordinates, System.IntPtr[] ptrVertexData, float[] weight, System.IntPtr[] dataOut)
        {
            double[] vertex = new double[6];
            int i;

            vertex[0] = coordinates[0];
            vertex[1] = coordinates[1];
            vertex[2] = coordinates[2];

            double[] v = new double[6];
            
            for (i = 3; i < 6; i++)
            {
                vertex[i] = weight[0] * vertexData[i] + weight[1] * vertexData[i] + weight[2] * vertexData[i] + weight[3] * vertexData[i];
            }

            dataOut = vertex;
        }



выдиляет строчку кода где идет подписка на делегат и пишет след. ошибку:

Array size control parameter must be an integral type.

Хотя вроде все по примеру сделал, и входные параметры одинаковые, я проверял.   smile 

Автор: Rpahut 14.9.2008, 19:21
Эт вопрос по тао и c#, а я в них ни в зуб ногой.
А вобще - нашел в сети:
Код

public delegate void Glu.TessCombineCallback(
   double[] coordinates,
   IntPtr[] vertexData,
   float[] weight,
   IntPtr[] outData
);

так что второй параметр возможно неправильный.

Автор: inkognitum 14.9.2008, 19:51
Цитата(Rpahut @ 14.9.2008,  19:21)
Эт вопрос по тао и c#, а я в них ни в зуб ногой.
А вобще - нашел в сети:
Код

public delegate void Glu.TessCombineCallback(
   double[] coordinates,
   IntPtr[] vertexData,
   float[] weight,
   IntPtr[] outData
);

так что второй параметр возможно неправильный.

Угу и такое есть. 
Там перезагруженая функция.

Бум разбиратся.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)