Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

1038417 Posts in 41963 Topics- by 33588 Members - Latest Member: JayJaySut

September 02, 2014, 08:40:27 PM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)Normal Generation Issue
Pages: [1] 2
Print
Author Topic: Normal Generation Issue  (Read 857 times)
okelly4408
Guest
« on: January 22, 2013, 03:11:42 PM »

While setting up normals for spherical terrain I tried the following code:
Code:
for(int i = 0; i< pointarray.length/3; i+=3){
float x = pointarray[i].x;
float y = pointarray[i].y;
float z = pointarray[i].z;
float x1 = pointarray[i+1].x;
float y1= pointarray[i+1].y;
float z1 = pointarray[i+1].z;
float x2 = pointarray[i+2].x;
float y2 = pointarray[i+2].y;
float z2 = pointarray[i+2].z;
Vector3f v1 = new Vector3f(x1 - x, y1-y, z1 - z);
Vector3f v2 = new Vector3f(x2 - x, y2-y, z2 - z);
Vector3f v3 = new Vector3f(x1 - x2, y1-y2, z1 - z2);
Vector3f v4 = new Vector3f(x - x2, y-y2, z - z2);
Vector3f v5 = new Vector3f(x2 - x1, y2-y1, z2 - z1);
Vector3f v6 = new Vector3f(x - x1, y-y1, z - z1);
Vector3f c1 = new Vector3f(crossProduct(v1,v2));
Vector3f c2 = new Vector3f(crossProduct(v3,v4));
Vector3f c3 = new Vector3f(crossProduct(v5,v6));
Vector3f normal1 = new Vector3f(normalize(c1));
Vector3f normal2 = new Vector3f(normalize(c2));
Vector3f normal3 = new Vector3f(normalize(c3));
qu.setNormal(i, normal1);
qu.setNormal(i+2, normal2);
qu.setNormal(i+1, normal3);
}
This led to the following image:
Which is obviously not what I am going for... Thanks for any comments/help.
Logged
eigenbom
Level 10
*****



View Profile WWW
« Reply #1 on: January 22, 2013, 03:27:23 PM »

my guess is that one or two of the normals are inverted. the hack solution is to try switching the order of the parameters to the cross product independently (e.g., crossProduct(v6,v5)) until it looks ok. if that doesn't work, go back to basics and check each normal (on paper) to make sure they are all pointing outwards.
Logged

okelly4408
Guest
« Reply #2 on: January 22, 2013, 04:02:42 PM »

Hmm... so changing the order of each one yielded basically the same result and from what I can tell from a few calculations the vectors seem to be pointing outward...Could it just be I am applying them to the wrong vertices (ie my index ordering is incorrect)?
Logged
eigenbom
Level 10
*****



View Profile WWW
« Reply #3 on: January 22, 2013, 05:05:43 PM »

a couple of things .. is this order right?
Code:
qu.setNormal(i, normal1);
qu.setNormal(i+2, normal2);
qu.setNormal(i+1, normal3);

next .. check each normal by doing this... (compile and run for each normal)
Code:
qu.setNormal(i, normal1);
qu.setNormal(i+1, normal1);
qu.setNormal(i+2, normal1);

you should get a faceted earth

Finally, should i< pointarray.length/3; be i< pointarray.length;?

Logged

okelly4408
Guest
« Reply #4 on: January 24, 2013, 01:26:09 PM »

So after looking more closely at the code I found that I was not applying the normals to the correct vertices and I had two cross product vectors in the wrong order. After fixing this and running the program I found that the original problem was fixed but now running through the middle of the sphere is this large, black shadow. Also you can see the distinct outline of every polygon... Any Idea why this is?
Here is the code and a picture:
Code:
for(int i = 0; i<vertices.length; i+=4){
Vector3f v1, v2, v3, v4, v5, v6, v7, v8, n1, n2, n3, n4;
                //"sub" is just a subtraction method
v1 = sub(vertices[i+2] , vertices[i]);
v2 = sub(vertices[i+1] , vertices[i]);
v3 = sub(vertices[i] , vertices[i+1]);
v4 = sub(vertices[i+2] , vertices[i+1]);
v5 = sub(vertices[i+3] , vertices[i+2]);
v6 = sub(vertices[i+1] , vertices[i+2]);
v7 = sub(vertices[i] , vertices[i+3]);
v8 = sub(vertices[i+2] , vertices[i+3]);

n1 = crossProduct(v1, v2);
n2 = crossProduct(v3, v4);
n3 = crossProduct(v6, v5);
n4 = crossProduct(v8, v7);

normals[i] = n1;
normals[i+1] = n2;
normals[i+2] = n3;
normals[i+3] = n4;

}
Image:
Logged
eigenbom
Level 10
*****



View Profile WWW
« Reply #5 on: January 24, 2013, 01:52:18 PM »

A couple more things:
- make sure your normals are normalised (length=1), or either enable GL_NORMALIZE (if using GL)
- for the planet on the right, the normals still don't look right, but this may be a normalisation issue
- draw line segments for the normals out of the center of each face - this will show you graphically if something is funny

Seeing the sides of the polygons like that may be:
- a culling issue (check the "near" parameter for the projection matrix setup)
- a wrong-ward facing normal (they may be pointing inwards, in which case you are seeing the inside of the face as it curves around)

Lastly, if this is a spherical planet, something is going very wrong! Checking out this thread may help.


Logged

okelly4408
Guest
« Reply #6 on: January 24, 2013, 07:39:17 PM »

Well the normals are already....normalized. Yet that strange pixelated effect is still present. Also it is a spherical planet (transformed from a cube). That thread is really interesting, a lot of good stuff there yet I can't think of anything wrong with the code unless the normals are simply being generated incorrectly...Thanks for all your help.
Logged
eigenbom
Level 10
*****



View Profile WWW
« Reply #7 on: January 24, 2013, 08:13:46 PM »

Unless your crossProduct function also normalizes the vector, then that code doesn't produce normalized vectors for the 'normals'. (Unless by chance the distance between each pair of vertices is exactly 1.)

gl!
Logged

okelly4408
Guest
« Reply #8 on: January 25, 2013, 08:32:03 AM »

Oh, well they are normalized elsewhere. I tried averaging the normals together and setting the resulting normal for all vertices of the polygon. That did not provide any noticable difference in terms of the pixelated effect.
Logged
Fallsburg
Level 10
*****


Fear the CircleCat


View Profile
« Reply #9 on: January 25, 2013, 09:56:01 AM »

So, unless I'm misinterpreting how you have things setup, you have it like this:

Each quad on the sphere has 4 vertices.  There is no sharing of vertices between quads.

And that's your problem.  By having 4 separate vertices at each actual vertex (i.e. every spot where 4 quad corners come together), you have 4 separate normals and those are all different.  You can either average those 4 together, or share 1 vertex for 4 corners.  They should both get the same results, but the latter is better (since you are using 1/4 as many vertices).

Logged
zalzane
Level 5
*****


View Profile
« Reply #10 on: January 25, 2013, 11:59:31 AM »

So, unless I'm misinterpreting how you have things setup, you have it like this:
Each quad on the sphere has 4 vertices.  There is no sharing of vertices between quads.

This shouldn't change anything as long as the normal generation algorithm is working correctly. Despite there being two tiles with 4 vertexes each that share a side (so four vertexes are overlapping), the normal generation algo should assign the same normals to those shared points.

It's important to think of normal generation in terms of vertexes rather than quads. Without seeing OP's code I can't really speculate on what's wrong. It may help to have another set of working code to compare your own to, so here's some of my opencl terrain normal generation code.

I cut out loads of other code that's specific to how my terrain is generated, but if it turns out that that code is necessary to post then I will do so.

Code:
   //getting the normal of vertex O
    // +             v1
    // ^              |  
    // |              |
    // Z axis   v4----O----v2
    // |              |
    // v              |
    //               v3
    //           <- X axis -> +
float3 v1 = //whatever
float3 v2 = //whatever
float3 v3 = //whatever
float3 v4 = //whatever

//to make this simpler, we assume the center vertex has a height of zero
//height is the height of the center vertex
v1.y = v1.y - height;
v2.y = v2.y - height;
v3.y = v3.y - height;
v4.y = v4.y - height;

float3 crossSum = (float3)(0,0,0);
crossSum += cross(v1, v2);
crossSum += cross(v2, v3);
crossSum += cross(v3, v4);
crossSum += cross(v4, v1);

crossSum = normalize(crossSum);//this is the unit vector of the normal
v1 = normalize(v1);//this is later used as the binormal
v2 = normalize(v2);//this is later used as the tangent

normals[workerId] = crossSum;
Logged
Fallsburg
Level 10
*****


Fear the CircleCat


View Profile
« Reply #11 on: January 25, 2013, 12:49:16 PM »

@zalzane
You are wrong. 

Try making a cube with shared normals at vertices and a cube with separate normals at vertices.  Tell me they look the same.
Logged
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #12 on: January 25, 2013, 01:40:18 PM »

op's code to me looks like he's assigning multiple vertices with the same position different normals. The code should look more like zalzanes. That explains the patchwork look in the coloured bits, but not the blackness.

My theory for the missing tiles, is that op's problem is winding order. Depending on the arrangement of vertices, shading and culling settings, the backfacing polygons may not be rendered, or the inverted normals may cause them to shade as black.
Logged
okelly4408
Guest
« Reply #13 on: January 25, 2013, 02:18:08 PM »

So, unless I'm misinterpreting how you have things setup, you have it like this:
Each quad on the sphere has 4 vertices.  There is no sharing of vertices between quads.

This shouldn't change anything as long as the normal generation algorithm is working correctly. Despite there being two tiles with 4 vertexes each that share a side (so four vertexes are overlapping), the normal generation algo should assign the same normals to those shared points.

It's important to think of normal generation in terms of vertexes rather than quads. Without seeing OP's code I can't really speculate on what's wrong. It may help to have another set of working code to compare your own to, so here's some of my opencl terrain normal generation code.


I tried this code and the same tiled look was present. I also tried averaging the normals and only setting one normal for each vertex yet no luck, here is the code I used to try your (zalzane) method:
Code:
for(int i = 0; i<vertices.length; i+=4){
         Vector3f v1 = vertices[i];
Vector3f v2 = vertices[i+1];
Vector3f v3 = vertices[i+2];
Vector3f v4 = vertices[i+3];



Vector3f n = new Vector3f(0,0,0);
n = add(n, crossProduct(v1, v2));
n = add(n, crossProduct(v2, v3));
n = add(n, crossProduct(v3, v4));
n = add(n, crossProduct(v4, v1));

n = normalize(n);

normals[i] = normalize(n);
normals[i+1] = normalize(n);
normals[i+2] = normalize(n);
normals[i+3] = normalize(n);

}
Logged
eigenbom
Level 10
*****



View Profile WWW
« Reply #14 on: January 25, 2013, 02:39:00 PM »

Dude, you're getting really confused now. Did you draw the calculated normals as lines coming out of the vertices as I recommended? Do this and then take a screenshot showing the whole planet.
Logged

Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic