#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 между текущим пикселем и источником света и проверить, является ли текстура стены ровной на всем пути.