Skip to content

ThreeJS Drawing System

Charles Forman edited this page Apr 18, 2022 · 1 revision

Drawing system at a high level

Overview:

The drawing system works by drawing/compositing brush "stamps" on an image to create the illusion of a brush stroke.

If the stamp has a texture on it, it can get the illusion of the brush or the paper having texture.

Draw a stroke on a temporary layer:

Each complete stroke is first drawn to a temporary buffer while the stroke is in progress and is drawn to the main image only after the stroke is complete. The reason for this is that the stroke could have an opacity. If the stoke was just drawn directly to the main image, it would build up and you could not get a strokes opacity to look right.

How to draw strokes:

Lerp between each stroke node by 1 pixel. For example, if the stroke is just 2 nodes, starting at 0,0 and ending at 10,0, there will be 10 stamps to create that segment.

Brush Stamps:

A brush stamp in it's simplest form is a square texture with a specific color, and an alpha channel with the "shape" of the brush stamp. Additionally, a brush can have a texture, which is a seamless texture that is sampled to form the texture of the brush image. Per each stamp, the texture should be offset by the inverse of the stamp position. This will create the illustion of a texture when it is drawn to the stroke. (I can explain this more in detail)

Separate Input from Drawing:

The drawing should be decoupled from the user input. In some cases, the user will draw tons of big strokes very quickly. The computer may not be fast enough for this. Therefore, we should only draw a certain amount of operations per frame, and add subsequent actions to a queue that can be drawn on subsequent frames.

Specifically, don't draw more than 50 stamps on a frame. Any more, add to a queue and work through the queue in the next frames.

Stroke Smoothing:

Often times, the user will move their input device (pen or mouse) very fast per frame. The result is that the recorded nodes per frame are long straight lines. This will cause the drawing to look like the stroke is very jagged.

One thing we can do, is delay constructing the stroke for X amount of frames. After a certain amount of frames, we can smooth the users inputs into a smoother stroke to send to the drawing engine.

Performance tips:

  • Use only square brush textures
  • Try to keep the same render target as much as possible. Switching has high costs
  • When you set up a render target, reset the scissor rect and the viewport rect
  • Turn off mipmaps for texures that dont need them, it costs a lot of performance.
Clone this wiki locally