GLSL шейдер — тень между 2 текстурами на плоскости

#opengl #textures #glsl #shadow #plane

#opengl #Текстуры #glsl #тень #плоскость

Вопрос:

Я пишу игру с помощью AGK (App Game Kit), и я хотел сделать несколько теней с помощью шейдеров. (На данный момент AGK поддерживает только GLSL 1.20)

В моей игре у меня есть объект plane, где у меня есть 2 текстуры. Первая текстура — это текстура фона, а вторая — текстура переднего плана с прозрачным контуром, где мы видим текстуру фона (они похожи на стены), и у меня есть подсветка указателя.

Вот пример (слева — то, что у меня есть, справа — то, что я хочу) :

пример

И вот код :

 attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;

varying vec2 uvVarying;
varying vec3 normalVarying;
varying vec3 posVarying;

uniform vec4 uvBounds0;

uniform mat4 agk_World;
uniform mat4 agk_ViewProj;
uniform mat3 agk_WorldNormal;

void main()
{
    vec4 pos = agk_World * vec4(position,1);
    gl_Position = agk_ViewProj * pos;
    vec3 norm = agk_WorldNormal * normal;
    posVarying = pos.xyz;
    normalVarying = norm;
    uvVarying = uv * uvBounds0.xy   uvBounds0.zw;
}
  

И :

 uniform sampler2D texture0;
uniform sampler2D texture1;

varying vec2 uvVarying;
varying vec3 normalVarying;
varying vec3 posVarying;

uniform vec2 playerPos;
uniform vec2 agk_resolution;
uniform vec4 agk_PLightPos;
uniform vec4 agk_PLightColor;
uniform vec4 agk_ObjColor;

void main (void)
{
    vec4 lightPos = agk_PLightPos;
    lightPos.x = playerPos.x;
    lightPos.y = playerPos.y;


    vec3 dir = vec3(lightPos.x - posVarying.x, lightPos.y   posVarying.y, lightPos.z - posVarying.z);
    vec3 norm = normalize(normalVarying);
    float atten = dot(dir,dir);
    atten = clamp(lightPos.w/atten,0.0,1.0);
    float intensity = dot(normalize(dir),norm);
    intensity = clamp(intensity,0.0,1.0);
    vec3 color = agk_PLightColor.rgb * intensity * atten;

    if (texture2D(texture0, uvVarying).a == 0) {
        gl_FragColor = texture2D(texture1, uvVarying) * vec4(color,1) * agk_ObjColor;
    }
    else {
        gl_FragColor = texture2D(texture0, uvVarying) * agk_ObjColor;
    }
}
  

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

Итак, код выполняет левый пример изображения, и я хотел бы знать, можно ли рассчитать свет, чтобы он останавливался, если он проходит через непрозрачный фрагмент второй текстуры? Так что это похоже на правильный пример изображения.

Я много искал, но нашел только примеры теней с шейдерами с 3D-объектами, как создать карту теней и т. Д… но можете ли вы рассчитать это между 2 текстурами на одном объекте?

Ответ №1:

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

 bool inTheShadow = false;
//Check if you're in the light range
if (intensity>0){
  vec2 delta = dir.xy / numSamples; //You can either use constant number of samples, or base it on the distance to the light source
  vec2 currentPointer = vec2(posVarying.x,posVarying.y);
  for (int i=0; i<numSamples ; i  ){
    xxx //Calculate uv for currentPointer
    if(texture2D(texture0, YOUR_NEW_UV).a > 0){
      inTheShadow = true;
      break;
    }
    currentPointer  = delta;
  }
}
  

Это должно сработать. Вам нужно только вычислить YOUR_NEW_UV в строке, отмеченной «xxx». Я надеюсь, что вы понимаете эту идею. В основном вам нужно протестировать видимые UV между текущим пикселем и источником света и проверить, является ли текстура стены ровной на всем пути.