How does the sculpt draw brush work?

I can’t figure out the exact math of the draw brush.

static void do_draw_brush_task_cb_ex(
        void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
	SculptThreadedTaskData *data = userdata;
	SculptSession *ss = data->ob->sculpt;
	const Brush *brush = data->brush;
	const float *offset = data->offset;

	PBVHVertexIter vd;
	float (*proxy)[3];

	proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;

	SculptBrushTest test;
	SculptBrushTestFn sculpt_brush_test_sq_fn =
	        sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);

	BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
		if (sculpt_brush_test_sq_fn(&test, {
			/* offset vertex */
			const float fade = tex_strength(
			        ss, brush,, sqrtf(test.dist),
	, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);

			mul_v3_v3fl(proxy[vd.i], offset, fade);

			if (vd.mvert)
				vd.mvert->flag |= ME_VERT_PBVH_UPDATE;

They way the draw brush is supposed to work, is that it moves vertices along the average vector of the of all vertices in the sphere of influence of the brush.
To move a coordinate at a point in space, you multiply it by the direction of where the coordinate must go to, the magnitude of the vector would be the amount to move along said vector.

Looking at the do_draw_brush(), offset seems to be a scaled vector.

What does mul_v3_v3fl(proxy[vd.i], offset, fade); mean ?
Shouldn’t proxy[vd.i] be a coordinate, it seems to be direction ?

mul_v3_v3fl() is just multiplying a vector and a float.

Sculpting works by first computing the offsets and storing them in “proxy” nodes, and those offsets are then added to the actual vertex coordinates later in sculpt_combine_proxies_task_cb. That system is used to avoid certain problems with symmetric sculpting, where otherwise you get problems when the symmetry causes a vertex to be offset twice.

1 Like