Raycasting for raytracing: smooth normals and texture coords

A place to discuss everything related to Newton Dynamics.

Moderators: Sascha Willems, walaber

Raycasting for raytracing: smooth normals and texture coords

Postby AdrianCG » Thu Sep 08, 2011 8:59 am

Hi there!

This is my first post here and i must say i'm really excited about the ease of using Newton. I just started a few days ago, but i can't seem to get correct raycasting WITH normal and texture coords interpolation. I'm developing a simple(toy) raytracer and i need to find the closest intersection of the whole scene with a ray, the normal at that intersection and the texture coordinates. I'm using multiple objects (spheres and collision trees) but let's concentrate on collision trees because they are the source of my problem. I build the collision tree as follows:

Code: Select all
      NewtonCollision* collision;
      NewtonWorld* newtonWorld = (NewtonWorld*)worldPointer;

      // now create and empty collision tree
      collision = NewtonCreateTreeCollision (newtonWorld, 0);

      // start adding faces to the collision tree
      NewtonTreeCollisionBeginBuild (collision);

      faceArray.reset(new FaceArray);
      verticesArray.reset(new Endeavour::Assets::Vector3fArray);
      normalsArray.reset(new Endeavour::Assets::Vector3fArray);
      texCoordsArray.reset(new Endeavour::Assets::Vector2fArray);

      int i,oldFace = 0;
      for (i=0; i<faceArrays.size(); i++)
      {
         Endeavour::Assets::FaceArray* faceArray = faceArrays[i];
         Endeavour::Math::Vector3fArray* vertices = verticesArrays[i];
         Endeavour::Math::Vector3fArray* normals = normalsArrays[i];
         Endeavour::Math::Vector2fArray* texCoords = texCoordsArrays[i];

         int face;
         for (face=0; face<faceArray->size(); face++)
         {
            Face f = faceArray->at(face);
                  
            dVector faceVect[3];
            faceVect[0] = dVector(vertices->at(f.index1).x, vertices->at(f.index1).y, vertices->at(f.index1).z);
            faceVect[1] = dVector(vertices->at(f.index2).x, vertices->at(f.index2).y, vertices->at(f.index2).z);
            faceVect[2] = dVector(vertices->at(f.index3).x, vertices->at(f.index3).y, vertices->at(f.index3).z);
                        
            this->verticesArray->push_back(vertices->at(f.index1));
            this->verticesArray->push_back(vertices->at(f.index2));
            this->verticesArray->push_back(vertices->at(f.index3));

            this->normalsArray->push_back(normals->at(f.index1));
            this->normalsArray->push_back(normals->at(f.index2));
            this->normalsArray->push_back(normals->at(f.index3));
            /*
            this->texCoordsArray->push_back(texCoords->at(f.index1));
            this->texCoordsArray->push_back(texCoords->at(f.index2));
            this->texCoordsArray->push_back(texCoords->at(f.index3));
            */
            f.index1 = (oldFace+face)*3 + 0;
            f.index2 = (oldFace+face)*3 + 1;
            f.index3 = (oldFace+face)*3 + 2;

            this->faceArray->push_back(f);            
            
            NewtonTreeCollisionAddFace(collision, 3, &faceVect[0].m_x, sizeof (dVector), oldFace+face);
         }

         printf("numFaces=%d\n", this->faceArray->size());

         oldFace += faceArray->size();
      }
      printf("*numFaces=%d\n", this->faceArray->size());
      
      Endeavour::System::Timer timer;

      // end adding faces to the collision tree, also optimize the mesh for best performance
      NewtonTreeCollisionEndBuild (collision, 1);
            
      printf("Time to construct: %f\n", timer.elapsed());

      NewtonTreeCollisionSetUserRayCastCallback(collision, UserMeshCollisionCallback);



Also here is the UserMeshCollisionCallback function:

Code: Select all
static dFloat UserMeshCollisionCallback (const NewtonBody* const body, const NewtonCollision* const collisionTree, dFloat interception, dFloat* normal, int faceId, void* usedData)
{
   ((RaycastInfoObject*)usedData)->faceIndex = faceId;

   return interception;
}


And here is the RayCastFilter function, passed to NewtonWorldRayCast routine:

Code: Select all
static dFloat RayCastFilter (const NewtonBody* body, const dFloat* normal, int collisionID, void* userData, dFloat intersetParam)
{   
   if (intersetParam <  ((RaycastInfoObject*)userData)->pickedParam)
   {      
      ((RaycastInfoObject*)userData)->pickedParam = intersetParam;
      ((RaycastInfoObject*)userData)->pickedBody = (NewtonBody*)body;
      ((RaycastInfoObject*)userData)->normal =
         Endeavour::Math::Vector3f(normal[0], normal[1], normal[2]);
   }

   return intersetParam;
}


Here's what kind of image i'm getting by just outputting the normal retrieved from RayCastFilter:

Image

As you can see, the normal is not smooth, i need it to be that way for lighting computations. Is there a way to make the normal smooth? Also, how would i go about getting texture coordinates along with the smooth normal? Is there a way to pass texture coordinates to the collision tree while constructing it?

I must say that i've tried the following method for smoothing normals and getting texture coordinates: store face id's for each face added to the collision tree. Once a collision is found i lookup the face's vertices and based on this and the point of collision(transformed in local space by me) i compute barycentric coordinates. The problem is that sometimes the barycentric coordinates don't recognize the point i'm using to compute them, to be part of the triangle indexed by the face id returned by the collision routine. This is rather weird and it only happens on certain parts of the mesh: the white positions on the mesh generated wrong barycentric coordinates (that classified the input point as not being part of the input triangle):

Image

I wonder, if my barycentric coordinates routine is wrong in any way... I post the code for this also:

Code: Select all
Vector2<float> Endeavour::Math::barycentric(const Vector3<float> &P,
                     const Vector3<float> &A,
                     const Vector3<float> &B,
                     const Vector3<float> &C)
{
   // Compute vectors       
   Vector3<float> v0 = B - A;
   Vector3<float> v1 = C - A;
   Vector3<float> v2 = P - A;
   
   // Compute dot products
   float dot00 = dot(v0, v0);
   float dot01 = dot(v0, v1);
   float dot02 = dot(v0, v2);
   float dot11 = dot(v1, v1);
   float dot12 = dot(v1, v2);
   
   // Compute barycentric coordinates
   float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
   float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
   float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
   
//   if (!((u >= 0) && (v >= 0) && (u + v <= 1)))
//      printf("AAA: %f %f\n", u, v);

   return Vector2<float>(u, v);
}


So, my questions are: how to integrate smooth normals and texture coordinates into the collision information retrieval process? If this is something newton isn't supposed to do, what's wrong with my current approach to get a hold of this information?

EDIT: I used the latest sourced from the SVN (rev. 750) and compiled the projects in the coreLibrary_200 directory.
AdrianCG
 
Posts: 10
Joined: Thu Sep 08, 2011 6:55 am

Re: Raycasting for raytracing: smooth normals and texture co

Postby Julio Jerez » Thu Sep 08, 2011 10:27 am

you apreach is right,
my guess is that that you are optimizing the mesh in the collision tree.
Code: Select all
// end adding faces to the collision tree, also optimize the mesh for best performance
NewtonTreeCollisionEndBuild (collision, 1);

Optimization take complan or alomost complanar faces and make convex faces out of then.

for texture mapping this will lead to errors wen calculation varicenrtry cordinate of a hit point.
make yor collison tree wihout optimization, and pass only trungles, that way you will get what you pass in on the ray cast.
Code: Select all
NewtonTreeCollisionEndBuild (collision, 0);
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Raycasting for raytracing: smooth normals and texture co

Postby AdrianCG » Thu Sep 08, 2011 11:37 am

Thanks for the reply!

Unfortunately,switching the flag so that the tree is not optimized did not help... I'm wondering what else can i try?
AdrianCG
 
Posts: 10
Joined: Thu Sep 08, 2011 6:55 am

Re: Raycasting for raytracing: smooth normals and texture co

Postby Julio Jerez » Thu Sep 08, 2011 2:50 pm

check you calculation of the varicentric parameters of the point in the triangle.
I believe your bug is theree.
for each triangle, the values should be u0 + u1 + u2 = 1
but this is just a theoretical case.

The problem is the areocentric coordinate are an order error^
Bu this I mean the calculation of the values are based on the solution of a determinant,

You are down with dot product but it is the same.

Let me explain so that you understand where the error come form and how to solve it.

Say you have a float value n for each float operation (+, -, * /) the result is a values accurate to the machine precision, let us call the E,

Say you do and add
X = A0 + B0 = (A0 + B0) + abs (A + B) * E = A + B + Error
Y = A1 * B1 = (A1 + B1) + abs (A + B) * E = A + B + Error

Now let us say you add or multiply two values tah already have an error
Z = X + Y = X + error0 + Y + ErrorY = (X + Y) + abs (A0 + B0) * E + abs (A1 + B1) * E

As you can see in each operation the error keep growing.

Since varicentric coordinate use many dot product, multiplication and addition and divide, the result is a very inaccurate result specially when a point is very close to the edge of the triangle.

There is no amount to tolerance that will give you the correct answer. There are only two way to solve the problem.
The first is using exact precision arithmetic, but this is too sallow for real time so newton collision tree does no use that, but it uses for other calculation like building convex hull or building optimize collision trees and stuff like that.

The other way is to use two different calculations. The first is the areocentric coordinates, then check if the values to close to the limit with a large tolerance. For example
[0.1 < u1 < 0.9]

If any of the value is outside that range, then calculate the geometry distance to the edge and check if the point is with it acceptable distance and return a hit.
This is the method used by the collision tree.
So for you it translate to getting a hit for a ray the is very close to the edge but is actually outside the triangle, if you add that second check to you test, I believe you will be fine.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Raycasting for raytracing: smooth normals and texture co

Postby AdrianCG » Thu Sep 08, 2011 5:27 pm

Okay, i agree with the floating point errors, though i found that my errors were way bigger to be considered floating point precision issues. Here's a list of all the cases where (in the current render viewable in the following screen shots) the barycentric coordinates classify the input point (which should definitely lie on the triangle) as being outside of the triangle:

Code: Select all
u                v               w = 1.0 - u - v (not displayed)
1.396788 - -0.636360
1.413218 - -0.539698
1.595235 - -0.735158
1.457768 - -0.638764
1.486606 - -0.612576
1.393270 - -0.635735
1.481582 - -0.697410
1.431363 - -0.629867
1.547781 - -0.695785
1.366788 - -0.623721
1.286473 - -0.527972
1.538034 - -0.722588
1.301609 - -0.559582
1.381000 - -0.532077
1.459162 - -0.628268
1.418854 - -0.548494
1.479430 - -0.663006
1.329045 - -0.573640
1.511574 - -0.674060
1.407510 - -0.676536
1.281281 - -0.539315
1.428554 - -0.595161
1.277243 - -0.491572
1.359366 - -0.512427
1.443280 - -0.667959
1.602100 - -0.730335
1.374984 - -0.666896
1.400950 - -0.634129
1.311475 - -0.588842
1.411136 - -0.649171
1.477573 - -0.647370
1.513594 - -0.639968
1.493282 - -0.670537
1.454465 - -0.634437
1.351290 - -0.571488
1.571543 - -0.746684
1.625233 - -0.771162
1.342594 - -0.578333
1.342739 - -0.542601
1.258576 - -0.511889
1.380402 - -0.597316
1.489018 - -0.711306
1.415685 - -0.635914
1.481523 - -0.714073
1.568450 - -0.701863
1.274942 - -0.521680
1.362723 - -0.608506
1.394111 - -0.657862
1.424096 - -0.674873
1.401991 - -0.576451
1.517447 - -0.716766
1.650182 - -0.772852
1.352643 - -0.496590
1.340972 - -0.598117
1.428810 - -0.584001
1.326991 - -0.603845
1.386955 - -0.679766
1.635319 - -0.765043
1.339309 - -0.544426
1.550965 - -0.713628
1.309139 - -0.527480
1.423522 - -0.631054
1.289638 - -0.531591
1.316910 - -0.540598
1.447541 - -0.611082
1.354113 - -0.603601
1.620562 - -0.745509
1.488866 - -0.680625
1.526298 - -0.669001
1.589360 - -0.732992
1.485550 - -0.688106
1.400604 - -0.586268
1.451621 - -0.690111
1.626836 - -0.773950
1.584347 - -0.737575
1.256635 - -0.505519
1.483608 - -0.658071
1.444813 - -0.626658
1.466957 - -0.670903
1.413698 - -0.626154
1.501621 - -0.657663
1.527456 - -0.677619
1.390689 - -0.642321
1.374094 - -0.571128
1.434498 - -0.568141
1.412390 - -0.637387
1.303879 - -0.558187
1.610593 - -0.743091
1.641409 - -0.780040
1.488906 - -0.674127
1.495282 - -0.657255
1.586343 - -0.734128
1.405502 - -0.678007
1.404270 - -0.623321
1.471731 - -0.637496
1.662843 - -0.785729
1.550480 - -0.703854
1.412790 - -0.578395
1.513631 - -0.706351
1.484275 - -0.699489
1.516467 - -0.717677
1.489157 - -0.702209
1.447596 - -0.581083
1.462658 - -0.703843
1.489381 - -0.650484
1.544651 - -0.701757
1.517586 - -0.654473
1.431680 - -0.617025
1.343169 - -0.566722
1.514500 - -0.716556
1.493222 - -0.722551
1.324356 - -0.535957
1.450988 - -0.680404
1.485351 - -0.668589
1.247997 - -0.486286
1.314137 - -0.502920
1.489108 - -0.694089
1.365792 - -0.659661
1.415170 - -0.646631
1.303908 - -0.519881
1.578994 - -0.719514
1.614835 - -0.761965
1.474681 - -0.649899
1.451720 - -0.677600
1.296563 - -0.518196
1.413095 - -0.605164
1.359843 - -0.650912
1.397647 - -0.680337
1.369770 - -0.631792
1.432289 - -0.679972
1.448425 - -0.699607
1.340393 - -0.583046
1.315552 - -0.496333
1.441026 - -0.576147
1.470969 - -0.669064
1.559744 - -0.692899
1.376505 - -0.509916
1.447118 - -0.626468
1.439355 - -0.628229
1.629684 - -0.766293
1.400763 - -0.647031
1.521560 - -0.703084
1.420847 - -0.612910
1.330804 - -0.567530
1.417431 - -0.662525
1.591053 - -0.740118
1.568561 - -0.726983
1.407422 - -0.653310
1.572117 - -0.716283
1.382340 - -0.630096
1.394976 - -0.591141
1.503882 - -0.719596
1.539196 - -0.668027
1.559091 - -0.731344
1.410164 - -0.662352
1.345790 - -0.613554
1.394473 - -0.623210
1.461658 - -0.645989
1.352747 - -0.546080
1.315012 - -0.523010
1.412356 - -0.554641
1.359234 - -0.601600
1.552992 - -0.735312
1.300979 - -0.515628
1.344678 - -0.618688
1.385492 - -0.659742
1.340983 - -0.595652
1.314281 - -0.489470
1.355767 - -0.634603
1.450326 - -0.599671
1.422576 - -0.637261
1.404874 - -0.599391
1.441260 - -0.669208
1.536343 - -0.702714
1.500750 - -0.695682
1.571409 - -0.718120
1.578125 - -0.748786
1.464402 - -0.625825
1.379294 - -0.541790
1.562663 - -0.702097
1.490875 - -0.665414
1.666447 - -0.785500
1.393656 - -0.532895
1.536425 - -0.671513
1.462134 - -0.633950
1.543173 - -0.691829
1.433517 - -0.671690
1.651924 - -0.782360
1.442751 - -0.655001
1.393178 - -0.601419
1.535311 - -0.726258
1.274276 - -0.491476
1.477329 - -0.613468
1.444876 - -0.696126
1.373971 - -0.575810
1.543090 - -0.710607
1.451596 - -0.665501
1.342543 - -0.577038
1.500001 - -0.721711
1.340786 - -0.549647
1.451475 - -0.660546
1.570941 - -0.721130
1.348584 - -0.599005
1.516100 - -0.710448
1.538306 - -0.701882
1.264785 - -0.497058
1.337975 - -0.500354
1.474758 - -0.656372
1.447779 - -0.652827
1.364874 - -0.558797
1.355979 - -0.574218
1.430159 - -0.684445
1.387484 - -0.628821
1.462730 - -0.614093
1.297926 - -0.530737
1.391879 - -0.661281
1.293714 - -0.491182
1.373901 - -0.583666
1.387692 - -0.677582
1.524580 - -0.679687
1.472397 - -0.695036
1.326102 - -0.535093
1.448314 - -0.701590
1.303684 - -0.502201
1.611205 - -0.751147
1.302478 - -0.541539
1.636762 - -0.776993
1.444885 - -0.666897
1.318147 - -0.548908
1.531294 - -0.720814
1.556934 - -0.703616
1.413769 - -0.589547
1.268386 - -0.493405
1.493941 - -0.712935
1.511019 - -0.647638
1.353161 - -0.556740
1.409294 - -0.590875
1.493595 - -0.700657
1.468957 - -0.602323
1.313735 - -0.535848
1.531615 - -0.703018
1.361060 - -0.573950
1.404479 - -0.616113
1.346006 - -0.582989
1.438685 - -0.694194
1.372589 - -0.601765
1.399929 - -0.579425
1.271207 - -0.508162
1.475748 - -0.706254
1.489150 - -0.641282
1.603651 - -0.752236
1.414451 - -0.670370
1.316211 - -0.511952
1.381370 - -0.646349
1.327621 - -0.593606
1.438341 - -0.607877
1.333008 - -0.507446
1.472048 - -0.685509
1.640830 - -0.774699
1.326869 - -0.553055
1.624857 - -0.758988
1.479242 - -0.633758
1.530833 - -0.680777
1.352227 - -0.524070
1.392934 - -0.656669
1.355450 - -0.500799
1.372319 - -0.530757
1.497170 - -0.677133
1.403489 - -0.686690
1.454804 - -0.650323
1.533092 - -0.676901
1.576810 - -0.703128
1.256211 - -0.496987
1.421028 - -0.629255
1.522431 - -0.709864
1.289558 - -0.515481
1.433764 - -0.621463
1.323736 - -0.582441
1.416257 - -0.566967
1.546461 - -0.738641
1.462370 - -0.675427
1.454828 - -0.692766
1.412404 - -0.627744
1.465606 - -0.609037
1.359955 - -0.635526
1.401156 - -0.651191
1.386374 - -0.643225
1.620160 - -0.759246
1.442670 - -0.603097
1.492687 - -0.648230
1.373420 - -0.589101
1.423247 - -0.555548
1.569112 - -0.719042
1.336126 - -0.534700
1.388751 - -0.520000
1.540640 - -0.687381
1.388123 - -0.625134
1.340043 - -0.525616
1.511392 - -0.665946


Does it still mean it could be a floating point precision issue?

Also, after a little more testing i found some weird facts about the face id retrieved by newton. I'm coloring faces with different colors. Here's what i'm getting:

Image

Also, the same image rendered with the normal retrieved by the collision function:
Image

And the code to generate the colors of the first image is:

Code: Select all
         float values[] = {1,0,0,
                          0,1,0,
                          0,0,1,
                          1,1,0,
                          0,1,1,
                          1,0,1,
                          1,1,1};

         Endeavour::Math::Vector3f colors[7];
         memcpy(&colors[0].x, values, sizeof(float)*7*3);

         cInfo.normal = colors[(rcio.faceIndex) % 7];


where rcio.faceIndex is an unique number, it indexes in my own face array. Both images output normals, it's just they are calculated differently. Does this mean i could have a problem with the face index retrieval, somewhere in the code?
AdrianCG
 
Posts: 10
Joined: Thu Sep 08, 2011 6:55 am

Re: Raycasting for raytracing: smooth normals and texture co

Postby Julio Jerez » Thu Sep 08, 2011 5:39 pm

if you are enumerationg teh face with a unique ID, then you shoudl get the correct index.
who are you getting the face index?

I do not remeber now but I believe the is a call back that you cna set to ge the face that the ray hit.
I will check tonight.

Is your varicentric coordinate calculation right?
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Raycasting for raytracing: smooth normals and texture co

Postby AdrianCG » Fri Sep 09, 2011 3:03 am

Hi,

I tested two different barycentric calculation routines and they output the same results. As i mentioned in my first post here's the two callbacks responsible for retrieving collision information:

NewtonWorldRayCast
Code: Select all
static dFloat RayCastFilter (const NewtonBody* body, const dFloat* normal, int collisionID, void* userData, dFloat intersetParam)
{   
   if (intersetParam <  ((RaycastInfoObject*)userData)->pickedParam)
   {     
      ((RaycastInfoObject*)userData)->pickedParam = intersetParam;
      ((RaycastInfoObject*)userData)->pickedBody = (NewtonBody*)body;
      ((RaycastInfoObject*)userData)->normal =
         Endeavour::Math::Vector3f(normal[0], normal[1], normal[2]);
   }

   return intersetParam;
}


NewtonTreeCollisionSetUserRayCastCallback
Code: Select all
static dFloat UserMeshCollisionCallback (const NewtonBody* const body, const NewtonCollision* const collisionTree, dFloat interception, dFloat* normal, int faceId, void* usedData)
{
   ((RaycastInfoObject*)usedData)->faceIndex = faceId;

   return interception;
}


Anything suspicious about these two?
AdrianCG
 
Posts: 10
Joined: Thu Sep 08, 2011 6:55 am

Re: Raycasting for raytracing: smooth normals and texture co

Postby AdrianCG » Fri Sep 09, 2011 3:20 am

Well, i think i nailed it down: i have added a new field in my RayCastCollisionInfo structure and said something like this:

Code: Select all
static dFloat UserMeshCollisionCallback (const NewtonBody* const body, const NewtonCollision* const collisionTree, dFloat interception, dFloat* normal, int faceId, void* usedData)
{   
   
   if ( ((RaycastInfoObject*)usedData)->interception > interception)
   {
      ((RaycastInfoObject*)usedData)->interception = interception;

      ((RaycastInfoObject*)usedData)->faceIndex = faceId;
   }

   return interception;
}


Things are working as expected now :).
AdrianCG
 
Posts: 10
Joined: Thu Sep 08, 2011 6:55 am

Re: Raycasting for raytracing: smooth normals and texture co

Postby Julio Jerez » Fri Sep 09, 2011 10:31 am

AdrianCG wrote:Well, i think i nailed it down: i have added a new field in my RayCastCollisionInfo structure and said something like this:

Code: Select all
static dFloat UserMeshCollisionCallback (const NewtonBody* const body, const NewtonCollision* const collisionTree, dFloat interception, dFloat* normal, int faceId, void* usedData)
{   
   
   if ( ((RaycastInfoObject*)usedData)->interception > interception)
   {
      ((RaycastInfoObject*)usedData)->interception = interception;

      ((RaycastInfoObject*)usedData)->faceIndex = faceId;
   }

   return interception;
}



Things are working as expected now :).


Oh by adding that the problem when away? then you were probably getting the wrong face ID in the other method.
I like whe you did, very much. did you added to thsi structure class dgCollisionMeshRayHitDesc?
can you show me what you did so that I added to the core?
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Raycasting for raytracing: smooth normals and texture co

Postby AdrianCG » Fri Sep 09, 2011 3:39 pm

Hi again,

Sorry for the late response. To answer your question i did not add anything to dgCollisionMeshRayHitDesc. Here's how i'm doing the whole thing:

Code: Select all

struct collisionInfo
{
   Endeavour::Math::Vector3f position;
   Endeavour::Math::Vector3f normal;
   Endeavour::Math::Vector2f texCoords;

   void* userData;

   bool collisionOccured;
};

// some callbacks

static dFloat RayCastFilter (const NewtonBody* body, const dFloat* normal, int collisionID, void* userData, dFloat intersetParam)
{   
   if (intersetParam <  ((RaycastInfoObject*)userData)->pickedParam)
   {      
      ((RaycastInfoObject*)userData)->pickedParam = intersetParam;
      ((RaycastInfoObject*)userData)->pickedBody = (NewtonBody*)body;
      ((RaycastInfoObject*)userData)->normal =
         Endeavour::Math::Vector3f(normal[0], normal[1], normal[2]);
   
      ((RaycastInfoObject*)userData)->normal.normalize();
   }

   return intersetParam;
}

// this was set like this NewtonTreeCollisionSetUserRayCastCallback(collision, UserMeshCollisionCallback)
static dFloat UserMeshCollisionCallback (const NewtonBody* const body, const NewtonCollision* const collisionTree, dFloat interception, dFloat* normal, int faceId, void* usedData)
{   
   
   if ( ((RaycastInfoObject*)usedData)->interception > interception)
   {
      ((RaycastInfoObject*)usedData)->interception = interception;

      ((RaycastInfoObject*)usedData)->faceIndex = faceId;
   }
   
   return interception;
}

// the collision part

collisionInfo cInfo;

RaycastInfoObject rcio;
rcio.pickedBody = NULL;
rcio.pickedParam  = 100000.0f;
rcio.interception = 100000.0f;
      
NewtonWorldRayCast(newtonWorld, rayFrom, rayTo, RayCastFilter, &rcio, NULL);



after this, the RaycastInfoObject named rcio contains the relevant information i need. I can now find barycentric coordinates that let me interpolate various vertex attributes. If you need further information just let me know :).
AdrianCG
 
Posts: 10
Joined: Thu Sep 08, 2011 6:55 am

Re: Raycasting for raytracing: smooth normals and texture co

Postby AdrianCG » Sat Sep 10, 2011 2:24 pm

I have encountered one more challenge: I want to be able to shoot rays from INSIDE an object and get correct information. Currently this does not seem to work. I need this for implementing refraction. Is there any way that i can cast say a ray from INSIDE a sphere (or any other object) and receive correct collision information? Are there any flags i can set to achieve this?
AdrianCG
 
Posts: 10
Joined: Thu Sep 08, 2011 6:55 am

Re: Raycasting for raytracing: smooth normals and texture co

Postby Julio Jerez » Sat Sep 10, 2011 5:37 pm

The collision does no handle double side shapes, because for collision this is more of a problem that it si feature. However you could calculate the interaction of a Ray form the inside, by using the shape raycast function.
I assuming you am doing kind of a recursive ray tracer.
Say you say hit a sphere at some point, and you want to determine the refraction.
the you get the collision shape that the ray hit,
With the normal and the index or refraction you calculate the new ray direction, and you can that shape only but in reverse, basically you make a sufficiently long ray starting at point
P = P_intersction + rfrationNormal.Scale (distance), and ending at P_intersction

Cast a ray on the shape only, and find the hit point on the other side.
Then at that point, calculate the new ray direction base of the same index of refraction, and the continue tracing the Scene.
Each time you apply a diffuse value so that the algorithm do not recourse forever.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Raycasting for raytracing: smooth normals and texture co

Postby AdrianCG » Sun Sep 11, 2011 8:52 am

Well, that doesn't sound like good news. I understand your solution for working around the issue, although i can think of some cases when this won't really work. Let's consider a sphere inside another sphere, both refractive. This would need some moderately complex light paths, and your proposed solution will incorrectly refract the initial ray by taking into account only the outer (bigger) sphere. Let's say i'm going to use only tree collision objects(made by triangles of course). Is there a way to force collision with back faces too? Like commenting or writing a bit of code somewhere in the newton collision routines?
AdrianCG
 
Posts: 10
Joined: Thu Sep 08, 2011 6:55 am

Re: Raycasting for raytracing: smooth normals and texture co

Postby Julio Jerez » Sun Sep 11, 2011 10:54 am

sorry but the collison is designed to deal with physics solid objects, not for graphics where you deal wih transparency and translucent materials.
the collison system cast the outside surface of a shape. never during the design I considered woking with the insided of a shape.

what you could do is modify the collision engine. it is no too diffcult, and on he shapes classes modify the Raycast functions so tha they report hit for rays starting from the inside of a shape.
for example for a tree collision this is the ray cast function that is call on each face

from file: c:..\core\dgIntersections.cpp
Code: Select all
dgFloat32 FastRayTest::PolygonIntersect (const dgVector& normal, const dgFloat32* const polygon, dgInt32 strideInBytes, const dgInt32* const indexArray, dgInt32 indexCount) const
{
   _ASSERTE (m_p0.m_w == m_p1.m_w);

   dgFloat32 dist = normal % m_diff;
   if (dist < m_dirError) {

      dgInt32 stride = dgInt32 (strideInBytes / sizeof (dgFloat32));

      dgVector v0 (&polygon[indexArray[indexCount - 1] * stride]);
      dgVector p0v0 (v0 - m_p0);
      dgFloat32 tOut = normal % p0v0;
      // this only work for convex polygons and for single side faces
      // walk the polygon around the edges and calculate the volume
      if ((tOut < dgFloat32 (0.0f)) && (tOut > dist)) {
         for (dgInt32 i = 0; i < indexCount; i ++) {
            dgInt32 i2 = indexArray[i] * stride;
            dgVector v1 (&polygon[i2]);
            dgVector p0v1 (v1 - m_p0);
            // calculate the volume formed by the line and the edge of the polygon
            dgFloat32 alpha = (m_diff * p0v1) % p0v0;
            // if a least one volume is negative it mean the line cross the polygon outside this edge and do not hit the face
            if (alpha < DG_RAY_TOL_ERROR) {
               return 1.2f;
            }
            p0v0 = p0v1;
         }

         //the line is to the left of all the polygon edges,
         //then the intersection is the point we the line intersect the plane of the polygon
         tOut = tOut / dist;
         _ASSERTE (tOut >= dgFloat32 (0.0f));
         _ASSERTE (tOut <= dgFloat32 (1.0f));
         return tOut;
      }
   }
   return dgFloat32 (1.2f);

}


as you can see the collsion is based on a volumetric test, since volumes are positive or negatives that this is why the function can only cast positive side of a face.
howver it is very eassy to change so that it works for double sided faces. here is a version that work for double faces
Code: Select all
dgFloat32 FastRayTest::PolygonIntersect (const dgVector& normal, const dgFloat32* const polygon, dgInt32 strideInBytes, const dgInt32* const indexArray, dgInt32 indexCount) const
{
   _ASSERTE (m_p0.m_w == m_p1.m_w);

   dgFloat32 dist = normal % m_diff;
   if (dist < m_dirError) {

      dgInt32 stride = dgInt32 (strideInBytes / sizeof (dgFloat32));

      dgVector v0 (&polygon[indexArray[indexCount - 1] * stride]);
      dgVector p0v0 (v0 - m_p0);
      dgFloat32 tOut = normal % p0v0;
      // this only work for convex polygons and for single side faces
      // walk the polygon around the edges and calculate the volume
      if ((tOut < dgFloat32 (0.0f)) && (tOut > dist)) {
         for (dgInt32 i = 0; i < indexCount; i ++) {
            dgInt32 i2 = indexArray[i] * stride;
            dgVector v1 (&polygon[i2]);
            dgVector p0v1 (v1 - m_p0);
            // calculate the volume formed by the line and the edge of the polygon
            dgFloat32 alpha = (m_diff * p0v1) % p0v0;
            // if a least one volume is negative it means the line cross the polygon outside this edge and do not hit the face
            if (alpha < DG_RAY_TOL_ERROR) {
               return 1.2f;
            }
            p0v0 = p0v1;
         }

         //the line is to the left of all the polygon edges,
         //then the intersection is the point we the line intersect the plane of the polygon
         tOut = tOut / dist;
         _ASSERTE (tOut >= dgFloat32 (0.0f));
         _ASSERTE (tOut <= dgFloat32 (1.0f));
         return tOut;
      }
   } else if (-dist < m_dirError) {
      
      // casting the negative side of the shape
      dgInt32 stride = dgInt32 (strideInBytes / sizeof (dgFloat32));

      dgVector v0 (&polygon[indexArray[indexCount - 1] * stride]);
      dgVector p0v0 (v0 - m_p0);
      dgFloat32 tOut = normal % p0v0;
      // this only work for convex polygons and for single side faces
      // walk the polygon around the edges and calculate the volume
      if ((tOut < dgFloat32 (0.0f)) && (tOut > dist)) {
         for (dgInt32 i = 0; i < indexCount; i ++) {
            dgInt32 i2 = indexArray[i] * stride;
            dgVector v1 (&polygon[i2]);
            dgVector p0v1 (v1 - m_p0);

            // look here (veryu important !!!
            // calculate the volume formed by the line and the edge of the polygon (negate the volume here)
            dgFloat32 alpha = -((m_diff * p0v1) % p0v0);
            // if a least one volume is negative it means the line cross the polygon outside this edge and do not hit the face
            if (alpha < DG_RAY_TOL_ERROR) {
               return 1.2f;
            }
            p0v0 = p0v1;
         }

         //the line is to the left of all the polygon edges,
         //then the intersection is the point we the line intersect the plane of the polygon
         tOut = tOut / dist;
         _ASSERTE (tOut >= dgFloat32 (0.0f));
         _ASSERTE (tOut <= dgFloat32 (1.0f));
         return tOut;
      }
   }

   return dgFloat32 (1.2f);

}



Remember making that change may render the collision system useless for physics.
The physic part is based on the extract assumptions
- a surface has a positive and a negative side.
-every shape is convex,
- every shape has volume equal or large than zero
-every two pair of colliding shapes at least one has to have a positive volume.

this is why in Newton there cannot be triangle to triangle collision, because if two triangle collide
the minscownsky shape that result for the intersection may be another shape with zero volume and the
algorithm can break down.
It is and easy thong to work around, if one day I want to have collision tree to collision tree collision, but I do not like to break the elegance of the collision system by adding special cases.

anyway in your case, having a raycast function reporting hit on both side of a surface will make impossible for the Minkosky algorithm to build the convex sum,
but in your case I believe the ray cast functions on collision tree is no use for collision, or at least I do no remember is it is.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Raycasting for raytracing: smooth normals and texture co

Postby AdrianCG » Sun Sep 11, 2011 3:33 pm

Thanks for the info. Unfortunately making the modifications you suggested didn't work as expected. The FastRayTest::PolygonIntersect was never called for the intersection with the ray who's origin was inside a sphere, represented by a tree collision object. I never figured this would be so complicated , although i perfectly understand the reasons behind the collision detection design. Because i intended from the start to experiment with raytracing techniques first and not care about intersection routines, and later on to build my own acceleration and intersection routines, i guess i'll start coding intersection / acceleration routines sooner :).
AdrianCG
 
Posts: 10
Joined: Thu Sep 08, 2011 6:55 am

Next

Return to General Discussion

Who is online

Users browsing this forum: No registered users and 1 guest

cron