I got rather carried away with actually developing this next feature so this post covers 2 weeks of development . I have since completed more work which i’ll cover in the next post.
Generating Normals
The task for the next feature was to start adding trees to my landscape but only where the slope of the landscape below was suitable, this requires knowing the normals of the mesh so i started here.
My plan was to look at all of the points adjacent to another and use the cross product with 2 adjacent points at a time and then average them. In the first week my attempt was very problem filled, at one point the compiler had decided that the entire function had no purpose and optimised all of it away, making debugging the problem rather difficult. I also had a problem where the normals that were returned to me were just incorrect.
What did not help was that I had decided to use a complicated method to get the normals with the hope that it would run fast. This was a mistake and i should have started with a simpler approach and optimised it later if needed. I do this often and in future i’ll be assuring i don’t do it. KISS: Keep It Simple, Stupid.
My second approach worked immediately, further hammering down theĀ KISS “methodology”. First i initialise my blank array of normals to face along the z axis, this is so that all of the edge cases are handled. Then for each point that is not on an edge i calculate the normal for the positions above and right, then the positions below and left giving me two normals, then i can average these out. I only need to work out the two opposing normals as all four adjacent positions are factored into the calculation.
TArray<FVector> UMyFunctionLibrary::GenerateNormals(const TArray<FVector> positions) { // Output array TArray<FVector> Normals; // Set every vector to point up for (size_t i = 0; i < positions.Num(); i++) Normals.Add(FVector(0.f, 0.0f, 1.0f)); size_t size = sqrt(positions.Num()); // For each point that is not on the edge for (size_t y = 1; y < size - 1; y++) { for (size_t x = 1; x < size - 1; x++) { FVector thisPos = positions[y * size + x]; // Up and Right FVector up = thisPos - positions[(y + 1) * size + x]; up.Normalize(); FVector right = thisPos - positions[y * size + (x + 1)]; right.Normalize(); FVector normalA = FVector::CrossProduct(up, right); // Down and Left FVector down = thisPos - positions[(y - 1) * size + x]; down.Normalize(); FVector left = thisPos - positions[y * size + (x - 1)]; left.Normalize(); FVector normalB = FVector::CrossProduct(down, left); // Mean of both normals FVector normalAvg = (normalA + normalB) / 2; normalAvg.Normalize(); // Set ths normal in the array // Negated because Unreal uses an inverted y axis Normals[y * size + x] = -normalAvg; } } return Normals; }
Here’s some renders using the line renderer to visualise the normals.