1
1

Merge remote-tracking branch 'origin/blender-v3.1-release'

This commit is contained in:
2022-02-25 21:36:09 +01:00
13 changed files with 163 additions and 69 deletions

View File

@@ -128,9 +128,10 @@ ccl_device float point_radius(KernelGlobals kg, ccl_private const ShaderData *sd
return r;
}
else {
float3 dir = make_float3(r, r, r);
const float normalized_r = r * (1.0f / M_SQRT3_F);
float3 dir = make_float3(normalized_r, normalized_r, normalized_r);
object_dir_transform(kg, sd, &dir);
return average(dir);
return len(dir);
}
}

View File

@@ -67,6 +67,9 @@ CCL_NAMESPACE_BEGIN
#ifndef M_SQRT2_F
# define M_SQRT2_F (1.4142135623730950f) /* sqrt(2) */
#endif
#ifndef M_SQRT3_F
# define M_SQRT3_F (1.7320508075688772f) /* sqrt(3) */
#endif
#ifndef M_LN2_F
# define M_LN2_F (0.6931471805599453f) /* ln(2) */
#endif

View File

@@ -24,18 +24,30 @@ void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings,
const struct SubsurfModifierData *smd,
bool use_render_params);
bool BKE_subsurf_modifier_use_custom_loop_normals(const struct SubsurfModifierData *smd,
const struct Mesh *mesh);
/**
* Return true if GPU subdivision evaluation is disabled by force due to incompatible mesh or
* modifier settings. This will only return true if GPU subdivision is enabled in the preferences
* and supported by the GPU. It is mainly useful for showing UI messages.
*/
bool BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(
const struct SubsurfModifierData *smd, const struct Mesh *mesh);
/**
* \param skip_check_is_last: When true, we assume that the modifier passed is the last enabled
* modifier in the stack.
*/
bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const struct Scene *scene,
const struct Object *ob,
const struct Mesh *mesh,
const struct SubsurfModifierData *smd,
int required_mode,
bool skip_check_is_last);
bool BKE_subsurf_modifier_can_do_gpu_subdiv(const struct Scene *scene,
const struct Object *ob,
const struct Mesh *mesh,
int required_mode);
extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv);

View File

@@ -54,23 +54,20 @@ static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene,
return md;
}
bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const Scene *scene,
const Object *ob,
const SubsurfModifierData *smd,
int required_mode,
bool skip_check_is_last)
bool BKE_subsurf_modifier_use_custom_loop_normals(const SubsurfModifierData *smd, const Mesh *mesh)
{
if ((U.gpu_flag & USER_GPU_FLAG_SUBDIVISION_EVALUATION) == 0) {
return false;
}
return (smd->flags & eSubsurfModifierFlag_UseCustomNormals) && (mesh->flag & ME_AUTOSMOOTH) &&
CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
}
if (!skip_check_is_last) {
ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode);
if (md != (const ModifierData *)smd) {
return false;
}
}
bool subsurf_modifier_use_autosmooth_or_split_normals(const SubsurfModifierData *smd,
const Mesh *mesh)
{
return (mesh->flag & ME_AUTOSMOOTH) || BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh);
}
static bool is_subdivision_evaluation_possible_on_gpu(void)
{
/* Only OpenGL is supported for OpenSubdiv evaluation for now. */
if (GPU_backend_get_type() != GPU_BACKEND_OPENGL) {
return false;
@@ -88,8 +85,52 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const Scene *scene,
return true;
}
bool BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(const SubsurfModifierData *smd,
const Mesh *mesh)
{
if ((U.gpu_flag & USER_GPU_FLAG_SUBDIVISION_EVALUATION) == 0) {
/* GPU subdivision is explicitely disabled, so we don't force it. */
return false;
}
if (!is_subdivision_evaluation_possible_on_gpu()) {
/* The GPU type is not compatible with the subdivision. */
return false;
}
return subsurf_modifier_use_autosmooth_or_split_normals(smd, mesh);
}
bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const Scene *scene,
const Object *ob,
const Mesh *mesh,
const SubsurfModifierData *smd,
int required_mode,
bool skip_check_is_last)
{
if ((U.gpu_flag & USER_GPU_FLAG_SUBDIVISION_EVALUATION) == 0) {
return false;
}
/* Deactivate GPU subdivision if autosmooth or custom split normals are used as those are
* complicated to support on GPU, and should really be separate workflows. */
if (subsurf_modifier_use_autosmooth_or_split_normals(smd, mesh)) {
return false;
}
if (!skip_check_is_last) {
ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode);
if (md != (const ModifierData *)smd) {
return false;
}
}
return is_subdivision_evaluation_possible_on_gpu();
}
bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
const Object *ob,
const Mesh *mesh,
int required_mode)
{
ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode);
@@ -103,7 +144,7 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
}
return BKE_subsurf_modifier_can_do_gpu_subdiv_ex(
scene, ob, (SubsurfModifierData *)md, required_mode, true);
scene, ob, mesh, (SubsurfModifierData *)md, required_mode, true);
}
void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv) = NULL;

View File

@@ -1712,7 +1712,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
const int required_mode = BKE_subsurf_modifier_eval_required_mode(DRW_state_is_scene_render(),
is_editmode);
const bool do_subdivision = BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ob, required_mode);
const bool do_subdivision = BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ob, me, required_mode);
MeshBufferList *mbuflist = &cache->final.buff;

View File

@@ -67,7 +67,6 @@ enum {
SHADER_BUFFER_NORMALS_ACCUMULATE,
SHADER_BUFFER_NORMALS_FINALIZE,
SHADER_PATCH_EVALUATION,
SHADER_PATCH_EVALUATION_LIMIT_NORMALS,
SHADER_PATCH_EVALUATION_FVAR,
SHADER_PATCH_EVALUATION_FACE_DOTS,
SHADER_COMP_CUSTOM_DATA_INTERP_1D,
@@ -107,7 +106,6 @@ static const char *get_shader_code(int shader_type)
return datatoc_common_subdiv_normals_finalize_comp_glsl;
}
case SHADER_PATCH_EVALUATION:
case SHADER_PATCH_EVALUATION_LIMIT_NORMALS:
case SHADER_PATCH_EVALUATION_FVAR:
case SHADER_PATCH_EVALUATION_FACE_DOTS: {
return datatoc_common_subdiv_patch_evaluation_comp_glsl;
@@ -159,9 +157,6 @@ static const char *get_shader_name(int shader_type)
case SHADER_PATCH_EVALUATION: {
return "subdiv patch evaluation";
}
case SHADER_PATCH_EVALUATION_LIMIT_NORMALS: {
return "subdiv patch evaluation limit normals";
}
case SHADER_PATCH_EVALUATION_FVAR: {
return "subdiv patch evaluation face-varying";
}
@@ -199,13 +194,7 @@ static GPUShader *get_patch_evaluation_shader(int shader_type)
const char *compute_code = get_shader_code(shader_type);
const char *defines = nullptr;
if (shader_type == SHADER_PATCH_EVALUATION_LIMIT_NORMALS) {
defines =
"#define OSD_PATCH_BASIS_GLSL\n"
"#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
"#define LIMIT_NORMALS\n";
}
else if (shader_type == SHADER_PATCH_EVALUATION_FVAR) {
if (shader_type == SHADER_PATCH_EVALUATION_FVAR) {
defines =
"#define OSD_PATCH_BASIS_GLSL\n"
"#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
@@ -246,7 +235,6 @@ static GPUShader *get_subdiv_shader(int shader_type, const char *defines)
{
if (ELEM(shader_type,
SHADER_PATCH_EVALUATION,
SHADER_PATCH_EVALUATION_LIMIT_NORMALS,
SHADER_PATCH_EVALUATION_FVAR,
SHADER_PATCH_EVALUATION_FACE_DOTS)) {
return get_patch_evaluation_shader(shader_type);
@@ -1194,9 +1182,7 @@ static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache,
GPU_compute_dispatch(shader, dispatch_rx, dispatch_ry, 1);
}
void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
GPUVertBuf *pos_nor,
const bool do_limit_normals)
void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor)
{
Subdiv *subdiv = cache->subdiv;
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
@@ -1221,8 +1207,7 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
get_patch_param_format());
evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
GPUShader *shader = get_patch_evaluation_shader(
do_limit_normals ? SHADER_PATCH_EVALUATION_LIMIT_NORMALS : SHADER_PATCH_EVALUATION);
GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION);
GPU_shader_bind(shader);
GPU_vertbuf_bind_as_ssbo(src_buffer, 0);
@@ -1394,6 +1379,7 @@ void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache,
GPUVertBuf *pos_nor,
GPUVertBuf *face_adjacency_offsets,
GPUVertBuf *face_adjacency_lists,
GPUVertBuf *vertex_loop_map,
GPUVertBuf *vertex_normals)
{
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_ACCUMULATE, nullptr);
@@ -1404,6 +1390,7 @@ void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
GPU_vertbuf_bind_as_ssbo(face_adjacency_offsets, binding_point++);
GPU_vertbuf_bind_as_ssbo(face_adjacency_lists, binding_point++);
GPU_vertbuf_bind_as_ssbo(vertex_loop_map, binding_point++);
GPU_vertbuf_bind_as_ssbo(vertex_normals, binding_point++);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_verts);
@@ -1851,8 +1838,6 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
draw_cache->subdiv = subdiv;
draw_cache->optimal_display = optimal_display;
draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops);
/* We can only evaluate limit normals if the patches are adaptive. */
draw_cache->do_limit_normals = settings.is_adaptive;
draw_cache->use_custom_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) &&
(mesh_eval->flag & ME_AUTOSMOOTH) &&

View File

@@ -51,7 +51,6 @@ typedef struct DRWSubdivCache {
struct BMesh *bm;
struct Subdiv *subdiv;
bool optimal_display;
bool do_limit_normals;
bool use_custom_loop_normals;
/* Coordinates used to evaluate patches for UVs, positions, and normals. */
@@ -165,6 +164,7 @@ void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache,
struct GPUVertBuf *pos_nor,
struct GPUVertBuf *face_adjacency_offsets,
struct GPUVertBuf *face_adjacency_lists,
struct GPUVertBuf *vertex_loop_map,
struct GPUVertBuf *vertex_normals);
void draw_subdiv_finalize_normals(const DRWSubdivCache *cache,
@@ -176,9 +176,7 @@ void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache,
GPUVertBuf *src_custom_normals,
GPUVertBuf *pos_nor);
void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
struct GPUVertBuf *pos_nor,
bool do_limit_normals);
void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, struct GPUVertBuf *pos_nor);
void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
struct GPUVertBuf *src_data,

View File

@@ -217,14 +217,12 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
void *UNUSED(data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
const bool do_limit_normals = subdiv_cache->do_limit_normals &&
!subdiv_cache->use_custom_loop_normals;
/* Initialize the vertex buffer, it was already allocated. */
GPU_vertbuf_init_build_on_device(
vbo, get_pos_nor_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
draw_subdiv_extract_pos_nor(subdiv_cache, vbo, do_limit_normals);
draw_subdiv_extract_pos_nor(subdiv_cache, vbo);
if (subdiv_cache->use_custom_loop_normals) {
Mesh *coarse_mesh = subdiv_cache->mesh;
@@ -250,7 +248,7 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
GPU_vertbuf_discard(src_custom_normals);
GPU_vertbuf_discard(dst_custom_normals);
}
else if (!do_limit_normals) {
else {
/* We cannot evaluate vertex normals using the limit surface, so compute them manually. */
GPUVertBuf *subdiv_loop_subdiv_vert_index = draw_subdiv_build_origindex_buffer(
subdiv_cache->subdiv_loop_subdiv_vert_index, subdiv_cache->num_subdiv_loops);
@@ -263,6 +261,7 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
vbo,
subdiv_cache->subdiv_vertex_face_adjacency_offsets,
subdiv_cache->subdiv_vertex_face_adjacency,
subdiv_loop_subdiv_vert_index,
vertex_normals);
draw_subdiv_finalize_normals(subdiv_cache, vertex_normals, subdiv_loop_subdiv_vert_index, vbo);

View File

@@ -140,6 +140,13 @@ void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor)
set_vertex_nor(vertex_data, nor, 0);
}
void add_newell_cross_v3_v3v3(inout vec3 n, vec3 v_prev, vec3 v_curr)
{
n[0] += (v_prev[1] - v_curr[1]) * (v_prev[2] + v_curr[2]);
n[1] += (v_prev[2] - v_curr[2]) * (v_prev[0] + v_curr[0]);
n[2] += (v_prev[0] - v_curr[0]) * (v_prev[1] + v_curr[1]);
}
#define ORIGINDEX_NONE -1
#ifdef SUBDIV_POLYGON_OFFSET

View File

@@ -16,11 +16,33 @@ layout(std430, binding = 2) readonly buffer faceAdjacencyLists
uint face_adjacency_lists[];
};
layout(std430, binding = 3) writeonly buffer vertexNormals
layout(std430, binding = 3) readonly buffer vertexLoopMap
{
uint vert_loop_map[];
};
layout(std430, binding = 4) writeonly buffer vertexNormals
{
vec3 normals[];
};
void find_prev_and_next_vertex_on_face(
uint face_index, uint vertex_index, out uint curr, out uint next, out uint prev)
{
uint start_loop_index = face_index * 4;
for (uint i = 0; i < 4; i++) {
uint subdiv_vert_index = vert_loop_map[start_loop_index + i];
if (subdiv_vert_index == vertex_index) {
curr = i;
next = (i + 1) % 4;
prev = (i + 4 - 1) % 4;
break;
}
}
}
void main()
{
uint vertex_index = get_global_invocation_index();
@@ -39,18 +61,37 @@ void main()
uint adjacent_face = face_adjacency_lists[first_adjacent_face_offset + i];
uint start_loop_index = adjacent_face * 4;
/* Compute face normal. */
vec3 adjacent_verts[3];
for (uint j = 0; j < 3; j++) {
adjacent_verts[j] = get_vertex_pos(pos_nor[start_loop_index + j]);
/* Compute the face normal using Newell's method. */
vec3 verts[4];
for (uint j = 0; j < 4; j++) {
verts[j] = get_vertex_pos(pos_nor[start_loop_index + j]);
}
vec3 face_normal = normalize(
cross(adjacent_verts[1] - adjacent_verts[0], adjacent_verts[2] - adjacent_verts[0]));
accumulated_normal += face_normal;
vec3 face_normal = vec3(0.0);
add_newell_cross_v3_v3v3(face_normal, verts[0], verts[1]);
add_newell_cross_v3_v3v3(face_normal, verts[1], verts[2]);
add_newell_cross_v3_v3v3(face_normal, verts[2], verts[3]);
add_newell_cross_v3_v3v3(face_normal, verts[3], verts[0]);
/* Accumulate angle weighted normal. */
uint curr_vert = 0;
uint next_vert = 0;
uint prev_vert = 0;
find_prev_and_next_vertex_on_face(
adjacent_face, vertex_index, curr_vert, next_vert, prev_vert);
vec3 curr_co = verts[curr_vert];
vec3 prev_co = verts[next_vert];
vec3 next_co = verts[prev_vert];
vec3 edvec_prev = normalize(prev_co - curr_co);
vec3 edvec_next = normalize(curr_co - next_co);
float fac = acos(-dot(edvec_prev, edvec_next));
accumulated_normal += face_normal * fac;
}
float weight = 1.0 / float(number_of_adjacent_faces);
vec3 normal = normalize(accumulated_normal);
normals[vertex_index] = normal;
}

View File

@@ -394,12 +394,8 @@ void main()
evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv);
# if defined(LIMIT_NORMALS)
vec3 nor = normalize(cross(du, dv));
# else
/* This will be computed later. */
vec3 nor = vec3(0.0);
# endif
int origindex = input_vert_origindex[loop_index];
uint flag = 0;

View File

@@ -38,13 +38,18 @@ void main()
}
}
else {
/* Face is flat shaded, compute flat face normal from an inscribed triangle. */
vec3 verts[3];
for (int i = 0; i < 3; i++) {
verts[i] = get_vertex_pos(pos_nor[start_loop_index + i]);
}
vec3 v0 = get_vertex_pos(pos_nor[start_loop_index + 0]);
vec3 v1 = get_vertex_pos(pos_nor[start_loop_index + 1]);
vec3 v2 = get_vertex_pos(pos_nor[start_loop_index + 2]);
vec3 v3 = get_vertex_pos(pos_nor[start_loop_index + 3]);
vec3 face_normal = normalize(cross(verts[1] - verts[0], verts[2] - verts[0]));
vec3 face_normal = vec3(0.0);
add_newell_cross_v3_v3v3(face_normal, v0, v1);
add_newell_cross_v3_v3v3(face_normal, v1, v2);
add_newell_cross_v3_v3v3(face_normal, v2, v3);
add_newell_cross_v3_v3v3(face_normal, v3, v0);
face_normal = normalize(face_normal);
for (int i = 0; i < 4; i++) {
output_lnor[start_loop_index + i] = face_normal;
}

View File

@@ -234,7 +234,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
* assigned at this stage of modifier stack evaluation. */
const bool is_editmode = (mesh->edit_mesh != NULL);
const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode);
if (BKE_subsurf_modifier_can_do_gpu_subdiv_ex(scene, ctx->object, smd, required_mode, false)) {
if (BKE_subsurf_modifier_can_do_gpu_subdiv_ex(
scene, ctx->object, mesh, smd, required_mode, false)) {
subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd);
return result;
}
@@ -246,9 +247,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* Happens on bad topology, but also on empty input mesh. */
return result;
}
const bool use_clnors = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) &&
(mesh->flag & ME_AUTOSMOOTH) &&
CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
const bool use_clnors = BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh);
if (use_clnors) {
/* If custom normals are present and the option is turned on calculate the split
* normals and clear flag so the normals get interpolated to the result mesh. */
@@ -412,6 +411,13 @@ static void panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, ptr, "show_only_control_edges", 0, NULL, ICON_NONE);
SubsurfModifierData *smd = ptr->data;
Object *ob = ob_ptr.data;
Mesh *mesh = ob->data;
if (BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(smd, mesh)) {
uiItemL(layout, "Autosmooth or custom normals detected, disabling GPU subdivision", ICON_INFO);
}
modifier_panel_end(layout, ptr);
}