graphics.rst 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. Rendering Graphics
  2. ==================
  3. Libobs has a custom-made programmable graphics subsystem that wraps both
  4. Direct3D 11 and OpenGL. The reason why it was designed with a custom
  5. graphics subsystem was to accommodate custom capture features only
  6. available on specific operating systems.
  7. *(Author's note: In retrospect, I probably should have used something
  8. like ANGLE, but I would have to modify it to accommodate my specific
  9. use-cases.)*
  10. Most rendering is dependent upon effects. Effects are used by all video
  11. objects in libobs; they're used to easily bundle related vertex/pixel
  12. shaders in to one file.
  13. An effect file has a nearly identical syntax to Direct3D 11 HLSL effect
  14. files. The only differences are as follows:
  15. - Sampler states are named "sampler_state"
  16. - Position semantic is called "POSITION" rather than "SV_Position"
  17. - Target semantic is called "TARGET" rather than "SV_Target"
  18. *(Author's note: I'm probably missing a few exceptions here, if I am
  19. please let me know)*
  20. The Graphics Context
  21. --------------------
  22. Using graphics functions isn't possible unless the current thread has
  23. entered a graphics context, and the graphics context can only be used by
  24. one thread at a time. To enter the graphics context, use
  25. :c:func:`obs_enter_graphics()`, and to leave the graphics context, use
  26. :c:func:`obs_leave_graphics()`.
  27. Certain callback will automatically be within the graphics context:
  28. :c:member:`obs_source_info.video_render`, and the draw callback
  29. parameter of :c:func:`obs_display_add_draw_callback()`, and
  30. :c:func:`obs_add_main_render_callback()`.
  31. Creating Effects
  32. ----------------
  33. Effect Parameters
  34. ^^^^^^^^^^^^^^^^^
  35. To create an effect, it's recommended to start with the uniforms
  36. (parameters) of the effect.
  37. There are a number of different types of uniforms:
  38. +------------------+---------------+------------------+------------+------------+
  39. | Floating points: | **float** | **float2** | **float3** | **float4** |
  40. +------------------+---------------+------------------+------------+------------+
  41. | Matrices: | **float3x3** | **float4x4** | | |
  42. +------------------+---------------+------------------+------------+------------+
  43. | Integers: | **int** | **int2** | **int3** | **int4** |
  44. +------------------+---------------+------------------+------------+------------+
  45. | Booleans: | **bool** | | | |
  46. +------------------+---------------+------------------+------------+------------+
  47. | Textures: | **texture2d** | **texture_cube** | | |
  48. +------------------+---------------+------------------+------------+------------+
  49. To get the effect uniform parameters, you use
  50. :c:func:`gs_effect_get_param_by_name()` or
  51. :c:func:`gs_effect_get_param_by_idx()`.
  52. Then the uniforms are set through the following functions:
  53. - :c:func:`gs_effect_set_bool()`
  54. - :c:func:`gs_effect_set_float()`
  55. - :c:func:`gs_effect_set_int()`
  56. - :c:func:`gs_effect_set_matrix4()`
  57. - :c:func:`gs_effect_set_vec2()`
  58. - :c:func:`gs_effect_set_vec3()`
  59. - :c:func:`gs_effect_set_vec4()`
  60. - :c:func:`gs_effect_set_texture()`
  61. - :c:func:`gs_effect_set_texture_srgb()`
  62. There are two "universal" effect parameters that may be expected of
  63. effects: **ViewProj**, and **image**. The **ViewProj** parameter
  64. (which is a float4x4) is used for the primary view/projection matrix
  65. combination. The **image** parameter (which is a texture2d) is a
  66. commonly used parameter for the main texture; this parameter will be
  67. used with the functions :c:func:`obs_source_draw()`,
  68. :c:func:`gs_draw_sprite()`, and
  69. :c:func:`obs_source_process_filter_end()`.
  70. Here is an example of effect parameters:
  71. .. code:: cpp
  72. uniform float4x4 ViewProj;
  73. uniform texture2d image;
  74. uniform float4 my_color_param;
  75. uniform float my_float_param;
  76. Effect parameters can also have default values. Default parameters of
  77. elements that have multiple elements should be treated as an array.
  78. Here are some examples of default parameters:
  79. .. code:: cpp
  80. uniform float4x4 my_matrix = {1.0, 0.0, 0.0, 0.0,
  81. 0.0, 1.0, 0.0, 0.0,
  82. 0.0, 0.0, 1.0, 0.0,
  83. 0.0, 0.0, 0.0, 1.0};
  84. uniform float4 my_float4 = {1.0, 0.5, 0.25, 0.0};
  85. uniform float my_float = 4.0;
  86. uniform int my_int = 5;
  87. Effect Sampler States
  88. ^^^^^^^^^^^^^^^^^^^^^
  89. Then, if textures are used, sampler states should be defined. Sampler
  90. states have certain sub-parameters:
  91. - **Filter** - The type of filtering to use. Can be one of the
  92. following values:
  93. - **Anisotropy**
  94. - **Point**
  95. - **Linear**
  96. - **MIN_MAG_POINT_MIP_LINEAR**
  97. - **MIN_POINT_MAG_LINEAR_MIP_POINT**
  98. - **MIN_POINT_MAG_MIP_LINEAR**
  99. - **MIN_LINEAR_MAG_MIP_POINT**
  100. - **MIN_LINEAR_MAG_POINT_MIP_LINEAR**
  101. - **MIN_MAG_LINEAR_MIP_POINT**
  102. - **AddressU**, **AddressV** - Specifies how to handle the sampling
  103. when the coordinate goes beyond 0.0..1.0. Can be one of the following
  104. values:
  105. - **Wrap** or **Repeat**
  106. - **Clamp** or **None**
  107. - **Mirror**
  108. - **Border** (uses *BorderColor* to fill the color)
  109. - **MirrorOnce**
  110. - **BorderColor** - Specifies the border color if using the "Border"
  111. address mode. This value should be a hexadecimal value representing
  112. the color, in the format of: AARRGGBB. For example, 7FFF0000 would
  113. have its alpha value at 127, its red value at 255, and blue and green
  114. at 0. If *Border* is not used as an addressing type, this value is
  115. ignored.
  116. Here is an example of writing a sampler state in an effect file:
  117. .. code:: cpp
  118. sampler_state defaultSampler {
  119. Filter = Linear;
  120. AddressU = Border;
  121. AddressV = Border;
  122. BorderColor = 7FFF0000;
  123. };
  124. This sampler state would use linear filtering, would use border
  125. addressing for texture coordinate values beyond 0.0..1.0, and the border
  126. color would be the color specified above.
  127. When a sampler state is used, it's used identically to the HLSL form:
  128. .. code:: cpp
  129. [...]
  130. uniform texture2d image;
  131. sampler_state defaultSampler {
  132. Filter = Linear;
  133. AddressU = Clamp;
  134. AddressV = Clamp;
  135. };
  136. [...]
  137. float4 MyPixelShaderFunc(VertInOut vert_in) : TARGET
  138. {
  139. return image.Sample(def_sampler, vert_in.uv);
  140. }
  141. Effect Vertex/Pixel Semantics
  142. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  143. Then structures should be defined for inputs and outputs vertex
  144. semantics.
  145. Vertex components can have the following semantics:
  146. - **COLOR** - Color value (*float4*).
  147. - **POSITION** - Position value (*float4*).
  148. - **NORMAL** - Normal value (*float4*).
  149. - **TANGENT** - Tangent value (*float4*).
  150. - **TEXCOORD[0..7]** - Texture cooordinate value (*float2*, *float3*, or
  151. *float4*).
  152. Here is an example of a vertex semantic structure:
  153. .. code:: cpp
  154. struct VertexIn {
  155. float4 my_position : POSITION;
  156. float2 my_texcoord : TEXCOORD0;
  157. };
  158. These semantic structures are then passed in as a parameter to the
  159. primary shader entry point, and used as a return value for the vertex
  160. shader. Note that the vertex shader is allowed to return different
  161. semantics than it takes in; but the return type of the vertex shader and
  162. the parameter of the pixel shader must match.
  163. The semantic structure used for the parameter to the vertex shader
  164. function will require that the vertex buffer have those values, so if
  165. you have POSITION and TEXCOORD0, the vertex buffer will have to have at
  166. least a position buffer and a texture coordinate buffer in it.
  167. For pixel shaders, they need to return with a TARGET semantic (which is
  168. a float4 RGBA value). Here is an example of how it's usually used with
  169. a pixel shader function:
  170. .. code:: cpp
  171. float4 MyPixelShaderFunc(VertInOut vert_in) : TARGET
  172. {
  173. return image.Sample(def_sampler, vert_in.uv);
  174. }
  175. Effect Techniques
  176. ^^^^^^^^^^^^^^^^^
  177. Techniques are used to define the primary vertex/pixel shader entry
  178. functions per pass. One technique can have multiple passes or custom
  179. pass setup.
  180. *(Author's note: These days, multiple passes aren't really needed; GPUs
  181. are powerful enough to where you can perform all actions in the same
  182. shader. Named passes can be useful for custom draw setups, but even
  183. then you can just make it a separate technique. For that reason, it's
  184. best to just ignore the extra pass functionality.)*
  185. If you're making an effect filter for video sources, typically you'd
  186. name the pass **Draw**, and then
  187. :c:func:`obs_source_process_filter_end()` will automatically call that
  188. specific effect name. However, you can also use
  189. :c:func:`obs_source_process_filter_tech_end()` to make the filter use a
  190. specific technique by its name.
  191. The first parameter of the vertex/pixel shader functions in passes
  192. should always be the name of its vertex semantic structure parameter.
  193. For techniques, it's better to show some examples of how techniques
  194. would be used:
  195. .. code:: cpp
  196. uniform float4x4 ViewProj;
  197. uniform texture2d image;
  198. struct VertInOut {
  199. float4 my_position : POSITION;
  200. float2 my_texcoord : TEXCOORD0;
  201. };
  202. VertInOut MyVertexShaderFunc(VertInOut vert_in)
  203. {
  204. VertInOut vert_out;
  205. vert_out.pos = mul(float4(vert_in.pos.xyz, 1.0), ViewProj);
  206. vert_out.uv = vert_in.uv;
  207. return vert_out;
  208. }
  209. float4 MyPixelShaderFunc(VertInOut vert_in) : TARGET
  210. {
  211. return image.Sample(def_sampler, vert_in.uv);
  212. }
  213. technique Draw
  214. {
  215. pass
  216. {
  217. vertex_shader = MyVertexShaderFunc(vert_in);
  218. pixel_shader = MyPixelShaderFunc(vert_in);
  219. }
  220. };
  221. Using Effects
  222. -------------
  223. The recommended way to use effects is like so:
  224. .. code:: cpp
  225. for (gs_effect_loop(effect, "technique")) {
  226. [draw calls go here]
  227. }
  228. This will automatically handle loading/unloading of the effect and its
  229. shaders for a given technique name.
  230. Rendering Video Sources
  231. -----------------------
  232. A synchronous video source renders in its
  233. :c:member:`obs_source_info.video_render` callback.
  234. Sources can render with custom drawing (via the OBS_SOURCE_CUSTOM_DRAW
  235. output capability flag), or without. When sources render without custom
  236. rendering, it's recommended to render a single texture with
  237. :c:func:`obs_source_draw()`. Otherwise the source is expected to
  238. perform rendering on its own and manage its own effects.
  239. Libobs comes with a set of default/standard effects that can be accessed
  240. via the :c:func:`obs_get_base_effect()` function. You can use these
  241. effects to render, or you can create custom effects with
  242. :c:func:`gs_effect_create_from_file()` and render with a custom effect.
  243. Rendering Video Effect Filters
  244. ------------------------------
  245. For most video effect filters, it comprises of adding a layer of
  246. processing shaders to an existing image in its
  247. :c:member:`obs_source_info.video_render` callback. When this is the
  248. case, it's expected that the filter has its own effect created, and to
  249. draw the effect, one would simply use the
  250. :c:func:`obs_source_process_filter_begin()` function, set the parameters
  251. on your custom effect, then call either
  252. :c:func:`obs_source_process_filter_end()` or
  253. :c:func:`obs_source_process_filter_tech_end()` to finish rendering the
  254. filter.
  255. Here's an example of rendering a filter from the color key filter:
  256. .. code:: cpp
  257. static void color_key_render(void *data, gs_effect_t *effect)
  258. {
  259. struct color_key_filter_data *filter = data;
  260. if (!obs_source_process_filter_begin(filter->context, GS_RGBA,
  261. OBS_ALLOW_DIRECT_RENDERING))
  262. return;
  263. gs_effect_set_vec4(filter->color_param, &filter->color);
  264. gs_effect_set_float(filter->contrast_param, filter->contrast);
  265. gs_effect_set_float(filter->brightness_param, filter->brightness);
  266. gs_effect_set_float(filter->gamma_param, filter->gamma);
  267. gs_effect_set_vec4(filter->key_color_param, &filter->key_color);
  268. gs_effect_set_float(filter->similarity_param, filter->similarity);
  269. gs_effect_set_float(filter->smoothness_param, filter->smoothness);
  270. obs_source_process_filter_end(filter->context, filter->effect, 0, 0);
  271. UNUSED_PARAMETER(effect);
  272. }