Уроки, алгоритмы, программы, примеры

Вход на сайт

Материалы по разделам

Построения
на плоскости (2D)
Графика
в пространстве (3D)
Вычислительная
геометрия
Физическое
моделирование
Фрактальная
графика

Новые комментарии

torrvic, возможно, Вам нужно добавить -lGLU
Извините за тупой вопрос. У меня при сборке Вашего примера выходит ошибка: "undefined reference to gluLookAt". Не могу найти в какой библиотеке находится эта функция. У меня задано: -lGL -lglut ... Искал в /usr/lib таким образом: nm lib*so* | grep...
Здравствуйте. Спасибо за проект. У меня вопрос, по какой причине определение принадлежности точки многоугольнику работает некорректно, если координаты из больших чисел состоят, например: int[] vertex = new int[] {...
Сейчас проверила нашла причину не запускания // Создание контекста воспроизведения OpenGL и привязка его к панели на форме OpenGLControl1:=TOpenGLControl.Create(Self); with OpenGLControl1 do begin Name:='OpenGLControl1'; //вот тут...
Ну..кажется что то пошло не так http://pp.usera...

Счетчики и рейтинг

Рейтинг@Mail.ru
Среда программирования: 
Visual C

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

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

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

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

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

Когда нам нужно CPU или GPU для других вещей, то вы, вероятно, хотите сохранить эти ресурсы, сохраняя при этом поведение нашего приложения GLUT неизменным.

Для достижения этой цели мы должны избирательно позволить GLUT использовать функции дисплея. Вот для этого функция glutPostRedisplay и нужна нам.

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

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

В функции main мы имели:

int main(int argc, char **argv) {
 
	// инициализация GLUT и создание окна
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100,100);
	glutInitWindowSize(800,800);
	mainWindow = glutCreateWindow("Lighthouse3D - GLUT Tutorial");
 
	// регистрация обратных вызовов для главного окна
	glutDisplayFunc(renderScene);
	glutReshapeFunc(changeSize);
        glutIdleFunc(renderSceneAll);
        ...

Мы собираемся изменить отображение функции для основного окна renderSceneAll. Мы удалении регистрации обратных вызовов для простой функции.

int main(int argc, char **argv) {
 
	//  инициализация GLUT и создание окна
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100,100);
	glutInitWindowSize(800,800);
	mainWindow = glutCreateWindow("Lighthouse3D - GLUT Tutorial");
 
	// регистрация обратных вызовов для главного окна
	glutDisplayFunc(renderSceneAll);
	glutReshapeFunc(changeSize);
 
	// Удаление пустой функции для высвобождения ресурсов CPU и GPU
	//glutIdleFunc(renderSceneAll);
        ...

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

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

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

void mouseMove(int x, int y) {
	// когда левая кнопка нажата
	if (xOrigin >= 0) {
		// обновить deltaAngle
		deltaAngle = (x - xOrigin) * 0.001f;
		// обновить положение камеры
		lx = sin(angle + deltaAngle);
		lz = -cos(angle + deltaAngle);
	}
}

меняем на:

void mouseMove(int x, int y) {
 
	// когда левая кнопка нажата
	if (xOrigin >= 0) {
		// обновить deltaAngle
		deltaAngle = (x - xOrigin) * 0.001f;
		//  обновить положение камеры
		lx = sin(angle + deltaAngle);
		lz = -cos(angle + deltaAngle);
                //установка основного окна в качестве активного
                //и помечает его для перерисовки
		glutSetWindow(mainWindow);
		glutPostRedisplay();
	}
}

Теперь для клавиатуры. Функция, которая обрабатывает события нажатия клавиш - pressKey. Таким образом, мы собираемся изменить pressKey:

void pressKey(int key, int xx, int yy) {
	switch (key) {
		case GLUT_KEY_UP : deltaMove = 0.5f; break;
		case GLUT_KEY_DOWN : deltaMove = -0.5f; break;
	}
}

меняем на:

void pressKey(int key, int xx, int yy) {
	switch (key) {
		case GLUT_KEY_UP : deltaMove = 0.5f; break;
		case GLUT_KEY_DOWN : deltaMove = -0.5f; break;
	}
        //установка основного окна в качестве активного
        //и помечает его для перерисовки
	glutSetWindow(mainWindow);
	glutPostRedisplay();
 
}

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

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

Вот renderSceneAll функции из предыдущего примера:

// Глобальная функция рендеринга
void renderSceneAll() {
 
	// проверки наличия клавиатурных движений
	if (deltaMove) {
		computePos(deltaMove);
	}
 
	renderScene();
	renderScenesw1();
	renderScenesw2();
	renderScenesw3();
}

Переменная deltaMode будет иметь ненулевое значение, когда клавиша нажата изначально. Поэтому мы можем назвать glutPostRedisplay внутри, если заявление, как показано ниже.

// Глобальная функция рендеринга
void renderSceneAll() {
 
	// проверки наличия клавиатурных движений
	if (deltaMove) {
		computePos(deltaMove);
 
                //установка основного окна в качестве активного
                //и помечает его для перерисовки
		glutSetWindow(mainWindow);
		glutPostRedisplay();
	}
 
	renderScene();
	renderScenesw1();
	renderScenesw2();
	renderScenesw3();
}

Наша функцию рендерит сцену, пока deltaMove не равен нулю. Это происходит только когда пользователь отпускает клавишу, как описано в функции releaseKey:

void releaseKey(int key, int x, int y) {
	switch (key) {
		case GLUT_KEY_UP :
		case GLUT_KEY_DOWN : deltaMove = 0;break;
	}
}

Продолжение в следующем уроке