Диффузное освещение для движущегося объекта - PullRequest
3 голосов
/ 07 февраля 2020

При расчете рассеянного освещения для движущегося объекта мне нужно переместить источник света вместе с самим объектом:

@Override
public void draw() { // draw frame
  ...
  // Move object
  GLES20.glVertexAttribPointer(aPositionLink, 3, GLES30.GL_FLOAT,
                    false, 0, object3D.getVertices());
  // The luminous source moves nearby the object, so the 
  // object is always illuminated from one side
  GLES20.glUniform3f(lightPositionLink, object3D.getX(),
        object3D.getY(), object3D.getZ() + 2.0f);
  ...
}

Фрагмент вершинного шейдера:

#version 300 es
uniform mat4 u_mvMatrix; // model-view matrix of object
uniform vec3 u_lightPosition; // position of the luminous source
in vec4 a_position; // vertex data is loaded here
in vec3 a_normal; // normal data is loaded here
struct DiffuseLight { 
  vec3 color; 
  float intensity; 
};
uniform DiffuseLight u_diffuseLight;
...
void main() {
  ...
  vec3 modelViewNormal = vec3(u_mvMatrix * vec4(a_normal, 0.0));
  vec3 modelViewVertex = vec3(u_mvMatrix * a_position);
  // calculate the light vector by subtracting the
  // position of the object from the light position
  vec3 lightVector = normalize(u_lightPosition - modelViewVertex);
  float diffuse = max(dot(modelViewNormal, lightVector), 0.1);
  float distance = length(u_lightPosition - modelViewVertex);
  diffuse = diffuse * (1.0 / (1.0 + pow(distance, 2.0)));
  // calculate the final color for diffuse lighting
  lowp vec3 diffuseColor = diffuse * u_diffuseLight.color * u_diffuseLight.intensity;
  v_commonLight = vec4((ambientColor + diffuseColor), 1.0);
  ...
}

Это правильный подход? Или есть другой рациональный вариант со стационарным источником света, чтобы не тратить ресурсы на вычисление положения источника света в каждом кадре? Примечание: увеличение расстояния не помогает. Заранее спасибо.

РЕШЕНИЕ:

По совету Rabbid76 я применил направленный свет:

#version 300 es
const vec3 directionLight = vec3(0.7, 0.0, -1.0); // directional light vector
...
void main() {
  ...
  vec3 modelViewNormal = vec3(u_mvMatrix * vec4(a_normal, 0.0));
  float diffuse = max(-dot(modelViewNormal, directionLight), 0.0);
  lowp vec3 diffuseColor = diffuse * u_diffuseLight.color * u_diffuseLight.intensity;
  v_commonLight = vec4((ambientColor + diffuseColor), 1.0);
  ...
}

1 Ответ

5 голосов
/ 07 февраля 2020

Мне нужно переместить источник света вместе с самим объектом

Почему источник света движется вместе с объектом?

Если свет является точечным источником света в мире, и объект движется, то освещение объекта изменяется (в «реальном» мире).

В вашем случае, Освещение рассчитывается в пространстве зрения. Если источником света является точка в мире, то вам нужно преобразовать положение с помощью матрицы вида (матрица вида преобразуется из мирового пространства в пространство просмотра). Например:

uniform mat4 u_viewMatrix;

void main()
{
    // [...]

    vec3 lightPosView = vec3(u_viewMatrix * vec4(u_lightPosition.xyz, 1.0)); 
    vec3 lightVector  = normalize(u_lightPosition - modelViewVertex);

    // [...]
}

В любом случае, если объект перемещается и источник света каким-либо образом привязан к объекту, необходимо применить преобразования, которые применяются к вершинам объекта, к источник света тоже.
В этом случае u_lightPosition должна быть позицией в пространстве модели объекта, то есть она относительно объекта (u_lightModelPosition). Тогда вы можете сделать:

uniform vec3 u_lightModelPosition; 

void main()
{
    mat3 normalMat       = inverse(transpose(mat3(u_mvMatrix)));
    vec3 modelViewNormal = normalMat * a_normal;
    vec3 modelViewVertex = vec3(u_mvMatrix * a_position);
    vec3 modelViewLight  = vec3(u_mvMatrix * vec4(u_lightModelPosition, 1.0));

    vec3 lightVector = normalize(modelViewLight - modelViewVertex);

    // [...]
}

Если вы хотите источник света, который не зависит от позиции, вы должны использовать направленный источник света. В этом случае источник света - это не точка в мире, а только направление. Например:

vec3 lightVector = -u_lightRayDirection;

u_lightRayDirection должно быть в пространстве легких расчетов. Поскольку освещение вычисляется в пространстве обзора, u_lightRayDirection также должно быть направлением в пространстве обзора. Если u_lightRayDirection является вектором в мировом пространстве, то его необходимо преобразовать в mat3(u_viewMatrix).
Направленный источник света не имеет расстояния (или постоянного расстояния).


Если источник света Источник привязан к камере, никакие преобразования не требуются вообще (потому что вы вычисляете свет в пространстве обзора).

...