|
28.12.2013, 03:08
|
#46
|
Оператор ЭВМ
Регистрация: 21.12.2013
Сообщений: 20
Написано 10 полезных сообщений (для 10 пользователей)
|
Ответ: raycasting
Сообщение от Samodelkin
С таким форматом ничего не выйдет - нужно разработать другой формат, который хранит данные о карте в форме отрезков. Возможно для удобства потребуется редактор таких карт.
|
в zero tolerance тоже 2д-массив карты, просто каждый элемент массива может принимать значения от 00 до FF... но кривизна не произвольная.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
28.12.2013, 18:37
|
#47
|
Мастер
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений (для 631 пользователей)
|
Ответ: raycasting
Я думал над таким решением и мне кажется оно будет со временем усложнять код, ведь здесь используется ветвление - на каждый случай есть своя реализация как его обсчитать. И чем больше будет вариантов стен и их углов (а также еще и текстур или еще чего-то) - тем более запутанный будет становиться код.
Поэтому я считаю что нужно использовать обобщенный алгоритм пересечения луча и отрезков как я предложил выше.
Конечно ты можешь хранить карту в таком массиве, а перед расчетом лучей преобразовать ее в отрезки, но зачем лишние конвертации если можно сразу хранить и редактировать в отрезках.
Если ты уверен на 100%, что кроме стен под углом 45 тебе ничего не понадобиться, то можешь остановиться на этом варианте.
В любом случае тебе придется делать редактор, потому что править такой массив данных прямо в коде весьма утомительно.
|
(Offline)
|
|
28.12.2013, 22:41
|
#48
|
Оператор ЭВМ
Регистрация: 21.12.2013
Сообщений: 20
Написано 10 полезных сообщений (для 10 пользователей)
|
Ответ: raycasting
Если ты уверен на 100%, что кроме стен под углом 45 тебе ничего не понадобиться, то можешь остановиться на этом варианте.
|
Да, уверен.
В любом случае тебе придется делать редактор, потому что править такой массив данных прямо в коде весьма утомительно.
|
Сделать такой редактор не проблема... Но нужно спрва разобраться с этим движком. Пол и потолок всё-таки пришлось убрать. Ещё сделаю где-то на 1/4 экрана интерфейс, заодно меньше пикселей придётся обновлять на экране.
Щас не могу разобраться, как изменить точку схода перспективы, то есть поставить камеру выше. В процедуре рисования спрайтов это задаётся отдельным дефайном, а как быть со стенками не знаю.
|
(Offline)
|
|
29.12.2013, 00:55
|
#49
|
Оператор ЭВМ
Регистрация: 21.12.2013
Сообщений: 20
Написано 10 полезных сообщений (для 10 пользователей)
|
Ответ: raycasting
Samodelkin, видал в твоём проЭкте сделана фишка "затенение в глубину" (или туман, если инверсия)
Как сделать это в том движке, на который я глаз положил ?
Там в зависимости от переменной drawStart нужно произвести операцию тонирования со столбцом пикселей текстуры.
|
(Offline)
|
|
29.12.2013, 03:05
|
#50
|
Мастер
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений (для 631 пользователей)
|
Ответ: raycasting
К сожалению всё руки не доходят посмотреть тот движок, хотя я заметил там несколько классных фич которые надо бы перенять.
Вот мой код:
/*
================================================================================
rc2d::FogCompute
================================================================================
*/
auto rc::rc2d::FogCompute( Pyramid::Vector3f& outColor, const Pyramid::Vector3f& inColor, float rayLen ) const noexcept ->void {
if ( rayLen > desc.fogMaxClamp ) {
rayLen = desc.fogMaxClamp;
} else if ( rayLen < desc.fogMinClamp ) {
rayLen = desc.fogMinClamp;
}
float fogValue = ( rayLen - desc.fogMinClamp ) / ( desc.fogMaxClamp - desc.fogMinClamp );
fogValue *= desc.fogFactor;
outColor = inColor + ( desc.fogColor * fogValue );
outColor.Saturate();
}
Сразу замечу что представление цвета я храню в 3д векторе типа float и уже непосредственно при записи в пиксел я конвертирую в uint32. В твоём случае (для возможности игры на mmx и более старых машинах) так лучше не делать.
outColor - результирующий цвет.
inColor - исходный цвет.
rayLen - длина луча до стены (или пола/потолка).
Первая часть функции это условия чтобы регулировать на каком расстоянии туман начинается и на каком он достигает своего максимального значения ( desc.fogMinClamp и desc.fogMaxClamp соответственно ).
Между этими значениями происходит линейная интерполяция, которая осуществляется в следующей строке кода и записывается в fogValue. Результат будет в диапазоне 0.0f - 1.0f.
Затем идет домножение на desc.fogFactor чтобы нормализованное значение изменить таким образом в соответствии с решением задуманным дизайнером.
Дальше мы умножаем на desc.fogColor чтобы задать цвет туману и прибавляем результат цвета к исходному inColor цвету пиксела.
Затем функция Saturate просто обрезает (не нормализует) значения вектора в диапазон [0.0f; 1.0f] - это аналогично функции saturate или clamp( x, 0.0f, 1.0f ) из HLSL.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
29.12.2013, 13:29
|
#51
|
Оператор ЭВМ
Регистрация: 21.12.2013
Сообщений: 20
Написано 10 полезных сообщений (для 10 пользователей)
|
Ответ: raycasting
всё очень печально
Запускал только-что на пентиуме вариант без пола и потолка - 4 кадра в секунду (если в обзор попадает спрайт - 3 кадра)
Комп как бы намекает, что это всё плохая затея.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
29.12.2013, 17:26
|
#52
|
Мастер
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений (для 631 пользователей)
|
Ответ: raycasting
Сообщение от alko
всё очень печально
Запускал только-что на пентиуме вариант без пола и потолка - 4 кадра в секунду (если в обзор попадает спрайт - 3 кадра)
Комп как бы намекает, что это всё плохая затея.
|
Ну как я уже выше написал мой код расчитан на новое железо и хорошую графику
Попробуй вот так (код я не проверял и не компилировал):
uint32_t fog( const uint32_t inColor, const uint32_t rayLen, const uint8_t factor ) {
uint16_t color[ 3 ];
color[ 0 ] = ( char )( inColor >> 8 );
color[ 1 ] = ( char )( inColor >> 16 );
color[ 2 ] = ( char )( inColor >> 24 );
if ( rayLen < ( 256 << factor ) - 256 ) {
color[ 0 ] += ( rayLen >> factor );
color[ 1 ] += ( rayLen >> factor );
color[ 2 ] += ( rayLen >> factor );
if ( color[ 0 ] >= 256 ) color[ 0 ] = 255;
if ( color[ 1 ] >= 256 ) color[ 1 ] = 255;
if ( color[ 2 ] >= 256 ) color[ 2 ] = 255;
uint32_t outColor = 0;
outColor |= ( ( ( char )color[ 0 ] ) >> 8 );
outColor |= ( ( ( char )color[ 1 ] ) >> 16 );
outColor |= ( ( ( char )color[ 2 ] ) >> 24 );
return outColor;
} else {
return 0xffffff00;
}
}
factor сначала задавай 0, а потом 1 и выше до 7 включительно.
Тут главное не напутать с форматом цвета. Например согласно little endian 4 байтное число 0xaabbccdd на самом деле записывается в память в обратном порядке - ddccbbaa. Таким образом при преобразовании типа, например в 2 байтное число оно превратится в ddcc, то есть 0xccdd если в нормальном представлении. Так что я код написал что у тебя в памяти идет ARGB в таком порядке, то есть в 4 байтном числе это 0xBGRA. Однако операторы сдвига как раз работают с числами в нормальном представлении, то есть для числа 0xaabbccdd если применить >> 24 то будет ожидаемое aa, а не какое то значине справа от числа, так что я просто написал чтобы было понятно как работает внутри
Да кстати расширение mmx (а также sse в более новых машинах) может работать с упакованными значениями - и видимо они здесь как раз кстати подойдут, но я пока сам так еще не делал.
|
(Offline)
|
|
29.12.2013, 19:34
|
#53
|
Оператор ЭВМ
Регистрация: 21.12.2013
Сообщений: 20
Написано 10 полезных сообщений (для 10 пользователей)
|
Ответ: raycasting
Сообщение от alko
Запускал только-что на пентиуме вариант без пола и потолка - 4 кадра в секунду (если в обзор попадает спрайт - 3 кадра).
|
Это даже без тонирования в глубину.
|
(Offline)
|
|
29.12.2013, 20:07
|
#54
|
Оператор ЭВМ
Регистрация: 21.12.2013
Сообщений: 20
Написано 10 полезных сообщений (для 10 пользователей)
|
Ответ: raycasting
Дело не в рейкастинге... Дело в самом quickCG.
Попробовал написать элементарное Хыллоу Ворлд, где будет закрашиваться экран и выводится отмасштабированный в два раза спрайт. И таки шо ви думаете? Эта хрень рисуется тоже 4 кадра пер секонд. (на пентиуме, разумеется... На моём ноуте 150 кадров в секунду)
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include <SDL.h>
#include <cmath>
#include <string>
#include <vector>
#include <iostream>
#include "quickcg.h"
using namespace QuickCG;
#define screenWidth 800
#define screenHeight 600
struct Sprite
{
float x;
float y;
int texture;
};
Sprite sprite[50];
int main(int argc, char *argv[])
{
double time = 0;
double oldTime = 0;
std::vector<Uint32> texture[11];
unsigned long tw, th;
Uint32 buffer[screenWidth][screenHeight];
loadImage(texture[0], tw, th, "rc/gg1.png");
screen(800, 600, 1, "Metallix zone");
while(!done())
{
int i=0;
for(int xx=0;xx<800;xx++)
for(int yy=0;yy<600;yy++)
buffer[xx][yy]= 0x0f00f0;
int x=rand()%500,y=rand()%100;
for(int xx=0;xx<128;xx++){
for(int yy=0;yy<64;yy++){
Uint32 color = texture[0][i];
i++;
if(color!=0xffffffff)for(int i=0; i<2 ; i++)
for(int k=0; k<2 ; k++)
buffer[yy*2+i+x][xx*2+k+y]=color<<8;}
}
drawBuffer(buffer[0]);
oldTime = time;
time = getTicks();
double frameTime = (time - oldTime) / 1000.0;
print(1.0 / frameTime);
redraw();
}
}
|
(Offline)
|
|
29.12.2013, 20:18
|
#55
|
Оператор ЭВМ
Регистрация: 21.12.2013
Сообщений: 20
Написано 10 полезных сообщений (для 10 пользователей)
|
Ответ: raycasting
И тут дело даже не в выборке пикселей из png-картинки.
Тут дело в выводе пикселя, каким бы он ни был.
Там даже обычное заполнение сплошным цветом - 4-5 кадров в секунду.
|
(Offline)
|
|
29.12.2013, 22:45
|
#56
|
Мастер
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений (для 631 пользователей)
|
Ответ: raycasting
В топку этот quickCG значит. Зачем он нужен? Я у себя рендер делал целиком сам, затем готовый фрейм с помощью SDL 1.2 выводил на экран. Еще лучше заюзать OpenGL или D3D напрямую, даже если не использовать аппаратные плюшки, я просто не в курсе как делали во времена MMX, возможно напрямую VGA юзали. Через чего кстати видеокарта подключена на твоем компе? Может там шина PCI или AGP старая и медленная и менять пиксели из системы очень медленно? Либо алгоритм не самый лучший, например при программировании VGA напрямую есть режим отображения видеопамяти на системную - я так делал когда пробовал написать бутлоадер с графическим интерфейсом через графику BIOS.
Тут тебе видимо тоже рекомендуют на шейдеры перенести
Короче просто попробуй сделать хело ворлд вместе с SDL и посмотреть как на нем будет. Если медленно тогда придется искать другие способы взаимодействия с видеокартой.
|
(Offline)
|
|
29.12.2013, 23:21
|
#57
|
Оператор ЭВМ
Регистрация: 21.12.2013
Сообщений: 20
Написано 10 полезных сообщений (для 10 пользователей)
|
Ответ: raycasting
Через чего кстати видеокарта подключена на твоем компе? Может там шина PCI или AGP старая и медленная и менять пиксели из системы очень медленно?
|
Видяха PCI ati Rage II. Из api поддерживается только DX 5.0 , и то - для галочки. Tomb Raider на софтверном рендеринге ЦП и то быстрее рисует, нежели та видяха на DX. Она очень медленно текстурирует. А если кубик без текстур вращать - то она быстрее это делает, чем проц.
Тут тебе видимо тоже рекомендуют на шейдеры перенести
|
Ага. Всех уже задолбал этим рейкастингом.
А какие есть ещё API помимо SDL, чтоб шустро выводить пиксель на экран при помощи ЦП ?
Короче просто попробуй сделать хело ворлд вместе с SDL
|
quickCG - это набор функций, которые юзают непосредственно SDL. Только якобы быстрее... А на деле - эххх....
http://lodev.org/cgtutor/quickcg.html
Последний раз редактировалось alko, 30.12.2013 в 01:49.
|
(Offline)
|
|
30.12.2013, 02:29
|
#58
|
Мастер
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений (для 631 пользователей)
|
Ответ: raycasting
Подожди, тут нужно структурировать:
SDL является прослойкой между приложением и directx для windows или xlib|opengl для linux. Поэтому в твоем случае directx юзается всеравно. quickcg получается еще одной надстройкой над sdl, и если даже он использует sdl каким то хитрым способом, то это в любом случае медленнее чем dx. поэтому если у тебя на видеокарте медленный dx то у тебя sdl быстрей не будет.
Теперь о софтварном рендере. Монитор у тебя всеравно подключен к видеокарте и она в любом случае принимает участие в формировании изображения. Видеокарта соеденина с матплатой посредством agp, pci или pci-express (что там на mmx было?) и это обычно является самым узким местом. Преимущество аппаратного ускорения в том что все текстуры, вершинные буферы и прочая инфа один раз загружается в видеопамять (если не считать изменений и синхронизаций) и затем кадры формируются уже внутри видяхи не затрагивая шину разъема. В случае софтварного рендера у тебя кадр формируется в раме, и значит тебе нужно каждый раз новый кадр переправлять по разъему чтобы видяха его вывела на экран. вот. тут все решает размер этого кадра, то есть его разрешение, глубина цвета и прочие атрибуты.
Если же ты будешь прогать через vga напрямую то тебе даже не нужны ни ось, ни всякие gapi, то есть никакого оверхеда, а так как тебе нужно только копировать кадры из рамы в видяху, минимальных возможностей vga должно быть достаточно. Но там все через асм. И вобщем судя по твоим отчетам о скорости dx на старых компах, я еще больше убеждаюсь что игры тогда программировали именно так - напрямую, без юзания gapi.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
30.12.2013, 13:47
|
#59
|
Оператор ЭВМ
Регистрация: 21.12.2013
Сообщений: 20
Написано 10 полезных сообщений (для 10 пользователей)
|
Ответ: raycasting
Даже не знаю где бы инфу черпануть по перебросу содержимого системного ОЗУ в видео-память на асме. + инициализировать граф. режим надо.
На моём излюбленном спектруме это делалось 5-тью 6-тью инструкциями... IBM-PC куда сложнее в этом плане, при том что большинство инструкций - целые макрокоманды.
Более того, прежде чем перебрасывать содержимое оперы, надо как-то ещё туда и записать само изображение... Быть может SDL даже в буфер медленно записывает.
Хотя не. Кое-что нашёл по VGA-CGA-EGA. Читану на досуге.
http://www.codenet.ru/cat/Applicatio...ESA-Standarts/
Последний раз редактировалось alko, 30.12.2013 в 16:44.
|
(Offline)
|
|
30.12.2013, 21:55
|
#60
|
Мастер
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений (для 631 пользователей)
|
Ответ: raycasting
В режиме VGA ничего перебрасывать не надо, точней там идет отображение адресного пространства, ты пишешь в определенные адреса как в обычное ОЗУ, а система сама перегоняет это в видеопамять.
Ты видимо неправильно SDL использовал. Нужно создать фрейм буфер в ОЗУ через обычный malloc например и обращаться к нему как к двумерному массиву:
uint32_t* buffer = ( uint32_t* )malloc( 320 * 240 * sizeof( uint32_t ) );
buffer[ 100 ][ 200 ] = 0xaabbccdd; // обращение как в 2д массиву (порядок: высота, ширина)
*( buffer + 100 * 320 + 201 ) = 0xaabbccdd; // обращение посредством адресной арифметики (тоже самое по сути)
И затем достаточно сделать только ОДИН вызов SDL чтобы он весь буфер скопировал в видеопамять и вывел на экран. Если ты будешь вызывать каждый раз чтобы записать по одному пикселу то конечно всё будет очень медленно.
Вот я у себя целый класс FrameBuffer сделал чтобы работать с фреймами внутри ОЗУ.
ЗЫ: Размеры массивов в С++ ограничены, поэтому именно через malloc / free лучше с буферами работать.
|
(Offline)
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 20:25.
|