Передача значений между точками входа SCNShadable

В программе OpenGL вы обычно объявляете что-то подобное в вершинном шейдере

varying bool aBooleanVariable;

и затем прочитайте значение в фрагментном шейдере. Как вы делаете это в рамках SCNShadable точка входа? Например из SCNShaderModifierEntryPointGeometry в SCNShaderModifierEntryPointFragment,

Кажется, что получение аргумента определяется с помощью аргументов прагмы, я предоставляю свой тест SCNShaderModifierEntryPointFragment проиллюстрировать.

#pragma arguments
bool clipFragment

#pragma body

if (clipFragment) {
    discard_fragment();
}

Однако прагма arguments не работает для вывода значения в SCNShaderModifierEntryPointGeometry точка входа.

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

3 ответа

Решение

Вынужден использовать GLSL

Оказывается, вы можете заставить его работать, если вы переключите SCNView API рендеринга в OpenGL ES. Затем он примет код GLSL, включая изменяющийся квалификатор.

Точка входа в геометрию

varying float clipFragment;

#pragma body
clipFragment = 1.0;

Точка входа фрагмента

varying float clipFragment;

#pragma body
if (clipFragment > 0.0) {
    discard;
}

Обновление от Apple

Я открыл билет с Apple и получил следующий ответ -

Правильно. Команда SceneKit открыла официальный запрос на усовершенствование (ошибка № 28206462), чтобы изучить возможность добавления этой возможности в Metal. До тех пор вы должны будете использовать рендерер OpenGL.

У меня была похожая проблема, и мне удалось найти решение. Я не уверен, как далеко это работает, но это работает на XCode 9 с iOS 11. Вот пример поиска пользовательской текстуры кубической карты, используя переменную float3 для координаты.

Модификатор геометрии:

#include <metal_stdlib>

#pragma varyings
float3 cubemapCoord;

#pragma body;
out.cubemapCoord = _geometry.normal;

Модификатор поверхности:

#include <metal_stdlib>

#pragma arguments
texturecube<float> texture;

#pragma body
constexpr sampler s(filter::linear, mip_filter::linear);
_surface.diffuse = texture.sample(s, in.cubemapCoord);

И код Swift для назначения материала:

do {
    let loader = MTKTextureLoader.init(device: MTLCreateSystemDefaultDevice()!)
    let url = Bundle.main.url(forResource: "cubemap", withExtension: "pvr", subdirectory: "art.scnassets")!
    let texture = try loader.newTexture(URL: url, options: nil)
    let materialProperty = SCNMaterialProperty.init(contents: texture)
    geometry.setValue(materialProperty, forKey: "texture")
} catch {
    print(error.localizedDescription)
}

В какой-то момент вы столкнетесь с тем, что можно сделать с SCNShadable и нужно перейти на SCNProgram, К сожалению, это означает, что вам необходимо обеспечить полную реализацию вершинного и фрагментного шейдеров. С другой стороны, довольно просто передать значение из вершины в фрагментный шейдер. Вы просто добавляете переменную в структуру, которую вы идентифицируете с stage_in квалификатор (при условии, что вы используете металл). Но это не совсем то, что вы просили, и для этого есть обходной путь.

#pragma arguements как вы заметили, не будет работать в этом случае; это для передачи констант, которые не меняются в течение прохода рендеринга.

Вместо этого я бы посоветовал вам взглянуть на изменение одной из существующих переменных, которые SceneKit использует в своем шейдере. Теперь вы, несомненно, заметили, что SceneKit сбрасывает свой исходный код шейдера на стандартный вывод, когда он не может скомпилироваться. Металлический шейдер определяет commonprofile_io Структура, которая передается из вершины в фрагментный шейдер, включает в себя: положение, цвет, координаты текстуры, нормали и т. д. Если вы не используете цвета вершин, то можно использовать это для хранения 4 значений с плавающей запятой (rgba). Важно отметить, что SceneKit оптимизирует шейдер для визуализируемого источника геометрии; если ваш источник геометрии не содержит цвета вершин, то commonprofile_io структура не будет иметь vertexColor переменная.

Было бы очень интересно узнать о лучшем решении.

Я тоже борюсь с этим вопросом, и я сделал недавнее открытие, которое широко открыло для меня эту вещь. Это очень помогло мне понять, как SceneKit, шейдеры, модификаторы шейдеров и OpenGL/Metal работают вместе и какие инструменты / методы доступны при написании модификатора шейдера. Более того, я считаю, что принятый в настоящее время ответ уже неверен (к счастью!).

SceneKit предоставляет по умолчанию шейдеры вершин и фрагментов Metal. Именно в эти шейдеры вводятся модификаторы шейдеров. Вы можете найти эти металлические шейдеры по умолчанию при захвате кадра графического процессора в Xcode. Дважды щелкните либоcommonprofile_vert или commonprofile_frag (оба шейдера находятся внутри одного "файла", что демонстрируется одинаковыми значениями в столбце "Подробности").

В этом файле много информации, и он демонстрирует некоторые внутренние механизмы взаимодействия SceneKit с графическим процессором при рендеринге. Это пример файла (хотя этой версии уже несколько лет, но она все еще является образцовой).

Обратите внимание на то, что следующие строки - это места для инъекций модификаторов шейдера.

// DoLightModifier START

// DoLightModifier END

...

// DoGeometryModifier START

// DoGeometryModifier END

...

// DoSurfaceModifier START

// DoSurfaceModifier END

...

// DoFragmentModifier START

// DoFragmentModifier END

Вы увидите, что здесь размещены модификаторы шейдера.

Искать #ifdef USE_EXTRA_VARYINGS. любойvarying переменные, которые вы объявляете в модификаторе геометрии, отображаются как свойство на commonprofile_ioструктуры. Из них вы используете следующий экземпляр:commonprofile_io out;.

Этот файл также демонстрирует, зачем вам varyingsдля связи между геометрией и фрагментным шейдером. И почему_surface доступен во фрагментном шейдере: модификатор фрагмента и модификатор поверхности имеют одинаковую область действия.

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

Другие вопросы по тегам