Blender如何优雅的使用OpenGL之UniformBuffer

先说明一下Blender在使用OpenGL 的uniform时,需要通过在程序中生成相关的布局限定语句字符串,然后传递给对应的着色器程序,而存储对应uniform的名称和绑定点的信息的对象是一个ShaderCreateInfo结构体。

1.创建Uniform变量:

通过填充这个结构体来实现创建Uniform:

GPU_SHADER_CREATE_INFO(draw_view)
    .uniform_buf(DRW_VIEW_UBO_SLOT, "ViewMatrices", "drw_view_[DRW_VIEW_LEN]", Frequency::PASS)
    .define("drw_view", "drw_view_[drw_view_id]")
    .typedef_source("draw_shader_shared.h");

这段代码是使用GPU_SHADER_CREATE_INFO宏来创建着色器信息,并在其中指定变量的创建和数据来源。让我们逐步解释这个过程:

  1. GPU_SHADER_CREATE_INFO(draw_view):这是一个宏,用于创建一个ShaderCreateInfo结构体的实例,命名为draw_view。这个结构体用于存储着色器的相关信息。

  2. .uniform_buf(DRW_VIEW_UBO_SLOT, "ViewMatrices", "drw_view_[DRW_VIEW_LEN]", Frequency::PASS):这是在ShaderCreateInfo结构体中使用uniform_buf方法来设置uniform缓冲区的信息,具体含义和用法在之前的回答中已经解释过了。

  3. .define("drw_view", "drw_view_[drw_view_id]"):这是在ShaderCreateInfo结构体中使用define方法来定义一个宏。这个宏的作用是将"drw_view"替换为"drw_view_[drw_view_id]"。这样可以在着色器代码中使用宏来实现更灵活的变量命名。

  4. .typedef_source("draw_shader_shared.h"):这是在ShaderCreateInfo结构体中使用typedef_source方法来指定一个头文件。这个头文件中可能包含了一些类型定义或者其他的预处理指令,可以在着色器代码中使用。

GPU_SHADER_CREATE_INFO宏的定义如下:

#define GPU_SHADER_CREATE_INFO(_info) \
  ShaderCreateInfo *ptr_##_info = new ShaderCreateInfo(#_info); \
  ShaderCreateInfo &_info = *ptr_##_info; \
  g_create_infos->add_new(#_info, ptr_##_info); \
  _info

这段代码是一个宏定义,用于创建ShaderCreateInfo结构体的实例,并将其添加到一个全局的创建信息列表中。让我们逐步解释这个过程:

  1. ShaderCreateInfo *ptr_##_info = new ShaderCreateInfo(#_info);:这行代码创建了一个指向ShaderCreateInfo结构体的指针,并使用宏参数_info的字符串形式作为构造函数的参数,从而创建了一个ShaderCreateInfo实例。

  2. ShaderCreateInfo &_info = *ptr_##_info;:这行代码创建了一个ShaderCreateInfo的引用,将其指向刚刚创建的ShaderCreateInfo实例。这样可以通过_info来访问和操作ShaderCreateInfo的成员。

  3. g_create_infos->add_new(#_info, ptr_##_info);:这行代码将刚刚创建的ShaderCreateInfo实例添加到一个全局的创建信息列表中。这个列表可能是一个全局变量或者一个单例对象,用于存储所有的ShaderCreateInfo实例。

  4. _info:最后一行代码返回刚刚创建的ShaderCreateInfo实例,以便在代码中使用。

通过这个宏定义,你可以方便地创建和管理多个ShaderCreateInfo实例,并将它们添加到一个全局的创建信息列表中。这样可以更方便地组织和管理着色器的创建过程,并在需要的时候使用创建好的实例。具体的使用方法可能会根据你的代码结构和需求有所不同,但基本原理是相似的。

2.编码Uniform的绑定信息

在使用解析具体信息,生成对应的着色器代码时,使用下面的方法(以顶点着色器为例)

std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) const
{
  std::stringstream ss;
  std::string post_main;

  ss << "\n/* Inputs. */\n";
  for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) {
    if (GLContext::explicit_location_support &&
        /* Fix issue with AMDGPU-PRO + workbench_prepass_mesh_vert.glsl being quantized. */
        GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL) == false)
    {
      ss << "layout(location = " << attr.index << ") ";
    }
    ss << "in " << to_string(attr.type) << " " << attr.name << ";\n";
  }
  /* NOTE(D4490): Fix a bug where shader without any vertex attributes do not behave correctly. */
  if (GPU_type_matches_ex(GPU_DEVICE_APPLE, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL) &&
      info.vertex_inputs_.is_empty())
  {
    ss << "in float gpu_dummy_workaround;\n";
  }
  ss << "\n/* Interfaces. */\n";
  for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {
    print_interface(ss, "out", *iface);
  }
  if (!GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::LAYER)) {
    ss << "out int gpu_Layer;\n";
  }
  if (!GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::VIEWPORT_INDEX))
  {
    ss << "out int gpu_ViewportIndex;\n";
  }
  if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) {
    if (!GLContext::native_barycentric_support) {
      /* Disabled or unsupported. */
    }
    else if (epoxy_has_gl_extension("GL_AMD_shader_explicit_vertex_parameter")) {
      /* Need this for stable barycentric. */
      ss << "flat out vec4 gpu_pos_flat;\n";
      ss << "out vec4 gpu_pos;\n";

      post_main += "  gpu_pos = gpu_pos_flat = gl_Position;\n";
    }
  }
  ss << "\n";

  if (post_main.empty() == false) {
    std::string pre_main;
    ss << main_function_wrapper(pre_main, post_main);
  }
  return ss.str();
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值