GLSL mixing base texture with decal texture at needed place

♀尐吖头ヾ 提交于 2019-12-10 11:58:06

问题


Lets say we texturing quad (two triangles). I think what this question is similiar to texture splatting like in next example

precision lowp float;

uniform sampler2D Terrain;
uniform sampler2D Grass;
uniform sampler2D Stone;
uniform sampler2D Rock;

varying vec2 tex_coord;

void main(void)
{
vec4 terrain = texture2D(Terrain, tex_coord);
vec4 tex0    = texture2D(Grass, tex_coord * 4.0); // Tile
vec4 tex1    = texture2D(Rock,  tex_coord * 4.0); // Tile
vec4 tex2    = texture2D(Stone, tex_coord * 4.0); // Tile

tex0 *= terrain.r; // Red channel - puts grass
tex1 = mix( tex0, tex1, terrain.g ); // Green channel - puts rock and mix with grass 
vec4 outColor = mix( tex1, tex2, terrain.b ); // Blue channel - puts stone and mix with others

gl_FragColor = outColor; //final color
}

But i want to just place a 1 decal on base quad texture in desired place.
Algorithm is just the same, but i think we don't need extra texture with 1 filled layer to hold positions(e.g. where red layer != 0) of decal, some how we must generate our own "terrain.r"(is this float?) variable and mix base texture and decal texture with it.

precision lowp float;

uniform sampler2D base;
uniform sampler2D decal;
uniform vec2 decal_location; //where we want place decal (e.g. 0.5, 0.5 is center of quad)

varying vec2 base_tex_coord;
varying vec2 decal_tex_coord;

void main(void)
{
vec4 v_base = texture2D(base, base_tex_coord);
vec4 v_decal = texture2D(Grass, decal_tex_coord);
float decal_layer = /*somehow get our decal_layer based on decal_position*/

gl_FragColor = mix(v_base, v_decal, decal_layer);
}

How achieve such thing?
Or i may just generate splat texture on opengl side and pass it to first shader? This will give me up to 4 various decals on quad but will be slow for frequent updates (e.g. machine gun hits wall)


回答1:


Yes, decal_layer is a float as you've described. Its range is 0 to 1. But you don't have quite enough info, here you've specified decal_location but no size for the decal. You also don't know where this fragment falls in the quad, you'll need a varying vec2 quad_coord; or similar input from the vertex shader if you want to know where this fragment is relative to the quad being rendered.

But let's try a different approach. Edit the top of your 2nd example to include these uniforms:

uniform vec2 decal_location; // Location of decal relative to base_tex_coord uniform float decal_size; // Size of decal relative to base_tex_coord

Now, in main(), you should be able to compute decal_layer with something like this:

float decal_layer = 1.0 - smoothstep(decal_size - 0.01, decal_size, max(abs(decal_location.x - base_tex_coord.x), abs(decal_location.y - base_tex_coord.y)));

Basically you're trying to get decal_layer to be 1.0 within the decal, and 0.0 outside the decal. I've added a 0.01 fuzzy edge at the boundary that you can play with. Good luck!




回答2:


float decal_layer = /*somehow get our decal_layer based on decal_position*/

Well, it's up to you, how you interpret decal_position. I think a simple distance metric would suffice. but this also requires the size of the quad. Let's assume you provide this through an additional uniform decal_radius. Then we can use

decal_layer = clamp(length(decal_position - vec2(0.5, 0.5)) / decal_radius, 0., 1.);


来源:https://stackoverflow.com/questions/9973466/glsl-mixing-base-texture-with-decal-texture-at-needed-place

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!