Fix #90641: wireframe does not hide edges of coplanar faces #105352
|
@ -21,6 +21,7 @@
|
|||
#include "BKE_particle.h"
|
||||
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_math_base.hh"
|
||||
|
||||
#include "DRW_render.h"
|
||||
#include "GPU_shader.h"
|
||||
|
@ -29,6 +30,8 @@
|
|||
|
||||
#include "overlay_private.hh"
|
||||
|
||||
using namespace blender::math;
|
||||
|
||||
void OVERLAY_wireframe_init(OVERLAY_Data *vedata)
|
||||
{
|
||||
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
||||
|
@ -47,7 +50,13 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
|
|||
|
||||
View3DShading *shading = &draw_ctx->v3d->shading;
|
||||
|
||||
pd->shdata.wire_step_param = pd->overlay.wireframe_threshold - 254.0f / 255.0f;
|
||||
/* Use `sqrt` since the value stored in the edge is a variation of the cosine, so its square
|
||||
* becomes more proportional with a variation of angle. */
|
||||
pd->shdata.wire_step_param = sqrt(abs(pd->overlay.wireframe_threshold));
|
||||
|
||||
/* The maximum value (255 in the vbo) is used to force hide the edge. */
|
||||
pd->shdata.wire_step_param = interpolate(0.0f, 1.0f - (1.0f / 255), pd->shdata.wire_step_param);
|
||||
|
||||
pd->shdata.wire_opacity = pd->overlay.wireframe_opacity;
|
||||
|
||||
bool is_wire_shmode = (shading->type == OB_WIRE);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
|
||||
float get_edge_sharpness(float wd)
|
||||
bool is_edge_sharpness_visible(float wd)
|
||||
{
|
||||
return ((wd == 0.0) ? -1.5 : wd) + wireStepParam;
|
||||
return wd <= wireStepParam;
|
||||
}
|
||||
|
||||
void wire_color_get(out vec3 rim_col, out vec3 wire_col)
|
||||
|
@ -129,7 +129,7 @@ void main()
|
|||
#endif
|
||||
|
||||
/* Cull flat edges below threshold. */
|
||||
if (!no_attr && (get_edge_sharpness(wd) < 0.0)) {
|
||||
if (!no_attr && !is_edge_sharpness_visible(wd)) {
|
||||
edgeStart = vec2(-1.0);
|
||||
}
|
||||
|
||||
|
|
|
@ -1881,6 +1881,7 @@ void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
|
|||
void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
|
||||
GPUVertBuf *pos_nor,
|
||||
GPUVertBuf *edge_draw_flag,
|
||||
GPUVertBuf *poly_other_map,
|
||||
GPUVertBuf *edge_fac)
|
||||
{
|
||||
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_EDGE_FAC);
|
||||
|
@ -1889,6 +1890,7 @@ void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
|
|||
int binding_point = 0;
|
||||
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
|
||||
GPU_vertbuf_bind_as_ssbo(edge_draw_flag, binding_point++);
|
||||
GPU_vertbuf_bind_as_ssbo(poly_other_map, binding_point++);
|
||||
GPU_vertbuf_bind_as_ssbo(edge_fac, binding_point++);
|
||||
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
|
||||
|
||||
|
|
|
@ -259,6 +259,7 @@ void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
|
|||
void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
|
||||
struct GPUVertBuf *pos_nor,
|
||||
struct GPUVertBuf *edge_draw_flag,
|
||||
struct GPUVertBuf *poly_other_map,
|
||||
struct GPUVertBuf *edge_fac);
|
||||
|
||||
void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
|
||||
|
|
|
@ -7,11 +7,14 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_math_vector.hh"
|
||||
|
||||
#include "GPU_capabilities.h"
|
||||
|
||||
#include "draw_subdivision.h"
|
||||
#include "extract_mesh.hh"
|
||||
|
||||
#define FORCE_HIDE 255
|
||||
namespace blender::draw {
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
@ -19,27 +22,38 @@ namespace blender::draw {
|
|||
* Defines how much an edge is visible.
|
||||
* \{ */
|
||||
|
||||
struct MEdgeDataPrev {
|
||||
int corner_a;
|
||||
|
||||
/* Data that represents:
|
||||
* - the index of the polygon of `corner_a` before the 2nd loop is found
|
||||
* - the index of the next radial corner after the 2nd loop is found */
|
||||
int data;
|
||||
};
|
||||
|
||||
struct MeshExtract_EdgeFac_Data {
|
||||
uint8_t *vbo_data;
|
||||
bool use_edge_render;
|
||||
/* Number of loop per edge. */
|
||||
uint8_t *edge_loop_count;
|
||||
|
||||
MEdgeDataPrev *edge_pdata;
|
||||
};
|
||||
|
||||
static float loop_edge_factor_get(const float f_no[3],
|
||||
const float v_co[3],
|
||||
const float v_no[3],
|
||||
const float v_next_co[3])
|
||||
/**
|
||||
* Calculates a factor that is used to identify the minimum angle in the shader to display an edge.
|
||||
* NOTE: Keep in sync with `common_subdiv_vbo_edge_fac_comp.glsl`.
|
||||
*/
|
||||
BLI_INLINE uint8_t loop_edge_factor_get(const float3 &fa_no, const float3 &fb_no)
|
||||
{
|
||||
float enor[3], evec[3];
|
||||
sub_v3_v3v3(evec, v_next_co, v_co);
|
||||
cross_v3_v3v3(enor, v_no, evec);
|
||||
normalize_v3(enor);
|
||||
float d = fabsf(dot_v3v3(enor, f_no));
|
||||
const float cosine = math::dot(fa_no, fb_no);
|
||||
|
||||
/* Re-scale to the slider range. */
|
||||
d *= (1.0f / 0.065f);
|
||||
CLAMP(d, 0.0f, 1.0f);
|
||||
return d;
|
||||
float fac = (200 * (cosine - 1.0f)) + 1.0f;
|
||||
CLAMP(fac, 0.0f, 1.0f);
|
||||
|
||||
/* 255 is a reserved value to force hide the wire. */
|
||||
return uint8_t(fac * 254);
|
||||
}
|
||||
|
||||
static void extract_edge_fac_init(const MeshRenderData *mr,
|
||||
|
@ -59,10 +73,10 @@ static void extract_edge_fac_init(const MeshRenderData *mr,
|
|||
MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(tls_data);
|
||||
|
||||
if (mr->extract_type == MR_EXTRACT_MESH) {
|
||||
data->use_edge_render = !mr->me->runtime->subsurf_optimal_display_edges.is_empty();
|
||||
data->edge_loop_count = MEM_cnew_array<uint8_t>(mr->edge_len, __func__);
|
||||
if (!mr->me->runtime->subsurf_optimal_display_edges.is_empty()) {
|
||||
data->use_edge_render = true;
|
||||
}
|
||||
data->edge_pdata = (MEdgeDataPrev *)MEM_malloc_arrayN(
|
||||
mr->edge_len, sizeof(MEdgeDataPrev), __func__);
|
||||
}
|
||||
else {
|
||||
/* HACK to bypass non-manifold check in mesh_edge_fac_finish(). */
|
||||
|
@ -84,14 +98,12 @@ static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr,
|
|||
const int l_index = BM_elem_index_get(l_iter);
|
||||
|
||||
if (BM_edge_is_manifold(l_iter->e)) {
|
||||
float ratio = loop_edge_factor_get(bm_face_no_get(mr, f),
|
||||
bm_vert_co_get(mr, l_iter->v),
|
||||
bm_vert_no_get(mr, l_iter->v),
|
||||
bm_vert_co_get(mr, l_iter->next->v));
|
||||
data->vbo_data[l_index] = ratio * 253 + 1;
|
||||
BMFace *fb = l_iter->f != f ? l_iter->f : l_iter->radial_next->f;
|
||||
data->vbo_data[l_index] = loop_edge_factor_get(float3(bm_face_no_get(mr, f)),
|
||||
float3(bm_face_no_get(mr, fb)));
|
||||
}
|
||||
else {
|
||||
data->vbo_data[l_index] = 255;
|
||||
data->vbo_data[l_index] = 0;
|
||||
}
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
|
@ -106,32 +118,45 @@ static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr,
|
|||
|
||||
const int ml_index_end = poly->loopstart + poly->totloop;
|
||||
for (int ml_index = poly->loopstart; ml_index < ml_index_end; ml_index += 1) {
|
||||
const int vert = mr->corner_verts[ml_index];
|
||||
const int edge = mr->corner_edges[ml_index];
|
||||
|
||||
if (data->use_edge_render) {
|
||||
data->vbo_data[ml_index] = optimal_display_edges[edge] ? 255 : 0;
|
||||
if (data->use_edge_render && !optimal_display_edges[edge]) {
|
||||
data->vbo_data[ml_index] = FORCE_HIDE;
|
||||
}
|
||||
else {
|
||||
MEdgeDataPrev *medata = &data->edge_pdata[edge];
|
||||
|
||||
/* Count loop per edge to detect non-manifold. */
|
||||
if (data->edge_loop_count[edge] < 3) {
|
||||
data->edge_loop_count[edge]++;
|
||||
}
|
||||
if (data->edge_loop_count[edge] == 2) {
|
||||
/* Manifold */
|
||||
const int ml_index_last = poly->totloop + poly->loopstart - 1;
|
||||
const int ml_index_other = (ml_index == ml_index_last) ? poly->loopstart : (ml_index + 1);
|
||||
const int vert_next = mr->corner_verts[ml_index_other];
|
||||
float ratio = loop_edge_factor_get(mr->poly_normals[poly_index],
|
||||
mr->vert_positions[vert],
|
||||
mr->vert_normals[vert],
|
||||
mr->vert_positions[vert_next]);
|
||||
data->vbo_data[ml_index] = ratio * 253 + 1;
|
||||
}
|
||||
else {
|
||||
/* Non-manifold */
|
||||
data->vbo_data[ml_index] = 255;
|
||||
uint8_t corner_count = data->edge_loop_count[edge];
|
||||
if (corner_count < 4) {
|
||||
if (corner_count == 0) {
|
||||
/* Prepare to calculate the factor. */
|
||||
medata->corner_a = ml_index;
|
||||
medata->data = poly_index;
|
||||
|
||||
/* Consider boundary edge while second corner is not detected. Always visible. */
|
||||
data->vbo_data[ml_index] = 0;
|
||||
}
|
||||
else if (corner_count == 1) {
|
||||
/* Calculate the factor for both corners. */
|
||||
const int poly_index_a = medata->data;
|
||||
uint8_t fac = loop_edge_factor_get(float3(mr->poly_normals[poly_index_a]),
|
||||
float3(mr->poly_normals[poly_index]));
|
||||
data->vbo_data[medata->corner_a] = fac;
|
||||
data->vbo_data[ml_index] = fac;
|
||||
|
||||
/* If the count still changes, use this `data` member to inform the corner. */
|
||||
medata->data = ml_index;
|
||||
}
|
||||
else {
|
||||
/* Non-manifold edge. Always visible. */
|
||||
const int corner_a = medata->corner_a;
|
||||
const int corner_b = medata->data;
|
||||
data->vbo_data[corner_a] = 0;
|
||||
data->vbo_data[corner_b] = 0;
|
||||
}
|
||||
|
||||
/* Increment the corner_count count. */
|
||||
data->edge_loop_count[edge] = corner_count + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,8 +168,8 @@ static void extract_edge_fac_iter_loose_edge_bm(const MeshRenderData *mr,
|
|||
void *_data)
|
||||
{
|
||||
MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data);
|
||||
data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255;
|
||||
data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255;
|
||||
data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 0;
|
||||
data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 0;
|
||||
}
|
||||
|
||||
static void extract_edge_fac_iter_loose_edge_mesh(const MeshRenderData *mr,
|
||||
|
@ -154,8 +179,8 @@ static void extract_edge_fac_iter_loose_edge_mesh(const MeshRenderData *mr,
|
|||
{
|
||||
MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data);
|
||||
|
||||
data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255;
|
||||
data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255;
|
||||
data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 0;
|
||||
data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 0;
|
||||
}
|
||||
|
||||
static void extract_edge_fac_finish(const MeshRenderData *mr,
|
||||
|
@ -190,6 +215,7 @@ static void extract_edge_fac_finish(const MeshRenderData *mr,
|
|||
MEM_freeN(data->vbo_data);
|
||||
}
|
||||
MEM_SAFE_FREE(data->edge_loop_count);
|
||||
MEM_SAFE_FREE(data->edge_pdata);
|
||||
}
|
||||
|
||||
/* Different function than the one used for the non-subdivision case, as we directly take care of
|
||||
|
@ -208,39 +234,72 @@ static GPUVertFormat *get_subdiv_edge_fac_format()
|
|||
return &format;
|
||||
}
|
||||
|
||||
static GPUVertBuf *build_poly_other_map_vbo(const DRWSubdivCache *subdiv_cache)
|
||||
{
|
||||
GPUVertBuf *vbo = GPU_vertbuf_calloc();
|
||||
|
||||
static GPUVertFormat format = {0};
|
||||
if (format.attr_len == 0) {
|
||||
GPU_vertformat_attr_add(&format, "poly_other", GPU_COMP_I32, 1, GPU_FETCH_INT);
|
||||
}
|
||||
|
||||
GPU_vertbuf_init_with_format(vbo, &format);
|
||||
GPU_vertbuf_data_alloc(vbo, subdiv_cache->num_subdiv_loops);
|
||||
|
||||
MutableSpan vbo_data{static_cast<int *>(GPU_vertbuf_get_data(vbo)),
|
||||
subdiv_cache->num_subdiv_loops};
|
||||
|
||||
Array<MEdgeDataPrev> edge_data(subdiv_cache->num_subdiv_edges);
|
||||
Array<int> tmp_edge_corner_count(subdiv_cache->num_subdiv_edges, 0);
|
||||
int *subdiv_loop_subdiv_edge_index = subdiv_cache->subdiv_loop_subdiv_edge_index;
|
||||
|
||||
for (int corner : IndexRange(subdiv_cache->num_subdiv_loops)) {
|
||||
const int edge = subdiv_loop_subdiv_edge_index[corner];
|
||||
const int quad = corner / 4;
|
||||
const int corner_count = tmp_edge_corner_count[edge]++;
|
||||
|
||||
vbo_data[corner] = -1;
|
||||
if (corner_count == 0) {
|
||||
edge_data[edge].corner_a = corner;
|
||||
edge_data[edge].data = quad;
|
||||
}
|
||||
else if (corner_count == 1) {
|
||||
const int corner_a = edge_data[edge].corner_a;
|
||||
const int quad_a = edge_data[edge].data;
|
||||
vbo_data[corner_a] = quad;
|
||||
vbo_data[corner] = quad_a;
|
||||
edge_data[edge].data = corner;
|
||||
}
|
||||
else if (corner_count == 2) {
|
||||
const int corner_a = edge_data[edge].corner_a;
|
||||
const int corner_b = edge_data[edge].data;
|
||||
vbo_data[corner_a] = -1;
|
||||
vbo_data[corner_b] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return vbo;
|
||||
}
|
||||
|
||||
static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
|
||||
const MeshRenderData * /*mr*/,
|
||||
MeshBatchCache *cache,
|
||||
void *buffer,
|
||||
void * /*data*/)
|
||||
{
|
||||
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
|
||||
GPUVertBuf *edge_idx = cache->final.buff.vbo.edge_idx;
|
||||
GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
|
||||
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
|
||||
|
||||
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
|
||||
GPU_vertbuf_init_build_on_device(
|
||||
vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
|
||||
|
||||
/* Create a temporary buffer for the edge original indices if it was not requested. */
|
||||
const bool has_edge_idx = edge_idx != nullptr;
|
||||
GPUVertBuf *loop_edge_draw_flag = nullptr;
|
||||
if (has_edge_idx) {
|
||||
loop_edge_draw_flag = edge_idx;
|
||||
}
|
||||
else {
|
||||
loop_edge_draw_flag = GPU_vertbuf_calloc();
|
||||
draw_subdiv_init_origindex_buffer(
|
||||
loop_edge_draw_flag,
|
||||
static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_draw_flag)),
|
||||
subdiv_cache->num_subdiv_loops,
|
||||
0);
|
||||
}
|
||||
GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
|
||||
GPUVertBuf *poly_other_map = build_poly_other_map_vbo(subdiv_cache);
|
||||
|
||||
draw_subdiv_build_edge_fac_buffer(subdiv_cache, pos_nor, loop_edge_draw_flag, vbo);
|
||||
draw_subdiv_build_edge_fac_buffer(
|
||||
subdiv_cache, pos_nor, subdiv_cache->edges_draw_flag, poly_other_map, vbo);
|
||||
|
||||
if (!has_edge_idx) {
|
||||
GPU_vertbuf_discard(loop_edge_draw_flag);
|
||||
}
|
||||
GPU_vertbuf_discard(poly_other_map);
|
||||
}
|
||||
|
||||
static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
|
||||
|
|
|
@ -11,7 +11,12 @@ layout(std430, binding = 1) readonly buffer inputEdgeDrawFlag
|
|||
uint input_edge_draw_flag[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 2) writeonly buffer outputEdgeFactors
|
||||
layout(std430, binding = 2) readonly buffer inputPolyOtherMap
|
||||
{
|
||||
int input_poly_other_map[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 3) writeonly buffer outputEdgeFactors
|
||||
{
|
||||
#ifdef GPU_AMD_DRIVER_BYTE_BUG
|
||||
float output_edge_fac[];
|
||||
|
@ -28,42 +33,46 @@ void write_vec4(uint index, vec4 edge_facs)
|
|||
}
|
||||
#else
|
||||
/* Use same scaling as in extract_edge_fac_iter_poly_mesh. */
|
||||
uint a = uint(clamp(edge_facs.x * 253.0 + 1.0, 0.0, 255.0));
|
||||
uint b = uint(clamp(edge_facs.y * 253.0 + 1.0, 0.0, 255.0));
|
||||
uint c = uint(clamp(edge_facs.z * 253.0 + 1.0, 0.0, 255.0));
|
||||
uint d = uint(clamp(edge_facs.w * 253.0 + 1.0, 0.0, 255.0));
|
||||
uint packed_edge_fac = a << 24 | b << 16 | c << 8 | d;
|
||||
uint a = uint(edge_facs.x * 255);
|
||||
uint b = uint(edge_facs.y * 255);
|
||||
uint c = uint(edge_facs.z * 255);
|
||||
uint d = uint(edge_facs.w * 255);
|
||||
uint packed_edge_fac = d << 24 | c << 16 | b << 8 | a;
|
||||
output_edge_fac[index] = packed_edge_fac;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* From extract_mesh_vbo_edge_fac.cc, keep in sync! */
|
||||
float loop_edge_factor_get(vec3 f_no, vec3 v_co, vec3 v_no, vec3 v_next_co)
|
||||
float loop_edge_factor_get(vec3 fa_no, vec3 fb_no)
|
||||
{
|
||||
vec3 evec = v_next_co - v_co;
|
||||
vec3 enor = normalize(cross(v_no, evec));
|
||||
float d = abs(dot(enor, f_no));
|
||||
float cosine = dot(fa_no, fb_no);
|
||||
|
||||
/* Re-scale to the slider range. */
|
||||
d *= (1.0 / 0.065);
|
||||
return clamp(d, 0.0, 1.0);
|
||||
float fac = (200 * (cosine - 1.0)) + 1.0;
|
||||
|
||||
/* The maximum value (255) is unreachable through the UI. */
|
||||
return clamp(fac, 0.0, 1.0) * (254.0 / 255.0);
|
||||
}
|
||||
|
||||
float compute_line_factor(uint start_loop_index, uint corner_index, vec3 face_normal)
|
||||
float compute_line_factor(uint corner_index, vec3 face_normal)
|
||||
{
|
||||
uint vertex_index = start_loop_index + corner_index;
|
||||
uint edge_draw_flag = input_edge_draw_flag[vertex_index];
|
||||
if (input_edge_draw_flag[corner_index] == 0) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
if (edge_draw_flag == 0) {
|
||||
int quad_other = input_poly_other_map[corner_index];
|
||||
if (quad_other == -1) {
|
||||
/* Boundary edge or non-manifold. */
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* Mod 4 so we loop back at the first vertex on the last loop index (3), but only the corner
|
||||
* index needs to be wrapped. */
|
||||
uint next_vertex_index = start_loop_index + (corner_index + 1) % 4;
|
||||
vec3 vertex_pos = get_vertex_pos(pos_nor[vertex_index]);
|
||||
vec3 vertex_nor = get_vertex_nor(pos_nor[vertex_index]);
|
||||
vec3 next_vertex_pos = get_vertex_pos(pos_nor[next_vertex_index]);
|
||||
return loop_edge_factor_get(face_normal, vertex_pos, vertex_nor, next_vertex_pos);
|
||||
uint start_coner_index_other = quad_other * 4;
|
||||
vec3 v0 = get_vertex_pos(pos_nor[start_coner_index_other + 0]);
|
||||
vec3 v1 = get_vertex_pos(pos_nor[start_coner_index_other + 1]);
|
||||
vec3 v2 = get_vertex_pos(pos_nor[start_coner_index_other + 2]);
|
||||
vec3 face_normal_other = normalize(cross(v1 - v0, v2 - v0));
|
||||
|
||||
return loop_edge_factor_get(face_normal, face_normal_other);
|
||||
}
|
||||
|
||||
void main()
|
||||
|
@ -84,8 +93,8 @@ void main()
|
|||
vec3 face_normal = normalize(cross(v1 - v0, v2 - v0));
|
||||
|
||||
vec4 edge_facs = vec4(0.0);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
edge_facs[i] = compute_line_factor(start_loop_index, i, face_normal);
|
||||
for (uint i = 0; i < 4; i++) {
|
||||
edge_facs[i] = compute_line_factor(start_loop_index + i, face_normal);
|
||||
}
|
||||
|
||||
#ifdef GPU_AMD_DRIVER_BYTE_BUG
|
||||
|
|
Loading…
Reference in New Issue