Comments 63
id Software по-прежнему использует систему координат из игры Wolfenstein 3D 1992 года
Это не система координат Wolfenstein. Это обычная классическая система координат, где Z — это высота.
У вас разве на геометрии в школе Y высотой был в трехмерном пространстве?
Ось Y = верх/низ
Так вот откуда в KOMPAS-3D это извращение, там как раз используют OpenGL, все школьники и студенты привыкли что Z — высотная координата, но как только ты стал инженером — забудь все чему тебя учили.
Не всегда! Сначала оси Z — вообще не было в компьютерной графике. Отсюда и Y в качестве высоты, а когда появилась трёхмерность, то Z стала глубиной.
Вся суть в том, что:
- в геометрии, алгебре, физике итп: XY — это плоскость стола, и потому Z считается высотой от стола
- а в компьютерной графике: XY — это плоскость монитора, и потому Z считается глубиной от экрана
А из софта с Z-up я могу вспомнить только 3ds max и Unreal Engine.
Самому интуитивно Z-up, но не из соображений школьной геометрии, а т.к. начинал с макса еще в школе (т.е. я с ним около 15 лет уже) — синдром утенка, как-никак.
А Y-up сложилось чисто исторически в 3д-софте, т.к. если смотреть через экран компьютера, то X и Y — координаты плоскости, а вот Z — глубина в экран.
Оконный режим и потом, уже после перехода к 3D, много лет головной болью был.
Там ведь всё рисование-то:
LPDIRECTDRAWSURFACE7 lpddssecondary->Lock(NULL,&ddsd,DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT,NULL);
UINT* Video_Buffer=(UINT *)ddsd.lpSurface;
lPitch32=ddsd.lPitch>>2;
//рисуем
UINT *vptr=Video_Buffer;
UINT *sptr=ScreenBuffer;
for(y=0;y<480;y++,vptr+=lPitch32)
{
UINT *vptrx=vptr;
for(int x=0;x<640;x++,vptrx++,sptr++) *(vptrx)=*(sptr);
}
lpddssecondary->Unlock(NULL);
lpddsprimary->Flip(NULL,DDFLIP_WAIT);
Обычный проход по памяти с заполнением пикселя (как в MS-DOS). Большего в Q2 и не требовалось. А тут даже блиттер не нужен.
А вот на I740 OpenGL глючил в Q2 — это я хорошо помню. :)
— тратится всего 4 такта процессора Pentium на пиксель экрана (при условии всех кэш попаданий, конечно)
еще раз: каждые 4 такта движок выдавал пиксель на экране, т.е. вычислялись координаты нужного текселя в текстуре и с учетом всех преобразований нужный цвет записывался в видеопамять.
На самом деле, если брать среднее значение, то тратилось, конечно, больше чем 4 такта. 64 такта тратилось на серию из 16 пикселей. Дело в том, что для корректного перспективного проецировния текстуры в экран, требуется хотя бы одно деление на каждый пиксель. Деление во времена Pentium занимало немало. Что-то порядка 40 тактов (точно уже и не упомню). Поэтому все движки того времени так или иначе линейно интерполировали результаты делений на серию пикселей, обычно на 16. Визуально это выглядело, как лесенка, когда плоскость полигона с текстурой была почти параллельна направлению взгляда. Так вот, еще один трюк, который меня в свое время очень впечатлил: движок запускал операцию деления на сопроцессоре и в это время выдавал 16 пикселей, линейно интерполируя результат предыдущего деления. Т.е. 64 такта на 16 пикселей и 40 тактов на деление в итоге отрабатывали параллельно. Это было очень круто.
В нём нет ни одной карты освещённости. Он использует только GL_LIGHTING. Фишка в том, что можно для каждой грани выбрать 8 источников света (самых главных) и для них выполнить разбиение грани на компоненты, в которых из этих 8 источников некоторые включены, а некоторые выключены (не освещают эти компоненты). Что это даёт на практике? Чёткое цветное освещение с замечательными тенями и при этом любой источник можно динамически изменять прямо в процессе работы программы. Насколько я понимаю, нигде больше такой подход никто не применял — я ничего подобного не встречал. И вот последние 13 лет я всё никак не допишу статью со всей математикой для таких движков. :)
А вообще на первый взгляд по описанию похоже на вертексное освещение.
В нём нет ни одной карты освещённости. Он использует только GL_LIGHTING… Насколько я понимаю, нигде больше такой подход никто не применял — я ничего подобного не встречал.
У меня в освещение через GL_LIGHTING http://www.moddb.com/mods/wolfgl-3d
Правда, пока без теней и цвета.
В будущем планируется добавить ещё два режима на выбор:
- аппаратное освещение Ламберта (входит в стандарт OpenGL и поддерживается видеокартами)
- шейдеры
PS посмотрел Ваш движок, водичка в стиле Unreal — очень впечатляет!
Кстати, если интересно, вот ещё мои движки, который под MS-DOS, он 2002 года с мелкими модификациями в 2006 и 2015. И это полноценная игра с графикой из Doom (движок тоже на BSP, но разбиение до линий, а не полигонов). А который для Windows написан прошлым летом, когда я решил этот MS-DOS движок переделать в отдельный движок. :) Дальше энтузиазм угас. :)
Ссылка
Скриншот:
в копилку шотов при чем по теме…
Я так понимаю, вы нарочно Point Light вперед от лампочки выдвинули? Сделайте скрин, если бы Лайты стояли на уровне лампочек, пожалуйста.
Я примерно тогда же игрался с этим, На выходе фигня. — честный ппл лучше…
Фишка в том, что можно для каждой грани выбрать 8 источников света (самых главных) и для них выполнить разбиение грани на компоненты, в которых из этих 8 источников некоторые включены, а некоторые выключены (не освещают эти компоненты).
Правильно ли я понимаю, что перед рисованием группы полигонов Вы включаете и выключаете источники освещения, а затем проделываете это со следующей группой полигонов?
1) Рисуется карта. Исходные многоугольники являются выпуклыми (пол+потолок+стены).
2) Берётся полигон и определяются главные для него источники света (по яркости). Таких источников максимум 8 штук (гарантируется OpenGL не менее 8).
3) Для этого полигона перебираем ВСЕ остальные полигоны и для каждого источника света из выбранных главных строим тень на исходный полигон от остальных. Получаем для каждого исходного полигона набор полигонов теней, для каждого из которых известно, какие источники света отключены, а какие включены.
4) Дальше уже движок просто включает или отключает источники света при отрисовке полигонов. И всё.
Вот отдельный модуль генерации теней: ссылка
гарантируется OpenGL не менее 8
У меня на старой видеокарте при включении всех 8 источников начинались глюки.
2) Берётся полигон и определяются главные для него источники света (по яркости). Таких источников максимум 8 штук (гарантируется OpenGL не менее 8).
3) Для этого полигона перебираем ВСЕ остальные полигоны и для каждого источника света из выбранных главных строим тень на исходный полигон от остальных. Получаем для каждого исходного полигона набор полигонов теней, для каждого из которых известно, какие источники света отключены, а какие включены.
4) Дальше уже движок просто включает или отключает источники света при отрисовке полигонов. И всё.
Офигительная идея! Даже не предполагал, что в одном проходе можно указывать разные источники света для каждого полигона.
Должно быть так:
#ifndef SHADOW_H
#define SHADOW_H
#define S_EPS 0.01
#define S_EPS1 0.0000001
#define S_EPS2 0.0001
#include "polygon.h"
long GetPointPositionPlane(SPoint sPoint_A,SPoint sPoint_Plane,SVector sVector_Normal);
bool GetLineIntersectionPlane(SPoint sPoint_A,SPoint sPoint_B,SPoint sPoint_Plane,SVector sVector_Normal,long mode,SPoint &sPointReturn);
long GetPointPositionInPlaneXZ(SPoint sPoint_A,SPoint sPoint_B,SPoint sPoint);
bool IsPointInPolygonXZ(SPoint sPoint,CPolygon cPolygon);
bool GetPieceIntersectionInPlaneXZ(SPoint A,SPoint B,SPoint C,SPoint D,SPoint &sPointReturn);
bool GetLineIntersectionPieceInPlaneXZ(SPoint A,SPoint B,SPoint C,SPoint D,SPoint &sPointReturn);
bool IsPointInPolygon(SPoint sPoint,CPolygon cPolygon);
bool GenerateShadow(CPolygon cPolygon_ShadowSource,CPolygon cPolygon_ShadowDestination,SPoint sPoint_Lighting,vector<CPolygon> &vector_CPolygon_Fragment);
#endif
Кстати, этот shadows.h-shadows.cpp как раз и делает разбиение выпуклого полигона на набор выпуклых фрагментов, зная полигон, отбрасывающий тень и источник света.
Даже не предполагал, что в одном проходе можно указывать разные источники света
Честно говоря, я не понял, что вы имели в виду. :)
Блин! Офигеть Круто!
bool GenerateShadow(CPolygon cPolygon_ShadowSource,CPolygon cPolygon_ShadowDestination,SPoint sPoint_Lighting,vector &vector_CPolygon_Fragment);
Там всё очень просто. Главное, что этот набор фрагментов нужно построить на этапе подготовки карты в редакторе. А в самом движке только использовать, не выполняя никаких пересчётов теней, а только меняя характеристики источников света (но не координаты).
В принципе, для одного наиболее сильного источника света можно пересчитывать поправки для координат тени, если источник света будет "слегка покачиваться", или переместится не слишком далеко.
Надо попробовать собраться и хоть что-то оформить, как статью. :) Вот сейчас смотрю код и нифига не понимаю, вот зачем нужно добавлять к полигону точек тени точки пересечения теневого объёма с плоскостью полигона, на который падает тень. и которые находятся внутри полигона, на который падает тень. Комментирую фрагмент — видны ошибки работы с некоторых случаях. :) Склероз — штука страшная. :)
Поэтому, лучше не трогать координаты источника света. А в реальном времени это вычислять очень дорого.
Простите, а какой тогда смысл? Я думал, это дешевые реалтайм источники света и подумал: «о, это клево». А если это бейкд, то лучше уж тогда лайтмапы — они дают очень красивые результаты
Не двигать — не значит "не выключать!" :)
Произвольно включаемые и выключаемые источники света — это тоже динамическое освещение, даже если они и не меняют координаты.
Кстати, почти дописал статью. :) Либо здесь, либо на geektimes отправлю. :)
Ссылка на статью da-nie => https://habrahabr.ru/post/328842/
PS уверен Вам стоит написать статью про Ваш движок!
А вот модуль разбиения и движок остался. :) transit gloria mundi :)
Да, освещение по вершинам — оно штатное в OpenGL и оно и используется. Только все эти вершины получены трассировкой лучей от источников света на этапе разбиения карты.
В самом движке: F1-F4 — управление рендерингом, пробел — открыть дверь, курсор — управление, enter-вычислить FPS (записывается в файл).
Сам движок по сути плоский как Doom — я в 3D карту нарисовать не могу и редактор такой не смог написать — не представлял на тот момент, как оно должно выглядеть. Да и для физического движка удобно работать с плоскостью. :)
Невозможно открыть рабочую среду в Visual Studio 2010. Необходимо использовать VS 2008.Печально. Неужели так сложно поддерживать обратную совместимость? Судя по тенденциям в моей любимой Mac OS X, скоро прошлогодние файлы в новом Xcode нельзя будет нормально открыть.
Видео с релиза QuakeWorld тоже шикарное. Особенно понравился кот на 8:15 и интервью с геймерами.
«If you stay underwater too long, real physics apply and you start gasping for air. If you fall into lava, you won't last very long—just like in real world!»
«When we finally got it… Let's say our girlfriends didn't see us for quite some time. They're Quake widows.»
Вы можете подсказать, насколько сложно прикрутить звуковой API A3D 2.0, чтобы звуковые волны отражались? Если что SDK и мануал по программированию есть тут http://www.worknd.ru/
Обзор исходного кода Quake 2