This PR migrates the subdiv_patch_evaluation_comp.glsl to use shader create info. The part of OSD that is used is included as a typedef source (osd_patch_basis.glsl). Pull Request: https://projects.blender.org/blender/blender/pulls/134917
404 lines
10 KiB
GLSL
404 lines
10 KiB
GLSL
/* SPDX-FileCopyrightText: 2021-2022 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "subdiv_lib.glsl"
|
|
|
|
COMPUTE_SHADER_CREATE_INFO(subdiv_patch_evaluation_fdots_normals)
|
|
|
|
#if defined(VERTS_EVALUATION)
|
|
float get_flag(int index)
|
|
{
|
|
int char_4 = flags_buffer[index / 4];
|
|
int flag = (char_4 >> ((index % 4) * 8)) & 0xFF;
|
|
if (flag >= 128) {
|
|
flag = -128 + (flag - 128);
|
|
}
|
|
|
|
return float(flag);
|
|
}
|
|
#endif
|
|
|
|
vec2 read_vec2(int index)
|
|
{
|
|
vec2 result;
|
|
result.x = srcVertexBuffer[index * 2];
|
|
result.y = srcVertexBuffer[index * 2 + 1];
|
|
return result;
|
|
}
|
|
|
|
vec3 read_vec3(int index)
|
|
{
|
|
vec3 result;
|
|
result.x = srcVertexBuffer[index * 3];
|
|
result.y = srcVertexBuffer[index * 3 + 1];
|
|
result.z = srcVertexBuffer[index * 3 + 2];
|
|
return result;
|
|
}
|
|
|
|
#if defined(ORCO_EVALUATION)
|
|
vec3 read_vec3_extra(int index)
|
|
{
|
|
vec3 result;
|
|
result.x = srcExtraVertexBuffer[index * 3];
|
|
result.y = srcExtraVertexBuffer[index * 3 + 1];
|
|
result.z = srcExtraVertexBuffer[index * 3 + 2];
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
OsdPatchArray GetPatchArray(int arrayIndex)
|
|
{
|
|
return patchArrayBuffer[arrayIndex];
|
|
}
|
|
|
|
OsdPatchParam GetPatchParam(int patchIndex)
|
|
{
|
|
return patchParamBuffer[patchIndex];
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------
|
|
* Patch Coordinate lookup. Return an OsdPatchCoord for the given patch_index and uvs.
|
|
* This code is a port of the OpenSubdiv PatchMap lookup code.
|
|
*/
|
|
|
|
PatchHandle bogus_patch_handle()
|
|
{
|
|
PatchHandle ret;
|
|
ret.array_index = -1;
|
|
ret.vertex_index = -1;
|
|
ret.patch_index = -1;
|
|
return ret;
|
|
}
|
|
|
|
int transformUVToQuadQuadrant(float median, inout float u, inout float v)
|
|
{
|
|
int uHalf = (u >= median) ? 1 : 0;
|
|
if (uHalf != 0)
|
|
u -= median;
|
|
|
|
int vHalf = (v >= median) ? 1 : 0;
|
|
if (vHalf != 0)
|
|
v -= median;
|
|
|
|
return (vHalf << 1) | uHalf;
|
|
}
|
|
|
|
int transformUVToTriQuadrant(float median, inout float u, inout float v, inout bool rotated)
|
|
{
|
|
|
|
if (!rotated) {
|
|
if (u >= median) {
|
|
u -= median;
|
|
return 1;
|
|
}
|
|
if (v >= median) {
|
|
v -= median;
|
|
return 2;
|
|
}
|
|
if ((u + v) >= median) {
|
|
rotated = true;
|
|
return 3;
|
|
}
|
|
return 0;
|
|
}
|
|
else {
|
|
if (u < median) {
|
|
v -= median;
|
|
return 1;
|
|
}
|
|
if (v < median) {
|
|
u -= median;
|
|
return 2;
|
|
}
|
|
u -= median;
|
|
v -= median;
|
|
if ((u + v) < median) {
|
|
rotated = false;
|
|
return 3;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
PatchHandle find_patch(int face_index, float u, float v)
|
|
{
|
|
if (face_index < shader_data.min_patch_face || face_index > shader_data.max_patch_face) {
|
|
return bogus_patch_handle();
|
|
}
|
|
|
|
QuadNode node = quad_nodes[face_index - shader_data.min_patch_face];
|
|
|
|
if (!is_set(node.child[0])) {
|
|
return bogus_patch_handle();
|
|
}
|
|
|
|
float median = 0.5;
|
|
bool tri_rotated = false;
|
|
|
|
for (int depth = 0; depth <= shader_data.max_depth; ++depth, median *= 0.5) {
|
|
int quadrant = shader_data.patches_are_triangular ?
|
|
transformUVToTriQuadrant(median, u, v, tri_rotated) :
|
|
transformUVToQuadQuadrant(median, u, v);
|
|
|
|
if (is_leaf(node.child[quadrant])) {
|
|
return input_patch_handles[get_index(node.child[quadrant])];
|
|
}
|
|
|
|
node = quad_nodes[get_index(node.child[quadrant])];
|
|
}
|
|
}
|
|
|
|
OsdPatchCoord bogus_patch_coord(int face_index, float u, float v)
|
|
{
|
|
OsdPatchCoord coord;
|
|
coord.arrayIndex = 0;
|
|
coord.patchIndex = face_index;
|
|
coord.vertIndex = 0;
|
|
coord.s = u;
|
|
coord.t = v;
|
|
return coord;
|
|
}
|
|
|
|
OsdPatchCoord GetPatchCoord(int face_index, float u, float v)
|
|
{
|
|
PatchHandle patch_handle = find_patch(face_index, u, v);
|
|
|
|
if (patch_handle.array_index == -1) {
|
|
return bogus_patch_coord(face_index, u, v);
|
|
}
|
|
|
|
OsdPatchCoord coord;
|
|
coord.arrayIndex = patch_handle.array_index;
|
|
coord.patchIndex = patch_handle.patch_index;
|
|
coord.vertIndex = patch_handle.vertex_index;
|
|
coord.s = u;
|
|
coord.t = v;
|
|
return coord;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------
|
|
* Patch evaluation. Note that the 1st and 2nd derivatives are always computed, although we
|
|
* only return and use the 1st derivatives if adaptive patches are used. This could
|
|
* perhaps be optimized.
|
|
*/
|
|
|
|
#if defined(FVAR_EVALUATION)
|
|
void evaluate_patches_limits(int patch_index, float u, float v, inout vec2 dst)
|
|
{
|
|
OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
|
|
OsdPatchArray array = GetPatchArray(coord.arrayIndex);
|
|
OsdPatchParam param = GetPatchParam(coord.patchIndex);
|
|
|
|
int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
|
|
|
|
float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
|
|
int nPoints = OsdEvaluatePatchBasis(
|
|
patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
|
|
|
int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
|
|
|
|
for (int cv = 0; cv < nPoints; ++cv) {
|
|
int index = patchIndexBuffer[indexBase + cv];
|
|
vec2 src_fvar = read_vec2(shader_data.src_offset + index);
|
|
dst += src_fvar * wP[cv];
|
|
}
|
|
}
|
|
#else
|
|
void evaluate_patches_limits(
|
|
int patch_index, float u, float v, inout vec3 dst, inout vec3 du, inout vec3 dv)
|
|
{
|
|
OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
|
|
OsdPatchArray array = GetPatchArray(coord.arrayIndex);
|
|
OsdPatchParam param = GetPatchParam(coord.patchIndex);
|
|
|
|
int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
|
|
|
|
float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
|
|
int nPoints = OsdEvaluatePatchBasis(
|
|
patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
|
|
|
int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
|
|
|
|
for (int cv = 0; cv < nPoints; ++cv) {
|
|
int index = patchIndexBuffer[indexBase + cv];
|
|
vec3 src_vertex = read_vec3(index);
|
|
|
|
dst += src_vertex * wP[cv];
|
|
du += src_vertex * wDu[cv];
|
|
dv += src_vertex * wDv[cv];
|
|
}
|
|
}
|
|
|
|
# if defined(ORCO_EVALUATION)
|
|
/* Evaluate the patches limits from the extra source vertex buffer. */
|
|
void evaluate_patches_limits_extra(int patch_index, float u, float v, inout vec3 dst)
|
|
{
|
|
OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
|
|
OsdPatchArray array = GetPatchArray(coord.arrayIndex);
|
|
OsdPatchParam param = GetPatchParam(coord.patchIndex);
|
|
|
|
int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
|
|
|
|
float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
|
|
int nPoints = OsdEvaluatePatchBasis(
|
|
patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
|
|
|
int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
|
|
|
|
for (int cv = 0; cv < nPoints; ++cv) {
|
|
int index = patchIndexBuffer[indexBase + cv];
|
|
vec3 src_vertex = read_vec3_extra(index);
|
|
|
|
dst += src_vertex * wP[cv];
|
|
}
|
|
}
|
|
# endif
|
|
#endif
|
|
|
|
/* ------------------------------------------------------------------------------
|
|
* Entry point.
|
|
*/
|
|
|
|
#if defined(FVAR_EVALUATION)
|
|
void main()
|
|
{
|
|
/* We execute for each quad. */
|
|
uint quad_index = get_global_invocation_index();
|
|
if (quad_index >= shader_data.total_dispatch_size) {
|
|
return;
|
|
}
|
|
|
|
uint start_loop_index = quad_index * 4;
|
|
|
|
for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
|
|
vec2 fvar = vec2(0.0);
|
|
|
|
BlenderPatchCoord patch_co = patch_coords[loop_index];
|
|
vec2 uv = decode_uv(patch_co.encoded_uv);
|
|
|
|
evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, fvar);
|
|
output_fvar[shader_data.dst_offset + loop_index] = fvar;
|
|
}
|
|
}
|
|
#elif defined(FDOTS_EVALUATION)
|
|
bool is_face_selected(uint coarse_quad_index)
|
|
{
|
|
return (extra_coarse_face_data[coarse_quad_index] & shader_data.coarse_face_select_mask) != 0;
|
|
}
|
|
|
|
bool is_face_active(uint coarse_quad_index)
|
|
{
|
|
return (extra_coarse_face_data[coarse_quad_index] & shader_data.coarse_face_active_mask) != 0;
|
|
}
|
|
|
|
float get_face_flag(uint coarse_quad_index)
|
|
{
|
|
if (is_face_active(coarse_quad_index)) {
|
|
return -1.0;
|
|
}
|
|
|
|
if (is_face_selected(coarse_quad_index)) {
|
|
return 1.0;
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
bool is_face_hidden(uint coarse_quad_index)
|
|
{
|
|
return (extra_coarse_face_data[coarse_quad_index] & shader_data.coarse_face_hidden_mask) != 0;
|
|
}
|
|
|
|
void main()
|
|
{
|
|
/* We execute for each coarse quad. */
|
|
uint coarse_quad_index = get_global_invocation_index();
|
|
if (coarse_quad_index >= shader_data.total_dispatch_size) {
|
|
return;
|
|
}
|
|
|
|
BlenderPatchCoord patch_co = patch_coords[coarse_quad_index];
|
|
vec2 uv = decode_uv(patch_co.encoded_uv);
|
|
|
|
vec3 pos = vec3(0.0);
|
|
vec3 du = vec3(0.0);
|
|
vec3 dv = vec3(0.0);
|
|
evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv);
|
|
vec3 nor = normalize(cross(du, dv));
|
|
|
|
FDotVert vert;
|
|
vert.x = pos.x;
|
|
vert.y = pos.y;
|
|
vert.z = pos.z;
|
|
|
|
FDotNor fnor;
|
|
fnor.x = nor.x;
|
|
fnor.y = nor.y;
|
|
fnor.z = nor.z;
|
|
fnor.flag = get_face_flag(coarse_quad_index);
|
|
|
|
output_verts[coarse_quad_index] = vert;
|
|
# ifdef FDOTS_NORMALS
|
|
output_nors[coarse_quad_index] = fnor;
|
|
# endif
|
|
|
|
if (shader_data.use_hide && is_face_hidden(coarse_quad_index)) {
|
|
output_indices[coarse_quad_index] = 0xffffffff;
|
|
}
|
|
else {
|
|
output_indices[coarse_quad_index] = coarse_quad_index;
|
|
}
|
|
}
|
|
#else
|
|
void main()
|
|
{
|
|
/* We execute for each quad. */
|
|
uint quad_index = get_global_invocation_index();
|
|
if (quad_index >= shader_data.total_dispatch_size) {
|
|
return;
|
|
}
|
|
|
|
uint start_loop_index = quad_index * 4;
|
|
|
|
for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
|
|
vec3 pos = vec3(0.0);
|
|
vec3 du = vec3(0.0);
|
|
vec3 dv = vec3(0.0);
|
|
|
|
BlenderPatchCoord patch_co = patch_coords[loop_index];
|
|
vec2 uv = decode_uv(patch_co.encoded_uv);
|
|
|
|
evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv);
|
|
|
|
/* This will be computed later. */
|
|
vec3 nor = vec3(0.0);
|
|
|
|
int origindex = input_vert_origindex[loop_index];
|
|
float flag = 0.0;
|
|
if (origindex == -1) {
|
|
flag = -1.0;
|
|
}
|
|
else {
|
|
flag = get_flag(origindex);
|
|
}
|
|
|
|
PosNorLoop vertex_data;
|
|
vertex_data = subdiv_set_vertex_pos(vertex_data, pos);
|
|
vertex_data = subdiv_set_vertex_nor(vertex_data, nor);
|
|
vertex_data = subdiv_set_vertex_flag(vertex_data, flag);
|
|
output_verts[loop_index] = vertex_data;
|
|
|
|
# if defined(ORCO_EVALUATION)
|
|
pos = vec3(0.0);
|
|
evaluate_patches_limits_extra(patch_co.patch_index, uv.x, uv.y, pos);
|
|
|
|
/* Set w = 0.0 to indicate that this is not a generic attribute.
|
|
* See comments in `extract_mesh_vbo_orco.cc`. */
|
|
vec4 orco_data = vec4(pos, 0.0);
|
|
output_orcos[loop_index] = orco_data;
|
|
# endif
|
|
}
|
|
}
|
|
#endif
|