drbii 4 Report post Posted March 8, 2017 Ok started polybrushing a mesh and after doing some pretty major and time consuming work realize that additional vertex streams was checked on...so they are not actually applied to the mesh itself. Is there a way to apply those to the mesh and continue with data streams off. We tried saving as an OBJ but does not save the data stream manipulations done by polybrush. NEED THIS! Share this post Link to post Share on other sites
karl 321 Report post Posted March 9, 2017 That's a good feature request - and I think pretty easy to add. I'll try to get a quick utility written as a workaround for now. Share this post Link to post Share on other sites
drbii 4 Report post Posted March 9, 2017 13 hours ago, karl said: That's a good feature request - and I think pretty easy to add. I'll try to get a quick utility written as a workaround for now. That would be awesome. We work between unity and external 3d tools frequently and it would allow us to take our polybrushed objects back into them. Normally we don't have the additional streams on but sometimes (inevitably under short deadline) its on for some reason and we are stuck. A tool that saves the additional streams to the mesh would give us the best of both worlds....we could keep the additional stream and its effiecencies until we had to go back into a 3d program. Thanks! You guys rock! Share this post Link to post Share on other sites
karl 321 Report post Posted March 9, 2017 Okay, here's a utility for quickly merging additional vertex streams into the current mesh or a new composite mesh. If you've painted a single base mesh many times with the vertex streams option enabled make sure you use the "Create New Composite Mesh" options - if you apply to current you could lose all your other modifications. IMPORTANT - Make sure to back up your project before using this utility. There is no Undo and this will overwrite mesh assets. using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; using System.Linq; namespace Polybrush { /** * Utility for applying vertex stream data directly to a mesh. Can either override the existing * mesh arrays or create a new mesh from the composite. */ public class z_BakeAdditionalVertexStreams : EditorWindow { [MenuItem("Tools/Polybrush/Bake Vertex Streams")] static void Init() { EditorWindow.GetWindow<z_BakeAdditionalVertexStreams>(true, "Bake Vertex Streams", true); } void OnEnable() { Undo.undoRedoPerformed += UndoRedoPerformed; autoRepaintOnSceneChange = true; OnSelectionChange(); } void OnFocus() { OnSelectionChange(); } void OnDisable() { Undo.undoRedoPerformed -= UndoRedoPerformed; } private List<z_AdditionalVertexStreams> m_VertexStreams = new List<z_AdditionalVertexStreams>(); private Vector2 scroll = Vector2.zero; private GUIContent m_BatchNewMesh = new GUIContent("Create New\nComposite Mesh", "Create a new mesh for each selected mesh, automatically prefixing the built meshes with z_ and index. This is useful in situations where you have used Additional Vertex Streams to paint a single mesh source many times and would like to ensure that all meshes remain unique."); void OnGUI() { GUILayout.BeginHorizontal(); GUILayout.BeginVertical(); GUILayout.Label("Selected", EditorStyles.boldLabel); scroll = EditorGUILayout.BeginScrollView(scroll, false, true); foreach(z_AdditionalVertexStreams vertexStream in m_VertexStreams) { if(vertexStream != null) GUILayout.Label(string.Format("{0} ({1})", vertexStream.gameObject.name, vertexStream.mesh == null ? "null" : vertexStream.mesh.name)); } EditorGUILayout.EndScrollView(); GUILayout.EndVertical(); GUILayout.BeginVertical(); GUILayout.Label("Bake Options", EditorStyles.boldLabel); GUI.enabled = m_VertexStreams.Count == 1; if(GUILayout.Button("Apply to\nCurrent Mesh")) { if( EditorUtility.DisplayDialog("Apply Vertex Streams to Mesh", "This action is not undo-able, are you sure you want to continue?", "Yes", "Cancel") ) { foreach(var stream in m_VertexStreams) CreateComposite(stream, true); } m_VertexStreams.Clear(); } if(GUILayout.Button("Create New\nComposite Mesh")) { foreach(var stream in m_VertexStreams) CreateComposite(stream, false); m_VertexStreams.Clear(); } GUI.enabled = m_VertexStreams.Count > 0; GUILayout.Label("Batch Options", EditorStyles.boldLabel); if(GUILayout.Button(m_BatchNewMesh)) { string path = EditorUtility.OpenFolderPanel("Save Vertex Stream Meshes", "Assets", ""); for(int i = 0; i < m_VertexStreams.Count; i++) { path = path.Replace(Application.dataPath, "Assets"); if(m_VertexStreams[i] == null || m_VertexStreams[i].mesh == null) continue; CreateComposite(m_VertexStreams[i], false, string.Format("{0}/{1}.asset", path, m_VertexStreams[i].mesh.name)); } m_VertexStreams.Clear(); } GUILayout.EndVertical(); GUILayout.EndHorizontal(); } void OnSelectionChange() { m_VertexStreams = Selection.transforms.SelectMany(x => x.GetComponentsInChildren<z_AdditionalVertexStreams>()).ToList(); Repaint(); } void UndoRedoPerformed() { foreach(Mesh m in Selection.transforms.SelectMany(x => x.GetComponentsInChildren<MeshFilter>()).Select(y => y.sharedMesh)) { if(m != null) m.UploadMeshData(false); } } void CreateComposite(z_AdditionalVertexStreams vertexStream, bool applyToCurrent, string path = null) { GameObject go = vertexStream.gameObject; Mesh source = go.GetMesh(); Mesh stream = vertexStream.mesh; if(source == null || stream == null) { Debug.LogWarning("Mesh filter or vertex stream mesh is null, cannot continue."); return; } if(applyToCurrent) { CreateCompositeMesh(source, stream, source); MeshRenderer renderer = go.GetComponent<MeshRenderer>(); if(renderer != null) renderer.additionalVertexStreams = null; GameObject.DestroyImmediate(vertexStream); } else { Mesh composite = new Mesh(); CreateCompositeMesh(source, stream, composite); if( string.IsNullOrEmpty(path) ) { z_EditorUtility.SaveMeshAsset(composite, go.GetComponent<MeshFilter>(), go.GetComponent<SkinnedMeshRenderer>()); } else { AssetDatabase.CreateAsset(composite, path); MeshFilter mf = go.GetComponent<MeshFilter>(); SkinnedMeshRenderer smr = go.GetComponent<SkinnedMeshRenderer>(); if(mf != null) mf.sharedMesh = composite; else if(smr != null) smr.sharedMesh = composite; } Undo.DestroyObjectImmediate(vertexStream); } } void CreateCompositeMesh(Mesh source, Mesh vertexStream, Mesh composite) { int vertexCount = source.vertexCount; bool isNewMesh = composite.vertexCount != vertexCount; composite.name = source.name; composite.vertices = vertexStream.vertices != null && vertexStream.vertices.Length == vertexCount ? vertexStream.vertices : source.vertices; composite.normals = vertexStream.normals != null && vertexStream.normals.Length == vertexCount ? vertexStream.normals : source.normals; composite.tangents = vertexStream.tangents != null && vertexStream.tangents.Length == vertexCount ? vertexStream.tangents : source.tangents; composite.boneWeights = vertexStream.boneWeights != null && vertexStream.boneWeights.Length == vertexCount ? vertexStream.boneWeights : source.boneWeights; composite.colors32 = vertexStream.colors32 != null && vertexStream.colors32.Length == vertexCount ? vertexStream.colors32 : source.colors32; composite.bindposes = vertexStream.bindposes != null && vertexStream.bindposes.Length == vertexCount ? vertexStream.bindposes : source.bindposes; List<Vector4> uvs = new List<Vector4>(); vertexStream.GetUVs(0, uvs); if(uvs == null || uvs.Count != vertexCount) source.GetUVs(0, uvs); composite.SetUVs(0, uvs); vertexStream.GetUVs(1, uvs); if(uvs == null || uvs.Count != vertexCount) source.GetUVs(1, uvs); composite.SetUVs(1, uvs); vertexStream.GetUVs(2, uvs); if(uvs == null || uvs.Count != vertexCount) source.GetUVs(2, uvs); composite.SetUVs(2, uvs); vertexStream.GetUVs(3, uvs); if(uvs == null || uvs.Count != vertexCount) source.GetUVs(3, uvs); composite.SetUVs(3, uvs); if(isNewMesh) { composite.subMeshCount = source.subMeshCount; for(int i = 0; i < source.subMeshCount; i++) composite.SetIndices(source.GetIndices(i), source.GetTopology(i), i); } } } } Share this post Link to post Share on other sites
drbii 4 Report post Posted March 9, 2017 Wow thanks! I'll give it try later today. You rock! 1 karl reacted to this Share this post Link to post Share on other sites
drbii 4 Report post Posted March 10, 2017 Getting around to trying out the above code but I keep getting the following message: Assets/ProCore/Polybrush/z_BakeAdditionalVertexStreams.cs(157,21): error CS0103: The name `z_EditorUtility' does not exist in the current context Share this post Link to post Share on other sites
drbii 4 Report post Posted March 10, 2017 figured it out. needs to be placed in the procore>polybrush>code>editor folder. Works like a charm!!! Thanks so much for this!!! 1 karl reacted to this Share this post Link to post Share on other sites
drbii 4 Report post Posted March 17, 2017 Hmmm. Well I thought it was working as expected by I guess it is not. It does save the stream to the mesh, but I cannot use polybrush on the object after I bake the stream on to the mesh. Any mesh that I have baked cannot be rebrushed by polybrush. See the attached image. Any ideas? Looks like something is being manipulated (the blue mesh which is the brush highlight) deforms but the mesh does not...also painting textures stops as well. Share this post Link to post Share on other sites
drbii 4 Report post Posted March 17, 2017 I think if I save the mesh as an assest and re-import it I can then polybrush on it again. Share this post Link to post Share on other sites
drbii 4 Report post Posted March 17, 2017 Or should I have saved a composite mesh? Is that what you mean by composite mesh, one that has been deformed and painted on? Share this post Link to post Share on other sites
karl 321 Report post Posted March 23, 2017 So you used the "Apply to Current Mesh" option? If that is the case the attributes will have been baked into the selection. I can't think of a reason that it wouldn't be editable after this process, unless there was a mixup wherein Polybrush thinks there is an Additional Vertex Streams mesh still present. Make sure that there isn't a "z_AdditionalVertexStreams" component on that mesh still. Share this post Link to post Share on other sites
drbii 4 Report post Posted March 30, 2017 It not working seems to be something else. After a restart it hasn't done that again. I'll keep you posted. All-in-all this a very awesome addition to the tool...thanks!!! 1 karl reacted to this Share this post Link to post Share on other sites