Я сделал эту статью из своего твиттер-треда https://twitter.com/i_dianov/status/1367136469853351944
Пересечение сферы с пересечением гироида и сферы
Привет! Это туториал о том, как найти пересечение двух или более поверхностей (не объёмов), чтобы делать сложные #SDF формы для #raymarching.
- Начнём с базовой настройки реймаршинга
#define SPHERE length(p)-1.
#define SDF(p) SPHERE
vec3 p; float d=0.,i,e=1.; for(;i++<99.&&e>.01; p=d*normalize(vec3((FC.xy-.5*r)/r.y,1))+ vec3(0,0,-5), p*=rotate3D(t,vec3(.3,1,0)), d+=e=.5*SDF(p)); o+=100./i/i;
Не нужно понимать нижнюю строку, давайте сосредоточимся на строке, начинающейся с
#define SDF(p) …
Она определяет форму для рендеринга. Вот сфера:
#define SPHERE length(p)-1.
#define SDF(p) SPHERE

- А вот SDF для плоскости Z (она параллельна осям X и Y) https://bit.ly/3e4nd1D
#define PLANE_Z -p.z
#define SDF(p) PLANE_Z

- Чтобы найти пересечение этих двух поверхностей, просто пишем
#define SDF(p) length(vec2(PLANE_Z, SPHERE))
И БУМ!💥 Круг появился! https://bit.ly/3bXGTBJ
Дело в том, что length двух SDF близок к нулю, только если оба SDF близки к нулю.

- Мы можем надуть эту поверхность, вычитая небольшое значение из SDF:
#define SDF(p) length(vec2(PLANE_Z, SPHERE))-.2
Обратите внимание на -.2 в конце формулы.
https://bit.ly/3bXGTBJ

- Можете сделать небольшую паузу и подумать, как сделать цилиндр, используя этот трюк?
- Отлично, у вас получилось! Это просто пересечение двух плоскостей, надутое вычитанием небольшого значения:
#define SDF(p) length(vec2(PLANE_X, PLANE_Z))-1.2
Часто это сокращают до length(p.xz)-1.2, что фактически то же самое.
https://bit.ly/30me4cZ

- Пересечём цилиндры! Получатся два пересекающихся круга
#define CYLINDER_Y length(vec2(PLANE_X, PLANE_Z))-1.2
#define CYLINDER_X length(vec2(PLANE_Y, PLANE_Z))-1.2
SPHERE))-.01
#define SDF(p) length(vec2(CYLINDER_Y, CYLINDER_X))-.1
https://bit.ly/3883WbT

- Начинается безумие! Осторожно, гироид
#define GYROID dot(sin(p*9.),cos(p.zxy*9.))*.1
#define SDF(p) GYROID
Сложно понять его форму, потому что гироид бесконечен и мы внутри него https://bit.ly/3070hqe

- Чтобы лучше понять его форму, нужно пересечь его с каким-то другим примитивом. Почему бы не со сферой?
#define SDF(p) length(vec2(SPHERE, GYROID))-.02
https://bit.ly/30a2scU
Подробнее о гироидах можно узнать на https://en.wikipedia.org/wiki/Gyroid

- Хотите пересечь пересечения? Без проблем! Можем использовать нашу странную форму из твита #7:
#define CROSS_RINGS length(vec2(CYLINDER_Y, CYLINDER_X))-.2
#define SDF(p) length(vec2(CROSS_RINGS, GYROID))-.01
https://bit.ly/3kGYWjr

- Можно пересечь больше двух поверхностей сразу! Используйте для этого vec3 или vec4:
#define SDF(p) length(vec3(CYLINDER_Y, CYLINDER_X, SPHERE))-.1
https://bit.ly/3uT3ZSu

- Иииии… обычный SDF сферы — это сокращение той же самой формулы!
#define SDF(p) length(vec3(PLANE_X, PLANE_Y, PLANE_Z))-.9
↓
#define SDF(p) length(p.xyz)-.9
↓
#define SDF(p) length(p)-.9
Я был в шоке, когда узнал об этом! 🤯
- Вот и всё! Попробуйте поиграть с кодом, интересные паттерны могут внезапно появиться https://bit.ly/3uSmvdO
Это мой первый туториал-тред. Буду благодарен, если поделитесь мыслями по теме, зададите вопросы или похвастаетесь SDF, которые откроете.
