412.2
Karma
741.8
Rating
1012
Subscribers

Довожу здравый смысл до абсурда

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 2

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

+1
Смотрите, вот я хочу иметь четыре канала r,g,b и a, они все варьируются между 0 и 255 включительно (беззнаковый байт). Но когда я хочу присвоить цвет одного пикселя, я не хочу делать четыре присваивания, я хочу одно. Вопрос почему оставим за рамками текущего обсуждения.

Поэтому я беру беззнаковый тип, который имеет размер четыре байта, uint32_t. Теперь встаёт вопрос, как конвертировать одно в другое. В одну сторону очень просто:

uint32_t color = r + 256*g + 256*256*b + 256*256*256*a


Почему так? Попробуйте записать каждую компоненту в двоичном виде, и вспомните, что умножение на 256 — это побитовый сдвиг влево на 8 бит. А вот как обратно? Да точно так же. Давайте возьмём чистый зелёный цвет, чему будет равно значение color?

uint32_t color = 0 + 256*255 + 256*256*0 + 256*256*256*0


То есть, 65280. Мы стартуем от этого числа и пытаемся найти значения индивидуальных каналов.


uint8_t r = color % 256;
uint8_t g = (color/256) % 256;
uint8_t b = (color/(256*256)) % 256;
uint8_t a = (color/(256*256*256)) % 256;


Ваш вопрос, зачем мне остаток от деления на 256. Попробуйте сами на бумажке: мой цвет — 65280. Проще всего это видно, если записать в двоичной системе. 65280 в двоичной системе как выглядит? Это тридцать два бита (четыре группы по восемь бит, каждая группа — наш цветовой канал):


00000000 00000000 11111111 00000000
    a       b        g        r


Чтобы получить красную компоненту, мне нужно взять число 00000000 00000000 11111111 00000000 и оттуда вытащить младшие 8 бит. Я сделаю побитовое сравнение с 255 (в двоичной системе это восемь битов единичек):


00000000 00000000 11111111 00000000  &   // цвет, 65280 в десятичной
00000000 00000000 00000000 11111111      // маска, 255 в десятичной


Побитовое И мне даст просто 0, что и требовалось доказать. Оно откинет старшие, ненужные мне биты. Да, забыл. Остаток от деления на (2 в степени n) — это то же самое, что и побитовое И с числом ((2 в степени n)-1). А обычное целочисленное деление на (2 в степени n) — это побитовый сдвиг вправо на n бит.

Теперь хочу вытащить зелёный канал. Я сначала сдвину вправо на восемь бит (поделю на 256), а затем сделаю побитовое И с числом 255, чтобы оставшиеся синий и альфа мне не мешали:


 00000000 00000000 11111111 00000000      // цвет, 65280 в десятичной
(00000000 00000000 11111111 00000000>>8)  // цвет, поделенный на 256
 00000000 00000000 00000000 11111111      // результат деления
 00000000 00000000 00000000 11111111      // маска, 255 в десятичной


Ну и получим нашу зелёную компоненту как (65280/256)%256 = 255.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 2

0
Век живи — век учись. Для моих усохших мозгов гит слишком сложен :)
Спасибо за хинт. Разные операционки — мой каждодневный кошмар.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 2

0
Ещё хуже. Туда попадает постоянная борьба между \r\n и \n от нескольких разработчиков.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

0
Ну собственно да. Косинус — это прилежащий катет, делённый на гипотенузу. Если мы смотрим прямо на стенку, то катет — это оранжевый отрезок, и именно его длина нам нужна. Когда при отрисовке фиолетового луча мы помножим на косинус угла, то гипотенуза (фиолетовый луч) * катет / гипотенуза = катет. Что и требовалось доказать.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 2

+1
Так я и разрешаю делать любую игру, всё честно. Пусть себе делают что хотят. Я просто пытаюсь показать вещи, которые лично мне кажутся интересными (показать, а не принудить!). И зря вы считаете, что большинство идёт по пути наименьшего сопротивления. Они такие игры выкатывают, что закачаешься, пусть и не в 3д.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

+1
Мы решаем задачу доставления удовольствия студенту, которая будет стимулировать обучение. На двух сотнях пикселей никто играть не будет, не те времена.

Массив указателей нужно а) инициализировать б) суметь скормить SDL и в) отдать потом обратно операционке. Это сразу десятка два-три строчек кода, которые трудно понимать, которые фрагментируют память и которые практически не решают никакой задачи.

Короче, я лучшего решения не нашёл, если вы найдёте, присылайте пулл реквест.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

+1
Я только за, но реально, упаковка в одномерный массив — это вообще не проблема, тем более, что оно спрятано внутри set_pixel(x, y).

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

0
Я правильно понял, что вы мне только что предложили сделать игру с разрешением экрана 20 на 20?

Покажите мне, пожалуйста, объявление двумерного массива в куче? (кстати да, в куче можно объявить именно двумерный массив, а не массив указателей).

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

0
Давайте я даже конкретный пример приведу:
ssloy@daffodil:~/tmp$ cat test.cpp 
#include <cstdint>

int main() {
    uint32_t array[ 1920 ][ 1680 ];
    return array[344][563];
}

ssloy@daffodil:~/tmp$ g++ -O0 test.cpp -o test && ./test
Segmentation fault


Откуда взялся сегфолт?

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

0
Окей, давайте считать. Вы мне объявляете массив в стеке. Положим для простоты картинку 1000x1000, это один миллион пикселей. Каждый пиксель четыре байта. В сухом остатке мы кладём в стек четыре мегабайта? У вас какой размер стека?

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

0
Покажите, пожалуйста, объявление двумерного массива? Очень интересно посмотреть.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 2

+3
Вы какую-то не ту книгу помните. 2 дискеты 3.5 дюймов должны были идти с моей книгой, но их не было. Обратите внимание, что мне пришлось просверлить и прошить книгу леской, настолько я её зачитал :)

Скрытый текст

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

0
Давайте по пунктам.
0) скажите, пожалуйста, в какой структуре данных вы предлагаете хранить изображение?

1)
Еще я не понял, что такое вот эти магические значения:
ofs << «P6\n» << w << " " << h << "\n255\n";

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

2)
В этом коммите, что вообще происходит в функции texture_column? Почему колонка, где нам рассказывали про колонки? Что-то умножается, делится на два, в итоге получается колонка. Пока не ясно.

Этап 11 довольно подробно рассказывает про колонки. А в функции texture_column на два не делится ничего.

3)
В последнем коммите, что это за чиселки на 97 строке? Почему они такие, а не любые другие?


Ссылку в студию, а то я не понимаю, про какой файл вы говорите.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 2

+5
Окей, тут мы уже ближе к истине. А что вас удивляет? Разработчики практически никогда не пишут сразу начисто, особенно в тех местах, где ещё не очень очевидно, как оно будет в конце выглядеть. Сначала быстрый прототип, потом рефакторинг. Вот вам сразу умножить на два.

Количество изменений строк кода — очень странная мера сложности проекта, особенно на таких маленьких базах кода.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 2

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

0
Уф, отлично. А то я уже испугался, что опять несбалансированный текст написал!

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 2

+4
Вы это серьёзно? Загрузить, а потом, когда отпала необходимость, удалить стороннюю библиотеку stb_image.h на семь с половиной тысяч строк — это очень сложно?

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

0
А на самом деле всё равно, все эти методы сильно отличаются от простой записи 1/sqrt(x).

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

0
Гхм. Я не очень понял, в каком месте я предлагаю дорисовать сову. Ведь все коммиты в обеих статьях примерно одинакового размера? Куда там сову упрятать, в пять сотен строк кода? :)

Или вы просто так вспомнили, безотносительно к данному тексту?

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 2

+7
Ага, узнали! Эта книга определила мою профессию, я её до сих пор бережно храню. Обратите внимание, что текстуры для статьи я взял с прилагавшихся к этой книге дискет :)

Точнее, дискет к той книге мне так и не продали, и в детстве я страшно по этому поводу страдал. Ну а двадцать пять лет спустя я вдруг подумал, что интернет помнит всё. Оказывается, оригинальная книга шла с компакт-диском:
Скрытый текст

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

+4
Хаки — это прекрасно, и никуда они не убегут. Но всему своё время. Конкретно этот текст рассчитан на тех, кто c++ впервые в жизни увидел. Ни к чему им в этот момент 0x5f3759df.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

0
Я имел в виду лишь то, что при отсутствии регулирования стандартом, мы получаем некроссплатформенность кода как самый минимум. Байты получить можно, а вот что внутри этих байтов будет — сюрприз.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

0
§ 6.7.1.8 There are three floating-point types: float, double, and long double. The type double provides at least as much precision as float, and the type long double provides at least as much precision as double. The set of values of the type float is a subset of the set of values of the type double; the set of values of the type double is a subset of the set of values of the type long double. The value representation of floating-point types is implementation-defined.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

+1
Это называется type punning. Стандарт говорит следующее (6.5 Expressions paragraph 7):

An object shall have its stored value accessed only by an lvalue expression that has one of the following types — a type compatible with the effective type of the object,

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 2

+9
Так тут моделирования никакого нет, ровно такие же спрайты.

Введение в программирование: простой 3D-шутер с нуля за выходные, часть 1

О создании бюджетных стереоизображений на пальцах (стереограмма, анаглиф, стереоскоп)

0
Спасибо за ссылку на плагин; а в какой момент вообще мы потеряли стандартную фичу всех браузеров? Почему теперь нужен плагин?

О создании бюджетных стереоизображений на пальцах (стереограмма, анаглиф, стереоскоп)

0
Да достаточно вспомнить тот самый magic carpet, что я процитировал в самом начале статьи :)

256 строчек голого C++: пишем трассировщик лучей с нуля за несколько часов

+1
В том виде, как есть, specular компонента моделирует это отражение лучей, попадающее в некий конус вокруг идеального отражения. Впрочем, угловой размер источника тоже можно туда добавить.

О создании бюджетных стереоизображений на пальцах (стереограмма, анаглиф, стереоскоп)

0
Во-первых, я не говорил, что дельфи плох; во-вторых, примеры хороших проектов не показывают ничего. Я могу такой трассировщик без особых проблем вообще на брейнфаке сделать. В-третьих, для обучения паскаль мне нравится, но вот только дельфи умер давным-давно, и поэтому обучать на нём сейчас студентов ни к чему, как мне кажется.

256 строчек голого C++: пишем трассировщик лучей с нуля за несколько часов

Рисуем мультяшный взрыв за 180 строчек голого C++

0
Картинка отличная, выкладывайте код!
И давайте ссылку на определение нужной вам проекции.

256 строчек голого C++: пишем трассировщик лучей с нуля за несколько часов

О создании бюджетных стереоизображений на пальцах (стереограмма, анаглиф, стереоскоп)

0
Я не очень согласен с вами. Мне кажется, что вы смешиваете слишком много в одну кучу. Я, сидя в партере театра, не всегда фокусирую взгляд на том месте, где хотел бы режиссёр. Слишком динамичные сцены сложны для восприятия даже в реальной жизни. Стереоизображения своими неидеальностями создают дополнительный стресс для зрительного аппарата; стереограммы большой, анаглиф меньше, поляризованные системы ещё меньше, но стресс не уходит полностью. Однако же этот стресс имеет мало общего с тем, о чём вы говорите. Фокусировка/расфокусировка каждого глаза отдельно играет существенно меньше роли, нежели рассинхронизация глаз, а она имеет место быть в обоих случаях, как в реальности, так и в виртуальности.

256 строчек голого C++: пишем трассировщик лучей с нуля за несколько часов

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

О создании бюджетных стереоизображений на пальцах (стереограмма, анаглиф, стереоскоп)

0
На самом деле, анаглифом лучше вообще не пользоваться, мой мозг страшно протестует против картинок разного цвета для разных глаз :)

О создании бюджетных стереоизображений на пальцах (стереограмма, анаглиф, стереоскоп)

+1
Это проблема того, что параллакс целочисленный в этой реализации. На плоскости под шарами увидеть сложно, т.к. площадь каждой ступеньки маленькая. С текущим разрешением картинки и межглазным расстоянием можно представить 35 разных слоёв глубины. Самый простой способ сгладить — сгенерировать картинку с гораздо большим разрешением (например, хотя бы *4), а затем просто её уменьшить назад, получите гладкие переходы глубины.

О создании бюджетных стереоизображений на пальцах (стереограмма, анаглиф, стереоскоп)

0
Да, анимировать можно без проблем, особенно если если исходную картинку использовать одну и ту же.
1 There