Jump to content
Wikzo

Can I manually hardcode the UV values?

Recommended Posts

We are making a game in Unity that only uses flat colors (no textures). Instead of having many different materials that have different colors, we are considering making a texture atlas that will be used as a color chart. Each model will then pick the right color in this atlas using its UV coordinates. This is to limit the amount of batches we need to make.

64fFk3S.png

E.g., UV coordinate (0,0) is red; UV coordinate (1,1) is green.

Is it possible to manually override all UV coordinates for models made in ProBuilder? I have tried the UV Editor, but what I want is to just specify the values manually. I can do it via a script, but this creates a new Mesh instance and requires some run-time code.

Vector2 Color = new Vector2(1,1); // green
mesh = GetComponent<MeshFilter>().mesh;
Vector2[] uvs = mesh.uv;
for (int i = 0; i < uvs.Length; i++)
 {
    uvs[i] = Color;
    mesh.uv = uvs;
  }

 

Share this post


Link to post
Share on other sites

If you want to do this as a post-processing step check out the `CleanUnusedAttributes.cs` API example. It runs code on the shared mesh after ProBuilder has compiled it, so this would be the place to make edits to the UnityEngine mesh.

using UnityEngine;
using UnityEditor;
using System.Collections;
using ProBuilder.Core;
using ProBuilder.EditorCore;

namespace ProBuilder.EditorExamples
{
	[InitializeOnLoad]
	public class ClearUnusedAttributes : Editor
	{
		/**
		 *	Static constructor is called and subscribes to the OnMeshCompiled delegate.
		 */
		static ClearUnusedAttributes()
		{
			pb_EditorUtility.AddOnMeshCompiledListener(OnMeshCompiled);
		}

		~ClearUnusedAttributes()
		{
			pb_EditorUtility.RemoveOnMeshCompiledListener(OnMeshCompiled);
		}

		/**
		 *	When a ProBuilder object is compiled to UnityEngine.Mesh this is called.
		 */
		static void OnMeshCompiled(pb_Object pb, Mesh mesh)
		{
			mesh.uv = null;
			mesh.colors32 = null;
			mesh.tangents = null;

			// Print out the mesh attributes in a neatly formatted string.
			// Debug.Log( pb_MeshUtility.Print(mesh) );
		}
	}
}

 

Alternatively, you could just set the ProBuilder stored UV coordinates when the object is created and not worry about it again:

using UnityEngine;
using UnityEditor;
using System.Collections;
using ProBuilder2.Common;
using ProBuilder2.EditorCommon;

namespace ProBuilder.EditorExamples
{
	[InitializeOnLoad]
	class SetManualUVsOnObjectCreation : Editor
	{
		static SetManualUVsOnObjectCreation()
		{
			pb_EditorUtility.AddOnObjectCreatedListener(OnProBuilderObjectCreated);
		}

		~SetManualUVsOnObjectCreation()
		{
			pb_EditorUtility.RemoveOnObjectCreatedListener(OnProBuilderObjectCreated);
		}

		static void OnProBuilderObjectCreated(pb_Object pb)
		{
			Vector2[] uvs = pb.uv ?? new Vector2[pb.vertexCount];

			foreach(pb_Face face in pb.faces)
			{
				// ToQuad returns null if face isn't a 4 edged polygon. Also orders the indices so that iterating them
				// forms a loop.
				int[] quad = face.ToQuad();

				if(quad != null)
				{
					uvs[quad[0]] = Vector2.zero;
					uvs[quad[1]] = Vector2.right;
					uvs[quad[2]] = Vector2.one;
					uvs[quad[3]] = Vector2.up;

					// Important - if this isn't set then ProBuilder will unwrap UVs automatically on any change,
					// wiping your manually set coordinates.
					face.manualUV = true;
				}
			}

			pb.SetUV(uvs);
		}
	}
}

 

Share this post


Link to post
Share on other sites

Thanks, it seems to work using OnMeshCompleted:

private static Vector2 Color = new Vector2(1,0);
private static Vector2[] tempUVs;

	static void OnMeshCompiled(pb_Object pb, Mesh mesh)
	{
	    tempUVs = mesh.uv;

        for (int i = 0; i < tempUVs.Length; i++)
            tempUVs[i] = Color;

        mesh.uv = tempUVs;
		mesh.colors32 = null;
		mesh.tangents = null;
	}

However, I would like my designers to be able to define the UVs themselves, preferably via the editor. Would it be possible to make a button where they can set the UVs as shown in the example image below?

 

uv_probuilder.png

Can I somehow get the current pb object and update its UVs via a custom editor window?

Or, alternatively, can I add a Vector2 field in the Shape Tool, so we can set the UVs when creating the object?

Share this post


Link to post
Share on other sites

Sure, it would be pretty easy to do a script that applies UVs to selected faces like that. Here's the ProBuilder specific bit:

foreach (var pb in Selection.gameObjects.Select(x => x.GetComponent<pb_Object>().Where(y != null)))
{
   pb.ToMesh();
   Vector2[] uvs = pb.uv;
   foreach (var face in pb.SelectedFaces)
      foreach(var index in face.distinctIndices)
         uvs[index] = color;
   pb.SetUV(uvs);
   pb.Refresh();
   pb.Optimize();
}

Alternatively you could skip the texturing entirely and use vertex colors. The Vertex Colors panel has two modes, painting and palette. If you set it to palette that will apply colors per-face.

Share this post


Link to post
Share on other sites

You are right; the vertex colors seem to work perfectly fine!

I just recorded a small video of a use scenario where we have some floor tiles. Previously, we needed to define the "crack" object to have a different material in order to show a grid between each tile. This would make batching difficult. Now, using the vertex colors, we can have the same material for all tiles+cracks, but just change the color. It seems like the batching count is constant.

I've never worked with vertex colors before. Is there anything I should be aware of? Also, is it possible to add more colors to the Vertex Colors panel?

VertexColors.mp4

Share this post


Link to post
Share on other sites

As far as things to be aware, not really. Rendering-wise they're quite cheap.

Adding more colors to the panel, not at the moment. It's something we'd like to improve in the future though.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×