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

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

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

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

У меня проблема вот с этим: gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);. Вылезает ошибка: CS1061 "object" не содержит определения "GL_COLOR_BUFFER_BIT", и не удалось найти доступный метод расширения "GL_COLOR_BUFFER_BIT",...
Большое спасибо. Единственный код который прошел без каких либо ошибок. Ура!!!
Скажите пожалуйста, подскажите алгоритм по которому по заданным точкам можно определить тип многогранника, скажем это куб или прямоугольный параллелепипед. Нашел теорию по этим фигурам: https://www.mat... https://www.mat... Акцентировать внимание...
Всем у кого не работает. файл wizard.script Ещё одно упоминание Glut32 в строке "if (!VerifyLibFile(dir_nomacro_lib, _T("glut32"), _T("GLUT's"))) return false;" меняем на "if (!VerifyLibFile(dir_nomacro_lib, _T("freeglut"), _T("GLUT's"))) return...
Не получается, емаё

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

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

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

Обнаружение щелчков мыши

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

void glutMouseFunc(void (*func)(int button, int state, int x, int y));

Параметры:

*func - имя функции, которая будет обрабатывать события мыши.

Как мы видим, с момента подписания glutMouseFunc, функция, которая будет обрабатывать события мыши, должна иметь 4 параметра. Первый из них касается того, какая кнопка была нажата или отпущена. Этот аргумент может иметь одно из трех значений:
- GLUT_LEFT_BUTTON;
- GLUT_MIDDLE_BUTTON;
- GLUT_RIGHT_BUTTON;
Второй аргумент относится к состоянию кнопки, то есть идентификации момента нажатия и отпускания кнопки. Возможные значения:
- GLUT_DOWN;
- GLUT_UP;
Если ответный вызов генерируется со статусом GLUT_DOWN, приложение может предположить, что GLUT_UP будет после этого события, даже если мышь перемещается за пределы окна. Остальные два параметра обеспечивают (х, у) координаты мыши относительно левого верхнего угла рабочей области окна.

Определение перемещения мыши

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

void glutMotionFunc(void (*func) (int x,int y));
void glutPassiveMotionFunc(void (*func) (int x, int y));

Параметры:

*func - функция, которая будет отвечать за соответствующий тип движения.

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

Обнаружение попадания или выхода из рабочей области окна курсора мыши

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

void glutEntryFunc(void (*func)(int state));

Параметры:

*func - функция, которая будет обрабатывать эти события.

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

- GLUT_LEFT;
- GLUT_ENTERED;

Управление камерой с использованием мыши

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

float deltaAngle = 0.0f;
int xOrigin = -1;

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

Следующая функция отвечает за обработку изменения состояния кнопки:

void mouseButton(int button, int state, int x, int y) {
 
	// только при начале движения, если нажата левая кнопка
	if (button == GLUT_LEFT_BUTTON) {
 
		// когда кнопка отпущена
		if (state == GLUT_UP) {
			angle += deltaAngle;
			xOrigin = -1;
		}
		else  {// state = GLUT_DOWN
			xOrigin = x;
		}
	}
}

Обратите внимание, что переменная xOrigin имеет значение -1, если кнопка зажата.

Функцию для обработки движения мыши​:

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

В функции main() мы должны зарегистрировать две новые функции обратного вызова:

int main(int argc, char **argv) {
 
	// инициализация GLUT и создание окна
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100,100);
	glutInitWindowSize(400,400);
	glutCreateWindow("Урок - 7");
 
	// регистрация
	glutDisplayFunc(renderScene);
	glutReshapeFunc(changeSize);
	glutIdleFunc(renderScene);
 
	glutIgnoreKeyRepeat(1);
	glutKeyboardFunc(processNormalKeys);
	glutSpecialFunc(pressKey);
	glutSpecialUpFunc(releaseKey);
 
	// регистрируем две новые функции
	glutMouseFunc(mouseButton);
	glutMotionFunc(mouseMove);
 
	// OpenGL - инициализация функции теста
	glEnable(GL_DEPTH_TEST);
 
	// главный цикл
	glutMainLoop();
 
	return 1;
}

Итоговый код приложения:

#include <stdlib.h>
#include <math.h>
#include <glut.h>
 
// угол поворота камеры
float angle=0.0;
// координаты вектора направления движения камеры
float lx=0.0f, lz=-1.0f;
// XZ позиция камеры
float x=0.0f, z=5.0f;
//Ключи статуса камеры. Переменные инициализируются нулевыми значениями
//когда клавиши не нажаты
float deltaAngle = 0.0f;
float deltaMove = 0;
int xOrigin = -1;
 
void changeSize(int w, int h) {
	// предотвращение деления на ноль
	if (h == 0)
		h = 1;
	float ratio =  w * 1.0 / h;
	// используем матрицу проекции
	glMatrixMode(GL_PROJECTION);
	// обнуляем матрицу
	glLoadIdentity();
	// установить параметры вьюпорта
	glViewport(0, 0, w, h);
	// установить корректную перспективу
	gluPerspective(45.0f, ratio, 0.1f, 100.0f);
	// вернуться к матрице проекции
	glMatrixMode(GL_MODELVIEW);
}
 
void drawSnowMan() {
 	glColor3f(1.0f, 1.0f, 1.0f);
 	// тело снеговика
	glTranslatef(0.0f ,0.75f, 0.0f);
	glutSolidSphere(0.75f,20,20);
 	// голова снеговика
	glTranslatef(0.0f, 1.0f, 0.0f);
	glutSolidSphere(0.25f,20,20);
	// глаза снеговика
	glPushMatrix();
	glColor3f(0.0f,0.0f,0.0f);
	glTranslatef(0.05f, 0.10f, 0.18f);
	glutSolidSphere(0.05f,10,10);
	glTranslatef(-0.1f, 0.0f, 0.0f);
	glutSolidSphere(0.05f,10,10);
	glPopMatrix();
	// нос снеговика
	glColor3f(1.0f, 0.5f , 0.5f);
	glRotatef(0.0f,1.0f, 0.0f, 0.0f);
	glutSolidCone(0.08f,0.5f,10,2);
}
 
void computePos(float deltaMove) 
{
	x += deltaMove * lx * 0.1f;
	z += deltaMove * lz * 0.1f;
}
 
void renderScene(void) {
	if (deltaMove)
		computePos(deltaMove);
	//очистить буфер цвета и глубины
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// обнулить трансформацию
	glLoadIdentity();
	// установить камеру
	gluLookAt(	   x,	1.0f,	  z,
				x+lx,	1.0f,  z+lz,
				0.0f,   1.0f,  0.0f		);
	// нарисуем "землю"
	glColor3f(0.9f, 0.9f, 0.9f);
	// полигон (plaine)
	glBegin(GL_QUADS);
		glVertex3f(-100.0f, 0.0f, -100.0f);
		glVertex3f(-100.0f, 0.0f,  100.0f);
		glVertex3f( 100.0f, 0.0f,  100.0f);
		glVertex3f( 100.0f, 0.0f, -100.0f);
	glEnd();
	// Нарисуем 64 снеговика
	for (int i = -4; i < 4; i++)
		for (int j=-4; j < 4; j++)
		{
			glPushMatrix();
			glTranslatef(i*5.0, 0, j * 5.0);
			drawSnowMan();
			glPopMatrix();
		}
 
	glutSwapBuffers();
}
 
void processNormalKeys(unsigned char key, int xx, int yy) { 	
 
        if (key == 27)
              exit(0);
} 
 
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 releaseKey(int key, int x, int y) { 	
 
        switch (key) {
             case GLUT_KEY_UP :
             case GLUT_KEY_DOWN : deltaMove = 0;break;
        }
} 
 
void mouseMove(int x, int y) { 	
 
         // this will only be true when the left button is down
         if (xOrigin >= 0) {
 
		// update deltaAngle
		deltaAngle = (x - xOrigin) * 0.001f;
 
		// update camera's direction
		lx = sin(angle + deltaAngle);
		lz = -cos(angle + deltaAngle);
	}
}
 
void mouseButton(int button, int state, int x, int y) {
 
	// only start motion if the left button is pressed
	if (button == GLUT_LEFT_BUTTON) {
 
		// when the button is released
		if (state == GLUT_UP) {
			angle += deltaAngle;
			xOrigin = -1;
		}
		else  {// state = GLUT_DOWN
			xOrigin = x;
		}
	}
}
 
int main(int argc, char **argv) {
 
	// инициализация GLUT и создание окна
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100,100);
	glutInitWindowSize(400,400);
	glutCreateWindow("Урок - 7");
 
	// регистрация
	glutDisplayFunc(renderScene);
	glutReshapeFunc(changeSize);
	glutIdleFunc(renderScene);
 
	glutIgnoreKeyRepeat(1);
	glutKeyboardFunc(processNormalKeys);
	glutSpecialFunc(pressKey);
	glutSpecialUpFunc(releaseKey);
 
	// регистрируем две новые функции
	glutMouseFunc(mouseButton);
	glutMotionFunc(mouseMove);
 
	// OpenGL - инициализация функции теста
	glEnable(GL_DEPTH_TEST);
 
	// главный цикл
	glutMainLoop();
 
	return 1;
}

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

Прикрепленный файлРазмер
testapp.rar4.52 кб

Комментарии

torrvic аватар
Опубликовано torrvic в 26. Июнь 2017 - 8:38.

Извините за тупой вопрос. У меня при сборке Вашего примера выходит ошибка: "undefined reference to gluLookAt". Не могу найти в какой библиотеке находится эта функция. У меня задано: -lGL -lglut ... Искал в /usr/lib таким образом: nm lib*so* | grep LookAt -ничего не находит... И также не находит gluPerspective... Спасибо.

Мурат аватар
Опубликовано Мурат в 30. Июнь 2017 - 13:24.

torrvic, возможно, Вам нужно добавить -lGLU