Blender  V3.3
draw_hair.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2017 Blender Foundation. All rights reserved. */
3 
10 #include "DRW_render.h"
11 
12 #include "BLI_string_utils.h"
13 #include "BLI_utildefines.h"
14 
15 #include "DNA_collection_types.h"
16 #include "DNA_customdata_types.h"
17 #include "DNA_modifier_types.h"
18 #include "DNA_particle_types.h"
19 
20 #include "BKE_duplilist.h"
21 
22 #include "GPU_batch.h"
23 #include "GPU_capabilities.h"
24 #include "GPU_compute.h"
25 #include "GPU_material.h"
26 #include "GPU_shader.h"
27 #include "GPU_texture.h"
28 #include "GPU_vertex_buffer.h"
29 
30 #include "DRW_gpu_wrapper.hh"
31 
32 #include "draw_hair_private.h"
33 #include "draw_shader.h"
34 #include "draw_shader_shared.h"
35 
36 #ifndef __APPLE__
37 # define USE_TRANSFORM_FEEDBACK
38 # define USE_COMPUTE_SHADERS
39 #endif
40 
42 {
43 #ifdef USE_COMPUTE_SHADERS
46  }
47 #endif
48 #ifdef USE_TRANSFORM_FEEDBACK
50 #endif
52 }
53 
54 #ifndef USE_TRANSFORM_FEEDBACK
55 struct ParticleRefineCall {
56  struct ParticleRefineCall *next;
57  GPUVertBuf *vbo;
58  DRWShadingGroup *shgrp;
59  uint vert_len;
60 };
61 
62 static ParticleRefineCall *g_tf_calls = nullptr;
63 static int g_tf_id_offset;
64 static int g_tf_target_width;
65 static int g_tf_target_height;
66 #endif
67 
68 static GPUVertBuf *g_dummy_vbo = nullptr;
69 static GPUTexture *g_dummy_texture = nullptr;
70 static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
72 
74 {
76 }
77 
78 void DRW_hair_init(void)
79 {
80 #if defined(USE_TRANSFORM_FEEDBACK) || defined(USE_COMPUTE_SHADERS)
81  g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_NO_DRAW);
82 #else
83  g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR);
84 #endif
85 
86  if (g_dummy_vbo == nullptr) {
87  /* initialize vertex format */
88  GPUVertFormat format = {0};
90 
92 
93  const float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f};
95  GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert);
96  /* Create vbo immediately to bind to texture buffer. */
98 
100 
101  g_dummy_curves_info = MEM_new<blender::draw::UniformBuffer<CurvesInfos>>(
102  "g_dummy_curves_info");
103  memset(g_dummy_curves_info->is_point_attribute,
104  0,
105  sizeof(g_dummy_curves_info->is_point_attribute));
106  g_dummy_curves_info->push_update();
107  }
108 }
109 
111  ParticleHairCache *cache,
112  const int subdiv)
113 {
114  DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", cache->point_tex);
115  DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex);
116  DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex);
117  DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1);
118 }
119 
120 static void drw_hair_particle_cache_update_compute(ParticleHairCache *cache, const int subdiv)
121 {
122  const int strands_len = cache->strands_len;
123  const int final_points_len = cache->final[subdiv].strands_res * strands_len;
124  if (final_points_len > 0) {
126  DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass);
128  DRW_shgroup_vertex_buffer(shgrp, "posTime", cache->final[subdiv].proc_buf);
129 
130  const int max_strands_per_call = GPU_max_work_group_count(0);
131  int strands_start = 0;
132  while (strands_start < strands_len) {
133  int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call);
134  DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp);
135  DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start);
136  DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1);
137  strands_start += batch_strands_len;
138  }
139  }
140 }
141 
143  const int subdiv)
144 {
145  const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len;
146  if (final_points_len > 0) {
148 
149 #ifdef USE_TRANSFORM_FEEDBACK
151  tf_shader, g_tf_pass, cache->final[subdiv].proc_buf);
152 #else
153  DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
154 
155  ParticleRefineCall *pr_call = (ParticleRefineCall *)MEM_mallocN(sizeof(*pr_call), __func__);
156  pr_call->next = g_tf_calls;
157  pr_call->vbo = cache->final[subdiv].proc_buf;
158  pr_call->shgrp = tf_shgrp;
159  pr_call->vert_len = final_points_len;
160  g_tf_calls = pr_call;
161  DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
162  DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
163  DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
164 #endif
165 
166  drw_hair_particle_cache_shgrp_attach_resources(tf_shgrp, cache, subdiv);
167  DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len);
168  }
169 }
170 
172  ParticleSystem *psys,
173  ModifierData *md,
174  GPUMaterial *gpu_material,
175  int subdiv,
176  int thickness_res)
177 {
178  ParticleHairCache *cache;
180  object, psys, md, &cache, gpu_material, subdiv, thickness_res);
181 
182  if (update) {
185  }
186  else {
188  }
189  }
190  return cache;
191 }
192 
194 {
195  const DRWContextState *draw_ctx = DRW_context_state_get();
196  Scene *scene = draw_ctx->scene;
197 
198  int subdiv = scene->r.hair_subdiv;
199  int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
200 
202  object, psys, md, nullptr, subdiv, thickness_res);
203 
204  return cache->final[subdiv].proc_buf;
205 }
206 
208  ParticleSystem *UNUSED(psys),
209  ModifierData *UNUSED(md),
210  float (*dupli_mat)[4])
211 {
212  Object *dupli_parent = DRW_object_get_dupli_parent(object);
213  DupliObject *dupli_object = DRW_object_get_dupli(object);
214 
215  if ((dupli_parent != nullptr) && (dupli_object != nullptr)) {
216  if (dupli_object->type & OB_DUPLICOLLECTION) {
217  unit_m4(dupli_mat);
218  Collection *collection = dupli_parent->instance_collection;
219  if (collection != nullptr) {
220  sub_v3_v3(dupli_mat[3], collection->instance_offset);
221  }
222  mul_m4_m4m4(dupli_mat, dupli_parent->obmat, dupli_mat);
223  }
224  else {
225  copy_m4_m4(dupli_mat, dupli_object->ob->obmat);
226  invert_m4(dupli_mat);
227  mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat);
228  }
229  }
230  else {
231  unit_m4(dupli_mat);
232  }
233 }
234 
236  ParticleSystem *psys,
237  ModifierData *md,
238  DRWShadingGroup *shgrp_parent,
239  GPUMaterial *gpu_material)
240 {
241  const DRWContextState *draw_ctx = DRW_context_state_get();
242  Scene *scene = draw_ctx->scene;
243  float dupli_mat[4][4];
244 
245  int subdiv = scene->r.hair_subdiv;
246  int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
247 
249  object, psys, md, gpu_material, subdiv, thickness_res);
250 
251  DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent);
252 
253  /* TODO: optimize this. Only bind the ones GPUMaterial needs. */
254  for (int i = 0; i < hair_cache->num_uv_layers; i++) {
255  for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->uv_layer_names[i][n][0] != '\0'; n++) {
256  DRW_shgroup_uniform_texture(shgrp, hair_cache->uv_layer_names[i][n], hair_cache->uv_tex[i]);
257  }
258  }
259  for (int i = 0; i < hair_cache->num_col_layers; i++) {
260  for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->col_layer_names[i][n][0] != '\0'; n++) {
262  shgrp, hair_cache->col_layer_names[i][n], hair_cache->col_tex[i]);
263  }
264  }
265 
266  /* Fix issue with certain driver not drawing anything if there is no texture bound to
267  * "ac", "au", "u" or "c". */
268  if (hair_cache->num_uv_layers == 0) {
271  }
272  if (hair_cache->num_col_layers == 0) {
275  }
276 
277  DRW_hair_duplimat_get(object, psys, md, dupli_mat);
278 
279  /* Get hair shape parameters. */
280  ParticleSettings *part = psys->part;
281  float hair_rad_shape = part->shape;
282  float hair_rad_root = part->rad_root * part->rad_scale * 0.5f;
283  float hair_rad_tip = part->rad_tip * part->rad_scale * 0.5f;
284  bool hair_close_tip = (part->shape_flag & PART_SHAPE_CLOSE_TIP) != 0;
285 
286  DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_tex);
287  if (hair_cache->length_tex) {
288  DRW_shgroup_uniform_texture(shgrp, "l", hair_cache->length_tex);
289  }
290 
291  DRW_shgroup_uniform_block(shgrp, "drw_curves", *g_dummy_curves_info);
292  DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
293  DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
294  DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape);
295  DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", dupli_mat);
296  DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root);
297  DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip);
298  DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip);
299  if (gpu_material) {
300  /* \note: This needs to happen before the drawcall to allow correct attribute extraction.
301  * (see T101896) */
302  DRW_shgroup_add_material_resources(shgrp, gpu_material);
303  }
304  /* TODO(fclem): Until we have a better way to cull the hair and render with orco, bypass
305  * culling test. */
306  GPUBatch *geom = hair_cache->final[subdiv].proc_hairs[thickness_res - 1];
307  DRW_shgroup_call_no_cull(shgrp, geom, object);
308 
309  return shgrp;
310 }
311 
313 {
314 #ifndef USE_TRANSFORM_FEEDBACK
325  if (g_tf_calls == nullptr) {
326  return;
327  }
328 
329  /* Search ideal buffer size. */
330  uint max_size = 0;
331  for (ParticleRefineCall *pr_call = g_tf_calls; pr_call; pr_call = pr_call->next) {
332  max_size = max_ii(max_size, pr_call->vert_len);
333  }
334 
335  /* Create target Texture / Frame-buffer */
336  /* Don't use max size as it can be really heavy and fail.
337  * Do chunks of maximum 2048 * 2048 hair points. */
338  int width = 2048;
339  int height = min_ii(width, 1 + max_size / width);
342  g_tf_target_height = height;
343  g_tf_target_width = width;
344 
345  GPUFrameBuffer *fb = nullptr;
346  GPU_framebuffer_ensure_config(&fb,
347  {
348  GPU_ATTACHMENT_NONE,
349  GPU_ATTACHMENT_TEXTURE(tex),
350  });
351 
352  float *data = (float *)MEM_mallocN(sizeof(float[4]) * width * height, "tf fallback buffer");
353 
355  while (g_tf_calls != nullptr) {
356  ParticleRefineCall *pr_call = g_tf_calls;
357  g_tf_calls = g_tf_calls->next;
358 
359  g_tf_id_offset = 0;
360  while (pr_call->vert_len > 0) {
361  int max_read_px_len = min_ii(width * height, pr_call->vert_len);
362 
363  DRW_draw_pass_subset(g_tf_pass, pr_call->shgrp, pr_call->shgrp);
364  /* Read back result to main memory. */
366  /* Upload back to VBO. */
367  GPU_vertbuf_use(pr_call->vbo);
368  GPU_vertbuf_update_sub(pr_call->vbo,
369  sizeof(float[4]) * g_tf_id_offset,
370  sizeof(float[4]) * max_read_px_len,
371  data);
372 
373  g_tf_id_offset += max_read_px_len;
374  pr_call->vert_len -= max_read_px_len;
375  }
376 
377  MEM_freeN(pr_call);
378  }
379 
380  MEM_freeN(data);
382 #else
383  /* Just render the pass when using compute shaders or transform feedback. */
387  }
388 #endif
389 }
390 
391 void DRW_hair_free(void)
392 {
395  MEM_delete(g_dummy_curves_info);
396 }
#define BLI_INLINE
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
bool invert_m4(float R[4][4])
Definition: math_matrix.c:1206
void unit_m4(float m[4][4])
Definition: rct.c:1090
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
MINLINE void sub_v3_v3(float r[3], const float a[3])
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED(x)
#define MIN2(a, b)
Object groups, one object can be in many groups at once.
@ OB_DUPLICOLLECTION
@ PART_SHAPE_CLOSE_TIP
@ SCE_HAIR_SHAPE_STRAND
#define DRW_shgroup_vertex_buffer(shgroup, name, vert)
Definition: DRW_render.h:647
#define DRW_shgroup_call_no_cull(shgroup, geom, ob)
Definition: DRW_render.h:431
@ DRW_STATE_NO_DRAW
Definition: DRW_render.h:300
@ DRW_STATE_WRITE_COLOR
Definition: DRW_render.h:303
#define DRW_shgroup_uniform_block(shgroup, name, ubo)
Definition: DRW_render.h:651
#define DRW_TEXTURE_FREE_SAFE(tex)
Definition: DRW_render.h:183
GPUBatch
Definition: GPU_batch.h:78
bool GPU_compute_shader_support(void)
int GPU_max_work_group_count(int index)
bool GPU_shader_storage_buffer_objects_support(void)
struct GPUFrameBuffer GPUFrameBuffer
void GPU_framebuffer_free(GPUFrameBuffer *fb)
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
struct GPUShader GPUShader
Definition: GPU_shader.h:20
void GPU_memory_barrier(eGPUBarrier barrier)
Definition: gpu_state.cc:371
@ GPU_BARRIER_SHADER_STORAGE
Definition: GPU_state.h:29
struct GPUTexture GPUTexture
Definition: GPU_texture.h:17
GPUTexture * GPU_texture_create_from_vertbuf(const char *name, struct GPUVertBuf *vert)
Definition: gpu_texture.cc:361
@ GPU_DATA_FLOAT
Definition: GPU_texture.h:171
@ GPU_RGBA32F
Definition: GPU_texture.h:90
#define GPU_vertbuf_create_with_format(format)
struct GPUVertBuf GPUVertBuf
void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data)
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
#define GPU_VERTBUF_DISCARD_SAFE(verts)
void GPU_vertbuf_use(GPUVertBuf *)
void GPU_vertbuf_attr_fill(GPUVertBuf *, uint a_idx, const void *data)
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Scene scene
bool particles_ensure_procedural_data(Object *object, ParticleSystem *psys, ModifierData *md, ParticleHairCache **r_hair_cache, GPUMaterial *gpu_material, int subdiv, int thickness_res)
DRWShadingGroup * DRW_shgroup_hair_create_sub(Object *object, ParticleSystem *psys, ModifierData *md, DRWShadingGroup *shgrp_parent, GPUMaterial *gpu_material)
Definition: draw_hair.cc:235
BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get()
Definition: draw_hair.cc:41
static blender::draw::UniformBuffer< CurvesInfos > * g_dummy_curves_info
Definition: draw_hair.cc:71
static GPUTexture * g_dummy_texture
Definition: draw_hair.cc:69
static GPUVertBuf * g_dummy_vbo
Definition: draw_hair.cc:68
static void drw_hair_particle_cache_update_compute(ParticleHairCache *cache, const int subdiv)
Definition: draw_hair.cc:120
void DRW_hair_duplimat_get(Object *object, ParticleSystem *UNUSED(psys), ModifierData *UNUSED(md), float(*dupli_mat)[4])
Definition: draw_hair.cc:207
static GPUShader * hair_refine_shader_get(ParticleRefineShader refinement)
Definition: draw_hair.cc:73
static void drw_hair_particle_cache_shgrp_attach_resources(DRWShadingGroup *shgrp, ParticleHairCache *cache, const int subdiv)
Definition: draw_hair.cc:110
GPUVertBuf * DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, ModifierData *md)
Definition: draw_hair.cc:193
void DRW_hair_init(void)
Definition: draw_hair.cc:78
void DRW_hair_update()
Definition: draw_hair.cc:312
static void drw_hair_particle_cache_update_transform_feedback(ParticleHairCache *cache, const int subdiv)
Definition: draw_hair.cc:142
void DRW_hair_free(void)
Definition: draw_hair.cc:391
static DRWPass * g_tf_pass
Definition: draw_hair.cc:70
static ParticleHairCache * drw_hair_particle_cache_get(Object *object, ParticleSystem *psys, ModifierData *md, GPUMaterial *gpu_material, int subdiv, int thickness_res)
Definition: draw_hair.cc:171
ParticleRefineShader
@ PART_REFINE_CATMULL_ROM
#define MAX_LAYER_NAME_CT
struct Object * DRW_object_get_dupli_parent(const Object *UNUSED(ob))
Definition: draw_manager.c:264
struct DupliObject * DRW_object_get_dupli(const Object *UNUSED(ob))
Definition: draw_manager.c:269
const DRWContextState * DRW_context_state_get(void)
void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value)
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
void DRW_shgroup_call_compute(DRWShadingGroup *shgroup, int groups_x_len, int groups_y_len, int groups_z_len)
void DRW_shgroup_call_procedural_points(DRWShadingGroup *shgroup, Object *ob, uint point_count)
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value)
DRWShadingGroup * DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass)
void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
DRWShadingGroup * DRW_shgroup_transform_feedback_create(struct GPUShader *shader, DRWPass *pass, GPUVertBuf *tf_target)
void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial *material)
DRWShadingGroup * DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
DRWPass * DRW_pass_create(const char *name, DRWState state)
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
void DRW_shgroup_uniform_mat4_copy(DRWShadingGroup *shgroup, const char *name, const float(*value)[4])
void DRW_draw_pass(DRWPass *pass)
void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
GPUTexture * DRW_texture_pool_query_2d(int w, int h, eGPUTextureFormat format, DrawEngineType *engine_type)
GPUShader * DRW_shader_hair_refine_get(ParticleRefineShader refinement, eParticleRefineShaderType sh_type)
Definition: draw_shader.cc:64
eParticleRefineShaderType
Definition: draw_shader.h:19
@ PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND
Definition: draw_shader.h:21
@ PART_REFINE_SHADER_COMPUTE
Definition: draw_shader.h:22
@ PART_REFINE_SHADER_TRANSFORM_FEEDBACK
Definition: draw_shader.h:20
void GPU_framebuffer_read_color(GPUFrameBuffer *gpu_fb, int x, int y, int w, int h, int channels, int slot, eGPUDataFormat format, void *data)
BLI_INLINE float fb(float length, float L)
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static ulong * next
static void update(bNodeTree *ntree)
float instance_offset[3]
struct Scene * scene
Definition: DRW_render.h:979
struct Object * ob
Definition: BKE_duplilist.h:34
struct Collection * instance_collection
float obmat[4][4]
GPUTexture ** col_tex
GPUTexture * uv_tex[MAX_MTFACE]
GPUTexture * length_tex
char uv_layer_names[MAX_MTFACE][MAX_LAYER_NAME_CT][MAX_LAYER_NAME_LEN]
GPUTexture * strand_seg_tex
GPUTexture * point_tex
GPUTexture * strand_tex
ParticleHairFinalCache final[MAX_HAIR_SUBDIV]
char(* col_layer_names)[MAX_LAYER_NAME_CT][MAX_LAYER_NAME_LEN]
GPUBatch * proc_hairs[MAX_THICKRES]
ParticleSettings * part
struct RenderData r