Workbench: Use eGPUSamplerState to change texture sampling behavior
This removes some fragment shader hacks and improve the support of different repeat & filtering modes. This fix T77453 Image texture not repeating in viewport
This commit is contained in:
parent
11ba9eec70
commit
1f6d1213d2
Notes:
blender-bot
2023-02-14 07:39:46 +01:00
Referenced by issue #78772, Textures do not tile in Viewport > Solid > Texture (works in 2.90, broken in 2.83 LTS) Referenced by issue #77453, Image texture not repeating in viewport, renders correctly (2.83.0 and 2.90)
|
@ -4,17 +4,20 @@ bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
|
|||
{
|
||||
vec2 tile_pos = floor(co.xy);
|
||||
|
||||
if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10)
|
||||
if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float tile = 10.0 * tile_pos.y + tile_pos.x;
|
||||
if (tile >= textureSize(map, 0).x)
|
||||
if (tile >= textureSize(map, 0).x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Fetch tile information. */
|
||||
float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x;
|
||||
if (tile_layer < 0.0)
|
||||
if (tile_layer < 0.0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0);
|
||||
|
||||
|
@ -22,59 +25,29 @@ bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
|
|||
return true;
|
||||
}
|
||||
|
||||
vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling)
|
||||
{
|
||||
/* TODO(fclem) We could do the same with sampler objects.
|
||||
* But this is a quick workaround instead of messing with the GPUTexture itself. */
|
||||
if (nearest_sampling) {
|
||||
/* Use texelFetch for nearest_sampling to reduce glitches. See: T73726 */
|
||||
vec2 tex_size = vec2(textureSize(image, 0).xy);
|
||||
ivec2 uv = ivec2(floor(coord * tex_size) + 0.5);
|
||||
return texelFetch(image, uv, 0);
|
||||
}
|
||||
else {
|
||||
return texture(image, coord);
|
||||
}
|
||||
}
|
||||
|
||||
vec4 workbench_sample_texture_array(sampler2DArray tile_array,
|
||||
sampler1DArray tile_data,
|
||||
vec2 coord,
|
||||
bool nearest_sampling)
|
||||
{
|
||||
|
||||
vec3 uv = vec3(coord, 0);
|
||||
if (!node_tex_tile_lookup(uv, tile_array, tile_data))
|
||||
return vec4(1.0, 0.0, 1.0, 1.0);
|
||||
|
||||
/* TODO(fclem) We could do the same with sampler objects.
|
||||
* But this is a quick workaround instead of messing with the GPUTexture itself. */
|
||||
if (nearest_sampling) {
|
||||
/* Use texelFetch for nearest_sampling to reduce glitches. See: T73726 */
|
||||
vec3 tex_size = vec3(textureSize(tile_array, 0));
|
||||
uv.xy = floor(uv.xy * tex_size.xy) + 0.5;
|
||||
return texelFetch(tile_array, ivec3(uv), 0);
|
||||
}
|
||||
else {
|
||||
return texture(tile_array, uv);
|
||||
}
|
||||
}
|
||||
|
||||
uniform sampler2DArray imageTileArray;
|
||||
uniform sampler1DArray imageTileData;
|
||||
uniform sampler2D imageTexture;
|
||||
|
||||
uniform float imageTransparencyCutoff = 0.1;
|
||||
uniform bool imageNearest;
|
||||
uniform bool imagePremult;
|
||||
|
||||
vec3 workbench_image_color(vec2 uvs)
|
||||
{
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
vec4 color;
|
||||
|
||||
# ifdef TEXTURE_IMAGE_ARRAY
|
||||
vec4 color = workbench_sample_texture_array(imageTileArray, imageTileData, uvs, imageNearest);
|
||||
vec3 co = vec3(uvs, 0.0);
|
||||
if (node_tex_tile_lookup(co, imageTileArray, imageTileData)) {
|
||||
color = texture(imageTileArray, co);
|
||||
}
|
||||
else {
|
||||
color = vec4(1.0, 0.0, 1.0, 1.0);
|
||||
}
|
||||
# else
|
||||
vec4 color = workbench_sample_texture(imageTexture, uvs, imageNearest);
|
||||
|
||||
color = texture(imageTexture, uvs);
|
||||
# endif
|
||||
|
||||
/* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
|
||||
|
@ -90,6 +63,7 @@ vec3 workbench_image_color(vec2 uvs)
|
|||
|
||||
return color.rgb;
|
||||
#else
|
||||
|
||||
return vec3(1.0);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -141,10 +141,10 @@ static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object
|
|||
struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
|
||||
if (geom) {
|
||||
Image *ima = imapaint->canvas;
|
||||
int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
|
||||
SHD_INTERP_CLOSEST;
|
||||
eGPUSamplerState state = GPU_SAMPLER_REPEAT;
|
||||
SET_FLAG_FROM_TEST(state, imapaint->interp == IMAGEPAINT_INTERP_LINEAR, GPU_SAMPLER_FILTER);
|
||||
|
||||
DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, interp);
|
||||
DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, state);
|
||||
DRW_shgroup_call(grp, geom, ob);
|
||||
}
|
||||
}
|
||||
|
@ -210,10 +210,10 @@ static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd,
|
|||
|
||||
const ImagePaintSettings *imapaint = use_texpaint_mode ? &scene->toolsettings->imapaint : NULL;
|
||||
Image *ima = (imapaint && imapaint->mode == IMAGEPAINT_MODE_IMAGE) ? imapaint->canvas : NULL;
|
||||
int interp = (imapaint && imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
|
||||
SHD_INTERP_CLOSEST;
|
||||
eGPUSamplerState state = 0;
|
||||
SET_FLAG_FROM_TEST(state, imapaint->interp == IMAGEPAINT_INTERP_LINEAR, GPU_SAMPLER_FILTER);
|
||||
DRWShadingGroup *grp = (use_texpaint_mode) ?
|
||||
workbench_image_hair_setup(wpd, ob, matnr, ima, NULL, interp) :
|
||||
workbench_image_hair_setup(wpd, ob, matnr, ima, NULL, state) :
|
||||
workbench_material_hair_setup(wpd, ob, matnr, color_type);
|
||||
|
||||
DRW_shgroup_hair_create_sub(ob, psys, md, grp);
|
||||
|
|
|
@ -101,31 +101,34 @@ BLI_INLINE Material *workbench_object_material_get(Object *ob, int mat_nr)
|
|||
}
|
||||
|
||||
BLI_INLINE void workbench_material_get_image(
|
||||
Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp)
|
||||
Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, eGPUSamplerState *r_sampler)
|
||||
{
|
||||
bNode *node;
|
||||
*r_sampler = 0;
|
||||
|
||||
ED_object_get_active_image(ob, mat_nr, r_image, r_iuser, &node, NULL);
|
||||
if (node && *r_image) {
|
||||
switch (node->type) {
|
||||
case SH_NODE_TEX_IMAGE: {
|
||||
NodeTexImage *storage = node->storage;
|
||||
*r_interp = storage->interpolation;
|
||||
const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST);
|
||||
const bool use_repeat = (storage->extension == SHD_IMAGE_EXTENSION_REPEAT);
|
||||
const bool use_clip = (storage->extension == SHD_IMAGE_EXTENSION_CLIP);
|
||||
SET_FLAG_FROM_TEST(*r_sampler, use_filter, GPU_SAMPLER_FILTER);
|
||||
SET_FLAG_FROM_TEST(*r_sampler, use_repeat, GPU_SAMPLER_REPEAT);
|
||||
SET_FLAG_FROM_TEST(*r_sampler, use_clip, GPU_SAMPLER_CLAMP_BORDER);
|
||||
break;
|
||||
}
|
||||
case SH_NODE_TEX_ENVIRONMENT: {
|
||||
NodeTexEnvironment *storage = node->storage;
|
||||
*r_interp = storage->interpolation;
|
||||
const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST);
|
||||
SET_FLAG_FROM_TEST(*r_sampler, use_filter, GPU_SAMPLER_FILTER);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert(!"Node type not supported by workbench");
|
||||
*r_interp = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*r_interp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true if the current material ubo has changed and needs to be rebind. */
|
||||
|
@ -164,11 +167,11 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
|
|||
{
|
||||
Image *ima = NULL;
|
||||
ImageUser *iuser = NULL;
|
||||
int interp;
|
||||
eGPUSamplerState sampler;
|
||||
const bool infront = (ob->dtx & OB_DRAWXRAY) != 0;
|
||||
|
||||
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
|
||||
workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp);
|
||||
workbench_material_get_image(ob, mat_nr, &ima, &iuser, &sampler);
|
||||
if (ima == NULL) {
|
||||
/* Fallback to material color. */
|
||||
color_type = V3D_SHADING_MATERIAL_COLOR;
|
||||
|
@ -177,7 +180,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
|
|||
|
||||
switch (color_type) {
|
||||
case V3D_SHADING_TEXTURE_COLOR: {
|
||||
return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, hair);
|
||||
return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, sampler, hair);
|
||||
}
|
||||
case V3D_SHADING_MATERIAL_COLOR: {
|
||||
/* For now, we use the same ubo for material and object coloring but with different indices.
|
||||
|
@ -247,13 +250,13 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
|
|||
int mat_nr,
|
||||
Image *ima,
|
||||
ImageUser *iuser,
|
||||
int interp,
|
||||
eGPUSamplerState sampler,
|
||||
bool hair)
|
||||
{
|
||||
GPUTexture *tex = NULL, *tex_tile_data = NULL;
|
||||
|
||||
if (ima == NULL) {
|
||||
workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp);
|
||||
workbench_material_get_image(ob, mat_nr, &ima, &iuser, &sampler);
|
||||
}
|
||||
|
||||
if (ima) {
|
||||
|
@ -284,13 +287,12 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
|
|||
|
||||
*grp_tex = grp = DRW_shgroup_create_sub(grp);
|
||||
if (tex_tile_data) {
|
||||
DRW_shgroup_uniform_texture(grp, "imageTileArray", tex);
|
||||
DRW_shgroup_uniform_texture_ex(grp, "imageTileArray", tex, sampler);
|
||||
DRW_shgroup_uniform_texture(grp, "imageTileData", tex_tile_data);
|
||||
}
|
||||
else {
|
||||
DRW_shgroup_uniform_texture(grp, "imageTexture", tex);
|
||||
DRW_shgroup_uniform_texture_ex(grp, "imageTexture", tex, sampler);
|
||||
}
|
||||
DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL));
|
||||
DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
|
||||
return grp;
|
||||
}
|
||||
|
|
|
@ -462,7 +462,7 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
|
|||
int mat_nr,
|
||||
Image *ima,
|
||||
ImageUser *iuser,
|
||||
int interp,
|
||||
eGPUSamplerState sampler,
|
||||
bool hair);
|
||||
|
||||
#define workbench_material_setup(wpd, ob, mat_nr, color_type, r_transp) \
|
||||
|
|
|
@ -458,6 +458,10 @@ void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
|
|||
float depth,
|
||||
uchar stencil);
|
||||
|
||||
void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup,
|
||||
const char *name,
|
||||
const struct GPUTexture *tex,
|
||||
eGPUSamplerState sampler_state);
|
||||
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup,
|
||||
const char *name,
|
||||
const struct GPUTexture *tex);
|
||||
|
|
|
@ -247,11 +247,19 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
|
|||
drw_shgroup_uniform_create_ex(shgroup, location, type, value, 0, length, arraysize);
|
||||
}
|
||||
|
||||
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
|
||||
void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup,
|
||||
const char *name,
|
||||
const GPUTexture *tex,
|
||||
eGPUSamplerState sampler_state)
|
||||
{
|
||||
BLI_assert(tex != NULL);
|
||||
int loc = GPU_shader_get_texture_binding(shgroup->shader, name);
|
||||
drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE, tex, GPU_SAMPLER_MAX, 0, 1);
|
||||
drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE, tex, sampler_state, 0, 1);
|
||||
}
|
||||
|
||||
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
|
||||
{
|
||||
DRW_shgroup_uniform_texture_ex(shgroup, name, tex, GPU_SAMPLER_MAX);
|
||||
}
|
||||
|
||||
void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
|
||||
|
@ -1278,8 +1286,7 @@ static void drw_shgroup_material_texture(DRWShadingGroup *grp,
|
|||
{
|
||||
GPUTexture *gputex = GPU_texture_from_blender(tex->ima, tex->iuser, NULL, textarget);
|
||||
|
||||
int loc = GPU_shader_get_texture_binding(grp->shader, name);
|
||||
drw_shgroup_uniform_create_ex(grp, loc, DRW_UNIFORM_TEXTURE, gputex, state, 0, 1);
|
||||
DRW_shgroup_uniform_texture_ex(grp, name, gputex, state);
|
||||
|
||||
GPUTexture **gputex_ref = BLI_memblock_alloc(DST.vmempool->images);
|
||||
*gputex_ref = gputex;
|
||||
|
|
Loading…
Reference in New Issue