Close Menu
Versa AI hub
  • AI Ethics
  • AI Legislation
  • Business
  • Cybersecurity
  • Media and Entertainment
  • Content Creation
  • Art Generation
  • Research
  • Tools
  • Resources

Subscribe to Updates

Subscribe to our newsletter and stay updated with the latest news and exclusive offers.

What's Hot

Midjourney AI image generator launches on PicLumen: Expand your fall art creation with AI tools | AI News Details

October 17, 2025

DoubleVerify expands the reach of AI-powered brand suitability measurement across metathreads

October 17, 2025

Trillion Parameter AI Model: Ant Group’s Ling-1T Announcement

October 17, 2025
Facebook X (Twitter) Instagram
Versa AI hubVersa AI hub
Friday, October 17
Facebook X (Twitter) Instagram
Login
  • AI Ethics
  • AI Legislation
  • Business
  • Cybersecurity
  • Media and Entertainment
  • Content Creation
  • Art Generation
  • Research
  • Tools
  • Resources
Versa AI hub
Home»Tools»Convert vertex color mesh to textured mesh
Tools

Convert vertex color mesh to textured mesh

By January 21, 2025No Comments6 Mins Read
Share Facebook Twitter Pinterest LinkedIn Tumblr Reddit Telegram Email
Share
Facebook Twitter LinkedIn Pinterest Email


Open with Colab

Converts a mesh of vertex colors to a UV-mapped textured mesh.

introduction

Vertex colors are an easy way to add color information directly to the vertices of a mesh. This is often how generative 3D models like InstantMesh generate meshes. However, for most applications, a UV-mapped textured mesh is preferred.

This tutorial provides a simple solution to convert a vertex color mesh to a UV mapped textured mesh. This includes a short version for quick results and a long version for a detailed walkthrough.

short version

For easy conversion, install the InstantTexture library. This is a small library we created that implements the steps described in the “long version” below.

pip install git+https://github.com/dylanebert/InstantTexture

Usage

The code below converts a vertex-colored .obj mesh into a UV-mapped textured .glb mesh and saves it to output.glb.

from instant texture import Converter input mesh path = “https://raw.githubusercontent.com/dylanebert/InstantTexture/refs/heads/main/examples/chair.obj”

Converter = Converter() converter.convert(input_mesh_path)

Let’s visualize the output mesh.

import trimesh mesh = trimesh.load(“output.glb”) mesh.show()

that’s it!

Keep reading for a detailed walkthrough.

long version

Install the following dependencies:

numpy mesh for numerical operations trimesh for loading and saving data xatlas for generating UV maps Pillow for image processing opencv-python for image processing httpx for image processing pip install numpy trimesh xatlas opencv- pythonpillow httpx

Import dependencies.

import CV2
import numb as NP
import trimesh
import Zatras
from pill import images, image filters

Loads the input mesh with vertex colors. This must be an .obj file located in input_mesh_path.

For local files, use trimesh.load() instead of trimesh.load_remote().

mesh = trimesh.load_remote(input_mesh_path) mesh.show()

Access the vertex colors of the mesh.

If this fails, make sure the mesh is a valid .obj file with vertex colors.

vertex color = mesh.visual.vertex color

Generate a UV map using xatlas.

This is the most time-consuming part of the process.

vmapping, index, uvs = xatlas.parametrize(mesh.vertices, Mesh.faces)

Remaps vertices and vertex colors to UV maps.

vertex = mesh.vertex(vmapping) vertex_color = vertex_color(vmapping) mesh.vertex = vertex mesh.face = index

Define the desired texture size.

Builds a texture buffer upscaled by upscale_factor to create higher quality textures.

texture size = 1024

Upscale factor = 2
buffer size = texture size * upscale factor texture buffer = np.zeros((buffer size, buffer size, 4), dtype=np.uint8)

Fills the texture of a UV-mapped mesh using centroid interpolation.

Centroid interpolation: Computes the interpolated color of point p within the triangle defined by vertices v0, v1, v2 and corresponding colors c0, c1, c2. Point-in-Triangle test: Determine whether point p lies within the triangle defined by vertices v0, v1, and v2. Texture Filling Loop: Iterates over each face of the mesh. Gets the UV coordinates (uv0, uv1, uv2) and color (c0, c1, c2) of the current face. Convert UV coordinates to buffer coordinates. Determines the bounding box of a triangle on the texture buffer. For each pixel in the bounding box, use the triangle-inside-point test to check whether the pixel is inside the triangle. If inside, use centroid interpolation to calculate the interpolated color. Assigns a color to the corresponding pixel in the texture buffer.

surely barycentric_interpolate(v0, v1, v2, c0, c1, c2, p): v0v1 = v1 – v0 v0v2 = v2 – v0 v0p = p – v0 d00 = np.dot(v0v1, v0v1) d01 = np.dot(v0v1, v0v2) d11 = np.dot(v0v2, v0v2) d20 = np .dot(v0p, v0v1) d21 = np.dot(v0p, v0v2) denom = d00 * d11 – d01 * d01
if abs(denom) 1e-8:
return (c0 + c1 + c2) / 3
v = (d11 * d20 – d01 * d21) / denom w = (d00 * d21 – d01 * d20) / denom u = 1.0 – v – wu = np.clip(u, 0, 1) v = np.clip(v, 0, 1) w = np.clip(w, 0, 1) interpolate_color = u * c0 + v * c1 + w * c2
return np.clip(interpolation color, 0, 255)

surely is_point_in_triangle(p, v0, v1, v2):
surely sign(p1, p2, p3):
return (p1(0) – p3(0)) * (p2(1) – p3(1)) – (p2(0) – p3(0)) * (p1(1) – p3(1)) d1 = sign(p, v0, v1) d2 = sign(p, v1, v2) d3 = sign(p, v2, v0) has_neg = (d1 0) or (d2 0) or (d3 0) has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0)

return do not have (I’m a negative person. and has_pos)

for face in Mesh.faces: uv0, uv1, uv2 = uvs(face) c0, c1, c2 = vertex_colors(face) uv0 = (uv0 * (buffer_size – 1)).astype(integer) uv1 = (uv1 * (buffer size – 1)).astype(integer) uv2 = (uv2 * (buffer size – 1)).astype(integer) min_x = maximum(integer(np.floor(minutes(uv0(0), uv1(0), uv2(0)))), 0) max_x = minutes(integer(np.ceil(maximum(uv0(0), uv1(0), uv2(0)))), buffer_size – 1) min_y = maximum(integer(np.floor(minutes(uv0(1), uv1(1), uv2(1)))), 0) max_y = minutes(integer(np.ceil(maximum(uv0(1), uv1(1), uv2(1)))), buffer_size – 1)

for y in range(min_y, max_y + 1):
for × in range(min_x, max_x + 1): p = np.array((x + 0.5,y + 0.5))
if is_point_in_triangle(p, uv0, uv1, uv2): color = barycentric_interpolate(uv0, uv1, uv2, c0, c1, c2, p) texture_buffer(y, x) = np.clip(color, 0, 255).astype( np.uint8 )

Let’s visualize what the texture looks like so far.

from IPython.display import display image_texture = Image.fromarray(texture_buffer) display(image_texture)

texture with holes

As you can see, the texture has a lot of holes.

To fix this, combine the following four techniques:

Inpainting: Fills holes using the average color of surrounding pixels. Median filter: Removes noise by replacing each pixel with the median color of surrounding pixels. Gaussian Blur: Smoothes the texture and removes any remaining noise. Downsample: Use LANCZOS resampling to resize up to texture_size. image_bgra = texture_buffer.copy() mask = (image_bgra(:, :, 3) == 0).astype(np.uint8) * 255
image_bgr = cv2.cvtColor(image_bgra, cv2.COLOR_BGRA2BGR) inPaint_bgr = cv2.inpaint( image_bgr, mask, inpaintRadius=3flags=cv2.INPAINT_TELEA ) inPaint_bgra = cv2.cvtColor(inPaint_bgr, cv2.COLOR_BGR2BGRA) texture_buffer = inPaint_bgra(::-1) image_texture = Image.fromarray(texture_buffer) image_texture = image_texture.filter(ImageFilter.MedianFilter(size=3)) ImageTexture = ImageTexture.filter(ImageFilter.GaussianBlur(radius=1)) image_texture = image_texture.resize((texture_size, texture_size), Image.LANCZOS) display(image_texture)

texture without holes

As you can see, the texture is now much smoother and has no holes.

This can be further improved with more advanced techniques and manual texture editing.

Finally, you can construct a new mesh using the generated UV coordinates and texture.

Material = trimesh.visual.material.PBRmaterial(baseColorFactor=(1.0, 1.0, 1.0, 1.0), baseColorTexture=image_texture, metallicFactor=0.0roughness coefficient =1.0) Visuals = trimesh.visual.TextureVisuals(uv=uvs,material=material) Mesh.visual = Visuals Mesh.show()

final mesh

here we go! The mesh is UV mapped and textured.

To export when running locally, call mesh.export(“output.glb”).

Restrictions

As you can see, the mesh still has many small artifacts.

The quality of the UV maps and textures is also well below the standard for producible meshes.

However, if you’re looking for a quick solution to mapping from a vertex-colored mesh to a UV-mapped mesh, this approach might be useful.

conclusion

This tutorial showed you how to convert a vertex color mesh to a UV-mapped textured mesh.

If you have any questions or feedback, feel free to open an issue on GitHub or Space.

Thank you for reading!

author avatar
See Full Bio
Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
Previous ArticleWhat to expect in 2025
Next Article Nio forms team to research AI robot dog project, reports say

Related Posts

Tools

Trillion Parameter AI Model: Ant Group’s Ling-1T Announcement

October 17, 2025
Tools

Google Cloud C4 improves TCO of GPT OSS by 70% using Intel and Hugging Face

October 16, 2025
Tools

Edit AI videos with the new Veo 3.1 update to Flow

October 16, 2025
Add A Comment

Comments are closed.

Top Posts

Corteva, Profluent partners use AI to enable more resilient crops

October 6, 20253 Views

Digital doubles has arrived. What does AI mean for creator and brand collaboration?

October 10, 20252 Views

Adds AI tools for on-demand video creation to Google TV sets

October 9, 20252 Views
Stay In Touch
  • YouTube
  • TikTok
  • Twitter
  • Instagram
  • Threads
Latest Reviews

Subscribe to Updates

Subscribe to our newsletter and stay updated with the latest news and exclusive offers.

Most Popular

Corteva, Profluent partners use AI to enable more resilient crops

October 6, 20253 Views

Digital doubles has arrived. What does AI mean for creator and brand collaboration?

October 10, 20252 Views

Adds AI tools for on-demand video creation to Google TV sets

October 9, 20252 Views
Don't Miss

Midjourney AI image generator launches on PicLumen: Expand your fall art creation with AI tools | AI News Details

October 17, 2025

DoubleVerify expands the reach of AI-powered brand suitability measurement across metathreads

October 17, 2025

Trillion Parameter AI Model: Ant Group’s Ling-1T Announcement

October 17, 2025
Service Area
X (Twitter) Instagram YouTube TikTok Threads RSS
  • About Us
  • Contact Us
  • Privacy Policy
  • Terms and Conditions
  • Disclaimer
© 2025 Versa AI Hub. All Rights Reserved.

Type above and press Enter to search. Press Esc to cancel.

Sign In or Register

Welcome Back!

Login to your account below.

Lost password?