Skip to content

Instantly share code, notes, and snippets.

@habibg1232191
Created May 1, 2024 23:09
Show Gist options
  • Save habibg1232191/b745200a12ead18234c3405782fd03eb to your computer and use it in GitHub Desktop.
Save habibg1232191/b745200a12ead18234c3405782fd03eb to your computer and use it in GitHub Desktop.
#include "Render.h"
#include <sstream>
#include <iostream>
#include <windows.h>
#include <GL\GL.h>
#include <GL\GLU.h>
#include "MyOGL.h"
#include "Camera.h"
#include "Light.h"
#include "Primitives.h"
#include "GUItextRectangle.h"
bool textureMode = true;
bool lightMode = true;
bool textureReplace = true; // (Н) Эта переменная отвечает за смену текстур
//класс для настройки камеры
class CustomCamera : public Camera
{
public:
//дистанция камеры
double camDist;
//углы поворота камеры
double fi1, fi2;
//значния масеры по умолчанию
CustomCamera()
{
camDist = 15;
fi1 = 1;
fi2 = 1;
}
//считает позицию камеры, исходя из углов поворота, вызывается движком
void SetUpCamera()
{
//отвечает за поворот камеры мышкой
lookPoint.setCoords(0, 0, 0);
pos.setCoords(camDist*cos(fi2)*cos(fi1),
camDist*cos(fi2)*sin(fi1),
camDist*sin(fi2));
if (cos(fi2) <= 0)
normal.setCoords(0, 0, -1);
else
normal.setCoords(0, 0, 1);
LookAt();
}
void CustomCamera::LookAt()
{
//функция настройки камеры
gluLookAt(pos.X(), pos.Y(), pos.Z(), lookPoint.X(), lookPoint.Y(), lookPoint.Z(), normal.X(), normal.Y(), normal.Z());
}
} camera; //создаем объект камеры
//Класс для настройки света
class CustomLight : public Light
{
public:
CustomLight()
{
//начальная позиция света
pos = Vector3(1, 1, 3);
}
//рисует сферу и линии под источником света, вызывается движком
void DrawLightGhismo()
{
glDisable(GL_LIGHTING);
glColor3d(0.9, 0.8, 0);
Sphere s;
s.pos = pos;
s.scale = s.scale*0.08;
s.Show();
if (OpenGL::isKeyPressed('G'))
{
glColor3d(0, 0, 0);
//линия от источника света до окружности
glBegin(GL_LINES);
glVertex3d(pos.X(), pos.Y(), pos.Z());
glVertex3d(pos.X(), pos.Y(), 0);
glEnd();
//рисуем окруность
Circle c;
c.pos.setCoords(pos.X(), pos.Y(), 0);
c.scale = c.scale*1.5;
c.Show();
}
}
void SetUpLight()
{
GLfloat amb[] = { 0.2, 0.2, 0.2, 0 };
GLfloat dif[] = { 1.0, 1.0, 1.0, 0 };
GLfloat spec[] = { .7, .7, .7, 0 };
GLfloat position[] = { pos.X(), pos.Y(), pos.Z(), 1. };
// параметры источника света
glLightfv(GL_LIGHT0, GL_POSITION, position);
// характеристики излучаемого света
// фоновое освещение (рассеянный свет)
glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
// диффузная составляющая света
glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
// зеркально отражаемая составляющая света
glLightfv(GL_LIGHT0, GL_SPECULAR, spec);
glEnable(GL_LIGHT0);
}
} light; //создаем источник света
//старые координаты мыши
int mouseX = 0, mouseY = 0;
void mouseEvent(OpenGL *ogl, int mX, int mY)
{
int dx = mouseX - mX;
int dy = mouseY - mY;
mouseX = mX;
mouseY = mY;
//меняем углы камеры при нажатой левой кнопке мыши
if (OpenGL::isKeyPressed(VK_RBUTTON))
{
camera.fi1 += 0.01*dx;
camera.fi2 += -0.01*dy;
}
//двигаем свет по плоскости, в точку где мышь
if (OpenGL::isKeyPressed('G') && !OpenGL::isKeyPressed(VK_LBUTTON))
{
LPPOINT POINT = new tagPOINT();
GetCursorPos(POINT);
ScreenToClient(ogl->getHwnd(), POINT);
POINT->y = ogl->getHeight() - POINT->y;
Ray r = camera.getLookRay(POINT->x, POINT->y);
double z = light.pos.Z();
double k = 0, x = 0, y = 0;
if (r.direction.Z() == 0)
k = 0;
else
k = (z - r.origin.Z()) / r.direction.Z();
x = k*r.direction.X() + r.origin.X();
y = k*r.direction.Y() + r.origin.Y();
light.pos = Vector3(x, y, z);
}
if (OpenGL::isKeyPressed('G') && OpenGL::isKeyPressed(VK_LBUTTON))
{
light.pos = light.pos + Vector3(0, 0, 0.02*dy);
}
}
void mouseWheelEvent(OpenGL *ogl, int delta)
{
if (delta < 0 && camera.camDist <= 1)
return;
if (delta > 0 && camera.camDist >= 100)
return;
camera.camDist += 0.01*delta;
}
void keyDownEvent(OpenGL *ogl, int key)
{
if (key == 'L')
{
lightMode = !lightMode;
}
if (key == 'T')
{
textureMode = !textureMode;
}
if (key == 'R')
{
camera.fi1 = 1;
camera.fi2 = 1;
camera.camDist = 15;
light.pos = Vector3(1, 1, 3);
}
if (key == 'F')
{
light.pos = camera.pos;
}
if (key == 'E') // (Н) Смена текстуры происходит по этой кнопке
{
textureReplace = !textureReplace;
}
}
void keyUpEvent(OpenGL *ogl, int key)
{
}
GLuint texId;
GLuint texId2; // (Н) Я хз как по другому делать, поэтому я просто скопировал часть кода, ко всем переменным в конце добавил "2", и всё работает
//выполняется перед первым рендером
void initRender(OpenGL *ogl)
{
//настройка текстур
//4 байта на хранение пикселя
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
//настройка режима наложения текстур
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
//включаем текстуры
glEnable(GL_TEXTURE_2D);
//массив трехбайтных элементов (R G B) (Н) Код брался и копировался отсюда
RGBTRIPLE *texarray;
//массив символов, (высота*ширина*4 4, потомучто выше, мы указали использовать по 4 байта на пиксель текстуры - R G B A)
char *texCharArray;
int texW, texH;
OpenGL::LoadBMP("texture.bmp", &texW, &texH, &texarray); // (Н) Чтоб не мучаться с картинками, я коприовал старую и рисовал на ней
OpenGL::RGBtoChar(texarray, texW, texH, &texCharArray);
//генерируем ИД для текстуры
glGenTextures(1, &texId);
//биндим айдишник, все что будет происходить с текстурой, будте происходить по этому ИД
glBindTexture(GL_TEXTURE_2D, texId);
//загружаем текстуру в видеопямять, в оперативке нам больше она не нужна
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texW, texH, 0, GL_RGBA, GL_UNSIGNED_BYTE, texCharArray);
//отчистка памяти
free(texCharArray);
free(texarray);
//наводим шмон
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // (Н) И досюда
//массив трехбайтных элементов (R G B)
RGBTRIPLE* texarray2;
//массив символов, (высота*ширина*4 4, потомучто выше, мы указали использовать по 4 байта на пиксель текстуры - R G B A)
char* texCharArray2;
int texW2, texH2;
OpenGL::LoadBMP("texture1.bmp", &texW2, &texH2, &texarray2);
OpenGL::RGBtoChar(texarray2, texW2, texH2, &texCharArray2);
//генерируем ИД для текстуры
glGenTextures(1, &texId2);
//биндим айдишник, все что будет происходить с текстурой, будте происходить по этому ИД
glBindTexture(GL_TEXTURE_2D, texId2);
//загружаем текстуру в видеопямять, в оперативке нам больше она не нужна
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texW2, texH2, 0, GL_RGBA, GL_UNSIGNED_BYTE, texCharArray2);
//отчистка памяти
free(texCharArray2);
free(texarray2);
//наводим шмон
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//камеру и свет привязываем к "движку"
ogl->mainCamera = &camera;
ogl->mainLight = &light;
// нормализация нормалей : их длины будет равна 1
glEnable(GL_NORMALIZE);
// устранение ступенчатости для линий
glEnable(GL_LINE_SMOOTH);
// задать параметры освещения
// параметр GL_LIGHT_MODEL_TWO_SIDE -
// 0 - лицевые и изнаночные рисуются одинаково(по умолчанию),
// 1 - лицевые и изнаночные обрабатываются разными режимами
// соответственно лицевым и изнаночным свойствам материалов.
// параметр GL_LIGHT_MODEL_AMBIENT - задать фоновое освещение,
// не зависящее от сточников
// по умолчанию (0.2, 0.2, 0.2, 1.0)
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
camera.fi1 = -1.3;
camera.fi2 = 0.8;
}
void crossProduct(const double vec1[3], const double vec2[3], double result[3]) {
result[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
result[1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
result[2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
}
// Функция для нормализации вектора
void normalize(double vec[3]) {
double length = std::sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
if (length != 0.0f) {
vec[0] /= length;
vec[1] /= length;
vec[2] /= length;
}
}
// Функция для вычисления нормали по трем векторам
void computeNormal(const double vec1[3], const double vec2[3], const double vec3[3], double normal[3]) {
double vecA[3] = { vec2[0] - vec1[0], vec2[1] - vec1[1], vec2[2] - vec1[2] };
double vecB[3] = { vec3[0] - vec1[0], vec3[1] - vec1[1], vec3[2] - vec1[2] };
crossProduct(vecA, vecB, normal);
normalize(normal);
}
// Функция для вычисления нормали по четырем векторам
void computeQuadNormal(const double A[3], const double B[3], const double C[3], const double D[3], double normal[3]) {
double vec1[3] = { B[0] - A[0], B[1] - A[1], B[2] - A[2] };
double vec2[3] = { D[0] - A[0], D[1] - A[1], D[2] - A[2] };
crossProduct(vec1, vec2, normal);
normalize(normal);
}
void Render(OpenGL *ogl)
{
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
if (textureMode)
glEnable(GL_TEXTURE_2D);
if (lightMode)
glEnable(GL_LIGHTING);
if (textureReplace) // (Н) Здесь переключаются текстуры: textureReplace - создаётся на 20 строчке
glBindTexture(GL_TEXTURE_2D, texId); // (Н) Назначение кнопки на 225
else
glBindTexture(GL_TEXTURE_2D, texId2);
//альфаналожение
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA);
glDisable(GL_BLEND);
//настройка материала
GLfloat amb[] = { 0.2, 0.2, 0.1, 1. };
GLfloat dif[] = { 0.4, 0.65, 0.5, 1. };
GLfloat spec[] = { 0.9, 0.8, 0.3, 1. };
GLfloat sh = 0.1f * 256;
//фоновая
glMaterialfv(GL_FRONT, GL_AMBIENT, amb);
//дифузная
glMaterialfv(GL_FRONT, GL_DIFFUSE, dif);
//зеркальная
glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
//размер блика
glMaterialf(GL_FRONT, GL_SHININESS, sh);
//чтоб было красиво, без квадратиков (сглаживание освещения)
glShadeModel(GL_SMOOTH);
//===================================
//Прогать тут (Н) это обман, пришлось прогать не только тут
//Начало рисования квадратика станкина
double A[] = { 0.0, 0.0, 0.0 };
double B[] = { 7, -3, 0 };
double C[] = { 5, -7, 0 };
double D[] = { 8, -11, 0 };
double E[] = { 2, -13, 0 }; //polukrug dlya 40
double F[] = { 2, -8, 0 }; //polukrug dlya 40
double G[] = { -6, -7, 0 };
double H[] = { 0, -6, 0 };
double A1[] = { 0.0, 0.0, 5 };
double B1[] = { 7, -3, 5 };
double C1[] = { 5, -7, 5 };
double D1[] = { 8, -11, 5 };
double E1[] = { 2, -13, 5 }; //polukrug dlya 40
double F1[] = { 2, -8, 5 }; //polukrug dlya 40
double G1[] = { -6, -7, 5 };
double H1[] = { 0, -6, 5 };
glColor3d(0.7, 0.7, 0.7);
glBegin(GL_TRIANGLES);
double normal[3];
computeNormal(A, B, H, normal);
glNormal3d(normal[0], normal[1], -0.01); // (Н) Это нормаль
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(A);
glVertex3dv(B);
glVertex3dv(H);
glEnd();
glBegin(GL_TRIANGLES);
computeNormal(B, H, C, normal);
glNormal3d(normal[0], normal[1], -0.01);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(B);
glVertex3dv(H);
glVertex3dv(C);
glEnd();
glBegin(GL_TRIANGLES);
computeNormal(D, E, C, normal);
glNormal3d(normal[0], normal[1], -0.01);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(D);
glVertex3dv(E);
glVertex3dv(C);
glEnd();
glBegin(GL_TRIANGLES);
computeNormal(C, F, E, normal);
glNormal3d(normal[0], normal[1], -0.01);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(C);
glVertex3dv(F);
glVertex3dv(E);
glEnd();
glBegin(GL_TRIANGLES);
computeNormal(G, H, C, normal);
glNormal3d(normal[0], normal[1], -0.01);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(G);
glVertex3dv(H);
glVertex3dv(C);
glEnd();
glBegin(GL_TRIANGLES);
computeNormal(C, F, G, normal);
glNormal3d(normal[0], normal[1], -0.01);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(C);
glVertex3dv(F);
glVertex3dv(G);
glEnd();
glBegin(GL_TRIANGLES);
computeNormal(B1, H1, C1, normal);
glNormal3d(normal[0], normal[1], 5); // (Н) Это нормаль
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(B1);
glVertex3dv(H1);
glVertex3dv(C1);
glEnd();
glBegin(GL_TRIANGLES);
computeNormal(D1, E1, C1, normal);
glNormal3d(normal[0], normal[1], 5);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(D1);
glVertex3dv(E1);
glVertex3dv(C1);
glEnd();
glBegin(GL_TRIANGLES);
computeNormal(C1, F1, E1, normal);
glNormal3d(normal[0], normal[1], 5);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(C1);
glVertex3dv(F1);
glVertex3dv(E1);
glEnd();
glBegin(GL_TRIANGLES);
computeNormal(G1, H1, C1, normal);
glNormal3d(normal[0], normal[1], 5);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(G1);
glVertex3dv(H1);
glVertex3dv(C1);
glEnd();
glBegin(GL_TRIANGLES);
computeNormal(C1, F1, G1, normal);
glNormal3d(normal[0], normal[1], 5);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(C1);
glVertex3dv(F1);
glVertex3dv(G1);
glEnd();
glBegin(GL_TRIANGLES);
computeNormal(A1, B1, H1, normal);
glNormal3d(normal[0], normal[1], 5);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3dv(A1);
glVertex3dv(B1);
glVertex3dv(H1);
glEnd();
glBegin(GL_QUADS);
glColor3f(0.3f, 0.3f, 0.3f);
computeQuadNormal(A, A1, B1, B, normal);
glNormal3dv(normal);
glTexCoord2d(0, 0);
glVertex3dv(A);
glTexCoord2d(0, 1);
glVertex3dv(A1);
glTexCoord2d(1, 1);
glVertex3dv(B1);
glTexCoord2d(1, 0);
glVertex3dv(B);
glEnd();
glBegin(GL_QUADS);
glColor3f(0.3f, 0.3f, 0.3f);
computeQuadNormal(B, B1, C1, C, normal);
glNormal3dv(normal);
glTexCoord2d(0, 0); // (Н) Это накладывается текстура (x, y) это углы текстуры, пишутся поверх углов квадратов
glVertex3dv(B);
glTexCoord2d(0, 1);
glVertex3dv(B1);
glTexCoord2d(1, 1);
glVertex3dv(C1);
glTexCoord2d(1, 0);
glVertex3dv(C);
glEnd();
glBegin(GL_QUADS);
glColor3f(0.3f, 0.3f, 0.3f);
computeQuadNormal(C1, C, D, D1, normal);
glNormal3d(-normal[0], -normal[1], normal[2]); // 2
glTexCoord2d(0, 0);
glVertex3dv(C1);
glTexCoord2d(1, 0);
glVertex3dv(C);
glTexCoord2d(1, 1);
glVertex3dv(D);
glTexCoord2d(0, 1);
glVertex3dv(D1);
glEnd();
glBegin(GL_QUADS);
glColor3f(0.3f, 0.3f, 0.3f);
computeQuadNormal(D1, D, E, E1, normal);
glNormal3d(-normal[0], -normal[1], normal[2]); // 1
glTexCoord2d(0, 0);
glVertex3dv(D1);
glTexCoord2d(1, 0);
glVertex3dv(D);
glTexCoord2d(1, 1);
glVertex3dv(E);
glTexCoord2d(0, 1);
glVertex3dv(E1);
glEnd();
glBegin(GL_QUADS);
glColor3f(0.3f, 0.3f, 0.3f);
computeQuadNormal(E, E1, F1, F, normal);
glNormal3dv(normal);
glTexCoord2d(0, 0);
glVertex3dv(E);
glTexCoord2d(1, 0);
glVertex3dv(E1);
glTexCoord2d(1, 1);
glVertex3dv(F1);
glTexCoord2d(0, 1);
glVertex3dv(F);
glEnd();
glBegin(GL_QUADS);
glColor3f(0.3f, 0.3f, 0.3f);
computeQuadNormal(F, F1, G1, G, normal);
glNormal3dv(normal);
glTexCoord2d(0, 0);
glVertex3dv(F);
glTexCoord2d(0, 1);
glVertex3dv(F1);
glTexCoord2d(1, 1);
glVertex3dv(G1);
glTexCoord2d(1, 0);
glVertex3dv(G);
glEnd();
glBegin(GL_QUADS);
glColor3f(0.3f, 0.3f, 0.3f);
computeQuadNormal(G, G1, H1, H, normal);
glNormal3dv(normal);
glTexCoord2d(0, 0);
glVertex3dv(G);
glTexCoord2d(0, 1);
glVertex3dv(G1);
glTexCoord2d(1, 1);
glVertex3dv(H1);
glTexCoord2d(1, 0);
glVertex3dv(H);
glEnd();
glBegin(GL_QUADS);
glColor3f(0.3f, 0.3f, 0.3f);
computeQuadNormal(H, H1, A1, A, normal);
glNormal3dv(normal);
glTexCoord2d(0, 0);
glVertex3dv(H);
glTexCoord2d(0, 1);
glVertex3dv(H1);
glTexCoord2d(1, 1);
glVertex3dv(A1);
glTexCoord2d(1, 0);
glVertex3dv(A);
glEnd();
glEnable(GL_BLEND); // (Н) Здесь строится крышка. Чтоб Альфа наложение хорошо работало, то объект, который должен быть прозрачным(для этого альфа и существует)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //Должен строится в последнию очередь, иначе он будет просвечиваться "насквозь", если захотите сами поэксперементируйте
// (Н) Аргументы объяснять не буду, сами найдёте инфу
glDisable(GL_BLEND);
//Сообщение вверху экрана
glMatrixMode(GL_PROJECTION); //Делаем активной матрицу проекций.
//(всек матричные операции, будут ее видоизменять.)
glPushMatrix(); //сохраняем текущую матрицу проецирования (которая описывает перспективную проекцию) в стек
glLoadIdentity(); //Загружаем единичную матрицу
glOrtho(0, ogl->getWidth(), 0, ogl->getHeight(), 0, 1); //врубаем режим ортогональной проекции
glMatrixMode(GL_MODELVIEW); //переключаемся на модел-вью матрицу
glPushMatrix(); //сохраняем текущую матрицу в стек (положение камеры, фактически)
glLoadIdentity(); //сбрасываем ее в дефолт
glDisable(GL_LIGHTING);
GuiTextRectangle rec; //классик моего авторства для удобной работы с рендером текста.
rec.setSize(300, 200);
rec.setPosition(10, ogl->getHeight() - 200 - 10);
std::stringstream ss;
ss << "T - вкл/выкл текстур" << std::endl;
ss << "E - Переключение текстур" << std::endl;
ss << "L - вкл/выкл освещение" << std::endl;
ss << "F - Свет из камеры" << std::endl;
ss << "G - двигать свет по горизонтали" << std::endl;
ss << "G+ЛКМ двигать свет по вертекали" << std::endl;
ss << "Коорд. света: (" << light.pos.X() << ", " << light.pos.Y() << ", " << light.pos.Z() << ")" << std::endl;
ss << "Коорд. камеры: (" << camera.pos.X() << ", " << camera.pos.Y() << ", " << camera.pos.Z() << ")" << std::endl;
ss << "Параметры камеры: R=" << camera.camDist << ", fi1=" << camera.fi1 << ", fi2=" << camera.fi2 << std::endl;
ss << "UV-развёртка" << std::endl;
rec.setText(ss.str().c_str());
rec.Draw();
glMatrixMode(GL_PROJECTION); //восстанавливаем матрицы проекции и модел-вью обратьно из стека.
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment