Смешивание карты освещения с диффузной текстурой

Я использую c++, opengl 4.0 и язык шейдеров glsh.

Мне интересно, как правильно смешать диффузную текстуру с текстурой карты освещения.

Предположим, что у нас есть комната. Каждый объект имеет диффузную текстуру и карту освещения. На каждом форуме типа gamedev.net или stackoverflow люди говорят, что эти текстуры надо множить. И в большинстве случаев это дает хорошие результаты, но иногда некоторые объекты находятся очень близко к источнику света (например, белая лампочка). Этот источник света для близких объектов генерирует белую карту освещения. Но когда мы умножаем диффузную текстуру на белую карту освещения, мы получаем исходный цвет диффузной текстуры.

Но если источник света находится близко к какому-либо объекту, то цвет света должен быть доминирующим

Это означает, что если белый сильный свет близок к красной стене, то какая-то часть этой стены должна быть белой, а не красной!

Я думаю, мне нужно что-то большее, чем просто карта освещения. Lightmap не имеет информации об интенсивности света. Это значит, что самый блестящий цвет — это как раз максимально рассеянный цвет.

Может быть, у меня должно быть 2 текстуры - карта теней и карта освещения? Тогда уравнения должны выглядеть так:

vec3 color = shadowmapColor * diffuseTextureColor + lightmapColor;

Это хороший подход?


person majakthecoder    schedule 04.09.2013    source источник
comment
Это похоже на зеркальное освещение, когда вы видите отражение света в объекте. Во многих системах освещения возможно иметь цвет отражения, отличный от цвета рассеяния, или даже отдельную текстуру отражения, показывающую, какие части объекта блестят...   -  person jcoder    schedule 04.09.2013
comment
@jcoder, зеркальное освещение зависит от вида, и у меня много статического освещения. Так что я не могу использовать какое-либо динамическое освещение - только статические карты (lightmaps, shadowmas или что-то еще)   -  person majakthecoder    schedule 04.09.2013
comment
Ах, хорошо, это была всего лишь мысль (отсюда комментарий, а не ответ)   -  person jcoder    schedule 04.09.2013


Ответы (2)


Вообще говоря, если вы все еще используете карты освещения, вы, вероятно, также не используете рендеринг HDR. А без того то, что вы хотите, не особо разумно. Если ваша карта освещения не предоставляет интенсивность света в виде значения HDR с плавающей запятой (возможно, в формате GL_R11F_G11F_B10F или GL_RGBA16F), это не будет работать очень хорошо.

И, конечно же, вам придется делать обычные вещи, которые вы делаете с HDR, такие как отображение тонов и так далее.

Наконец, ваше аддитивное уравнение не имеет смысла. Если цвет карты освещения представляет диффузное взаимодействие между светом и поверхностью, то простое добавление цвета карты освещения ничего не значит. Стандартное уравнение диффузного освещения — C * (dot(N, L) * I * D), где I — интенсивность света, D — коэффициент ослабления на расстоянии, а C — диффузный цвет. Значение из карты освещения предположительно является величиной в скобках. Так что добавлять смысла нет.

Его все еще нужно умножить на диффузный цвет поверхностей. Любое чрезмерное осветление будет связано с эффективной интенсивностью света как функцией D.

person Nicol Bolas    schedule 04.09.2013
comment
HDR дает отличное качество, но это довольно сложно. Я думаю, что мне нужна обычная карта освещения с дополнительной информацией (например, сохраненной в альфа-канале) с интенсивностью. Если интенсивность › 1.0, то объект будет чрезмерно осветлен светлым цветом. К сожалению, 3d studio max не включает такую ​​информацию в карты освещения... значит, HDR - единственное решение? - person majakthecoder; 04.09.2013
comment
@majakthecoder: HDR — правильное решение. HDR (или, скорее, отсутствие реальности, чтобы соответствовать фиксированному динамическому диапазону интенсивности света) — вот почему эффект происходит в реальности (и в действительности красный объект не становится полностью белым, если интенсивность света не огромный). Если вы просто хотите собрать что-то, что может/вроде/вроде нормально работает, вы можете делать все, что захотите. - person Nicol Bolas; 05.09.2013

Что вам нужно, так это расстояние (или, чтобы сэкономить немного, квадрат расстояния) источника света до освещаемого фрагмента. Затем вы можете, в простейшем случае, линейно интерполировать между картой освещения и вкладом источника света:

Расстояние — это простой расчет, который можно выполнить для каждой вершины в вашем вершинном шейдере:

in      vec4  VertexPosition; // let's assume world space for simplicity
uniform vec4  LightPosisiton; // world-space - might also be part of a uniform block etc.
out     float LightDistance;  // pass the distance to the fragment shader

// other stuff you need here ....

void main()
{
  // do stuff 
  LightDistance = length(VertexPosition - LightPosisiton);
}

В вашем фрагментном шейдере вы используете расстояние для вычисления коэффициентов интерполяции между вкладами источника света и карты освещения:

in      float     LightDistance;
const   float     MAX_DISTANCE = 10.0;
uniform sampler2D LightMap;

// other stuff ...

out vec4 FragColor;

void main()
{
  vec4 LightContribution;
  // calculate illumination (including shadow map evaluation) here
  // store in LightContribution

  vec4 LightMapConstribution = texture(LightMap, /* tex coords here */);

  // The following DistanceFactor will map distances in the range [0, MAX_DISTANCE] to
  // [0,1]. The idea is that at LightDistance >= MAX_DISTANCE, the light source
  // doesn't contribute anymore.
  float DistanceFactor  = min(1.0, LightDistance / MAX_DISTANCE); 

  // linearly interpolat between LightContribution and LightMapConstribution 
  vec4 FinalContribution = mix(LightContribution, LightMapConstribution, DistanceFactor);

  FragColor = WhatEverColor * vec4(FinalContribution.xyz, 1.0);
}

ХТН.

РЕДАКТИРОВАТЬ: чтобы учесть замечания Никола Боласа, я предполагаю, что LightMap хранит вклад, закодированный как цвет RGB, сохраняя вклады для каждого канала. Если у вас на самом деле есть карта освещения с одним каналом, которая хранит только монохроматические вклады, вам придется либо использовать цвет поверхности, либо использовать цвет источника света, либо уменьшить вклад источника света в один канал.

EDIT2: хотя это работает математически, это определенно не правильно физически. Возможно, вам потребуется некоторая коррекция окончательного вклада, чтобы сделать его хотя бы физически правдоподобным. Если вы стремитесь только к эффекту, вы можете просто поиграть с поправочными коэффициентами, пока не будете удовлетворены результатом.

person thokra    schedule 04.09.2013
comment
Спасибо за это предложение, но я не хочу использовать динамическое освещение, потому что у меня много источников света, и все они статичны. Поэтому мне нужны карты освещения (с поддержкой 3d studio max) - person majakthecoder; 04.09.2013
comment
Блин, невнимательно прочитал твой пост. Ну, это 20 минут потраченных впустую... :) - person thokra; 04.09.2013
comment
Ваше предположение, что мне нужно расстояние до источника света, верно ;) Единственная разница в том, что мне нужно, чтобы это расстояние вычислялось при создании карт освещения. - person majakthecoder; 04.09.2013