Workbench: Support node texture "closest" interpolation option

This makes it possible to paint pixel art using the workbench.

Cubic interpolation is not supported but could be added if needed.
This commit is contained in:
Clément Foucault 2018-12-23 15:20:06 +01:00
parent 1459a70489
commit 9177bb33f6
7 changed files with 71 additions and 45 deletions

View File

@ -159,3 +159,13 @@ vec4 srgb_to_linearrgb(vec4 col_from)
col_to.a = col_from.a;
return col_to;
}
vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool srgb, bool nearest_sampling)
{
vec2 tex_size = vec2(textureSize(image, 0).xy);
/* TODO(fclem) We could do the same with sampler objects.
* But this is a quick workaround instead of messing with the GPUTexture itself. */
vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord;
vec4 color = texture(image, uv);
return (srgb) ? srgb_to_linearrgb(color) : color;
}

View File

@ -2,6 +2,7 @@
uniform float ImageTransparencyCutoff = 0.1;
uniform sampler2D image;
uniform bool imageSrgb;
uniform bool imageNearest;
uniform mat4 ProjectionMatrix;
uniform mat4 ViewMatrixInverse;
@ -35,13 +36,10 @@ void main()
vec4 diffuse_color;
#ifdef V3D_SHADING_TEXTURE_COLOR
diffuse_color = texture(image, uv_interp);
diffuse_color = workbench_sample_texture(image, uv_interp, imageSrgb, imageNearest);
if (diffuse_color.a < ImageTransparencyCutoff) {
discard;
}
if (imageSrgb) {
diffuse_color = srgb_to_linearrgb(diffuse_color);
}
#else
diffuse_color = vec4(materialDiffuseColor, 1.0);
#endif /* V3D_SHADING_TEXTURE_COLOR */

View File

@ -7,6 +7,7 @@ uniform float materialRoughness;
uniform sampler2D image;
uniform float ImageTransparencyCutoff = 0.1;
uniform bool imageSrgb;
uniform bool imageNearest;
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
in vec3 normal_viewport;
@ -37,13 +38,10 @@ void main()
vec4 color;
# ifdef V3D_SHADING_TEXTURE_COLOR
color = texture(image, uv_interp);
color = workbench_sample_texture(image, uv_interp, imageSrgb, imageNearest);
if (color.a < ImageTransparencyCutoff) {
discard;
}
if (imageSrgb) {
color = srgb_to_linearrgb(color);
}
# else
color.rgb = materialDiffuseColor;
# endif

View File

@ -709,7 +709,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata)
}
static WORKBENCH_MaterialData *get_or_create_material_data(
WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int color_type)
WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int color_type, int interp)
{
WORKBENCH_StorageList *stl = vedata->stl;
WORKBENCH_PassList *psl = vedata->psl;
@ -725,6 +725,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.interp = interp;
uint hash = workbench_material_get_hash(&material_template, is_ghost);
material = BLI_ghash_lookup(wpd->material_hash, POINTER_FROM_UINT(hash));
@ -736,7 +737,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
workbench_material_copy(material, &material_template);
DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1);
workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, true);
workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, true, interp);
BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material);
}
@ -764,11 +765,12 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
if (draw_as == PART_DRAW_PATH) {
Image *image = NULL;
Material *mat = give_current_material(ob, part->omat);
ED_object_get_active_image(ob, part->omat, &image, NULL, NULL, NULL);
Material *mat;
Image *image;
int interp;
workbench_material_get_image_and_mat(ob, part->omat, &image, &interp, &mat);
int color_type = workbench_material_determine_color_type(wpd, image, ob);
WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, color_type);
WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, color_type, interp);
struct GPUShader *shader = (color_type != V3D_SHADING_TEXTURE_COLOR) ?
wpd->prepass_solid_hair_sh :
@ -779,7 +781,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o
shader);
DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1);
workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, true);
workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, true, interp);
}
}
}
@ -829,11 +831,12 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
for (int i = 0; i < materials_len; i++) {
if (geom_array != NULL && geom_array[i] != NULL) {
Material *mat = give_current_material(ob, i + 1);
Material *mat;
Image *image;
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
int interp;
workbench_material_get_image_and_mat(ob, i + 1, &image, &interp, &mat);
int color_type = workbench_material_determine_color_type(wpd, image, ob);
material = get_or_create_material_data(vedata, ob, mat, image, color_type);
material = get_or_create_material_data(vedata, ob, mat, image, color_type, interp);
DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob);
}
}
@ -842,7 +845,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
V3D_SHADING_SINGLE_COLOR, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR))
{
/* Draw solid color */
material = get_or_create_material_data(vedata, ob, NULL, NULL, wpd->shading.color_type);
material = get_or_create_material_data(vedata, ob, NULL, NULL, wpd->shading.color_type, 0);
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
}
@ -858,7 +861,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
if (is_sculpt_mode) {
/* Multiple materials are not supported in sculpt mode yet. */
Material *mat = give_current_material(ob, 1);
material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR);
material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
}
else {
@ -870,7 +873,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
for (int i = 0; i < materials_len; ++i) {
if (geoms != NULL && geoms[i] != NULL) {
Material *mat = give_current_material(ob, i + 1);
material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR);
material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
DRW_shgroup_call_object_add(material->shgrp, geoms[i], ob);
}
}

View File

@ -139,7 +139,7 @@ static void workbench_init_object_data(DrawData *dd)
}
static WORKBENCH_MaterialData *get_or_create_material_data(
WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int color_type)
WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int color_type, int interp)
{
WORKBENCH_StorageList *stl = vedata->stl;
WORKBENCH_PassList *psl = vedata->psl;
@ -155,6 +155,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.interp = interp;
uint hash = workbench_material_get_hash(&material_template, false);
material = BLI_ghash_lookup(wpd->material_hash, POINTER_FROM_UINT(hash));
@ -177,7 +178,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
}
workbench_material_shgroup_uniform(wpd, grp, material, ob, false, false);
workbench_material_shgroup_uniform(wpd, grp, material, ob, false, false, interp);
material->shgrp = grp;
/* Depth */
@ -430,11 +431,12 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
if (draw_as == PART_DRAW_PATH) {
Image *image = NULL;
Material *mat = give_current_material(ob, part->omat);
ED_object_get_active_image(ob, part->omat, &image, NULL, NULL, NULL);
Material *mat;
Image *image;
int interp;
workbench_material_get_image_and_mat(ob, part->omat, &image, &interp, &mat);
int color_type = workbench_material_determine_color_type(wpd, image, ob);
WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, color_type);
WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, color_type, interp);
struct GPUShader *shader = (color_type != V3D_SHADING_TEXTURE_COLOR)
? wpd->transparent_accum_hair_sh
@ -444,7 +446,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O
psl->transparent_accum_pass,
shader);
DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo);
workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false);
workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp);
DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
/* Hairs have lots of layer and can rapidly become the most prominent surface.
* So lower their alpha artificially. */
@ -509,20 +511,12 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol));
struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
for (int i = 0; i < materials_len; i++) {
Material *mat = give_current_material(ob, i + 1);
Material *mat;
Image *image;
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
/* use OB_SOLID when no texture could be determined */
int color_type = wpd->shading.color_type;
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
/* use OB_SOLID when no texture could be determined */
if (image == NULL) {
color_type = V3D_SHADING_MATERIAL_COLOR;
}
}
material = get_or_create_material_data(vedata, ob, mat, image, color_type);
int interp;
workbench_material_get_image_and_mat(ob, i + 1, &image, &interp, &mat);
int color_type = workbench_material_determine_color_type(wpd, image, ob);
material = get_or_create_material_data(vedata, ob, mat, image, color_type, interp);
DRW_shgroup_call_object_add(material->shgrp_object_outline, geom_array[i], ob);
DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob);
}
@ -538,7 +532,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
/* No material split needed */
struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
if (geom) {
material = get_or_create_material_data(vedata, ob, NULL, NULL, wpd->shading.color_type);
material = get_or_create_material_data(vedata, ob, NULL, NULL, wpd->shading.color_type, 0);
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat);
if (!is_wire) {
@ -569,7 +563,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
}
Material *mat = give_current_material(ob, i + 1);
material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR);
material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat);
if (!is_wire) {

View File

@ -5,10 +5,15 @@
#include "BIF_gl.h"
#include "BKE_image.h"
#include "BKE_node.h"
#include "BLI_dynstr.h"
#include "BLI_hash.h"
#include "DNA_node_types.h"
#include "ED_uvedit.h"
#define HSV_SATURATION 0.5
#define HSV_VALUE 0.8
@ -186,9 +191,24 @@ int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, Image *i
return color_type;
}
void workbench_material_get_image_and_mat(Object *ob, int mat_nr, Image **r_image, int *r_interp, Material **r_mat)
{
bNode *node;
*r_mat = give_current_material(ob, mat_nr);
ED_object_get_active_image(ob, mat_nr, r_image, NULL, &node, NULL);
if (node) {
BLI_assert(node->type == SH_NODE_TEX_IMAGE);
NodeTexImage *storage = node->storage;
*r_interp = storage->interpolation;
}
else {
*r_interp = 0;
}
}
void workbench_material_shgroup_uniform(
WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, Object *ob,
const bool use_metallic, const bool deferred)
const bool use_metallic, const bool deferred, const int interp)
{
if (deferred && !MATDATA_PASS_ENABLED(wpd)) {
return;
@ -201,6 +221,7 @@ void workbench_material_shgroup_uniform(
GPUTexture *tex = GPU_texture_from_blender(material->ima, NULL, GL_TEXTURE_2D, false, 0.0f);
DRW_shgroup_uniform_texture(grp, "image", tex);
DRW_shgroup_uniform_bool_copy(grp, "imageSrgb", do_color_correction);
DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
}
else {
DRW_shgroup_uniform_vec3(grp, "materialDiffuseColor", (use_metallic) ? material->base_color : material->diffuse_color, 1);

View File

@ -234,6 +234,7 @@ typedef struct WORKBENCH_MaterialData {
float roughness;
int object_id;
int color_type;
int interp;
Image *ima;
/* Linked shgroup for drawing */
@ -295,6 +296,7 @@ int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata);
/* workbench_materials.c */
int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, Image *ima, Object *ob);
void workbench_material_get_image_and_mat(Object *ob, int mat_nr, Image **r_image, int *r_interp, Material **r_mat);
char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair);
void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, WORKBENCH_MaterialData *data);
uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost);
@ -303,7 +305,7 @@ int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, bool
int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair);
void workbench_material_shgroup_uniform(
WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, Object *ob,
const bool use_metallic, const bool deferred);
const bool use_metallic, const bool deferred, const int interp);
void workbench_material_copy(WORKBENCH_MaterialData *dest_material, const WORKBENCH_MaterialData *source_material);
/* workbench_studiolight.c */