Cycles / Ray Depth:
* Added a Ray Depth output to the Light Path node, which gives the user access to the current bounce. This can be used to limit the maximum ray bounce on a per shader basis. Another use case is to restrict light influence with this, to have a lamp only contribute to the direct lighting. http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/More#Light_Path This is part of my GSoC 2013 project. SVN merge of r58091 and r58772 from soc-2013-dingto.
This commit is contained in:
@@ -57,7 +57,7 @@ __device void kernel_shader_evaluate(KernelGlobals *kg, __global uint4 *input, _
|
||||
#endif
|
||||
|
||||
/* setup shader data */
|
||||
shader_setup_from_background(kg, &sd, &ray);
|
||||
shader_setup_from_background(kg, &sd, &ray, 0);
|
||||
|
||||
/* evaluate */
|
||||
int flag = 0; /* we can't know which type of BSDF this is for */
|
||||
|
@@ -21,7 +21,7 @@ CCL_NAMESPACE_BEGIN
|
||||
/* Direction Emission */
|
||||
|
||||
__device_noinline float3 direct_emissive_eval(KernelGlobals *kg, float rando,
|
||||
LightSample *ls, float u, float v, float3 I, differential3 dI, float t, float time)
|
||||
LightSample *ls, float u, float v, float3 I, differential3 dI, float t, float time, int bounce)
|
||||
{
|
||||
/* setup shading at emitter */
|
||||
ShaderData sd;
|
||||
@@ -41,7 +41,7 @@ __device_noinline float3 direct_emissive_eval(KernelGlobals *kg, float rando,
|
||||
#ifdef __CAMERA_MOTION__
|
||||
ray.time = time;
|
||||
#endif
|
||||
shader_setup_from_background(kg, &sd, &ray);
|
||||
shader_setup_from_background(kg, &sd, &ray, bounce+1);
|
||||
eval = shader_eval_background(kg, &sd, 0, SHADER_CONTEXT_EMISSION);
|
||||
}
|
||||
else
|
||||
@@ -49,10 +49,10 @@ __device_noinline float3 direct_emissive_eval(KernelGlobals *kg, float rando,
|
||||
{
|
||||
#ifdef __HAIR__
|
||||
if(ls->type == LIGHT_STRAND)
|
||||
shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, ls->prim);
|
||||
shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, bounce+1, ls->prim);
|
||||
else
|
||||
#endif
|
||||
shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, ~0);
|
||||
shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, bounce+1, ~0);
|
||||
|
||||
ls->Ng = sd.Ng;
|
||||
|
||||
@@ -74,7 +74,7 @@ __device_noinline float3 direct_emissive_eval(KernelGlobals *kg, float rando,
|
||||
|
||||
__device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
|
||||
float randt, float rando, float randu, float randv, Ray *ray, BsdfEval *eval,
|
||||
bool *is_lamp)
|
||||
bool *is_lamp, int bounce)
|
||||
{
|
||||
LightSample ls;
|
||||
|
||||
@@ -97,7 +97,7 @@ __device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd, int li
|
||||
differential3 dD = differential3_zero();
|
||||
|
||||
/* evaluate closure */
|
||||
float3 light_eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -ls.D, dD, ls.t, sd->time);
|
||||
float3 light_eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -ls.D, dD, ls.t, sd->time, bounce);
|
||||
|
||||
if(is_zero(light_eval))
|
||||
return false;
|
||||
@@ -185,7 +185,7 @@ __device_noinline float3 indirect_primitive_emission(KernelGlobals *kg, ShaderDa
|
||||
|
||||
/* Indirect Lamp Emission */
|
||||
|
||||
__device_noinline bool indirect_lamp_emission(KernelGlobals *kg, Ray *ray, int path_flag, float bsdf_pdf, float randt, float3 *emission)
|
||||
__device_noinline bool indirect_lamp_emission(KernelGlobals *kg, Ray *ray, int path_flag, float bsdf_pdf, float randt, float3 *emission, int bounce)
|
||||
{
|
||||
LightSample ls;
|
||||
int lamp = lamp_light_eval_sample(kg, randt);
|
||||
@@ -209,7 +209,7 @@ __device_noinline bool indirect_lamp_emission(KernelGlobals *kg, Ray *ray, int p
|
||||
/* todo: missing texture coordinates */
|
||||
float u = 0.0f;
|
||||
float v = 0.0f;
|
||||
float3 L = direct_emissive_eval(kg, 0.0f, &ls, u, v, -ray->D, ray->dD, ls.t, ray->time);
|
||||
float3 L = direct_emissive_eval(kg, 0.0f, &ls, u, v, -ray->D, ray->dD, ls.t, ray->time, bounce);
|
||||
|
||||
if(!(path_flag & PATH_RAY_MIS_SKIP)) {
|
||||
/* multiple importance sampling, get regular light pdf,
|
||||
@@ -224,7 +224,7 @@ __device_noinline bool indirect_lamp_emission(KernelGlobals *kg, Ray *ray, int p
|
||||
|
||||
/* Indirect Background */
|
||||
|
||||
__device_noinline float3 indirect_background(KernelGlobals *kg, Ray *ray, int path_flag, float bsdf_pdf)
|
||||
__device_noinline float3 indirect_background(KernelGlobals *kg, Ray *ray, int path_flag, float bsdf_pdf, int bounce)
|
||||
{
|
||||
#ifdef __BACKGROUND__
|
||||
int shader = kernel_data.background.shader;
|
||||
@@ -240,7 +240,7 @@ __device_noinline float3 indirect_background(KernelGlobals *kg, Ray *ray, int pa
|
||||
|
||||
/* evaluate background closure */
|
||||
ShaderData sd;
|
||||
shader_setup_from_background(kg, &sd, ray);
|
||||
shader_setup_from_background(kg, &sd, ray, bounce+1);
|
||||
|
||||
float3 L = shader_eval_background(kg, &sd, path_flag, SHADER_CONTEXT_EMISSION);
|
||||
|
||||
|
@@ -215,7 +215,7 @@ __device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ra
|
||||
return true;
|
||||
|
||||
ShaderData sd;
|
||||
shader_setup_from_ray(kg, &sd, &isect, ray);
|
||||
shader_setup_from_ray(kg, &sd, &isect, ray, state->bounce+1);
|
||||
shader_eval_surface(kg, &sd, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
|
||||
|
||||
throughput *= shader_bsdf_transparency(kg, &sd);
|
||||
@@ -300,7 +300,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
|
||||
float light_t = path_rng_1D(kg, rng, sample, num_samples, rng_offset + PRNG_LIGHT);
|
||||
float3 emission;
|
||||
|
||||
if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission))
|
||||
if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission, state.bounce))
|
||||
path_radiance_accum_emission(&L, throughput, emission, state.bounce);
|
||||
}
|
||||
#endif
|
||||
@@ -318,7 +318,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
|
||||
|
||||
#ifdef __BACKGROUND__
|
||||
/* sample background shader */
|
||||
float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf);
|
||||
float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf, state.bounce);
|
||||
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
|
||||
#endif
|
||||
|
||||
@@ -327,7 +327,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
|
||||
|
||||
/* setup shading */
|
||||
ShaderData sd;
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray);
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce);
|
||||
float rbsdf = path_rng_1D(kg, rng, sample, num_samples, rng_offset + PRNG_BSDF);
|
||||
shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
|
||||
|
||||
@@ -464,7 +464,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
|
||||
light_ray.time = sd.time;
|
||||
#endif
|
||||
|
||||
if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
|
||||
if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
@@ -575,7 +575,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
|
||||
float light_t = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_LIGHT);
|
||||
float3 emission;
|
||||
|
||||
if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission))
|
||||
if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission, state.bounce))
|
||||
path_radiance_accum_emission(L, throughput, emission, state.bounce);
|
||||
}
|
||||
#endif
|
||||
@@ -583,7 +583,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
|
||||
if(!hit) {
|
||||
#ifdef __BACKGROUND__
|
||||
/* sample background shader */
|
||||
float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf);
|
||||
float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf, state.bounce);
|
||||
path_radiance_accum_background(L, throughput, L_background, state.bounce);
|
||||
#endif
|
||||
|
||||
@@ -592,7 +592,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
|
||||
|
||||
/* setup shading */
|
||||
ShaderData sd;
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray);
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce);
|
||||
float rbsdf = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF);
|
||||
shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_INDIRECT);
|
||||
shader_merge_closures(kg, &sd);
|
||||
@@ -706,7 +706,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
|
||||
#endif
|
||||
|
||||
/* sample random light */
|
||||
if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
|
||||
if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
@@ -838,7 +838,7 @@ __device_noinline void kernel_path_non_progressive_lighting(KernelGlobals *kg, R
|
||||
float light_u, light_v;
|
||||
path_rng_2D(kg, &lamp_rng, sample*num_samples + j, aa_samples*num_samples, rng_offset + PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
if(direct_emission(kg, sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
|
||||
if(direct_emission(kg, sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
@@ -867,7 +867,7 @@ __device_noinline void kernel_path_non_progressive_lighting(KernelGlobals *kg, R
|
||||
if(kernel_data.integrator.num_all_lights)
|
||||
light_t = 0.5f*light_t;
|
||||
|
||||
if(direct_emission(kg, sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
|
||||
if(direct_emission(kg, sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
@@ -1013,7 +1013,7 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
|
||||
|
||||
#ifdef __BACKGROUND__
|
||||
/* sample background shader */
|
||||
float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf);
|
||||
float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf, state.bounce);
|
||||
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
|
||||
#endif
|
||||
|
||||
@@ -1022,7 +1022,7 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
|
||||
|
||||
/* setup shading */
|
||||
ShaderData sd;
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray);
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce);
|
||||
shader_eval_surface(kg, &sd, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
|
||||
shader_merge_closures(kg, &sd);
|
||||
|
||||
|
@@ -64,7 +64,7 @@ __device_noinline
|
||||
__device
|
||||
#endif
|
||||
void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
|
||||
const Intersection *isect, const Ray *ray)
|
||||
const Intersection *isect, const Ray *ray, int bounce)
|
||||
{
|
||||
#ifdef __INSTANCING__
|
||||
sd->object = (isect->object == ~0)? kernel_tex_fetch(__prim_object, isect->prim): isect->object;
|
||||
@@ -80,6 +80,7 @@ void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
|
||||
|
||||
sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
|
||||
sd->ray_length = isect->t;
|
||||
sd->ray_depth = bounce;
|
||||
|
||||
#ifdef __HAIR__
|
||||
if(kernel_tex_fetch(__prim_segment, isect->prim) != ~0) {
|
||||
@@ -277,7 +278,7 @@ __device
|
||||
#endif
|
||||
void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
|
||||
const float3 P, const float3 Ng, const float3 I,
|
||||
int shader, int object, int prim, float u, float v, float t, float time, int segment)
|
||||
int shader, int object, int prim, float u, float v, float t, float time, int bounce, int segment)
|
||||
{
|
||||
/* vectors */
|
||||
sd->P = P;
|
||||
@@ -300,6 +301,7 @@ void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
|
||||
sd->v = v;
|
||||
#endif
|
||||
sd->ray_length = t;
|
||||
sd->ray_depth = bounce;
|
||||
|
||||
/* detect instancing, for non-instanced the object index is -object-1 */
|
||||
#ifdef __INSTANCING__
|
||||
@@ -408,12 +410,12 @@ __device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
|
||||
|
||||
/* watch out: no instance transform currently */
|
||||
|
||||
shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v, 0.0f, TIME_INVALID, ~0);
|
||||
shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v, 0.0f, TIME_INVALID, 0, ~0);
|
||||
}
|
||||
|
||||
/* ShaderData setup from ray into background */
|
||||
|
||||
__device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray)
|
||||
__device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray, int bounce)
|
||||
{
|
||||
/* vectors */
|
||||
sd->P = ray->D;
|
||||
@@ -426,6 +428,7 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData
|
||||
sd->time = ray->time;
|
||||
#endif
|
||||
sd->ray_length = 0.0f;
|
||||
sd->ray_depth = bounce;
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
sd->object = ~0;
|
||||
|
@@ -540,6 +540,9 @@ typedef struct ShaderData {
|
||||
|
||||
/* length of the ray being shaded */
|
||||
float ray_length;
|
||||
|
||||
/* ray bounce depth */
|
||||
int ray_depth;
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
/* differential of P. these are orthogonal to Ng, not N */
|
||||
|
@@ -84,6 +84,7 @@ ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
|
||||
ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
|
||||
#endif
|
||||
ustring OSLRenderServices::u_path_ray_length("path:ray_length");
|
||||
ustring OSLRenderServices::u_path_ray_depth("path:ray_depth");
|
||||
ustring OSLRenderServices::u_trace("trace");
|
||||
ustring OSLRenderServices::u_hit("hit");
|
||||
ustring OSLRenderServices::u_hitdist("hitdist");
|
||||
@@ -660,6 +661,11 @@ bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData *
|
||||
float f = sd->ray_length;
|
||||
return set_attribute_float(f, type, derivatives, val);
|
||||
}
|
||||
else if (name == u_path_ray_depth) {
|
||||
/* Ray Depth */
|
||||
int f = sd->ray_depth;
|
||||
return set_attribute_int(f, type, derivatives, val);
|
||||
}
|
||||
else if (name == u_ndc) {
|
||||
/* NDC coordinates with special exception for otho */
|
||||
OSLThreadData *tdata = kg->osl_tdata;
|
||||
@@ -919,7 +925,10 @@ bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg, ustring source, ustri
|
||||
|
||||
if(!tracedata->setup) {
|
||||
/* lazy shader data setup */
|
||||
shader_setup_from_ray(kg, sd, &tracedata->isect, &tracedata->ray);
|
||||
ShaderData *original_sd = (ShaderData *)(sg->renderstate);
|
||||
int bounce = original_sd->ray_depth + 1;
|
||||
|
||||
shader_setup_from_ray(kg, sd, &tracedata->isect, &tracedata->ray, bounce);
|
||||
tracedata->setup = true;
|
||||
}
|
||||
|
||||
|
@@ -135,6 +135,7 @@ public:
|
||||
static ustring u_curve_thickness;
|
||||
static ustring u_curve_tangent_normal;
|
||||
static ustring u_path_ray_length;
|
||||
static ustring u_path_ray_depth;
|
||||
static ustring u_trace;
|
||||
static ustring u_hit;
|
||||
static ustring u_hitdist;
|
||||
|
@@ -26,7 +26,8 @@ shader node_light_path(
|
||||
output float IsSingularRay = 0.0,
|
||||
output float IsReflectionRay = 0.0,
|
||||
output float IsTransmissionRay = 0.0,
|
||||
output float RayLength = 0.0)
|
||||
output float RayLength = 0.0,
|
||||
output float RayDepth = 0.0)
|
||||
{
|
||||
IsCameraRay = raytype("camera");
|
||||
IsShadowRay = raytype("shadow");
|
||||
@@ -37,5 +38,9 @@ shader node_light_path(
|
||||
IsTransmissionRay = raytype("refraction");
|
||||
|
||||
getattribute("path:ray_length", RayLength);
|
||||
|
||||
int ray_depth;
|
||||
getattribute("path:ray_depth", ray_depth);
|
||||
RayDepth = (float)ray_depth;
|
||||
}
|
||||
|
||||
|
@@ -34,6 +34,7 @@ __device void svm_node_light_path(ShaderData *sd, float *stack, uint type, uint
|
||||
case NODE_LP_transmission: info = (path_flag & PATH_RAY_TRANSMIT)? 1.0f: 0.0f; break;
|
||||
case NODE_LP_backfacing: info = (sd->flag & SD_BACKFACING)? 1.0f: 0.0f; break;
|
||||
case NODE_LP_ray_length: info = sd->ray_length; break;
|
||||
case NODE_LP_ray_depth: info = (float)sd->ray_depth; break;
|
||||
}
|
||||
|
||||
stack_store_float(stack, out_offset, info);
|
||||
|
@@ -153,7 +153,8 @@ typedef enum NodeLightPath {
|
||||
NODE_LP_reflection,
|
||||
NODE_LP_transmission,
|
||||
NODE_LP_backfacing,
|
||||
NODE_LP_ray_length
|
||||
NODE_LP_ray_length,
|
||||
NODE_LP_ray_depth
|
||||
} NodeLightPath;
|
||||
|
||||
typedef enum NodeLightFalloff {
|
||||
|
@@ -2064,6 +2064,7 @@ LightPathNode::LightPathNode()
|
||||
add_output("Is Reflection Ray", SHADER_SOCKET_FLOAT);
|
||||
add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT);
|
||||
add_output("Ray Length", SHADER_SOCKET_FLOAT);
|
||||
add_output("Ray Depth", SHADER_SOCKET_FLOAT);
|
||||
}
|
||||
|
||||
void LightPathNode::compile(SVMCompiler& compiler)
|
||||
@@ -2118,6 +2119,12 @@ void LightPathNode::compile(SVMCompiler& compiler)
|
||||
compiler.stack_assign(out);
|
||||
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_length, out->stack_offset);
|
||||
}
|
||||
|
||||
out = output("Ray Depth");
|
||||
if(!out->links.empty()) {
|
||||
compiler.stack_assign(out);
|
||||
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, out->stack_offset);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -38,6 +38,7 @@ static bNodeSocketTemplate sh_node_light_path_out[] = {
|
||||
{ SOCK_FLOAT, 0, N_("Is Reflection Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
||||
{ SOCK_FLOAT, 0, N_("Is Transmission Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
||||
{ SOCK_FLOAT, 0, N_("Ray Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
||||
{ SOCK_FLOAT, 0, N_("Ray Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
||||
{ -1, 0, "" }
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user