-
Смастерил свой ZBuffer. Алгоритм простой, но у меня не работает в некоторых случаях. Может глаз замылился, может не вижу очевидного.
Смысл в том, что отсечение по глубине делается попиксельно, а соответственно должно работать независимо от порядки отрисовки объектов, но выходит так, что дальний объект рисуется поверх ближнего.
Вот и думаю как такое может быть?
Тут картинка: https://hostingkartinok.com/show-image.php?id=19e75764f790be54b1b68c67cf4e2e09
Очистка буфера производится с заполнением буфера максимальной дальностью.
const
MAXZDEPTH = $7FFFFFFF;
procedure TBitmap64.ClearZBuffer;
begin
if (FZBuffer <> nil) then StoreDWords(FZBufferAddr, (FZBufferSize shr 2), MAXZDEPTH);
end;
Все объекты на картинке нарисованы этими двумя процедурами.
Логика ZPixel простая — всегда рисуется самый ближний пиксел.
procedure TBitmap64.ZPixel32(x, y, z: integer; dColor: TColorRef);
var
zA: TAddress;
begin
if FClipRegion.PtInRegion(x, y) then
begin
zA := ZAddress32(x, y);
if (z < PInteger(zA)^) then //Всегда рисуем более ближний пиксел
begin
PInteger(zA)^ := z; //Новая позиция в Z-Buffer
PDWord(PixelAddress32(x, y))^ := dColor;
end;
end;
end;
procedure TBitmap64.ZLine(x0, y0, z0, x1, y1, z1 : integer; dColor: TColorRef);
var
x, y: integer;
fX, fY, fZ: float;
cr: TClipStruct;
lp: integer;
gradX, gradY, gradZ: float;
i: integer;
z: integer;
dZ, dL: integer;
w, h: integer;
begin
//2D-отсечение
if not ClipLine(x0, y0, x1, y1, cr) then exit;
//Длинная сторона линии
dL := Max(cr.W, cr.H);
//глубина линии по Z
dZ := Abs(z1 - z0);
//Стартовая глубина
z := z0;
//Стартовая глубина для приращения
fZ := z;
//Шаг по Z
if (z0 = z1) then
begin
gradZ := 0;
end
else
if (z1 > z0) then
begin
//Шаг приращения Z
gradZ := Abs(dZ / dL);
end
else
if (z0 > z1) then
begin
//Шаг приращения Z
gradZ := -(dZ / dL);
end;
//Учет последней точки
if FDrawLastPoint then lp := 0 else lp := 1;
x := cr.x0;
y := cr.y0;
//Горизонтальная линия
if (cr.dx > cr.dy) then
begin
//Приращение по Y
gradY := (cr.gradY * cr.yinc);
//Горизонтальная ПРЯМАЯ линия
if (gradY = 0) then
begin
//Выбор первой точки с которой начинается отрисовка линии
if (cr.xinc = 1) then x := cr.x0 else x := cr.x1;
//Цикл по ширине линии
for i := 1 to (cr.W - lp) do
begin
//Точка
ZPixel32(x, y, z, dColor);
//Приращение X
x := (x + cr.xinc);
//Приращение Z
fZ := (fZ + gradZ);
//Целочисленный Z
z := Round(fZ);
end;
end
else
//НЕ прямая горизонтальная линия
begin
//Приращение по Y
fY := y;
//Цикл по ширине линии
for i := 1 to (cr.W - lp) do
begin
//Точка
ZPixel32(x, y, z, dColor);
//Приращение X
x := (x + cr.xinc);
//Приращение Y
fY := (fY + gradY);
//Приращение Z
fZ := (fZ + gradZ);
//Целочисленный Y
y := Round(fY);
//Целочисленный Z
z := Round(fZ);
end;
end;
end
//Вертикальная линия
else
begin
//Приращение по X
gradX := (cr.gradX * cr.xinc);
//Вертикальная ПРЯМАЯ линия
if (gradX = 0) then
begin
//Выбор первой точки с которой начинается отрисовка линии
if (cr.yinc = 1) then y := cr.y0 else y := cr.y1;
//Цикл по высоте линии
for i := 1 to (cr.H - lp) do
begin
//Целочисленный Z
z := Round(fZ);
//Точка
ZPixel32(x, y, z, dColor);
//Приращение Y
y := (y + cr.yinc);
//Приращение Z
fZ := (fZ + gradZ);
end;
end
else
//НЕ прямая вертикальная линия
begin
//Приращение по X
fX := x;
//Цикл по высоте линии
for i := 1 to (cr.H - lp) do
begin
//Точка
ZPixel32(x, y, z, dColor);
//Приращение X
fX := (fX + gradX);
//Приращение Y
y := (y + cr.yinc);
//Приращение Z
fZ := (fZ + gradZ);
//Целочисленный X
x := Round(fX);
//Целочисленный Z
z := Round(fZ);
end;
end;
end;
end; -
Вопрос отпал. Это я лошара. Буфер очищался каждый раз при отрисовке объектов.
Вынес за цикл отрисовки - все исправилось. Извиняшки! -
D7 (24.04.17 11:56) [3]Я пытался скачать ваши разные демки (ссылки из разных тем), но все ссылки дохлые.
Если можно - загрузите куда-то на Яндекс.Диск что ли, очень любопытно посмотреть. Спасибо! -
>Я пытался скачать ваши разные демки (ссылки из разных тем), но все ссылки дохлые.
Удалил. Попозже выложу. Только это не демки - это просто разработка своей 3D-библиотеки. Она сыровата во многих местах. -
Здесь EXE(64):
https://cloud.mail.ru/public/FRPk/owdwz7dgR
Здесь картинка:
https://hostingkartinok.com/show-image.php?id=105a8ff7a70052f7de9fd108b999e3a1
Еще в процессе разработки, поэтому DivideByZero и AV вполне возможны.
F - на полный экран
На 3D-объекты камерой лучше не наезжать. -
Тут полетать вокруг объектов можно
https://cloud.mail.ru/public/MBsB/czGvVeK2n
WSAD - обычная раскладка
QE - вверх/вниз
ALT - вращение по X
Колесо мыши - масштаб.
ESC - прервать тест или если не тест, то выход
В 3D-массив добавлена поддержка потоков.
У меня 50 тыс. объектов с включенной заливкой ~60 fps ;)
Для софтверного движка и начала думаю неплохо. -
SHIFT - ускорение.
Не 50 тыс, а 5 тысяч. Извиняюсь.
Разрешение 2560×1600. -
Новый вариант. Теперь добавил свет.
https://hostingkartinok.com/show-image.php?id=3eecb14661b03bf92057c1ed64d41df9
Тут EXE64: https://cloud.mail.ru/public/3YxC/kqXfVsj9k
gray +, gray- : Вращение света. Свет глобальный.
WSAD - передвижение
QE - вверх/вниз
с ALT - свободный полет
C - точкой вращения будет источник света.
Стрелки - передвигать объекты
NumPad 4 и 6 - вращать объекты
Массив объектов - просто летящие треугольники.
https://hostingkartinok.com/show-image.php?id=8bf2072e54f09da0bc7427059de4d531
Сначала включить 3д-объекты для инициализации света, а потом можно переключить на массив. Включить заливку и другой фон, а то почти ничего не видно по умолчанию.
Все еще пилю :) -
Pavia © (24.06.17 16:47) [9]Меню с лева не помещается на экране 1366х768
-
ну да. В новой версии помещается. Потом выложу. Сейчас фруструм и отсечение дописываю.
-
Самое главное, что видеокарта здесь не используется вообще. И все написано на Delphi.
Тяжеловато с математикой. Говорили мне «учи матчасть» :) -
Игорь Шевченко © (25.06.17 10:30) [12]
> И все написано на Delphi.
компилятор Delphi генерирует не самый оптимальный код, особенно для 64-х разрядной платформы. "Все написано на Delphi" - не повод для хвастовства. -
>генерирует не самый оптимальный код
критические участки оптимизированы на ассемблере, в основном отрисовка и трансформация. Да и не хвастался я в общем. Меня просили выкладывать, что получается.
а ссылки мне нужны самому для проверки на других машинах. -
Сделал 3 уровня оптимизации. 1. На «чистом Delphi» 2. MMX 3. SIMD.
На чистом Delphi около 25 fps. На MMX около 50 fps. SIMD - 70 и выше fps. Хотя в целом все зависит от кол-ва полигонов. 30K-50K полигонов при 30 fps стабильно на одном ядре.
Можно еще AVX, AVX2 использовать, но к сожалению пока AVX не на всех процессорах присутствует. Потом все распараллелю на другие ядра. -
Новый EXE с укороченным меню.
https://cloud.mail.ru/public/LFYU/mYd1C2Per
F - FullScreen.
Вращение объекта: NumPad 4/6 + shift + отпустить NumPad 4/6.
Остановить вращение: NumPad 4/6.
gray +, gray- : Вращение света по Z, а с Ctrl по Y -
Pavia © (25.06.17 21:13) [16]Из явных глюков:
1) При старте не обновляется форма. Скорее всего при ресайзе.
https://yadi.sk/i/cehpw0ff3KSRaM
2) 4 поточный https://yadi.sk/i/KTIwNayA3KSRCu
3) 3D-массив просит выключить 3D объекты?!
Если не трудно, можете провести испытание скорости на TLazyBitmap;
https://yadi.sk/d/6wtcRRaN3KSRqS -
Потоки не работают пока на 3D. Только на 2D. Если включить например 20-40к линий, то будет видна разница между 1 потоком и несколькими. Потоки пока только на линии, круги и треугольники работают. Мне нужно чтобы понять как с потоками работать и насколько шустрее рисует. На моем компе раз в 7-10 быстрее. у меня 10-и ядерник. Мне это для теста стабильности надо. Я например включаю 750 тысяч линий и жду. + глюки хорошо выявляет.
Тест Лэзи
https://hostingkartinok.com/show-image.php?id=5f0814b8510a4838c5ea1f61117806bd -
>3) 3D-массив просит выключить 3D объекты?!
Да. Общие переменные используются. Если их вместе включить, то будет AV.
Это просто тестовая площадка. Пытаюсь игрушку написать :)
Вот кусочек уровня: https://hostingkartinok.com/show-image.php?id=c04e41c84e7ea7d2f616f052d51ffe11 -
Или шахматишки очередные можно ;)
https://hostingkartinok.com/show-image.php?id=cfe5152555e11892ec2bf8b1d8d808d3