Hi,

On rendering particles as unit spheres everything works fine, but obivously calculation of normals

for an ellipsoid fails in my code. OptiX API uses RH and Y UP axis, right?

The particles (using water material desinged as in OptiX Introduction in Advanced Samples) are actually

ellipsoids. Each of them has 3 vectors (U, V, W) and a 3D-scale. W is the normal vector when applied with ellipsoid spatting on a rasterizer.

Intersection checking is done by simply using a sphere on transformed RayOrigin and transformed RayDirection.

The transform is performed using an inverse matrix containing all U,V,W vectors and xyz scales. That seems to work.

The normals I simply calculate from the spherical coord angles theta and phi; based on this answer:

https://math.stackexchange.com/questions/2974280/normal-vector-to-ellisoid-surface

That calc seems to be Z UP axis, so I changed my code to Y UP axis.

But yet the normals are invalid (cause the reflection+refraction of the water material should behave “upside-done” in an ellipsoid also)

I’m glad for any advice, cause this took hours, but no result yet…

in my source file ellipsoid_texcoord_tangent.cu:

```
OO = OO - center;
#ifdef SPHERE_TEST
float radius = sphere.w;
#else // then ellipsoid // then apply inverse matrix (rotation and scale on Origin OO and direction DD)
const float radius = 1.0f;
OO = make_float3( make_float4(OO.x, OO.y, OO.z, 1.0f) * invTransMatrix );
DD = make_float3( make_float4(DD.x, DD.y, DD.z, 0.0f) * invTransMatrix );
float len = length(DD); float _1div_len = 1.0f / len;
DD = make_float3(DD.x * _1div_len, DD.y * _1div_len, DD.z * _1div_len); // unit length
#endif
// ... calculate intersection as on a unit sphere (as in sphere_texcoord_tangent.cu of optixMDLsphere SDK sample)
// on potential intersection:
float3 p = (OO + (root1 + root11)*D);
#ifdef SPHERE_TEST
shading_normal = geometric_normal = p/radius;
#else
const float phi = atan2f(p.z, p.x); // Azimuth angle -180° .. +180°
const float theta = acosf(clamp(p.y, -1.0f, 1.0f)); // Polar angle 0..180°
// pre-calc sin+cos for phi and theta
float sin_phi, cos_phi, sin_theta, cos_theta;
sincosf(phi, &sin_phi, &cos_phi); sincosf(theta, &sin_theta, &cos_theta);
/* // is Z UP coord obviously (here the transform matrix also contained scaling)
float nx = cos_theta * cos_phi;
float ny = cos_theta * sin_phi;
float nz = sin_theta;
*/
// Y UP // the TransMatrix only contains the rotation; no scaling
float nx = cos_theta * cos_phi / scales.x;
float nz = cos_theta * sin_phi / scales.z;
float ny = sin_theta / scales.y;
float3 norm = make_float3(nx, ny, nz);
// rotation transform this point back to final coords
norm = make_float3( make_float4(norm.x, norm.y, norm.z, 1.0f) * TransMatrix ); // point transform (w=1) direction transform (w=0)
norm = normalize(norm);
shading_normal = geometric_normal = norm;
#endif
```