I want to import and display an .obj file at runtime in Unity (2017.3.1f1) and found a fixed version (click, direct link to pastebin) of the FastObjImporter from the Unity wiki (click).
Since my .obj file doesn't include normals, I had to make the following change:
if(faceData[i].z >= 1) {
if(normals.Count != 0) {
newNormals[i] = normals[faceData[i].z - 1];
}
}
I also added mesh.RecalculateNormals(); in the beginning.
The problem and reason why I'm opening this question is that Unity doesn't display anything. The scene is pretty simply: The standard directional light and standard camera with a player character as its child.
My code (I have to rotate to align it properly):
Mesh m = FastObjImporter.Instance.ImportFile(path);
Material mat = new Material(Shader.Find("Hidden/Internal-Colored")) { color = new Color(0,0,1) };
GameObject obj = new GameObject();
if(obj.GetComponent<MeshFilter>()==null) { obj.AddComponent<MeshFilter>(); }
if(obj.GetComponent<MeshRenderer>()==null) { obj.AddComponent<MeshRenderer>(); }
obj.GetComponent<MeshFilter>().mesh = m;
obj.GetComponent<MeshRenderer>().material = mat;
obj.transform.Rotate(new Vector3(270,0,0));
obj.transform.Rotate(new Vector3(0,0,180));
I've tried different shaders and models and I'm using the same code to create my own meshes and GameObjects with vertices information I'm reading from a .txt file and everything works fine there - just not here.
I also noticed that the "triangles" list always carries 0 items, even though there are loads of "t ...." entries in my .obj file. If I change "j=1" to "j=0" here, it fills the list:
info += j;
j = 0;
while(j + 2 < info) {
In the end Unity still doesn't display anything, so there has to be something else that's wrong.
Does anyone have a suspicion what it could be and what I can do to make it work?
Related
First of all, i created a GIF to show what is currently happen.
GIF with my current problem
and
Awhat I want
I have a List of GameObject which add the bodyParts temp and Instantiate it in the correct time and position.
Now this is working like expected, but i want this new bodyParts below another object instead of above.
As you can see the Head is "under" the new body parts, but it should always on Top and every new part should spawn under the next. (only should looks like! I dont want to change the Z position.)
i tried :
bodyParts.transform.SetAsFirstSibling();
to change the Hierarchy, but this do nothing. I also can drag and drop the Clones to a other position in Hierarchy but they just stay at the same position (above another).
Is this possible and what should i have to do?
Here some of my Code which makes the process:
private void CreateBodyParts()
{
if (snakeBody.Count == 0)
{
GameObject temp1 = Instantiate(bodyParts[0], transform.position, transform.rotation, transform);
if (!temp1.GetComponent<MarkerManager>())
temp1.AddComponent<MarkerManager>();
if (!temp1.GetComponent<Rigidbody2D>())
{
temp1.AddComponent<Rigidbody2D>();
temp1.GetComponent<Rigidbody2D>().gravityScale = 0;
}
snakeBody.Add(temp1);
bodyParts.RemoveAt(0);
}
MarkerManager markM = snakeBody[snakeBody.Count - 1].GetComponent<MarkerManager>();
if (countUp == 0)
{
markM.ClearMarkerList();
}
countUp += Time.deltaTime;
if (countUp >= distanceBetween)
{
GameObject temp = Instantiate(bodyParts[0], markM.markerList[0].position, markM.markerList[0].rotation, transform);
if (!temp.GetComponent<MarkerManager>())
temp.AddComponent<MarkerManager>();
if (!temp.GetComponent<Rigidbody2D>())
{
temp.AddComponent<Rigidbody2D>();
temp.GetComponent<Rigidbody2D>().gravityScale = 0;
}
snakeBody.Add(temp);
bodyParts.RemoveAt(0);
temp.GetComponent<MarkerManager>().ClearMarkerList();
countUp = 0;
}
}
Finally i found the working Solution.
It has nothing to do with which hierarchy order GameObjects spawn in.
Just the Layer and the LayerOrder are responsible for it.
So I give my parent object a specific layer name (manually in the inspector under "Additional Settings" or programmatically)
I chose the programmatic way...
Any newly spawned GameObject that is Child would get a lower number
yourGameObject.GetComponent<Renderer>().sortingLayerID = SortingLayer.NameToID("Player");
yourGameObject.GetComponent<Renderer>().sortingOrder = -snakeBody.Count;
I used Gizmos.DrawMesh in unity but when I build the program, I can't see any colors.
My code:
private void OnDrawGizmos()
{
if(mesh)
{
Gizmos.color = Color.red;
Gizmos.DrawMesh(mesh, transform.position, transform.rotation);
}
}
When I built the app, the colors I coded didn't show up. I'm wondering if Gizmos can only be used when I view it in the unity editor. when built, it is no longer usable.
Why aren't these colors showing up?
Yes, Gizmos are only visible in the editor. Maybe this can help you out:
https://github.com/popcron/gizmos
Edit:
Sorry I did not see that you want to use DrawMesh(), that's not supported by that lib. (if you want to use it anyway you can add it through the package manager "add from url" and insert "com.popcron.gizmos")
Are you creating the mesh in code? If so, you could use a line mesh: https://docs.unity3d.com/ScriptReference/MeshTopology.html
It should also be possible to convert a triangle mesh into a line mesh without too much trouble.
Edit2:
(I think this is overkill and does not offer much configuration)
I wrote a class that adds a context menu to the component "Mesh Filter". Place it in a folder named "Editor" and you should be able to right-click on a MeshFilter and convert it with "Convert To Line Mesh...". (The line mesh is very basic without a custom shader, so you wont get anything like line thickness)
If I have time I'll write a script that converts the lines to two triangles instead, that should then solve the issue.
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public static class MeshConverterEditor
{
[MenuItem("CONTEXT/MeshFilter/Convert To Line Mesh...")]
public static void ConvertToLineMesh(MenuCommand menuCommand)
{
MeshFilter mf = menuCommand.context as MeshFilter;
Mesh m = mf.sharedMesh;
if (m.GetTopology(0) != MeshTopology.Triangles)
{
Debug.LogError("Can only convert triangle meshes.");
return;
}
mf.sharedMesh = ConvertToLineMesh(m);
}
public static Mesh ConvertToLineMesh(Mesh mesh)
{
var lineMesh = new Mesh();
var tris = mesh.triangles;
List<int> lineIndices = new List<int>(tris.Length * 2);
for (int i = 0; i < tris.Length; i += 3)
{
lineIndices.Add(tris[i]);
lineIndices.Add(tris[i + 1]);
lineIndices.Add(tris[i + 1]);
lineIndices.Add(tris[i + 2]);
lineIndices.Add(tris[i + 2]);
lineIndices.Add(tris[i]);
}
lineMesh.vertices = mesh.vertices;
lineMesh.uv = mesh.uv;
lineMesh.normals = mesh.normals;
lineMesh.tangents = mesh.tangents;
lineMesh.SetIndices(lineIndices, MeshTopology.Lines, 0, true);
return lineMesh;
}
}
Edit3:
I found a very simple and nice looking library:
https://github.com/Chaser324/unity-wireframe
Just copy the folders:
unity-wireframe-master\Assets\Wireframe\Shaders
unity-wireframe-master\Assets\Wireframe\Examples\Materials
into your project, drag a material on your GameObject and you should be good.
I'm attempting to dynamically add an FBX model into a scene and add the following components to the child objects of the main GameObject created from the FBX model:
MeshCollider (I Add a mesh to this using the sharedMesh variable)
ManipulationHandler
NearInteractionGrabbable
When I test the functionality in Unity it works flawlessly. When I deploy to the HoloLens 2 only the objects that wouldn't require "convex = true" are working.
It makes me feel like setting convex = true isn't working when deployed on the hololens 2.
Here's my code for your reference on how I'm getting things to work:
void Start()
{
//Grab object from Resources/Objects using provided unique identifier
//I'm instantiating like this because I'm setting the parent to another GameObject in the original code and I got errors if I didn't do it this way
GameObject go = Instantiate(Resources.Load<GameObject>("Objects/" + objectId));
//Loop through child objects of model
for (int i = 0; i < go.transform.childCount; i++)
{
AddManipulationComponents(go.transform.GetChild(i).gameObject);
}
}
void AddManipulationComponents(GameObject item)
{
//Get MeshFilter so I can set the mesh of it to the sharedMesh of the MeshCollider
MeshFilter meshFilter = item.GetComponent<MeshFilter>();
//Only Add MeshCollider components if there's a mesh on the object.
if (meshFilter != null)
{
Mesh mesh = item.GetComponent<MeshFilter>().mesh;
if (mesh != null)
{
//Add MeshCollider
MeshCollider collider = item.EnsureComponent<MeshCollider>();
//A lot of components are curved and need convex set to false
collider.convex = true;
//Add NearInteractionGrabbable
item.EnsureComponent<NearInteractionGrabbable>();
//Add ManipulationHandler
item.EnsureComponent<ManipulationHandler>();
//Set mesh to MeshCollider
collider.sharedMesh = mesh;
}
}
//If current component has children, then loop through those.
if (item.transform.childCount > 0)
{
for (int i = 0; i < item.transform.childCount; i++)
{
AddManipulationComponents(item.transform.GetChild(i).gameObject);
}
}
}
This works when I run it through Unity, but when I build it and deploy to the HoloLens 2 it doesn't completely work. By that I mean there's only 3 or 4 child objects that actually work and they happen to be flat objects. It makes me think the "convex" variable in MeshCollider is not behaving as I'd hope.
Anyone have a fix for this?
Here's a photo of it working through unity (I clipped out proprietary information):
Convex mesh colliders are limited to 255 triangles, perhaps this is why its not working?
When importing the FBX you need to select the checkbox for "Read/Write"
I enabled that and made sure to export all materials as well.
I'm making a voice line + subtitle system, using a custom inspector to make it easier to use.
All is working perfectly until i tried to show a subtitle EditorGUILayout.TextField similar to how I am using EditorGUILayout.ObjectField for the voice audio clips.
This works (No subtitle functions):
showAudioClipList = EditorGUILayout.BeginFoldoutHeaderGroup(showAudioClipList, new GUIContent("Audio Clips", "Audio clips available to play when interacting with this object."));
if (showAudioClipList)
{
GUILayout.BeginVertical("box");
for (int i = 0; i < _AudioClips.arraySize; i++)
{
SerializedProperty AC_ref = _AudioClips.GetArrayElementAtIndex(i);
EditorGUILayout.BeginHorizontal("box");
AC_ref.objectReferenceValue = EditorGUILayout.ObjectField("Clip " + (i + 1) + ":", AC_ref.objectReferenceValue, typeof(AudioClip), false);
if (GUILayout.Button(new GUIContent("X", "Remove this clip"), GUILayout.MaxWidth(20)))
t.AudioClips.RemoveAt(i);
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button(new GUIContent("Add Clip", "Add new clip entry")))
t.AudioClips.Add(null);
if (GUILayout.Button(new GUIContent("Remove All Clips", "Remove all clip entries")))
t.AudioClips.Clear();
EditorGUILayout.EndHorizontal();
GUILayout.EndVertical();
}
EditorGUILayout.EndFoldoutHeaderGroup();
I want to make it show a text field underneath each audioclip box so I can write in subtitles for each voice line. I got it working for a non-list string, but cant get it working for a list of strings in the same way that the list of AudioClips works.
I've tried
t.Subtitles[i] = EditorGUILayout.TextField(etc...
and
ST_ref.stringValue = EditorGUILayout.TextField(etc... trying to replicate how the audioclip one works, plus some others, but all cause errors in console and collapse the inspector.
Can you understand my problem from just this code?
Solved it.
I'm using
SerializedProperty SC_ref = _Subtitles.GetArrayElementAtIndex(i);
(goes under the SerializedProperty AC_ref = _AudioClips.GetArrayElementAtIndex(i);)in the same way as the audio clips, and
EditorGUILayout.PropertyField(SC_ref);
(goes at the bottom of the FOR loop inside, in its own BeginHorizontal("box")) to show, set, and save each string value as each is displayed under its corresponding AudioClip object. EditorGUILayout.PropertyField saves changes at the same time as showing the variable in inspector, so it only needs that short code line to work.
_Subtitles is a SerializedProperty of a List, and by using GetArrayElementAtIndex() I can specify a specific entry in the list to modify by temporarily saving it as its own SerializedProperty.
First of all I'm not a professional coder but have done some C# in the past. I have problem with my Unity project at the moment. I'm loading images from my resources folder and rendering them on a 3D object. Problem is with my nex texture "buttons" which are supposed to look at variable "n" and determinate which image is loaded as texture on a 3D object based on their order in the images folder. Currently when I click on a next image button it renders the next texture but only for the first 2 images in the folder. After that it does go in to the loop I've checked with debug.log but it does not render next image as a texture. Code is as following:
For the next button (that calls render texture and changes variable 'n' value):
void OnMouseDown() {
if (this.name == "NextTexture") {
LevelSelect.n=+2;
LevelSelect.RenderTextures();
}
if (this.name == "PreviousTexture") {
LevelSelect.n-=2;
LevelSelect.RenderTextures();
}
and for the image to texture rendering:
public static void RenderTextures(){
Mesh mesh = staticMeshFilter.mesh;
Vector3[] vertices = mesh.vertices;
Vector2[] uvs = new Vector2[vertices.Length];
for (int i=0; i < uvs.Length; i++) {
uvs[i] = new Vector2(vertices[i].x, vertices[i].y);
}
mesh.uv = uvs;
rend.material.mainTexture = loader.LoadImages ("images") [n];
transformTexture.renderer.material.mainTextureOffset = new Vector2(0.4f, 0.28f); // +0.1x
transformTexture.renderer.material.mainTextureScale = new Vector2(0.8f, 0.8f);
}
So at the moment I'm confused about how and why my code doesn't render the 3rd and 4th image from the images folder as textures.
Cheers!