- Home /
Problem with setting vertices positions and smoothing groups.
So, I have a two-part problem. I've started playing around with mesh/vertex manipulation in code with the information available in the docs. I have a planar that, when hit with a raycast takes the closest x amount of vertices from the hit point and lowers their Y position by 0.02. This works fine. I wanted to keep the hard, visible edges, so I exported a plane (both flat and curved, to test both) from 3DS with all smoothing groups cleared. With the flat plane, it works fine, but automatically smooths all of the normals, which I don't want. With the curved plane, it smooths some of the normals, but also breaks some of the edges. I've made sure there are no overlapping vertices, tried messing with the normals and tangents settings in the importer dialog but nothing seems to be working so far. Does anyone know how to stop both/either of these from happening?
#pragma strict
private var distances : float[];
private var allVerts : Vector3[];
private var indexNum : int[];
var theMesh : Mesh;
var countLength : int;
function Start(){
theMesh = this.GetComponent.<MeshFilter>().mesh;
}
function CheckVerts(hitPos : Vector3){
indexNum = new int[countLength];
var targetPosition : Vector3 = transform.TransformPoint(hitPos);
allVerts = theMesh.vertices;
distances = new float[allVerts.Length];
for(var xx : int = 0; xx < allVerts.Length; xx++){
var myPosition : Vector3 = transform.TransformPoint(allVerts[xx]);
distances[xx] = Vector3.Distance(targetPosition, myPosition);
}
for(var yy : int = 0; yy < indexNum.Length; yy++){
var currentLowestIndex : int;
var lowestNum : float = 1000;
for(var zz : int = 0; zz < distances.Length; zz++){
if(distances[zz] >= 0 && distances[zz] < lowestNum){
currentLowestIndex = zz;
lowestNum = distances[zz];
}
}
indexNum[yy] = currentLowestIndex;
distances[currentLowestIndex] = -100;
}
ChangePositions();
}
function ChangePositions(){
for(var xx : int = 0; xx < indexNum.Length; xx++){
allVerts[indexNum[xx]] = Vector3(allVerts[indexNum[xx]].x, allVerts[indexNum[xx]].y - 0.02, allVerts[indexNum[xx]].z);
}
theMesh.vertices = allVerts;
theMesh.RecalculateBounds();
theMesh.RecalculateNormals();
this.GetComponent.<MeshCollider>().sharedMesh = theMesh;
}
Answer by seth_slax · Sep 20, 2015 at 08:55 AM
So I've managed to sort the problem with the normal smoothing out, but the edges are still breaking.
edit(moved from comment)
So I've solved the second problem as well. According to a really old thread that was difficult to find, having a non-smoothed object uses multiple vertices to render additional normal directions, so the edges weren't 'breaking' per-se, the vertices simply weren't all being moved. I've written something to get all the duplicate verts here, if anyone's interested. This is quite an expensive operation, however, so any refinement or less CPU-heavy code would be greatly appreciated!
function CheckVerts(hitPos : Vector3){
var targetPosition : Vector3 = hitPos;;
distances = new float[allVerts.Length];
for(var xx : int = 0; xx < allVerts.Length; xx++){
var myPosition : Vector3 = transform.TransformPoint(allVerts[xx]);
distances[xx] = Vector3.Distance(targetPosition, myPosition);
}
for(var yy : int = 0; yy < indexNum.Length; yy++){
var currentLowestIndex : int;
var lowestNum : float = 1000;
for(var zz : int = 0; zz < distances.Length; zz++){
if(distances[zz] >= 0 && distances[zz] < lowestNum){
currentLowestIndex = zz;
lowestNum = distances[zz];
}
}
indexNum[yy] = currentLowestIndex;
distances[currentLowestIndex] = -100;
}
targetPosition = Vector3.zero;
GetDuplicates();
}
function GetDuplicates(){
var tempArr = new Array();
for(var xx : int = 0; xx < indexNum.Length; xx++){
for(var zz : int = 0; zz < allVerts.Length; zz++){
if(allVerts[zz] == allVerts[indexNum[xx]]){
tempArr.Push(zz);
}
}
}
var dups : int[] = tempArr.ToBuiltin(int) as int[];
allPoints = dups;
tempArr = null;
dups = null;
}
Basically, this gets the X amount of vertices closest to the hit point and stores the index numbers of those vertices in an array. It then takes that array and iterates through it, checking the rest of the verts for identical positions, which are added to a JS array. It converts the JS array to a built-in, which can then be modifed however you wish.
Your actual answer wasn't a valid answer since you just said "you sorted the problem out" which isn't an answer that answers the question. However your comment is much more an answer and there you actually explained something.
So i edited you answer and integrated your comment into the answer.
Finally some additions on topic:
Since you use a raycast against a $$anonymous$$eshCollider you get far more informations than the world space hit point. You get also the triangle index of the triangle that was hit as well as the barycentric coordinates of the hit point within that triangle. With that information you can easily find the closest vertex without any looping. However as you have discovered already, if the mesh doesn't fully share the one vertex you get in trouble. If you know or plan to have many manipulations on a certain mesh, you can simply create some additional preprocessed information for the mesh.
Common additional data for meshes are:
triangle neighbor information
vertex groups
With prebuild vertex groups you need no loops as you can directly access all information that you need.
Final note: $$anonymous$$eep in $$anonymous$$d that you have to update the $$anonymous$$eshCollider as well. This will be the thing which most likely take the most time. Also watch out, the $$anonymous$$eshCollider is a bit buggy when you dynamically change the mesh. I'm not sure if this is already fixed, however if not just search here on UA and the forums and you'll find quite a bit on that topic.
Sorry about that. I found that for the normal smoothing, if the adjustments to the vertices are in smaller increments, the smoothing effect seems to be a lot less. Also, having figured out the multiple vertex problem, the normals seem to retain their hard edges now anyway.
As for the rest, I found a less CPU-intensive way of comparing the Vector3 positions on this line:
if(allVerts[zz] == allVerts[indexNum[xx]]){
I changed this to simply create two temporary floats, adding the Vector3 values together and then simply comparing the floats. Probably a much more elegant solution to doing so, but since it's only looking for verts that are in the absolute same world-space position, it works well enough since I'm comparing around 3,500 verts against 40, 80 or 100.
I do have the mesh, bounds and normals recalculating in a seperate function (run every 0.3 seconds while the mesh is being modified, since it's another heavy call), but I'm curious about what you said about the vertex groups. Is this something within 3DS $$anonymous$$ax? Because within $$anonymous$$ax there are no overlapping vertices, which leads me to believe the additional verts are added in the exporting process.