Posts
Search
Contact
Cookies
About
RSS

Painting on a 3d Mesh with Raylib

Added 2 Aug 2019, 11:15 p.m. edited 18 Jun 2023, 5:56 p.m.

Recently a new example textures_mouse_painting was added to raylib, and I thought "that's neat scribbling on a texture.... hmm...." wouldn't it be cool to paint on a 3d model instead, while looking at models_mesh_picking, thinking "nah this is going to be too complicated", I noticed it was using Vector3Barycenter "oooh....." I thought! I seem to remember that has something to do with interpolating textures on a triangle when rendering. After a slight false start, it all came together quite quickly, there's some source code below to demonstrate the technique but before explaining the maths, I'll detail the controls for the demo - there's a whole bunch as I was too lazy to build a proper GUI!

YUK a program desperately in need of a GUI....!

Right math time! First there is a bonus routine to make a single Matrix from 3 Euler angles, this saves having to multiply three matrices together... Its not ideal as you can induce gimbal lock, I might do a later post on a technique that uses cumulative Quaternion rotations to side step this issue but that's something for a later date...

I'll assume you have seen the models_mesh_picking example and understand it, if not have a quick look its simple enough...

Because info like texture coordinates and barycentre info isn't commonly needed when doing 3d picking, its very understandably missing from raylibs model picking, I simply copied and pasted the appropriate code and added the info I needed.

Barycentre coordinates can very simply converted to UV coordinates if you have the 3 UV coordinates of the triangle in question

    float u = mhi.bazza.x * mhi.uv1.x +
                mhi.bazza.y * mhi.uv2.x +
                mhi.bazza.z * mhi.uv3.x;

    float v = mhi.bazza.x * mhi.uv1.y +
                mhi.bazza.y * mhi.uv2.y +
                mhi.bazza.z * mhi.uv3.y;

Once you have UV coordinates then everything else is just 2d drawing, which just goes to show - when something initially looks complex, sometimes with the right technique everything falls into place rather easily.

Because I wanted to render cursors on the model I needed to use two render textures, one that the actual drawing is done on, and one that actually textures the model, each frame the drawing texture is used to "clear" the texture that's actually used on the model, we then have a clean sheet we can render triangles and cursors on.

I'd be willing to collaborate on this with someone, if you're interested in taking this further, but in the mean time here's the source.