Передача значений между точками входа 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. Я понятия не имею, как люди, у которых нет пары недель свободного времени, могут понять, как все это работает.