Взаимодействие материала, текстуры и света
Я написал простую программу просмотра 3D-моделей (с использованием OpenGL 3.2 и GLSL), которая может загружать и отображать модели U3D (как автономные, так и из PDF-файла). Он может в основном визуализировать все различные сетки, нарисовать их по цвету вершины, текстуре или материалу и соответствующим образом осветить их.
Однако я не совсем понял, каков "ожидаемый способ" сочетания материалов и текстур. Я видел учебные пособия, которые освещают объекты, у которых есть материалы (с рассеянными / зеркальными / окружающими компонентами и фактором для непрозрачности и блеска), и другие учебные пособия, которые используют текстуры и освещают их, но я не нашел хороших ресурсов относительно того, что ожидалось Поведение - это когда они объединены (т.е. сетка имеет материал и один или несколько слоев текстуры).
Также в соответствии со спецификацией для формата файла U3D в их описании "LitTextureShader" я поддерживаю 4 различные функции наложения, которые определяют, как один слой текстуры комбинируется с результатом из предыдущих:
// Multiply
blended = current * previous;
// Add
blended = clamp(current + previous, 0.0, 1.0);
// Replace
blended = current;
// Blend
blended = mix( previous , current, current.a );
Первоначально я думал, что это просто применяется между слоями текстуры, но когда я смотрю на модели в Adobe Reader, эти операции наложения, кажется, иногда применяются также и между текстурой и материалом, но результат никогда не будет таким, как я ожидал (и выглядит совсем не так, как мой результат), поэтому я предположил, что есть некоторая основополагающая часть, которую я не до конца понял.
Для своих тестов я создал сетку из одного треугольника, красного материала и двух текстур шахматной доски:
а также
Мой фрагментный шейдер обычно выглядит так (сокращенно и упрощенно, без учета зеркального или испускаемого света):
// uniforms, lights etc
// ...
// material input
flat in vec4 matDiffuse;
flat in float matOpacity;
// ...
// globals
vec3 accumulatedLight = vec3(0.0);
vec4 currAmbientColor = vec4(0.0);
vec4 currDiffuseColor = vec4(0.0);
float currOpacity = 1.0;
// ...
// lighting
void AddLightOutput()
{
// add ambient
vec3 ambientTerm = vec3(0.0);
if( Lights.enableAmbient == 1 )
{
ambientTerm = (vec3(currAmbientColor) * vec3(Lights.ambientIntensity));
}
// add diffuse and specular
vec3 diffuseTerm = vec3(0.0);
for( int index = 0; index < NUMBER_OF_LIGHTS; index++ )
{
// calculate ...
diffuseTerm += vec3(lgt.diffuse) * lightDot * attenuation;
// specular (disregard for now)
// ...
}
// add up results results
accumulatedLight = ambientTerm + (diffuseTerm * vec3(currDiffuseColor));
}
void main()
{
// set up colors and opacity
currDiffuseColor = texture(texSampler0, vertTexCoord0) * vec4( vec3(texIntensity0), 1.0 );
currOpacity = matOpacity;
// apply material-texture interaction ?
// ??
// iterate all lights
AddLightOutput();
// set result color
resultColor = vec4(accumulatedLight, currOpacity);
}
[Дополнительный вопрос: я храню все материалы в буфере текстурных объектов, а вершинный шейдер выбирает материал на основе униформы и передает его фрагментному шейдеру (вычерчивая / вставляя) - не уверен, что это хорошая идея (у некоторых из загруженных мною моделей было несколько сотен или даже более тысячи материалов, поэтому я попробовал это так)?]
Итак, основываясь на вышеупомянутом шейдере, я попробовал два случая, в одном из которых одна текстура (сине-зеленая шахматная доска) сочетается с красным материалом, а смешивание текстуры в первом случае установлено на "умножение", а во втором - на " добавить " (ни текстура, ни материал не должны быть полупрозрачными)
Мой шейдер:
// add base color info
currDiffuseColor = texture(texSampler0, vertTexCoord0) * vec4( vec3(texIntensity0), 1.0 );
// modify color according to blend factors
currOpacity = matOpacity * currDiffuseColor.a;
currDiffuseColor = matDiffuse * currDiffuseColor;
Это заставило меня поверить, что я на правильном пути, и материал и текстура должны быть обработаны, чтобы получить правильный результат, но затем добавить шейдер:
// add base color info
currDiffuseColor = texture(texSampler0, vertTexCoord0) * vec4( vec3(texIntensity0), 1.0 );
// modify color according to blend factors
currOpacity = matOpacity;
currDiffuseColor = vec4( clamp(matDiffuse + currDiffuseColor, 0.0, 1.0).rgb, currDiffuseColor.a );
и результат:
что заставило меня думать, что материал не должен влиять на это. Поэтому я также попробовал использовать две текстуры (те шахматные доски, которые, между прочим, не имеют прозрачности), которые должны быть добавлены друг к другу:
// set up colors and opacity
currDiffuseColor = texture(texSampler0, vertTexCoord0) * vec4( vec3(texIntensity0), 1.0 );
vec4 texLayer1 = texture(texSampler1, vertTexCoord1) * vec4( vec3(texIntensity1), 1.0 );
currDiffuseColor = vec4( clamp(currDiffuseColor + texLayer1, 0.0, 1.0).rgb, texLayer1.a );
Мой код добавляет это вместе, в то время как Adobe Reader, кажется, просто показывает слой текстуры 0.
Также, например, если я установлю U3D, чтобы сделать слой текстуры прозрачным (и использую константу наложения), Adobe даст мне следующее:
Однако Adobe, похоже, не принимает во внимание значение этой константы смешения, поэтому я снова получаю разные результаты.
Таким образом, все эти результаты приводят меня в замешательство, так как "обычно" текстуры и материалы должны влиять друг на друга. По сути, результат не обязательно должен быть точно таким же, как у Adobe, но я хотел бы получить предсказуемые результаты, чтобы кто-то, кто создает модель, мог знать, чего ожидать, основываясь на "типичном поведении" программного обеспечения для моделирования или рендеринга.
Если у меня будет прозрачность материала и текстуры, они будут умножены друг на друга? Разве только слои текстуры должны смешиваться / добавлять / размножаться / заменять друг друга или также взаимодействовать с материалом? Является ли материал единственным фактором для освещения? Или свет должен быть рассчитан на текстуру (ы)? Мне кажется, что результаты Adobe противоречивы, но, может быть, мне не хватает понимания.
Для справки я загрузил примеры PDF-файлов, которые я создал, в этот zip-архив: https://s3.amazonaws.com/drabeck/stackru/TestPDF3Ds.zip - он также содержит снимки экрана, созданные в моем приложении, а также текстовые файлы (IDTF) Я использовал для создания U3D (и с этого PDF).