В этом разделе я буду выкладывать маленькие фрагменты кода, используемые для решения простых задач, однако необходимость в которых возникает довольно регулярно.

Как получить уравнение прямой по двум точкам.

Как получить уравнение плоскости по трем точкам.

Лежит ли прямая в плоскости.

Параллельны ли два отрезка AB и CD.

Является ли число степенью двойки

Число единичных битов в 32-битовом слове.

Получение случайной точки, равномерно распределенной на сфере.

Получение случайной точки, равномерно распределенной в треугольнике ABC.

Площадь треугольника ABC.

Расстояние от точки до прямой AB.

Сохранение 24-битового значения (из [0,1]) как 3 8-битовых.

Сохранение float из [0,1) как 4 8-битовых (RGBA).

Расстояние от точки до отрезка.

Окружность, проходящая через три точки a, b и c.

Пересечение луча и плоскости.

Аналог угла, без использования тригонометрических функций.

Пересечение луча и сферы.

Площадь многоугольника со знаком (2D).

Площадь многоугольника со знаком (3D).

Поворот вектора v при помощи кватерниона q.

Пересечение луча и треугольника.

Пересечение луча с AABB.

Лежит ли точка внутри полигона (2D)

Получение frustum'а в OpenGL.

Как узнать направление обхода двухмерного многоугольника.

Является ли многоугольник выпуклым.

Как узнать расстояние между двумя прямыми в 3D

Классификация двух прямых в 3D (являются ли они скрещивающимися, параллельными или пересекающимися)

Матрица поворота вокруг вектора на заданный угол

Матрица поворота по кватерниону

Векторное произведение двух векторов

Вычисление определителя матрицы 3х3

Вычисление объема 3D Mesh'а

Как в скелетной анимации запаковать boneId и weight в один float

Как запаковать нормаль в один float

Как определить попадает ли сфера с усеченную пирамиду видимости

Округление вверх к степени двух

Определитель матрицы 4х4

Обнуление младшего ненулевого бита

Упаковка float <-> byte

Проверить поддержку расширения OpenGL

Как узнать объем видеопамяти на GPU


Как получить уравнение прямой по двум точкам.

Пусть заданы две точки a и b тогда прямая, проходящая через них задается уравнением:

p=a+t*(b-a).

Вектор l=b-a является направляющим вектором прямой.



Как получить уравнение плоскости по трем точкам.

Пусть заданы три точки a, b и c. Тогда плоскость, проходящая через них задается уравнением:

(p-a,n)=0 или уравнением (p,n)=d, где d=(a,n).

Вектор n=[b-a,c-a] является нормалью к плоскости.



Лежит ли прямая в плоскости.

Пусть заданы прямая p=a+t*l и плоскость (p,n)=d. Тогда прямая лежит в плоскости, если выполнены следующие два условия:

(p-a,n)=d и (l,n)=0.



Параллельны ли два отрезка AB и CD

По каждому отрезку строим разницы координат - (dx1,dy1) и (dx2,dy2).

Если один из отрезков имеет нулевую длину, то он параллелен любому отрезку. Если dx1==0, то отрезки параллельны тогда и только тогда, когда dx2==0.

Иначе у отрезков должны совпадать соотношения приращений по x и y, т.е. должно быть выполнено соотношение:

dy1*dx2==dy2*dx1.

bool areParallel ( const vec2& a, const vec2& b, const vec2& c, const vec2& d )
{
    float dx1 = b.x - a.x;
    float dy1 = b.y - a.y;
    float dx2 = d.x - c.x;
    float dy2 = d.y - c.y;
	
    if ( fabs ( dx1 ) + fabs ( dy1 ) < EPS )
        return true;

    if ( fabs ( dx2 ) + fabs ( dy2 ) < EPS )
        return true;

    if ( fabs ( dx1 ) < EPS )
        return fabs ( dx2 ) < EPS;

    return fabs ( dy1 * dx2 - dy2 * dx1 ) < EPS;
}

В трехмерном случае появляется еще одно соотношение - dz1*dx2==dz2*dx1.



Степени двойки

Число x является степенью двойки если справедливо (для x != 0):

x&(x-1)==0.

Число x имеет вид 2n-1, если справедливо:

x&(x+1)==0

bool isPowerOfTwo ( unsigned x )
{
    return x && ((x & (x - 1)) == 0);
}


Число единичных битов в 32-битовом слове

int pop ( unsigned x )
{
    x = x - ((x >> 1) & 0x55555555);
    x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
    x = (x + (x >> 4)) & 0x0F0F0F0F;
    x = x + (x >> 8);
    x = x + (x >> 16);
	
    return x & 0x3F;
}


Расстояние от точки до прямой

Пусть задана точка P и прямая, задаваемая уравнением u = u0 + t*l.

Тогда для произвольного значения параметра t квадрат расстояния от P до u(t) задается следующей формулой (считая, что l - единичный вектор):

d(t) = (P-u0, P-u0) + 2 * t * (P-u0, l) + t2

Минимальное значение эта функция принимает при t' = (P-u0, l). Подставляя это значение в уравнение для d(t) мы получаем квадрат расстояния от точки до прямой.



Получение случайной точки, равномерно распределенной на сфере

z = rnd ( -1, 1 )  		// случайное число, равномерно распределенное в [0,1]
t = rnd ( 0, 2*pi )		// случайное число, равномерно распределенное в [0,2*pi]
r = sqrt ( 1 - z*z )
x = r * cos ( t )
y = r * sin ( t )


Получение случайной точки, равномерно распределенной в треугольнике ABC

                       // находим случайные барицентрические координаты
a = rnd ( 0, 1 ) 
b = rnd ( 0, 1 )

if ( a + b > 1 )
{
    a = 1 - a
    b = 1 - b
}

c = 1 - a - b
p = a * A + b * B + c * C		// итоговая случайная точка


Площадь треугольника ABC

S = length ( cross ( C - A, B - A ) ) * 0.5


Расстояние от точки до прямой AB

Пусть есть точка A и плоскость, заданная уравнением (n,p)=d, где вектор n имеет единичную длину. Тогда расстояние (со знаком) от точки до плоскости (или от точки до прямой в двухмерном случае) задается следующей формулой:

dist=(A,n)-d



Сохранение 24-битового значения (из [0,1]) как 3 8-битовых

vec3  float2Color ( float f )
{
    vec3 color;

    f        *= 256.0;
    color.x   = floor ( f );
    f         = (f - color.x) * 256.0;
    color.y   = floor ( f );
    color.z   = f - color.y;
    color.xy *= 0.00390625;			// *= 1.0 / 256.0

    return color;
}

float color2Float ( vec3 color )
{
    const vec3 coeff = vec3 ( 1.0, 1.0 / 256.0, 1.0 / (256.0 * 256.0) );
	
    return dot ( color, coeff );
}


Расстояние от точки до отрезка

float squaredDistancePointToSegment ( const vec2& p, const Segment& seg, float& t )
{
    vec2 diff = p - seg.getDelta ();		// delta = seg.end - seg.start

    if ( (t = seg.getStart () & diff) > 0 )
    {
        float dot = seg.getDelta ().lengthSq ();

        if ( t < dot )
        {
            t    /= dot;
            diff -= t * seg.getStart;
        }
        else
        {
            t     = 1;
            diff -= seg.getStart ();
        }
    }
    else
        t = 0;
}


Окружность, проходящая через три точки a, b и c

A = b.x - a.x
B = b.y - a.y
C = c.x - a.x
D = c.y - a.y
E = A * (a.x + b.x) + B * (a.y + b.y)                // dot ( b - a, b + a )
F = C * (a.x + c.x) + D * (a.y + c.y)                // dot ( c - a, c + a )
G = 2 * ( A * ( c.y - b.y ) - B * ( c.x - b.x ) )

if abs ( G ) < EPS:
	error "Points collinear"
	
Center.x = (D*E - B*F) / G
Center.y = (A*F - C*E) / G


Пересечение луча и плоскости

bool intersect ( const Plane& plane, const Ray& ray, float& t )
{
    float numer = - (plane.getDist () + ( ray.getOrg () & plane.getNormal () ) );
    float denom = ray.getDir () & plane.getNormal ();

    if ( fabs ( denom ) < EPS )
        return false;
		
    t = numer / denom;

    return true;
}


Пересечение луча и сферы

bool intersect ( const Sphere& s, const Ray& ray )
{
    vec3 l   = s.getCenter () - ray.getOrg ();
    float    d   = l & ray.getDir ();
    float    lSq = l & l;

    if ( d < 0 && lSq > s.getRadiusSq () )
        return false;
		
    float mSq = lSq - d*d;

    return mSq <= s.getRadiusSq ();
}


Площадь многоугольника со знаком (2D)

float signedArea ( const vec2 p [], int n )
{
    float sum = p [0].x * ( p [1].y - p [n-1].y ) + p [n-1].x * ( p [0].y - p [n-2].y );
	 
    for ( int i = 1; i < n - 1; i++ )
        sum += p [i].x * ( p [i+1].y - p [i-1].y );

    return 0.5f * sum;
}



Площадь многоугольника со знаком (3D)

float signedArea ( const vec3 p [], int n, const vec3 normal )
{
    float sum = 0;
	 
    for ( int i = 0; i < n - 1; i++ )
        sum += dot ( normal,  cross ( p [i], p [i+1] ) );

    return 0.5f * sum;
}



Пересечение луча и треугольника
bool intersection ( vec2 start1, vec2 end1, vec2 start2, vec2 end2, vec2& intersection )
{
	vec2 dir1 = end1 - start1;
	vec2 dir2 = end2 - start2;

                            // считаем уравнения прямых проходящих через отрезки
	float a1 = -dir1.y;
	float b1 = +dir1.x;
	float d1 = -(a1*start1.x + b1*start1.y);

	float a2 = -dir2.y;
	float b2 = +dir2.x;
	float d2 = -(a2*start2.x + b2*start2.y);

                            // подставляем концы отрезков, для выяснения в каких полуплоскотях они
	float seg1_line2_start = a2*start1.x + b2*start1.y + d2;
	float seg1_line2_end   = a2*end1.x   + b2*end1.y   + d2;

	float seg2_line1_start = a1*start2.x + b1*start2.y + d1;
	float seg2_line1_end   = a1*end2.x   + b1*end2.y   + d1;

                            // если концы одного отрезка имеют один знак, значит он в одной полуплоскости и пересечения нет.
	if ( seg1_line2_start * seg1_line2_end >= 0 || seg2_line1_start * seg2_line1_end >= 0 )
		return false;

	float u = seg1_line2_start / (seg1_line2_start - seg1_line2_end);
	
	intersection = start1 + u * dir1;

	return true;
}

Взято у Winnie.



Аналог угла, без использования тригонометрических функций

Приведенная ниже функция является строго монотонной функций угла, что позволяет ее легко использовать в различных сравнениях.

float angleFunc ( const vec2& pt, const vec2& org )
{
    vec2	delta = pt - org;
	 
    if ( fabs ( delta.x ) < EPS && fabs ( delta.y ) < EPS )
        return 0;
		
    if ( delta.y >= 0 )
        if ( delta.x >= 0 )
           return delta.y / (delta.x + delta.y);
        else
           return 2 - delta.y / (delta.y - delta.x);
    else
        if ( delta.x >= 0 )
           return 4 + delta.y / (delta.x - delta.y);
        else
           return 2 + delta.y / (delta.x + delta.y);
}



Поворот вектора v при помощи кватерниона q

vec3 quat :: rotate ( const vec3& v )
{
    quat	p     ( v );				// (v.x, v.y, v.z, 0)
    quat	qConj ( -x, -y, -z, w );

    p  = *this * p * qConj;

    return vec3 ( p.x, p.y, p.z );
}



Пересечение луча и треугольника

#define EPSILON 0.000001

/* code rewritten to do tests on the sign of the determinant */
/* the division is at the end in the code                    */
bool	intersect_triangle1 ( const vec3& org, const vec3& dir,
			const vec3& vert0, const vec3& vert1, const vec3& vert2,
			vec3& t )
{
    vec3 pvec, qvec;
	
                       /* find vectors for two edges sharing vert0 */
    vec3 edge1 = vert1 - vert0;
    vec3 edge2 = vert2 - vert0;
   
                       /* begin calculating determinant - also used to calculate U parameter */
    pvec = cross ( dir,  edge2 );

                       /* if determinant is near zero, ray lies in plane of triangle */
    float det = dot ( edge1, pvec );

    if ( det > EPSILON )
    {
                       /* calculate distance from vert0 to ray origin */
        vec3 tvec = org - vert0;

                       /* calculate U parameter and test bounds */
        t.y = dot ( tvec,  pvec );

        if ( t.y < 0 || t.y > det )
            return false;

                       /* prepare to test V parameter */
        vec3 qvec = cross ( tvec, edge1 );

                       /* calculate V parameter and test bounds */
        t.z = dir & qvec;

        if ( t.z < 0 || t.y + t.z > det )
            return false;
    }
    else 
    if ( det < -EPSILON )
    {
                       /* calculate distance from vert0 to ray origin */
        vec3 tvec = org - vert0;

                       /* calculate U parameter and test bounds */
        t.y = tvec & pvec;

        if ( t.y > 0 || t.y < det )
            return false;

                       /* prepare to test V parameter */
        vec3 qvec = cross ( tvec,  edge1 );

                       /* calculate V parameter and test bounds */
        t.z = dir & qvec;

        if ( t.z > 0 || t.y + t.z < det )
            return false;
   }
   else 
        return false;  /* ray is parallell to the plane of the triangle */

    float invDet = 1.0 / det;

                       /* calculate t, ray intersects triangle */
   t.x  = (edge2 & qvec) * invDet;
   t.y *= invDet;
   t.z *= invDet;

   return true;
}



Пересечение луча с AABB

bool	intersect ( const Ray& ray, const BoundingBox& box )
{
    int	 i;
	
    for ( int i = 0; i < 3 && fabs ( ray.getDir () [i] ) < EPS; i++ )
        ;
		
    if ( i >= 3 )                 // some error, this means ray.dir == 0
        return false;
	
    float tMin = (box.getMin () [i] - ray.getOrg () [i]) / ray.getDir () [i];
    float tMax = (box.getMax () [i] - ray.getOrg () [i]) / ray.getDir () [i];

    for ( i++; i < 3; i++ )
    {
        if ( fabs ( ray.getDir () [i] ) < EPS )
            continue;

        float t1 = (box.getMin () [i] - ray.getOrg () [i]) / ray.getDir () [i];
        float t2 = (box.getMax () [i] - ray.getOrg () [i]) / ray.getDir () [i];
		
        if ( t1 > tMin )          // take maximum of all t1's
            tMin = t1;
			
        if ( t2 < tMax )          // take minimum of all t2's
            tMax = t2;
			
        if ( tMin >= tMax)
            return false;
    }
	
    return tMin < tMax && tMin >= 0;
}



Лежит ли точка внутри полигона (2D)

int ptInPoly ( int npol, float * xp, float * yp, float x, float y )
{
    int i, j, c = 0;
	
    for ( i = 0, j = npol - 1; i < npol; j = i++)
    {
        if ((((yp [i] <= y) && (y < yp [j])) || ((yp [j] <= y) && (y < yp [i]))) && (x < (xp [j] - xp [i]) * (y - yp [i]) / (yp [j] - yp [i]) + xp [i]))
            c = !c;
    }
	
    return c;
}



Получение frustum'а в OpenGL

float	proj  [16];                     // projection matrix
float	model [16];                     // modelview matrix
float	clip  [16];                     // transform to clip space matrix

glGetFloatv ( GL_PROJECTION_MATRIX, proj  );
glGetFloatv ( GL_MODELVIEW_MATRIX,  model );

                                        // now multiply them to get clip transform matrix
clip[ 0] = model[ 0] * proj[ 0] + model[ 1] * proj[ 4] + model[ 2] * proj[ 8] + model[ 3] * proj[12];
clip[ 1] = model[ 0] * proj[ 1] + model[ 1] * proj[ 5] + model[ 2] * proj[ 9] + model[ 3] * proj[13];
clip[ 2] = model[ 0] * proj[ 2] + model[ 1] * proj[ 6] + model[ 2] * proj[10] + model[ 3] * proj[14];
clip[ 3] = model[ 0] * proj[ 3] + model[ 1] * proj[ 7] + model[ 2] * proj[11] + model[ 3] * proj[15];

clip[ 4] = model[ 4] * proj[ 0] + model[ 5] * proj[ 4] + model[ 6] * proj[ 8] + model[ 7] * proj[12];
clip[ 5] = model[ 4] * proj[ 1] + model[ 5] * proj[ 5] + model[ 6] * proj[ 9] + model[ 7] * proj[13];
clip[ 6] = model[ 4] * proj[ 2] + model[ 5] * proj[ 6] + model[ 6] * proj[10] + model[ 7] * proj[14];
clip[ 7] = model[ 4] * proj[ 3] + model[ 5] * proj[ 7] + model[ 6] * proj[11] + model[ 7] * proj[15];

clip[ 8] = model[ 8] * proj[ 0] + model[ 9] * proj[ 4] + model[10] * proj[ 8] + model[11] * proj[12];
clip[ 9] = model[ 8] * proj[ 1] + model[ 9] * proj[ 5] + model[10] * proj[ 9] + model[11] * proj[13];
clip[10] = model[ 8] * proj[ 2] + model[ 9] * proj[ 6] + model[10] * proj[10] + model[11] * proj[14];
clip[11] = model[ 8] * proj[ 3] + model[ 9] * proj[ 7] + model[10] * proj[11] + model[11] * proj[15];

clip[12] = model[12] * proj[ 0] + model[13] * proj[ 4] + model[14] * proj[ 8] + model[15] * proj[12];
clip[13] = model[12] * proj[ 1] + model[13] * proj[ 5] + model[14] * proj[ 9] + model[15] * proj[13];
clip[14] = model[12] * proj[ 2] + model[13] * proj[ 6] + model[14] * proj[10] + model[15] * proj[14];
clip[15] = model[12] * proj[ 3] + model[13] * proj[ 7] + model[14] * proj[11] + model[15] * proj[15];

                                        // now extract clip planes params:
vec3	n [6];
float		d [6];
                                        // right plane
n [0].x = clip [3]  - clip [0];
n [0].y = clip [7]  - clip [4];
n [0].z = clip [11] - clip [8];
d [0]   = clip [15] - clip [12];

                                        // left plane
n [1].x = clip [3]  + clip [0];
n [1].y = clip [7]  + clip [4];
n [1].z = clip [11] + clip [8];
d [1]   = clip [15] + clip [12];

                                        // top plane
n [2].x = clip [3]  - clip [1];
n [2].y = clip [7]  - clip [5];
n [2].z = clip [11] - clip [9];
d [2]   = clip [15] - clip [13];

                                        // bottom plane
n [3].x = clip [3]  + clip [1];
n [3].y = clip [7]  + clip [5];
n [3].z = clip [11] + clip [9];
d [3]   = clip [15] + clip [13];

                                        // far plane
n [4].x = clip [3]  - clip [2];
n [4].y = clip [7]  - clip [6];
n [4].z = clip [11] - clip [10];
d [4]   = clip [15] - clip [14];

                                        // near plane
n [5].x = clip [3]  + clip [2];
n [5].y = clip [7]  + clip [6];
n [5].z = clip [11] + clip [10];
d [5]   = clip [15] + clip [14];

                                        // normalize
for ( int i = 0; i < 6; i++ )
{
    float	len = n [i].length ();

    if ( len > EPS )
    {
        n [i] /= len;
        d [i] /= len;
    }

    plane [i] = Plane ( n [i], d [i] );
}	



Как узнать направление обхода двухмерного многоугольника

Направление обхода (по или против часовой стрелки) определяется знаком "площади многоугольника со знаком"



Является ли многоугольник выпуклым

Многоугольник является выпуклым, тогда и только тогда, когда для каждого его ребра, все его вершины лежат по одну сторону от прямой, проведенной через это ребро.

bool isConvex ( vec2 * v, int n )
{
    vec2 prev = v [n-1];
    vec2 cur, dir, n;
    float    d, dp;
    int      sign, s;

    for ( int i = 0; i < n; i++ )
    {
        cur  = v [i];
        dir  = cur - prev;                     // edge direction vector
        n    = vec2 ( dir.y, -dir.x );     // normal to edge [prev, cur]
        d    = - dot ( n, cur );               // so line's equation is (p,n) + d = 0
        sign = 0;                              // unknown yet

        for ( int j = 0; j < n; j++ )
        {
            dp = d + dot ( n, v [j] );

            if ( fabs ( dp ) < EPS )        // too small
               continue;
				
            s = dp > 0 ? 1 : -1;               // sign for v [j]
			
            if ( sign == 0 )
               sign = s;
            else
            if ( sign != s )
                return false;
        }
    }

    return true;
}


Как узнать расстояние между двумя прямыми в 3D

float squaredLineToLineDistance ( const Line& l1, const Line& l2, float& s, float& t )
{
    vec3 diff =   line1.getOrg () - line2.getOrg ();
    float    a    =  dot ( line1.getDir (), line1.getDir () );
    float    b    = -dot ( line1.getDir (), ine2.getDir () );
    float    c    =  dot ( line2.getDir (), line2.getDir () );
    float    d    =  dot ( line1.getDir (), diff );
    float    f    =  dot ( diff, diff );
    float    det  =  fabs ( a*c - b*b );
	
    if ( det > EPS )
    {
        float e      = -dot ( line2.getDir (),  diff );
        float invDet = 1.0 / det;
		
        s = (b*e - c*d) * invDet;
        t = (b*d - a*e) * invDet;

        return s * (a*s + b*t + 2*d) + t * (b*s + c*s + 2*e);
    }

    s = - d / a;
    t = 0;

    return d*s + f;
}


Классификация двух прямых в 3D (являются ли они скрещивающимися, параллельными или пересекающимися)

Пусть даны две прямые p = p1 + t*l1 и p = p2 + t*l2.

Тогда нормаль плоскости, параллельной этим двум прямым будет задаваться формулой n = [l1, l2].

Если вектор n нулевой (или почти нулевой), то прямые параллельны. В противном случае они либо пересекаются (и тогда лежат в одной плоскости) или скрещивающиеся.

Чтобы проверить лежат ли они в одной плоскости достаточно проверить лежат ли точки p1 и p2 в плоскости с нормалью n. Это выполнено тогда и только тогда, когда (n, p1) = (n, p2).



Матрица поворота вокруг вектора на заданный угол

mat3 rotate ( const vec3& v, float angle )
{
    mat3 a;
    float    cosine = (float)cos ( angle );
    float    sine   = (float)sin ( angle );

    a.x [0][0] = v.x * v.x + (1-v.x*v.x) * cosine;
    a.x [0][1] = v.x * v.y * (1-cosine) + v.z * sine;
    a.x [0][2] = v.x * v.z * (1-cosine) - v.y * sine;
    a.x [1][0] = v.x * v.y * (1-cosine) - v.z * sine;
    a.x [1][1] = v.y * v.y + (1-v.y*v.y) * cosine;
    a.x [1][2] = v.y * v.z * (1-cosine) + v.x * sine;
    a.x [2][0] = v.x * v.z * (1-cosine) + v.y * sine;
    a.x [2][1] = v.y * v.z * (1-cosine) - v.x * sine;
    a.x [2][2] = v.z * v.z + (1-v.z*v.z) * cosine;

    return a;
}


Матрица поворота по кватерниону

mat3	quat :: getMatrix () const
{
    mat3 m;

		// 1st row
    m [0][0] = 1.0f - 2.0f * ( y * y + z * z );
    m [0][1] = 2.0f * ( x * y - w * z );
    m [0][2] = 2.0f * ( x * z + w * y );

		// 2nd row
    m [1][0] = 2.0f * ( x * y + w * z );
    m [1][1] = 1.0f - 2.0f * ( x * x + z * z );
    m [1][2] = 2.0f * ( y * z - w * x );

		// 3rd row
    m [2][0] = 2.0f * ( x * z - w * y );
    m [2][1] = 2.0f * ( y * z + w * x );
    m [2][2] = 1.0f - 2.0f * ( x * x + y * y );

    return m;
}


Векторное произведение двух векторов

vec3 cross ( const vec3& u, const vec3& v )
{
    return vec3 (u.y*v.z-u.z*v.y, u.z*v.x-u.x*v.z, u.x*v.y-u.y*v.x);
}


Вычисление определителя матрицы 3х3

float mat3 :: det () const
{
    return x [0][0]*(x [1][1]*x [2][2]-x [1][2]*x [2][1]) -
           x [0][1]*(x [1][0]*x [2][2]-x [1][2]*x [2][0]) +
           x [0][2]*(x [1][0]*x [2][1]-x [1][1]*x [2][0]);
}


Вычисление объема 3D Mesh'а

Пусть O - точка лежащая внутри мэша. Тогда для нахождения объема мэша для каждого треугольника AiBiCi находится ориентированный объем тетраэдра OAiBiCi как 1/6 смешанного произведения (Ai-O)(Bi-O)(Ci-O) и суммируя по всем таким треугольникам.

inline float mixedProduct ( const vec3& a, const vec3& b, const vec3& c )
{
	return dot ( a, cross ( b, c ) );
}

float Mesh :: volume ( const vec3& c )
{
    float vol = 0;

    for ( int i = 0; i < numTris; i++ )
        vol += mixedProduct ( tris [i].point [0] - c, tris [i].point [1] - c, tris [i].point [2] - c );
	
    return fabs ( col / 6.0f );
}


Как в скелетной анимации запаковать boneId и weight в один float

Паковка:

float floatValue = 0.5*boneWieght + (float) boneId;

Распаковка:

float	boneWeight = fract ( floatValue ) * 2.0;
int		boneId     = (int)floor ( floatValue );



Как запаковать нормаль в один float

Поскольку нормаль единичная, то нам достаточно запаковать только первые две компоненты и знак nz

Паковка:

float nx         = 0.5 * ( n.x + 1 );       // remap from [-1,1] to [0,1]
float ny         = 0.5 * ( n.y + 1 );       // remap from [-1,1] to [0,1]
float floatValue = fract ( 100.0 * nx ) + ny / 1000.0;

if ( n.z < 0.0 )                            // floatValue cannot be greater than 101.0
    floatValue += 200;

Распаковка:

bool	neg = false;

if ( floatValue > 102.0 )
{
    neg         = true;
    floatValue -= 200.0;
}

float ny = 2.0 * fract ( floatValue ) * 1000.0 - 1.0;
float nx = 2.0 * floor ( floatValue ) * 0.01 - 1.0;
vec3  n = vec3 ( nx, ny, sqrt ( 1.0 - nx * nx - ny * ny );

if ( neg )
    n.z = -n.z;



Как определить попадает ли сфера с усеченную пирамиду видимости

Пусть усеченная пирамида видимости задается шестью плоскостями (p,n)=d, где n - единичный вектор нормали к плоскости, а d - расстояние от плоскости до начала координат со знаком.

Будем считать, что нормаль для каждой плоскости ориентирована таким образом, что усеченная пирамида лежит в полупространстве (p,n)>d.

Тогда для проверки того, попадает ли сфера заданного радиуса с заданным центром в пирамиду видимости (хотя бы частично), можно использовать следующий фрагмент кода:

bool Frustum :: sphereIntersects ( const vec3& c, float radius ) const
{
    for ( int i = 0; i < 6; i++ )
        if ( dot ( plane [i].n, c ) < plane [i] - radius )
            return false;

    return true;
}



Округление вверх к степени двух

// compute the next highest power of 2 of 32-bit v
unsigned rountToPowerOfTwo ( unsigned v )
{
    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
	
    return ++v;
}


Сохранение float из [0,1) как 4 8-битовых (RGBA)

inline vec4 encodeFloatToRGBA ( float v ) 
{
    float4 enc = vec4 ( 1.0, 255.0, 65025.0, 160581375.0) * v;
	
    enc  = frac ( enc );
    enc -= enc.yzww * vec4 (1.0/255.0, 1.0/255.0, 1.0/255.0, 0.0 );
	
    return enc;
}
inline float decodeFloatFromRGBA ( vec44 rgba )
{
  return dot ( rgba, vec4 ( 1.0, 1/255.0, 1/65025.0, 1/160581375.0) );
}


Определитель матрицы 4x4

det(M) =
	(m [0][0] * m [1][1] - m [0][1] * m [1][0]) * (m [2][2] * m [3][3] - m [2][3] * m [3][2]) -
	(m [0][0] * m [1][2] - m [0][2] * m [1][0]) * (m [2][1] * m [3][3] - m [2][3] * m [3][1]) +
	(m [0][0] * m [1][3] - m [0][3] * m [1][0]) * (m [2][1] * m [3][2] - m [2][2] * m [3][1]) +
	(m [0][1] * m [1][2] - m [0][2] * m [1][1]) * (m [2][0] * m [3][3] - m [2][3] * m [3][0]) -
	(m [0][1] * m [1][3] - m [0][3] * m [1][1]) * (m [2][0] * m [3][2] - m [2][2] * m [3][0]) +
	(m [0][2] * m [1][3] - m [0][3] * m [1][2]) * (m [2][0] * m [3][1] - m [2][1] * m [3][0]);


Обнуление младшего ненулевого бита

n &= n - 1;


Упаковка float <-> byte

float byte2float ( byte b )
{
   return b / 255.0f;
}

byte float2byte ( float f )
{
   return int ( f * 255 + 0.5 )
}


Проверить поддержку расширения в OpenGL

Для OpenGL 1-2.1 список всех расширений, разделенных пробелами можно получить из функции glGetString

bool isExtensionSupported ( const char * name )
{
    const char * exts = (const char *) glGetString ( GL_EXTENSIONS );
    const char * ptr;

    while ( ( ptr = strstr ( start, name ) ) != NULL )
    {
										// we've found, ensure name is exactly ext
	    const char * end = ptr + strlen ( name );

	    if ( isspace ( *end ) || *end == '\0' )
		    return true;

	    start = end;
    }
    return false;
}

Для OpenGL 3 и выше этот способ объявлен deprecated и следует использовать функцию glGetStringi, которая по номеру возврщает имя одного расширения.

bool isExtensionSupported ( const char * name )
{
    GLint num;
	
    glGetIntegerv ( GL_NUM_EXTENSIONS, &num );

    for ( int i = 0; i < num; i++ )
        if ( strcmp ( glGetStringi ( GL_EXTENSIONS, i ), name ) == 0 )
            return true;

    return false;
}

Также это можно сделать используя библиотеку GLEW - после ее инициаолизации можно использовать функцию glewIsSupported или же просто проверить соответствующую константу - каждому расширению вида GL_xxx соотвествует константа GLEW_xxx, отличная от нуля в случае проверки расширения.

Так для проверки расширения GL_ARB_debug_output можно или использовать вызов glewIsSupported("GL_ARB_debug_output") или просто проверить на отличие от нуля константы GLEW_ARB_debug_output.



Как узнать объем памяти на GPU

Для Nvidia -

#define GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX 0x9048
#define GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX 0x9049

int	getNvTotalMemory ()
{
    GLint totalMemKb = 0;

    glGetIntegerv ( GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX, &totalMemKb );

    return totalMemKb;
}

Для ATI/AMD

int	getAtiTotalMemory ()
{
    UINT   n          = wglGetGPUIDsAMD ( 0, 0 );
    UINT * ids        = new UINT[n];
    size_t totalMemMb = 0;

    wglGetGPUIDsAMD  ( n, ids );
    wglGetGPUInfoAMD ( ids[0], WGL_GPU_RAM_AMD, GL_UNSIGNED_INT, sizeof(size_t), &totalMemMb );

    delete ids;

    return totalMemMb * 1024;
}