- Home /
constructive advice needed for using builtin arrays and programming in general
Foreward : While I appreciate all input, for this one question I am looking for decisive, precise answers rather than vague suggestions or open-ended comments. I also understand people may not want to answer my question, as it holds some elements to unlocking the keys of the Unity universe, and that's where some people make their bread and butter. I am not trying to ruin anyones livelyhood, merely want to make these things myself to use myself to expand my knowledge and save money I don't actually have =]
This stems from what I thought was a simple question. Basically I had a mesh script that worked with Unity 3.5.1, but when I went to 3.5.6 I started getting an error. Simple question. The details are I have a text mesh (meaning a quad is created per character in the string), when the length of that string changed, and on the first time that text mesh array length was changed, I would get an out of bounds error. However on the next construction of the mesh there was no error and the mesh worked as expected.
This is a simple problem I thought, and went through finding where the lengths of the arrays were assigned, made sure they were not being fed too much or too little information, and even doubly assigned the length of the mesh vertex info before assigning their values.
Here is the question I am speaking of, it has turned into a long mess, and totally irrelevant to the question I asked, only to receive "you are doing it wrong" : http://answers.unity3d.com/questions/334706/array-out-of-range-while-updating-mesh-variables.html
I know Kryptos is correct (he usually is!) but I just cannot see it when I have working meshes with verts animated every frame (reading curves) and they work perfectly without errors or clearing. phodges also seems very knowledgeable, but as in my comment I believe he contradicted his initial statement leaving me confused.
I don't believe so, and if I am wrong please leave a concise answer in a format I can follow and absorb, for example my method I have evolved into for creating my meshes is as follows :
// Variables
var verts : Vector3[];
var uvs : same for uvs, tris, normals
// Initialization
if(!mesh) { GetComponent(MeshFilter).mesh = mesh = new Mesh();}
verts = new Vector3[4];
verts[0] = new Vector3( 0, 0, 0);
verts[1] = same for all verts, uvs, tris, normals
mesh.vertices = new Vector3[verts.length];
mesh.uv = same for uvs, tris, normals
mesh.vertices = verts;
mesh.uv = same for uvs, tris, normals
mesh.RecalculateBounds();
mesh.RecalculateNormals();
// Update
mesh = this.transform.GetComponent(MeshFilter).mesh as Mesh;
verts[0] = new Vector3( 0, 0, 0);
verts[1] = same for all verts
mesh.vertices = verts;
The pattern I have made for myself can be seen in my questions (all of these have been answered, thanks. The asteroid script has moved on quite alot infact!)
Here : http://answers.unity3d.com/questions/277222/simply-assign-tangents-to-single-quad.html
Here : http://answers.unity3d.com/questions/305515/irregularities-with-procedurally-generated-sphere.html
I can provide the script for my animated 'sock' if required for reference also.
and on the script in my last comment Here : http://answers.unity3d.com/questions/290695/calculate-spline-points-on-complex-geometry-mesh.html
my forum box is the same as my handle on UA., I am happy to share my full sprite and text classes with those here who are easily able to create better (to preserve their income by not displaying those type of ready to use scripts here). I know that doesn't sound cool, but I do help alot of people out with scripts anyway, and what have I done attemting to quash all the 'noob' Slender questions with my guide?! But seriously I just want to get my text mesh and sprite class working for my own personal and commercial use, your constructive informative comments are much appreciated as always, thanks.
I also have a problem with my materials beco$$anonymous$$g 'instances' of those materials, and subsequently not batching which I just do not understand why. But I guess that is another question ...
I couldn't quite see what the question actually was, but just some info:
mesh = this.transform.GetComponent($$anonymous$$eshFilter).mesh as $$anonymous$$esh;
should just be
mesh = GetComponent($$anonymous$$eshFilter).mesh;
Also it shouldn't be in Update since it only needs to be done once.
I don't know if this has any negative effects, but it looks wrong:
if(!mesh) { GetComponent($$anonymous$$eshFilter).mesh = mesh = new $$anonymous$$esh();}
It should be
if (!mesh) {mesh = new $$anonymous$$esh(); GetComponent($$anonymous$$eshFilter).mesh = mesh;}
Also, this is definitely wrong:
verts = new Vector3[4];
...
mesh.vertices = new Vector3[verts.length];
mesh.vertices = verts;
It should be
verts = new Vector3[4];
...
mesh.vertices = verts;
When you assign vertices, they are uploaded to the mesh, so it's not like normal arrays where it would just be a reference. (Which, as an aside, is why I'm not entirely keen on properties, since you don't know what's "really" happening. It would be less confusing if Unity used functions for this sort of thing ins$$anonymous$$d.)
Thanks Eric.
1- I did a C# tutorial (3D Buzz 3rd Person char), and there was always (typecast) as type; and since then I have been hung up on typecasting everything properly (to also avoud warnings in console), even though you have told me in previous answers just to use mesh = GetComponent($$anonymous$$eshFilter).mesh; and you also stated this was fine for C#. SO I guess I have to remove the stigma and just use GetComponent(type).
2- $$anonymous$$y use of the keyword this has also previously been under debate. It comes from using actionscript2, and without cacheing transforms or gameobjects it just helps me to read my code for clarity. $$anonymous$$y arguement is if the compiler adds the keyword this anyway, is there any real harm in using it?
3- GetComponent($$anonymous$$eshFilter).mesh = mesh = new $$anonymous$$esh(); was just a small optimization of code to one line. I shall break it up again.
4- I'm not sure why I wrote mesh = GetComponent($$anonymous$$eshFilter).mesh; in the update! It is stored after initialization and then I just use the reference mesh in update. And to clarify, Update is when the mesh vertices locations are updated (although this could be every update as in my sock)
5- mesh.vertices = new Vector3[verts.length]; was a new addition after my issues in the question linked above. I never used it before, and as you say I don't know what's happening behind the scenes to make my scripts work, and was content enough to know that assigning my verts array to mesh.vertices both assigned the length and values happily.
6- I suppose my question is 'what (if anything) is wrong with the way I make meshes (using my simple quad as an example)', and 'what is the actual answer to my question array-out-of-range-while-updating-mesh-variables'. I would like an answer there, as it is very strange I had no errors in any of my projects using my textmesh class, but after 3.5.6 every project using textmesh that changes length of helloString throws an error the firt time the mesh is constructed.
Generally the "out of range" thing in this case means you should do $$anonymous$$esh.Clear() first.
Answer by Fattie · Oct 24, 2012 at 06:11 AM
(1) well if the array is out of range, the array is out of range
extremely simple final solution:
use Debug.Log to print all the .Count or .Lengths involved of all sides and you'll soon see what's going on.
(2) BTW one thing that I found very confusing when first using unity,
http://docs.unity3d.com/Documentation/ScriptReference/Mesh-vertices.html
were you aware that .vertices CREATES A COPY. it is completely different in use from every other (as far as I know) .property in Unity. You need to be totally clear on this.
(3) also did you know this:
http://answers.unity3d.com/questions/329116/do-we-need-to-call-recalculatenormals-if-normal-ve.html
so don't use their recalculate normals unless you specifically want to. You have to be real clear on this.
calculating normals is an incredibly fine art. like, you could have a massive "AI" project to figure out normals well, in certain situations and types of problems. it is completely non-trivial, it's like painting. the "RecalculateNormals" function is somewhat dangerous as it could make people think it's a mechanical process. it's only mechanical for say flat surfaces (even then how you treat the edges of reality is an issue). so think of Mesh.RecalculateNormals as a handy placeholder function for helloMesh projects to get you going, or a thing you use in very specific situations if it "just happens" to be what you need.
crib sheet ..
// Mesh.RecalculateBounds - "Assigning triangles will automatically Recalculate the bounding volume." // Mesh.RecalculateNormals - unity's routine for normals, generally not used for custom meshes
// Mesh.Optimize - internally figures optimisations, eg vertex cache locality. could possibly be useful, often not
// note that GetComponent(MeshCollider) does indeed have a "mesh" property
// (not just a "sharedMesh") although undocumented
also (4) note the comment there...
"SUGGESTION: notice they use the same name for "their" normals (normals) as the property name (.normals). FWIW is usually ask people to use a different name. Same deal for verts. For example use, "ourNormals" or "theNewMoreBendyNormals" or "theSpecialRuffledVerts" or "myCurrentSockShape" or something self-documenting. it's just much clearer if it's not the same."
(always write self-documenting code ....... and this is a good example. "if your code has comments, your variable names are too short")
(5) as Eric mentions I'm not sure precisely what you're asking?
(6) to repeat .. if you're struggling w/ the length of arrays. Just spend 2 seconds typing many Debug.Log statements to get the length of everything all over the place. could you be more clear about precisely what length is causing problems?
(7) one thing to consider. don't forget that with mesh you can - if you want - "share" verts. do you completely and totally understand this process? there is no reason, whatsoever, that you have to share verts. Every single triangle-point entry can have it's vertex-position entry (ie, length is identical). (of course, obviously if you want them to be in the same place, they'd have to be identical values. but there's no real reason they have to be in the same place, the pipeline is happy to paint just completely separate triangles floating in space.) for tricky mesh, it is often HUGELY simpler to not share any verts. in some situations, I sort of do all the work NOT sharing them, because it's so much easier. and then just as a final process, a script sweeps over and shares 'em. you should be comfortable with both approaches. my point is that may resolve your length issues.
(8) I"GetComponent(MeshFilter).mesh = mesh = new Mesh(); was just a small optimization of code to one line."
I would not in english describe that as "optimisation" since that word usually refers to, writing code in such a way that the final application runs faster. you should refer to that as "making the code shorter" or something similar. (Much like when you write a historic language called Perl - the national sport is being a smart ass in compact code.)
Regarding making code more compact. Never do it, ever. You don't have to "save ascii". In fact almost always, go for the more languid form.
(Regarding actual "optimisation." Never ever do it, or think about it for any reason. As a minor subset of that rule: note that how you write code is utterly irrelevant and has been for ten - fifteen years. The compiler takes over and does what it wants.)
(9) cacheing ... I think caching is probably the best spelling (although "eing" forms for newly minted words appeal to me generally)
(10) "remove the stigma " .. did you mean stigma there? is that a c# term?
Thanks heaps for another answer.
(1) Exactly! this is where I went, but
(6) everything starts with one item, a string called helloString. From this the length of the string is stored as helloStringLength. From that variable, all lengths of arrays are calculated thus : verts = new vector3[ helloStringLength 4]; tris = new int[ helloStringLength 6]; etc etc.
(5) all the script I am referring to is on this question : http://answers.unity3d.com/questions/334706/array-out-of-range-while-updating-mesh-variables.html . I guess that this is almost a duplicate question, I just want an answer to the actual question. But now with $$anonymous$$ryptos and Erics advice, I need to do some experiments with mesh.Clear(); This is just a reply to your nice answer.
(7) in this case I want control of the uvs, but am aware of sharing verts, thanks. For this issue, it is basically one quad per character in the string. That is it.
(8) you are right, this isn't really optimization. $$anonymous$$y thought when writing it was simply "they all equal the same thing, hence ..."
(9) that is just how it came out =]
(10) I was actually making a reference to my thought process of "if I don't explicitly typecast this component then the universe will implode"
(2) (3) and (4) are on my homework list =]
Just to clarify and step through the problem :
I have a string, the length is calculated.
For each character in the string, arrays are assigned lengths based on one quad per character.
While the string length and vertex info are debugged correctly, for the first loop that the length of helloString changes, I get out of range error. The next loop, everything is happy. The lengths of the arrays are assigned at the beginning of the loop, and that one value is used for all mesh calculations. Nothing changes or updates before the mesh is constructed. It is a complete mystery.
I am about to start testing with mesh.Clear(); and possibly rewriting the whole thing as the rotation is wrong anyway, this is just a reply until I have more iformation on my issue (including the Debugging I did before, but as you advised shall uncomment and diagnose).
"While the string length and vertex info are debugged correctly, for the first loop that the length of helloString changes, I get out of range error. The next loop, everything is happy. The lengths of the arrays are assigned at the beginning of the loop, and that one value is used for all mesh calculations. Nothing changes or updates before the mesh is constructed. It is a complete mystery."
I feel that you have some basic algorithm woe -- to be clear, I mean totally and completely and utterly unrelated to the $$anonymous$$esh aspect.
What you probably hace is what used to be called a "unity woe" of some type. (note, this has utterly no connection to "Unity3D".)
By "unity woe" it means you have an algorithm, but you are "out by one, either plus or $$anonymous$$us, somewhere"
It is very common mistake in program$$anonymous$$g. In fact there are many famous books of algorithms, where, the author (for goodness sake) makes a unity error here and there.
a very simple example might be
for ( x = 0 ... x <= 10 )
oh, I made a unity error! of course I mean "<" not "<="
another example us
while ( x < 6 ) { whatever, incrmement x}
oh! unity error! I forgot you have to subtract one from x after the loop to get the last-used value of x !
other very common unity errors are things like you forget to initialize something, you get confused leaving or exiting a loop, you forgot that prime numbers are odd, and so on.
I suggest you completely and totally strip all the code relating to the mesh,
and just have our code proceed. as the string changes (whatever it is), jut print the length (like "8")
itis very likely that you'll immediately see the error and it has no connection at all to the $$anonymous$$esh
next in the "other direction" you very simply have to unit test your mesh code
(Come to think of it - the word "unit" here, again has no relationship to the product "Unity3D" or the aforementioned "unity errors")
So, produce the complete and total mesh code, so that you can input a number like "7" and then it runs and does it's thing with the 7.
you have to do this regardless. simply you "have to do this" so it has to be done, so that's that!
youwill quickly find any problems
software technology like "unit tests," open source etc has been around for some time, and it's why today we can produce bugfree projects
you must unit test
http://en.wikipedia.org/wiki/Unit_test
you simply can't program unless you unit test. Enjoy !
reading your problem, what I now see is that you are not able to SEPARATELY unit test your mesh code, nor SEPARATELY unit test your "handles the length of the string over time" code
So, that is the decisive answer here. the problem is solved.
you must be able to "unit test" both halves, totally independently.
in unit testing the left side, you must replace all of the mesh crap with a print out "the output number form the left side was 8"
in unit testing all of the right side, you must replace all of the string crap with an input where you can type in for an input value "8"
Just BTW what you are trying to do, is 5 $$anonymous$$utes work with 2DToolkit, which is specialized in making quads with images on them, if that is what your aim is here. I realise it is a learning exercise for mesh.
Your answer
Follow this Question
Related Questions
Setting mesh.vertices to a 3-dimensional array 1 Answer
How to reduce vertex count? 0 Answers
Grouping vertices? 1 Answer
Create edges for vertices(JS) 1 Answer
Subdivide mesh? 2 Answers