diff options
author | Nicholas Bishop <nicholasbishop@gmail.com> | 2012-10-06 20:52:52 +0400 |
---|---|---|
committer | Nicholas Bishop <nicholasbishop@gmail.com> | 2012-10-06 20:52:52 +0400 |
commit | 0c0fa7dde66269f451d5b6ebe95860dd9e913d5f (patch) | |
tree | 4deabf5be6cbbf8772de494fe9094cf5b0084c65 /source/blender/gpu/intern | |
parent | 1df170bb96158abebc123256df04cebe6a5f8f08 (diff) |
Improve flat-shaded VBO drawing for sculpt meshes
Separate vertex copies are now made for flat-shading, such that the
normal is correctly flat-shaded. The element index buffer is not
created in this case.
Diffstat (limited to 'source/blender/gpu/intern')
-rw-r--r-- | source/blender/gpu/intern/gpu_buffers.c | 112 |
1 files changed, 91 insertions, 21 deletions
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index a0a379c3cee..201162262b2 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -1397,28 +1397,88 @@ void GPU_update_mesh_buffers(GPU_Buffers *buffers, MVert *mvert, int *vert_indices, int totvert, const float *vmask) { VertexBufferFormat *vert_data; - int i; + int i, j, k; buffers->vmask = vmask; if (buffers->vert_buf) { + int totelem = (buffers->smooth ? totvert : (buffers->tot_tri * 3)); + /* Build VBO */ glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); glBufferDataARB(GL_ARRAY_BUFFER_ARB, - sizeof(VertexBufferFormat) * totvert, - NULL, GL_STATIC_DRAW_ARB); + sizeof(VertexBufferFormat) * totelem, + NULL, GL_STATIC_DRAW_ARB); + vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); if (vert_data) { - for (i = 0; i < totvert; ++i) { - MVert *v = mvert + vert_indices[i]; - VertexBufferFormat *out = vert_data + i; - - copy_v3_v3(out->co, v->co); - memcpy(out->no, v->no, sizeof(short) * 3); - if (vmask) { - gpu_color_from_mask_copy(vmask[vert_indices[i]], - out->color); + /* Vertex data is shared if smooth-shaded, but seperate + copies are made for flat shading because normals + shouldn't be shared. */ + if (buffers->smooth) { + for (i = 0; i < totvert; ++i) { + MVert *v = mvert + vert_indices[i]; + VertexBufferFormat *out = vert_data + i; + + copy_v3_v3(out->co, v->co); + memcpy(out->no, v->no, sizeof(short) * 3); + if (vmask) { + gpu_color_from_mask_copy(vmask[vert_indices[i]], + out->color); + } + } + } + else { + for (i = 0; i < buffers->totface; ++i) { + const MFace *f = &buffers->mface[buffers->face_indices[i]]; + const unsigned int *fv = &f->v1; + const int vi[2][3] = {{0, 1, 2}, {3, 0, 2}}; + float fno[3]; + short no[3]; + + float fmask; + + /* Face normal and mask */ + if (f->v4) { + normal_quad_v3(fno, + mvert[fv[0]].co, + mvert[fv[1]].co, + mvert[fv[2]].co, + mvert[fv[3]].co); + if (vmask) { + fmask = (vmask[fv[0]] + + vmask[fv[1]] + + vmask[fv[2]] + + vmask[fv[3]]) * 0.25; + } + } + else { + normal_tri_v3(fno, + mvert[fv[0]].co, + mvert[fv[1]].co, + mvert[fv[2]].co); + if (vmask) { + fmask = (vmask[fv[0]] + + vmask[fv[1]] + + vmask[fv[2]]) / 3.0f; + } + } + normal_float_to_short_v3(no, fno); + + for (j = 0; j < (f->v4 ? 2 : 1); j++) { + for (k = 0; k < 3; k++) { + const MVert *v = &mvert[fv[vi[j][k]]]; + VertexBufferFormat *out = vert_data; + + copy_v3_v3(out->co, v->co); + memcpy(out->no, no, sizeof(short) * 3); + if (vmask) + gpu_color_from_mask_copy(fmask, out->color); + + vert_data++; + } + } } } @@ -1454,8 +1514,11 @@ GPU_Buffers *GPU_build_mesh_buffers(int (*face_vert_indices)[4], if (!paint_is_face_hidden(f, mvert)) tottri += f->v4 ? 2 : 1; } - - if (gpu_vbo_enabled()) + + /* An element index buffer is used for smooth shading, but flat + shading requires separate vertex normals so an index buffer is + can't be used there. */ + if (gpu_vbo_enabled() && buffers->smooth) glGenBuffersARB(1, &buffers->index_buf); if (buffers->index_buf) { @@ -1499,7 +1562,7 @@ GPU_Buffers *GPU_build_mesh_buffers(int (*face_vert_indices)[4], glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } - if (buffers->index_buf) + if (buffers->index_buf || !buffers->smooth) glGenBuffersARB(1, &buffers->vert_buf); buffers->tot_tri = tottri; @@ -1979,7 +2042,6 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers) void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) { const int has_mask = (buffers->vmask || buffers->gridkey.has_mask); - int smooth = 0; if (buffers->totface) { const MFace *f = &buffers->mface[buffers->face_indices[0]]; @@ -1992,9 +2054,9 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) return; } - glShadeModel(buffers->smooth ? GL_SMOOTH : GL_FLAT); + glShadeModel((buffers->smooth || buffers->totface) ? GL_SMOOTH : GL_FLAT); - if (buffers->vert_buf && buffers->index_buf) { + if (buffers->vert_buf) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); if (has_mask) { @@ -2006,7 +2068,9 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) } glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); + + if (buffers->index_buf) + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); if (buffers->tot_quad) { char *offset = 0; @@ -2027,6 +2091,8 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) } } else { + int totelem = buffers->tot_tri * 3; + glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), (void *)offsetof(VertexBufferFormat, co)); glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), @@ -2036,11 +2102,15 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial) (void *)offsetof(VertexBufferFormat, color)); } - glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, buffers->index_type, 0); + if (buffers->index_buf) + glDrawElements(GL_TRIANGLES, totelem, buffers->index_type, 0); + else + glDrawArrays(GL_TRIANGLES, 0, totelem); } glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + if (buffers->index_buf) + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); |