Implementation of the design task #142969. This adds the following: - Exact GPU interpolation of curves of all types. - Radius attribute support. - Cyclic curve support. - Resolution attribute support. - New Cylinder hair shape type.  What changed: - EEVEE doesn't compute random normals for strand hairs anymore. These are considered legacy now. - EEVEE now have an internal shadow bias to avoid self shadowing on hair. - Workbench Curves Strip display option is no longer flat and has better shading. - Legacy Hair particle system evaluates radius at control points before applying additional subdivision. This now matches Cycles. - Color Attribute Node without a name do not fetch the active color attribute anymore. This now matches Cycles. Notes: - This is not 100% matching the CPU implementation for interpolation (see the epsilons in the tests). - Legacy Hair Particle points is now stored in local space after interpolation. The new cylinder shape allows for more correct hair shading in workbench and better intersection in EEVEE. | | Strand | Strip | Cylinder | | ---- | --- | --- | --- | | Main |  |  | N/A | | PR |  |  |  | | | Strand | Strip | Cylinder | | ---- | --- | --- | --- | | Main |  | | N/A | | PR | ||  | Cyclic Curve, Mixed curve type, and proper radius support:  Test file for attribute lookup: [test_attribute_lookup.blend](/attachments/1d54dd06-379b-4480-a1c5-96adc1953f77) Follow Up Tasks: - Correct full tube segments orientation based on tangent and normal attributes - Correct V resolution property per object - More attribute type support (currently only color) TODO: - [x] Attribute Loading Changes - [x] Generic Attributes - [x] Length Attribute - [x] Intercept Attribute - [x] Original Coordinate Attribute - [x] Cyclic Curves - [x] Legacy Hair Particle conversion - [x] Attribute Loading - [x] Additional Subdivision - [x] Move some function to generic headers (VertBuf, OffsetIndices) - [x] Fix default UV/Color attribute assignment Pull Request: https://projects.blender.org/blender/blender/pulls/143180
235 lines
7.1 KiB
C++
235 lines
7.1 KiB
C++
/* SPDX-FileCopyrightText: 2020 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup draw_engine
|
|
*/
|
|
|
|
#include "draw_shader.hh"
|
|
|
|
#include "GPU_batch.hh"
|
|
#include "GPU_capabilities.hh"
|
|
|
|
#include "opensubdiv_capi_type.hh"
|
|
#include "opensubdiv_evaluator_capi.hh"
|
|
|
|
#include "DRW_render.hh"
|
|
|
|
#define SHADER_CUSTOM_DATA_INTERP_MAX_DIMENSIONS 4
|
|
|
|
static blender::StringRefNull get_subdiv_shader_info_name(SubdivShaderType shader_type)
|
|
{
|
|
switch (shader_type) {
|
|
case SubdivShaderType::BUFFER_LINES:
|
|
return "subdiv_lines";
|
|
|
|
case SubdivShaderType::BUFFER_LINES_LOOSE:
|
|
return "subdiv_lines_loose";
|
|
|
|
case SubdivShaderType::BUFFER_TRIS:
|
|
return "subdiv_tris_single_material";
|
|
|
|
case SubdivShaderType::BUFFER_TRIS_MULTIPLE_MATERIALS:
|
|
return "subdiv_tris_multiple_materials";
|
|
|
|
case SubdivShaderType::BUFFER_EDGE_FAC:
|
|
return "subdiv_edge_fac";
|
|
|
|
case SubdivShaderType::BUFFER_SCULPT_DATA:
|
|
return "subdiv_sculpt_data";
|
|
|
|
case SubdivShaderType::PATCH_EVALUATION:
|
|
return "subdiv_patch_evaluation_verts";
|
|
|
|
case SubdivShaderType::PATCH_EVALUATION_FVAR:
|
|
return "subdiv_patch_evaluation_fvar";
|
|
|
|
case SubdivShaderType::PATCH_EVALUATION_FACE_DOTS:
|
|
return "subdiv_patch_evaluation_fdots";
|
|
|
|
case SubdivShaderType::PATCH_EVALUATION_FACE_DOTS_WITH_NORMALS:
|
|
return "subdiv_patch_evaluation_fdots_normals";
|
|
|
|
case SubdivShaderType::PATCH_EVALUATION_ORCO:
|
|
return "subdiv_patch_evaluation_verts_orcos";
|
|
|
|
case SubdivShaderType::BUFFER_UV_STRETCH_ANGLE:
|
|
return "subdiv_edituv_stretch_angle";
|
|
|
|
case SubdivShaderType::BUFFER_UV_STRETCH_AREA:
|
|
return "subdiv_edituv_stretch_area";
|
|
|
|
case SubdivShaderType::BUFFER_NORMALS_ACCUMULATE:
|
|
return "subdiv_normals_accumulate";
|
|
|
|
case SubdivShaderType::BUFFER_PAINT_OVERLAY_FLAG:
|
|
return "subdiv_paint_overlay_flag";
|
|
|
|
case SubdivShaderType::BUFFER_LNOR:
|
|
return "subdiv_loop_normals";
|
|
|
|
case SubdivShaderType::COMP_CUSTOM_DATA_INTERP:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
BLI_assert_unreachable();
|
|
return "";
|
|
}
|
|
|
|
namespace blender::draw::Shader {
|
|
|
|
class ShaderCache {
|
|
static gpu::StaticShaderCache<ShaderCache> &get_static_cache()
|
|
{
|
|
static gpu::StaticShaderCache<ShaderCache> static_cache;
|
|
return static_cache;
|
|
}
|
|
|
|
public:
|
|
static ShaderCache &get()
|
|
{
|
|
return get_static_cache().get();
|
|
}
|
|
static void release()
|
|
{
|
|
get_static_cache().release();
|
|
}
|
|
|
|
gpu::StaticShader curves_topology = {"draw_curves_topology"};
|
|
gpu::StaticShader curves_evaluate_position = {"draw_curves_interpolate_position"};
|
|
gpu::StaticShader curves_evaluate_float4 = {"draw_curves_interpolate_float4_attribute"};
|
|
gpu::StaticShader curves_evaluate_float3 = {"draw_curves_interpolate_float3_attribute"};
|
|
gpu::StaticShader curves_evaluate_float2 = {"draw_curves_interpolate_float2_attribute"};
|
|
gpu::StaticShader curves_evaluate_float = {"draw_curves_interpolate_float_attribute"};
|
|
gpu::StaticShader curves_evaluate_length_intercept = {"draw_curves_evaluate_length_intercept"};
|
|
gpu::StaticShader debug_draw_display = {"draw_debug_draw_display"};
|
|
gpu::StaticShader draw_visibility_compute = {"draw_visibility_compute"};
|
|
gpu::StaticShader draw_view_finalize = {"draw_view_finalize"};
|
|
gpu::StaticShader draw_resource_finalize = {"draw_resource_finalize"};
|
|
gpu::StaticShader draw_command_generate = {"draw_command_generate"};
|
|
|
|
gpu::StaticShader subdiv_sh[SUBDIVISION_MAX_SHADERS];
|
|
gpu::StaticShader subdiv_custom_data_sh[SHADER_CUSTOM_DATA_INTERP_MAX_DIMENSIONS][GPU_COMP_MAX];
|
|
gpu::StaticShader subdiv_interp_corner_normals_sh = {
|
|
"subdiv_custom_data_interp_3d_f32_normalize"};
|
|
|
|
ShaderCache()
|
|
{
|
|
for (int i : IndexRange(SUBDIVISION_MAX_SHADERS)) {
|
|
if (SubdivShaderType(i) == SubdivShaderType::COMP_CUSTOM_DATA_INTERP) {
|
|
continue;
|
|
}
|
|
subdiv_sh[i] = {get_subdiv_shader_info_name(SubdivShaderType(i)).c_str()};
|
|
}
|
|
|
|
for (int dimension : IndexRange(SHADER_CUSTOM_DATA_INTERP_MAX_DIMENSIONS)) {
|
|
for (GPUVertCompType comp_type : {GPU_COMP_U16, GPU_COMP_I32, GPU_COMP_F32}) {
|
|
std::string info_name = "subdiv_custom_data_interp";
|
|
const char *dimension_names[] = {"_1d", "_2d", "_3d", "_4d"};
|
|
info_name += dimension_names[dimension];
|
|
|
|
switch (comp_type) {
|
|
case GPU_COMP_U16:
|
|
info_name += "_u16";
|
|
break;
|
|
case GPU_COMP_I32:
|
|
info_name += "_i32";
|
|
break;
|
|
case GPU_COMP_F32:
|
|
info_name += "_f32";
|
|
break;
|
|
default:
|
|
BLI_assert_unreachable();
|
|
}
|
|
|
|
subdiv_custom_data_sh[dimension][comp_type] = {info_name};
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace blender::draw::Shader
|
|
|
|
using namespace blender::draw::Shader;
|
|
|
|
blender::gpu::Shader *DRW_shader_curves_topology_get()
|
|
{
|
|
return ShaderCache::get().curves_topology.get();
|
|
}
|
|
|
|
blender::gpu::Shader *DRW_shader_curves_refine_get(blender::draw::CurvesEvalShader type)
|
|
{
|
|
switch (type) {
|
|
case blender::draw::CURVES_EVAL_POSITION:
|
|
return ShaderCache::get().curves_evaluate_position.get();
|
|
case blender::draw::CURVES_EVAL_FLOAT4:
|
|
return ShaderCache::get().curves_evaluate_float4.get();
|
|
case blender::draw::CURVES_EVAL_FLOAT3:
|
|
return ShaderCache::get().curves_evaluate_float3.get();
|
|
case blender::draw::CURVES_EVAL_FLOAT2:
|
|
return ShaderCache::get().curves_evaluate_float2.get();
|
|
case blender::draw::CURVES_EVAL_FLOAT:
|
|
return ShaderCache::get().curves_evaluate_float.get();
|
|
case blender::draw::CURVES_EVAL_LENGTH_INTERCEPT:
|
|
return ShaderCache::get().curves_evaluate_length_intercept.get();
|
|
}
|
|
BLI_assert_unreachable();
|
|
return nullptr;
|
|
}
|
|
|
|
blender::gpu::Shader *DRW_shader_debug_draw_display_get()
|
|
{
|
|
return ShaderCache::get().debug_draw_display.get();
|
|
}
|
|
|
|
blender::gpu::Shader *DRW_shader_draw_visibility_compute_get()
|
|
{
|
|
return ShaderCache::get().draw_visibility_compute.get();
|
|
}
|
|
|
|
blender::gpu::Shader *DRW_shader_draw_view_finalize_get()
|
|
{
|
|
return ShaderCache::get().draw_view_finalize.get();
|
|
}
|
|
|
|
blender::gpu::Shader *DRW_shader_draw_resource_finalize_get()
|
|
{
|
|
return ShaderCache::get().draw_resource_finalize.get();
|
|
}
|
|
|
|
blender::gpu::Shader *DRW_shader_draw_command_generate_get()
|
|
{
|
|
return ShaderCache::get().draw_command_generate.get();
|
|
}
|
|
|
|
blender::gpu::Shader *DRW_shader_subdiv_get(SubdivShaderType shader_type)
|
|
{
|
|
BLI_assert(!ELEM(shader_type, SubdivShaderType::COMP_CUSTOM_DATA_INTERP));
|
|
return ShaderCache::get().subdiv_sh[uint(shader_type)].get();
|
|
}
|
|
|
|
blender::gpu::Shader *DRW_shader_subdiv_custom_data_get(GPUVertCompType comp_type, int dimensions)
|
|
{
|
|
BLI_assert(dimensions >= 1 && dimensions <= SHADER_CUSTOM_DATA_INTERP_MAX_DIMENSIONS);
|
|
if (comp_type == GPU_COMP_U16) {
|
|
BLI_assert(dimensions == 4);
|
|
}
|
|
BLI_assert(ELEM(comp_type, GPU_COMP_U16, GPU_COMP_I32, GPU_COMP_F32));
|
|
|
|
return ShaderCache::get().subdiv_custom_data_sh[dimensions - 1][comp_type].get();
|
|
}
|
|
|
|
blender::gpu::Shader *DRW_shader_subdiv_interp_corner_normals_get()
|
|
{
|
|
return ShaderCache::get().subdiv_interp_corner_normals_sh.get();
|
|
}
|
|
|
|
void DRW_shaders_free()
|
|
{
|
|
GPU_shader_unbind();
|
|
ShaderCache::release();
|
|
}
|