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

Вход на сайт

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

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

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

Спасибо за реализацию, она действительно быстрая. Но не все линии отрисовывает в нужную сторону... Необходимо добавить проверку для случая X-линии if(y1 "<" y0) grad=-grad; и аналогично для Y-линии if(x1 "<" x0) grad=-grad; P.S. На...
Отличные уроки(учу GL по ним), только в renderScene нужно добавить очистку буфера цвета и буфера глубины. При изменении размеров треугольники размножаются)
как исправить это , сделал все по инструкции
Timer1 - выдает ошибку. Использовал IdleTimer1, работает! unit Unit1; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, OpenGLContext, GL, GLU; type { TForm1 } TForm1 =...
в коде присутствуют ошибки! // Считываем координаты procedure TForm1.getCoords(Sender: TObject); var j1:longint; begin n:= StrToInt(Edit2.Text); //число точек s1:=Edit1.Text; s2:=''; i := 1; j:=1; k:=0...

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

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

Прежде чем мы начнем давайте вспомним нашу систему обратных вызовов, как она определена, каким образом главное окно и подчиненные окна были созданы:

- idle function – renderSceneAll;
- display func for main window – renderScene;
- display func for subwindow 1 – renderScenesw1;
- display func for subwindow 2 – renderScenesw2;
- display func for subwindow 3 – renderScenesw3;

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

void renderScene() {
	glutSetWindow(mainWindow);
	glClear(GL_COLOR_BUFFER_BIT);
	glutSwapBuffers();
}

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

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

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

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

Следует отметить, что существует несколько различий в содержании окон. Верхнее окно будет отображать счётчик кадров с помощью растровых строк. Два окна снизу отображают красный конус в положении основной камеры.

// функция рендеринга для всех подокон
void renderScene2() {
 
// нарисуем землю
	glColor3f(0.9f, 0.9f, 0.9f);
	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 снеговика
	char number[4];
	for(int i = -4; i < 4; i++)
		for(int j=-4; j < 4; j++) {
 
			glPushMatrix();
			glTranslatef(i*10.0f, 0.0f, j * 10.0f);
			drawSnowMan();
			glPopMatrix();
		}
}
// Функция рендеринга для главного окна
void renderScene() {
	glutSetWindow(mainWindow);
	glClear(GL_COLOR_BUFFER_BIT);
	glutSwapBuffers();
}
// Функция рендеринга для подокна 1
void renderScenesw1() {
	glutSetWindow(subWindow1);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	gluLookAt(x, y, z,
		  x + lx,y + ly,z + lz,
		  0.0f,1.0f,0.0f);
	renderScene2();
	// показать кадры в секунду
 	frame++;
	time=glutGet(GLUT_ELAPSED_TIME);
	if (time - timebase > 1000) {
		sprintf(s,"Lighthouse3D - FPS:%4.2f",
			frame*1000.0/(time-timebase));
		timebase = time;
		frame = 0;
	}
 
	setOrthographicProjection();
 
	glPushMatrix();
	glLoadIdentity();
	renderBitmapString(5,30,0,GLUT_BITMAP_HELVETICA_12,s);
	glPopMatrix();
 
	restorePerspectiveProjection();
 
	glutSwapBuffers();
}
 
// Функция рендеринга для подокна 2
void renderScenesw2() {
	glutSetWindow(subWindow2);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	gluLookAt(x, y+15, z,
		  x ,y - 1,z,
		  lx,0,lz);
	// нарисовать красный конус
	glPushMatrix();
	glColor3f(1.0,0.0,0.0);
	glTranslatef(x,y,z);
	glRotatef(180-(angle+deltaAngle)*180.0/3.14,0.0,1.0,0.0);
	glutSolidCone(0.2,0.8f,4,4);
	glPopMatrix();
	renderScene2();
	glutSwapBuffers();
}
 
// Функция рендеринга для подокна 3
void renderScenesw3() {
	glutSetWindow(subWindow3);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	gluLookAt(x-lz*10 , y, z+lx*10,
		  x ,y ,z ,
		  0.0f,1.0f,0.0f);
	// нарисовать красный конус
	glPushMatrix();
	glColor3f(1.0,0.0,0.0);
	glTranslatef(x,y,z);
	glRotatef(180-(angle+deltaAngle)*180.0/3.14,0.0,1.0,0.0);
	glutSolidCone(0.2,0.8f,4,4);
	glPopMatrix();
 
	renderScene2();
 
	glutSwapBuffers();
}

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

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

// Глобальная функция отрисовки
void renderSceneAll() {
	// проверить перемещения с клавиатуры
	if (deltaMove)
		computePos(deltaMove);
	renderScenesw1();
	renderScenesw2();
	renderScenesw3();
}

Итоговый код

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <glut.h>
 
// угол поворота камеры
float angle = 0.0f;
// координаты вектора направления движения камеры
float lx=0.0f,lz=-1.0f, ly = 0.0f;
// XZ позиция камеры
float x=0.0f, z=5.5f, y = 1.65f;
//Ключи статуса камеры. Переменные инициализируются нулевыми значениями
//когда клавиши не нажаты
float deltaAngle = 0.0f;
float deltaMove = 0;
int xOrigin = -1;
//ширина и высота окна
int h,w;
//переменные для вычисления кадров в секунду
int frame;
long time, timebase;
char s[50];
// переменные для хранения идентификаторв окна
int mainWindow, subWindow1,subWindow2,subWindow3;
//Граница между подокнами
int border = 6;
 
void setProjection(int w1, int h1)
{
	float ratio;
	// предотвращение деления на ноль
	ratio = 1.0f * w1 / h1;
	// обнулить координаты матрицы проекции
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
 
	// установить вьюпорт
        glViewport(0, 0, w1, h1);
 
	// Установить объем отсечения
	gluPerspective(45,ratio,0.1,1000);
	glMatrixMode(GL_MODELVIEW);
}
 
void changeSize(int w1,int h1) {
 
	if(h1 == 0)
		h1 = 1;
 
	//сохраним эти значения
	w = w1;
	h = h1;
 
	// установить активным подокно 1
	glutSetWindow(subWindow1);
	// изменить размеры и позиция подокна
	glutPositionWindow(border,border);
	glutReshapeWindow(w-2*border, h/2 - border*3/2);
	setProjection(w-2*border, h/2 - border*3/2);
 
	// установить активным подокно 2
	glutSetWindow(subWindow2);
	// изменить размеры и позиция подокна
	glutPositionWindow(border,(h+border)/2);
	glutReshapeWindow(w/2-border*3/2, h/2 - border*3/2);
	setProjection(w/2-border*3/2,h/2 - border*3/2);
 
	// установить активным подокно 3
	glutSetWindow(subWindow3);
	// изменить размеры и позиция подокна
	glutPositionWindow((w+border)/2,(h+border)/2);
	glutReshapeWindow(w/2-border*3/2,h/2 - border*3/2);
	setProjection(w/2-border*3/2,h/2 - border*3/2);
}
 
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);
	glColor3f(1.0f, 1.0f, 1.0f);
}
 
void renderBitmapString(
		float x,
		float y,
		float z,
		void *font,
		char *string) {
 
	char *c;
	glRasterPos3f(x, y,z);
	for (c=string; *c != '\0'; c++) {
		glutBitmapCharacter(font, *c);
	}
}
 
void restorePerspectiveProjection() {
 
	glMatrixMode(GL_PROJECTION);
	//восстановить предыдущую матрицу проекции
	glPopMatrix();
	//вернуться в режим модели
	glMatrixMode(GL_MODELVIEW);
}
 
void setOrthographicProjection() {
	//выбрать режим проекции
	glMatrixMode(GL_PROJECTION);
	//Сохраняем предыдущую матрицу, которая содерж
	//параметры перспективной проекции
	glPushMatrix();
	//обнуляем матрицу
	glLoadIdentity();
	//устанавливаем 2D ортогональную проекцию
	gluOrtho2D(0, w, h, 0);
	//выбираем режим обзора модели
	glMatrixMode(GL_MODELVIEW);
}
 
void computePos(float deltaMove) {
 
	x += deltaMove * lx * 0.1f;
	z += deltaMove * lz * 0.1f;
}
 
// Общие элементы визуализации для всех подчиненных окон
void renderScene2() {
 
// нарисуем "землю"
 
	glColor3f(0.9f, 0.9f, 0.9f);
	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*10.0f, 0.0f, j * 10.0f);
			drawSnowMan();
			glPopMatrix();
		}
}
 
//функция рендеринга основного окна
void renderScene() {
	glutSetWindow(mainWindow);
	glClear(GL_COLOR_BUFFER_BIT);
	glutSwapBuffers();
}
 
// функция рендеринга для подокна 1
void renderScenesw1() {
 
	glutSetWindow(subWindow1);
 
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
	glLoadIdentity();
	gluLookAt(x, y, z,
		      x + lx,y + ly,z + lz,
			  0.0f,1.0f,0.0f);
 
	renderScene2();
 
	// показать кадры в секунду
 	frame++;
 
	time=glutGet(GLUT_ELAPSED_TIME);
	if (time - timebase > 1000) {
		sprintf(s,"Informatika - FPS:%4.2f",
			frame*1000.0/(time-timebase));
		timebase = time;
		frame = 0;
	}
 
	setOrthographicProjection();
 
	glPushMatrix();
	glLoadIdentity();
	renderBitmapString(5,30,0,GLUT_BITMAP_HELVETICA_12,s);
	glPopMatrix();
 
	restorePerspectiveProjection();
 
	glutSwapBuffers();
}
 
// функция рендеринга для подокна 2
void renderScenesw2() {
 
	glutSetWindow(subWindow2);
 
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
	glLoadIdentity();
	gluLookAt(x, y+15, z,
		      x ,y - 1,z,
			  lx,0,lz);
 
	// нарисовать красный конус в области основной камеры
	glPushMatrix();
	glColor3f(1.0,0.0,0.0);
	glTranslatef(x,y,z);
	glRotatef(180-(angle+deltaAngle)*180.0/3.14,0.0,1.0,0.0);
	glutSolidCone(0.2,0.8f,4,4);
	glPopMatrix();
 
	renderScene2();
 
	glutSwapBuffers();
}
 
// функция рендеринга для подокна 3
void renderScenesw3() {
 
	glutSetWindow(subWindow3);
 
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
	glLoadIdentity();
	gluLookAt(x-lz*10 , y, z+lx*10,
		      x ,y ,z ,
			  0.0f,1.0f,0.0f);
 
	//  нарисовать красный конус в области основной камеры
	glPushMatrix();
	glColor3f(1.0,0.0,0.0);
	glTranslatef(x,y,z);
	glRotatef(180-(angle+deltaAngle)*180.0/3.14,0.0,1.0,0.0);
	glutSolidCone(0.2,0.8f,4,4);
	glPopMatrix();
 
	renderScene2();
 
	glutSwapBuffers();
}
 
// Глобальная функция рендеринга
void renderSceneAll() {
 
	// проверить перемещения камеры от клавиатуры
	if (deltaMove)
		computePos(deltaMove);
 
	renderScenesw1();
	renderScenesw2();
	renderScenesw3();
}
 
// -----------------------------------	//
//            клавиатура				//
// -----------------------------------	//
 
void processNormalKeys(unsigned char key, int xx, int yy) {
 
	if (key == 27) {
		glutDestroyWindow(subWindow1);
		glutDestroyWindow(subWindow2);
		glutDestroyWindow(subWindow3);
		glutDestroyWindow(mainWindow);
		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) 
{
	// только когда левая кнопка не активна
	if (xOrigin >= 0) 
	{
		// обновить deltaAngle
		deltaAngle = (x - xOrigin) * 0.001f;
		// обновить направление камеры
		lx = sin(angle + deltaAngle);
		lz = -cos(angle + deltaAngle);
	}
}
 
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;
		}
	}
}
 
 
// ------------------------------------	//
//             main()					//
// -----------------------------------	//
 
void init() {
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
	// регистрация вызовов
	glutIgnoreKeyRepeat(1);
	glutKeyboardFunc(processNormalKeys);
	glutSpecialFunc(pressKey);
	glutSpecialUpFunc(releaseKey);
	glutMouseFunc(mouseButton);
	glutMotionFunc(mouseMove);
}
 
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("Урок - 16");
	// регистрация вызовов для главного окна
	glutDisplayFunc(renderScene);
	glutReshapeFunc(changeSize);
	glutIdleFunc(renderSceneAll);
	init();
	// для подокон
	subWindow1 = glutCreateSubWindow(mainWindow, border,border,w-2*border, h/2 - border*3/2);
	glutDisplayFunc(renderScenesw1);
	init();
	subWindow2 = glutCreateSubWindow(mainWindow, border,(h+border)/2,w/2-border*3/2, h/2 - border*3/2);
	glutDisplayFunc(renderScenesw2);
	init();
	subWindow3 = glutCreateSubWindow(mainWindow, (w+border)/2,(h+border)/2,w/2-border*3/2,h/2 - border*3/2);
	glutDisplayFunc(renderScenesw3);
	init();
	// главный цикл
	glutMainLoop();
	return 1;
}