Eevee: Add support for Alpha clip and Hashed Alpha transparency.
Hashed Alpha transparency offers a noisy output but has the benefit of being correctly ordered. Noise can be attenuated with Multisampling / AntiAliasing.
This commit is contained in:
parent
e2c0197a96
commit
05bef13b53
|
@ -1155,6 +1155,26 @@ class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel):
|
|||
layout.prop(raym, "gloss_factor", text="Roughness")
|
||||
|
||||
|
||||
class EEVEE_MATERIAL_PT_options(MaterialButtonsPanel, Panel):
|
||||
bl_label = "Options"
|
||||
bl_context = "material"
|
||||
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
return context.material and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material
|
||||
|
||||
layout.prop(mat, "blend_method")
|
||||
|
||||
if mat.blend_method == "CLIP":
|
||||
layout.prop(mat, "alpha_threshold")
|
||||
|
||||
classes = (
|
||||
MATERIAL_MT_sss_presets,
|
||||
MATERIAL_MT_specials,
|
||||
|
@ -1185,6 +1205,7 @@ classes = (
|
|||
MATERIAL_PT_custom_props,
|
||||
EEVEE_MATERIAL_PT_context_material,
|
||||
EEVEE_MATERIAL_PT_surface,
|
||||
EEVEE_MATERIAL_PT_options,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
|
|
|
@ -207,6 +207,8 @@ void BKE_material_init(Material *ma)
|
|||
ma->mode2 = MA_CASTSHADOW;
|
||||
ma->shade_flag = MA_APPROX_OCCLUSION;
|
||||
ma->preview = NULL;
|
||||
|
||||
ma->alpha_threshold = 0.5f;
|
||||
}
|
||||
|
||||
Material *BKE_material_add(Main *bmain, const char *name)
|
||||
|
|
|
@ -92,14 +92,12 @@ static void EEVEE_cache_populate(void *vedata, Object *ob)
|
|||
}
|
||||
}
|
||||
|
||||
struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob);
|
||||
if (geom) {
|
||||
EEVEE_materials_cache_populate(vedata, sldata, ob, geom);
|
||||
if (ELEM(ob->type, OB_MESH)) {
|
||||
EEVEE_materials_cache_populate(vedata, sldata, ob);
|
||||
|
||||
const bool cast_shadow = true;
|
||||
|
||||
if (cast_shadow) {
|
||||
EEVEE_lights_cache_shcaster_add(sldata, psl, geom, ob->obmat);
|
||||
BLI_addtail(&sldata->shadow_casters, BLI_genericNodeN(ob));
|
||||
EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(ob);
|
||||
oedata->need_update = ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0);
|
||||
|
|
|
@ -179,8 +179,6 @@ static char *eevee_get_defines(int options)
|
|||
{
|
||||
char *str = NULL;
|
||||
|
||||
BLI_assert(options < VAR_MAT_MAX);
|
||||
|
||||
DynStr *ds = BLI_dynstr_new();
|
||||
BLI_dynstr_appendf(ds, SHADER_DEFINES);
|
||||
|
||||
|
@ -202,6 +200,12 @@ static char *eevee_get_defines(int options)
|
|||
if ((options & VAR_MAT_BENT) != 0) {
|
||||
BLI_dynstr_appendf(ds, "#define USE_BENT_NORMAL\n");
|
||||
}
|
||||
if ((options & VAR_MAT_CLIP) != 0) {
|
||||
BLI_dynstr_appendf(ds, "#define USE_ALPHA_CLIP\n");
|
||||
}
|
||||
if ((options & VAR_MAT_HASH) != 0) {
|
||||
BLI_dynstr_appendf(ds, "#define USE_ALPHA_HASH\n");
|
||||
}
|
||||
|
||||
str = BLI_dynstr_get_cstring(ds);
|
||||
BLI_dynstr_free(ds);
|
||||
|
@ -491,6 +495,42 @@ struct GPUMaterial *EEVEE_material_mesh_get(
|
|||
return mat;
|
||||
}
|
||||
|
||||
struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, Material *ma, bool use_hashed_alpha)
|
||||
{
|
||||
const void *engine = &DRW_engine_viewport_eevee_type;
|
||||
int options = VAR_MAT_MESH;
|
||||
|
||||
if (use_hashed_alpha) {
|
||||
options |= VAR_MAT_HASH;
|
||||
}
|
||||
else {
|
||||
options |= VAR_MAT_CLIP;
|
||||
}
|
||||
|
||||
GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options);
|
||||
if (mat) {
|
||||
return mat;
|
||||
}
|
||||
|
||||
char *defines = eevee_get_defines(options);
|
||||
|
||||
DynStr *ds_frag = BLI_dynstr_new();
|
||||
BLI_dynstr_append(ds_frag, e_data.frag_shader_lib);
|
||||
BLI_dynstr_append(ds_frag, datatoc_prepass_frag_glsl);
|
||||
char *frag_str = BLI_dynstr_get_cstring(ds_frag);
|
||||
BLI_dynstr_free(ds_frag);
|
||||
|
||||
mat = GPU_material_from_nodetree(
|
||||
scene, ma->nodetree, &ma->gpumaterial, engine, options,
|
||||
datatoc_lit_surface_vert_glsl, NULL, frag_str,
|
||||
defines);
|
||||
|
||||
MEM_freeN(frag_str);
|
||||
MEM_freeN(defines);
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
struct GPUMaterial *EEVEE_material_hair_get(
|
||||
struct Scene *scene, Material *ma,
|
||||
bool use_ao, bool use_bent_normals)
|
||||
|
@ -637,7 +677,7 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sldata, Object *ob, struct Gwn_Batch *geom)
|
||||
void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sldata, Object *ob)
|
||||
{
|
||||
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
|
||||
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
|
||||
|
@ -650,12 +690,6 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
|
|||
const bool is_sculpt_mode = is_active && (ob->mode & OB_MODE_SCULPT) != 0;
|
||||
const bool is_default_mode_shader = is_sculpt_mode;
|
||||
|
||||
/* Depth Prepass */
|
||||
DRWShadingGroup *depth_shgrp = do_cull ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
|
||||
DRWShadingGroup *depth_clip_shgrp = do_cull ? stl->g_data->depth_shgrp_clip_cull : stl->g_data->depth_shgrp_clip;
|
||||
ADD_SHGROUP_CALL(depth_shgrp, ob, geom);
|
||||
ADD_SHGROUP_CALL(depth_clip_shgrp, ob, geom);
|
||||
|
||||
/* First get materials for this mesh. */
|
||||
if (ELEM(ob->type, OB_MESH)) {
|
||||
const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol));
|
||||
|
@ -740,6 +774,47 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
|
|||
if (mat_geom) {
|
||||
for (int i = 0; i < materials_len; ++i) {
|
||||
ADD_SHGROUP_CALL(shgrp_array[i], ob, mat_geom[i]);
|
||||
|
||||
/* Depth Prepass */
|
||||
DRWShadingGroup *depth_shgrp = NULL;
|
||||
DRWShadingGroup *depth_clip_shgrp;
|
||||
|
||||
Material *ma = give_current_material(ob, i + 1);
|
||||
|
||||
if (ma != NULL && (ma->use_nodes && ma->nodetree)) {
|
||||
if (ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED)) {
|
||||
Scene *scene = draw_ctx->scene;
|
||||
DRWPass *depth_pass, *depth_clip_pass;
|
||||
struct GPUMaterial *gpumat = EEVEE_material_mesh_depth_get(scene, ma, (ma->blend_method == MA_BM_HASHED));
|
||||
|
||||
depth_pass = do_cull ? psl->depth_pass_cull : psl->depth_pass;
|
||||
depth_clip_pass = do_cull ? psl->depth_pass_clip_cull : psl->depth_pass_clip;
|
||||
|
||||
/* Use same shader for both. */
|
||||
depth_shgrp = DRW_shgroup_material_create(gpumat, depth_pass);
|
||||
depth_clip_shgrp = DRW_shgroup_material_create(gpumat, depth_clip_pass);
|
||||
|
||||
if (ma->blend_method == MA_BM_CLIP) {
|
||||
DRW_shgroup_uniform_float(depth_shgrp, "alphaThreshold", &ma->alpha_threshold, 1);
|
||||
DRW_shgroup_uniform_float(depth_clip_shgrp, "alphaThreshold", &ma->alpha_threshold, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Shadow Pass */
|
||||
/* TODO clipped shadow map */
|
||||
EEVEE_lights_cache_shcaster_add(sldata, psl, mat_geom[i], ob->obmat);
|
||||
}
|
||||
|
||||
if (depth_shgrp == NULL) {
|
||||
depth_shgrp = do_cull ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
|
||||
depth_clip_shgrp = do_cull ? stl->g_data->depth_shgrp_clip_cull : stl->g_data->depth_shgrp_clip;
|
||||
|
||||
/* Shadow Pass */
|
||||
EEVEE_lights_cache_shcaster_add(sldata, psl, mat_geom[i], ob->obmat);
|
||||
}
|
||||
|
||||
ADD_SHGROUP_CALL(depth_shgrp, ob, mat_geom[i]);
|
||||
ADD_SHGROUP_CALL(depth_clip_shgrp, ob, mat_geom[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,11 @@ enum {
|
|||
/* Max number of variation */
|
||||
/* IMPORTANT : Leave it last and set
|
||||
* it's value accordingly. */
|
||||
VAR_MAT_MAX = (1 << 6)
|
||||
VAR_MAT_MAX = (1 << 6),
|
||||
/* These are options that are not counted in VAR_MAT_MAX
|
||||
* because they are not cumulative with the others above. */
|
||||
VAR_MAT_CLIP = (1 << 7),
|
||||
VAR_MAT_HASH = (1 << 8),
|
||||
};
|
||||
|
||||
typedef struct EEVEE_PassList {
|
||||
|
@ -438,14 +442,14 @@ EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob);
|
|||
struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */
|
||||
void EEVEE_materials_init(EEVEE_StorageList *stl);
|
||||
void EEVEE_materials_cache_init(EEVEE_Data *vedata);
|
||||
void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sldata, Object *ob, struct Gwn_Batch *geom);
|
||||
void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sldata, Object *ob);
|
||||
void EEVEE_materials_cache_finish(EEVEE_Data *vedata);
|
||||
struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo);
|
||||
struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo);
|
||||
struct GPUMaterial *EEVEE_material_world_volume_get(
|
||||
struct Scene *scene, struct World *wo, bool use_lights, bool use_volume_shadows, bool is_homogeneous, bool use_color_transmit);
|
||||
struct GPUMaterial *EEVEE_material_mesh_lightprobe_get(struct Scene *scene, Material *ma);
|
||||
struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, Material *ma, bool use_ao, bool use_bent_normals);
|
||||
struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, Material *ma, bool use_hashed_alpha);
|
||||
struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, bool use_ao, bool use_bent_normals);
|
||||
void EEVEE_materials_free(void);
|
||||
void EEVEE_draw_default_passes(EEVEE_PassList *psl);
|
||||
|
|
|
@ -19,8 +19,6 @@ uniform vec4 viewvecs[2];
|
|||
/* ------- Structures -------- */
|
||||
#ifdef VOLUMETRICS
|
||||
|
||||
#define NODETREE_EXEC
|
||||
|
||||
struct Closure {
|
||||
vec3 absorption;
|
||||
vec3 scatter;
|
||||
|
@ -49,12 +47,35 @@ Closure closure_add(Closure cl1, Closure cl2)
|
|||
cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */
|
||||
return cl;
|
||||
}
|
||||
#else
|
||||
|
||||
Closure nodetree_exec(void); /* Prototype */
|
||||
struct Closure {
|
||||
vec3 radiance;
|
||||
float opacity;
|
||||
};
|
||||
|
||||
#define CLOSURE_DEFAULT Closure(vec3(0.0), 0.0)
|
||||
|
||||
Closure closure_mix(Closure cl1, Closure cl2, float fac)
|
||||
{
|
||||
Closure cl;
|
||||
cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
|
||||
cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
|
||||
return cl;
|
||||
}
|
||||
|
||||
Closure closure_add(Closure cl1, Closure cl2)
|
||||
{
|
||||
Closure cl;
|
||||
cl.radiance = cl1.radiance + cl2.radiance;
|
||||
cl.opacity = cl1.opacity + cl2.opacity;
|
||||
return cl;
|
||||
}
|
||||
|
||||
#endif /* VOLUMETRICS */
|
||||
|
||||
Closure nodetree_exec(void); /* Prototype */
|
||||
|
||||
|
||||
struct LightData {
|
||||
vec4 position_influence; /* w : InfluenceRadius */
|
||||
|
|
|
@ -1,7 +1,85 @@
|
|||
|
||||
#ifdef USE_ALPHA_HASH
|
||||
|
||||
/* From the paper "Hashed Alpha Testing" by Chris Wyman and Morgan McGuire */
|
||||
float hash(vec2 a) {
|
||||
return fract(1e4 * sin(17.0 * a.x + 0.1 * a.y) * (0.1 + abs(sin(13.0 * a.y + a.x))));
|
||||
}
|
||||
|
||||
float hash3d(vec3 a) {
|
||||
return hash(vec2(hash(a.xy), a.z));
|
||||
}
|
||||
|
||||
//uniform float hashScale;
|
||||
float hashScale = 0.001;
|
||||
|
||||
float hashed_alpha_threshold(vec3 co)
|
||||
{
|
||||
/* Find the discretized derivatives of our coordinates. */
|
||||
float max_deriv = max(length(dFdx(co)), length(dFdy(co)));
|
||||
float pix_scale = 1.0 / (hashScale * max_deriv);
|
||||
|
||||
/* Find two nearest log-discretized noise scales. */
|
||||
float pix_scale_log = log2(pix_scale);
|
||||
vec2 pix_scales;
|
||||
pix_scales.x = exp2(floor(pix_scale_log));
|
||||
pix_scales.y = exp2(ceil(pix_scale_log));
|
||||
|
||||
/* Compute alpha thresholds at our two noise scales. */
|
||||
vec2 alpha;
|
||||
alpha.x = hash3d(floor(pix_scales.x * co));
|
||||
alpha.y = hash3d(floor(pix_scales.y * co));
|
||||
|
||||
/* Factor to interpolate lerp with. */
|
||||
float fac = fract(log2(pix_scale));
|
||||
|
||||
/* Interpolate alpha threshold from noise at two scales. */
|
||||
float x = mix(alpha.x, alpha.y, fac);
|
||||
|
||||
/* Pass into CDF to compute uniformly distrib threshold. */
|
||||
float a = min(fac, 1.0 - fac);
|
||||
float one_a = 1.0 - a;
|
||||
float denom = 1.0 / (2 * a * one_a);
|
||||
float one_x = (1 - x);
|
||||
vec3 cases = vec3(
|
||||
(x * x) * denom,
|
||||
(x - 0.5 * a) / one_a,
|
||||
1.0 - (one_x * one_x * denom)
|
||||
);
|
||||
|
||||
/* Find our final, uniformly distributed alpha threshold. */
|
||||
float threshold = (x < one_a) ? ((x < a) ? cases.x : cases.y) : cases.z;
|
||||
|
||||
/* Avoids threshold == 0. */
|
||||
threshold = clamp(threshold, 1.0e-6, 1.0);
|
||||
|
||||
return threshold;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_ALPHA_CLIP
|
||||
uniform float alphaThreshold;
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
/* For now do nothing.
|
||||
* In the future, output object motion blur.
|
||||
* This pass could also be controlled but nodetree (pixel depth offset, stochastic transparency). */
|
||||
* In the future, output object motion blur. */
|
||||
|
||||
#if defined(USE_ALPHA_HASH) || defined(USE_ALPHA_CLIP)
|
||||
#define NODETREE_EXEC
|
||||
|
||||
Closure cl = nodetree_exec();
|
||||
|
||||
#if defined(USE_ALPHA_HASH)
|
||||
/* Hashed Alpha Testing */
|
||||
if (cl.opacity < hashed_alpha_threshold(worldPosition))
|
||||
discard;
|
||||
#elif defined(USE_ALPHA_CLIP)
|
||||
/* Alpha clip */
|
||||
if (cl.opacity <= alphaThreshold)
|
||||
discard;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
#ifdef VOLUMETRICS
|
||||
|
||||
#define NODETREE_EXEC
|
||||
|
||||
#define VOLUMETRIC_INTEGRATION_MAX_STEP 256
|
||||
#define VOLUMETRIC_SHADOW_MAX_STEP 128
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ uniform vec4 CameraTexCoFactors;
|
|||
|
||||
/* Old glsl mode compat. */
|
||||
|
||||
#ifndef NODETREE_EXEC
|
||||
#ifndef CLOSURE_DEFAULT
|
||||
|
||||
struct Closure {
|
||||
vec3 radiance;
|
||||
|
@ -41,7 +41,7 @@ Closure closure_add(Closure cl1, Closure cl2)
|
|||
|
||||
Closure nodetree_exec(void); /* Prototype */
|
||||
|
||||
#endif /* NODETREE_EXEC */
|
||||
#endif /* CLOSURE_DEFAULT */
|
||||
|
||||
|
||||
/* Converters */
|
||||
|
@ -2890,7 +2890,7 @@ void node_bsdf_transparent(vec4 color, out Closure result)
|
|||
{
|
||||
/* this isn't right */
|
||||
result.radiance = color.rgb;
|
||||
result.opacity = 0.0;
|
||||
result.opacity = color.a;
|
||||
}
|
||||
|
||||
void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
|
||||
|
@ -4031,7 +4031,11 @@ void node_eevee_specular(
|
|||
|
||||
void node_output_eevee_material(Closure surface, out Closure result)
|
||||
{
|
||||
#if defined(USE_ALPHA_HASH) || defined(USE_ALPHA_CLIP)
|
||||
result = surface;
|
||||
#else
|
||||
result = Closure(surface.radiance, length(viewPosition));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* EEVEE_ENGINE */
|
||||
|
|
|
@ -211,6 +211,10 @@ typedef struct Material {
|
|||
char nmap_tangent_names[9][64]; /* [MAX_MTFACE+1][MAX_NAME]; +1 for empty name */
|
||||
int nmap_tangent_names_count, pad5;
|
||||
|
||||
/* Transparency */
|
||||
float alpha_threshold;
|
||||
char blend_method, pad6[3];
|
||||
|
||||
/* image to use for image/uv space, also bake target
|
||||
* (not to be used shading/rendering pipeline, this is editor featyure only!). */
|
||||
struct Image *edit_image;
|
||||
|
@ -491,5 +495,14 @@ typedef struct Material {
|
|||
#define MA_VOL_SHADE_MULTIPLE 3
|
||||
#define MA_VOL_SHADE_SHADEDPLUSMULTIPLE 4
|
||||
|
||||
/* blend_method */
|
||||
enum {
|
||||
MA_BM_SOLID,
|
||||
MA_BM_ADD,
|
||||
MA_BM_MULTIPLY,
|
||||
MA_BM_CLIP,
|
||||
MA_BM_HASHED,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1805,6 +1805,15 @@ void RNA_def_material(BlenderRNA *brna)
|
|||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static EnumPropertyItem prop_eevee_blend_items[] = {
|
||||
{MA_BM_SOLID, "OPAQUE", 0, "Opaque", "Render surface without transparency"},
|
||||
// {MA_BM_ADD, "ADD", 0, "Additive", "Render surface and blend the result with additive blending"},
|
||||
// {MA_BM_MULTIPLY, "MULTIPLY", 0, "Multiply", "Render surface and blend the result with multiplicative blending"},
|
||||
{MA_BM_CLIP, "CLIP", 0, "Alpha Clip", "Use the alpha threshold to clip the visibility (binary visibility)"},
|
||||
{MA_BM_HASHED, "HASHED", 0, "Alpha Hashed", "Use noise to dither the binary visibility (works well with multi-samples)"},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "Material", "ID");
|
||||
RNA_def_struct_ui_text(srna, "Material",
|
||||
"Material data-block to define the appearance of geometric objects for rendering");
|
||||
|
@ -1827,7 +1836,18 @@ void RNA_def_material(BlenderRNA *brna)
|
|||
RNA_def_property_enum_items(prop, transparency_items);
|
||||
RNA_def_property_ui_text(prop, "Transparency Method", "Method to use for rendering transparency");
|
||||
RNA_def_property_update(prop, 0, "rna_Material_update");
|
||||
|
||||
|
||||
/* Blending (only Eevee for now) */
|
||||
prop = RNA_def_property(srna, "blend_method", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, prop_eevee_blend_items);
|
||||
RNA_def_property_ui_text(prop, "Blend Mode", "Blend Mode for Transparent Faces");
|
||||
RNA_def_property_update(prop, 0, "rna_Material_draw_update");
|
||||
|
||||
prop = RNA_def_property(srna, "alpha_threshold", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_range(prop, 0, 1);
|
||||
RNA_def_property_ui_text(prop, "Clip Threshold", "A pixel is rendered only if its alpha value is above this threshold");
|
||||
RNA_def_property_update(prop, 0, "rna_Material_update");
|
||||
|
||||
/* For Preview Render */
|
||||
prop = RNA_def_property(srna, "preview_render_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "pr_type");
|
||||
|
|
Loading…
Reference in New Issue