Главная Статьи Ссылки Скачать Скриншоты Юмор Почитать Tools Обо мне Гостевая Форум |
В этом разделе я буду выкладывать маленькие фрагменты кода, используемые для решения простых задач, однако необходимость в которых возникает довольно регулярно.
Как получить уравнение прямой по двум точкам.
Как получить уравнение плоскости по трем точкам.
Параллельны ли два отрезка AB и CD.
Является ли число степенью двойки
Число единичных битов в 32-битовом слове.
Получение случайной точки, равномерно распределенной на сфере.
Получение случайной точки, равномерно распределенной в треугольнике ABC.
Расстояние от точки до прямой AB.
Сохранение 24-битового значения (из [0,1]) как 3 8-битовых.
Сохранение float из [0,1) как 4 8-битовых (RGBA).
Расстояние от точки до отрезка.
Окружность, проходящая через три точки a, b и c.
Аналог угла, без использования тригонометрических функций.
Площадь многоугольника со знаком (2D).
Площадь многоугольника со знаком (3D).
Поворот вектора v при помощи кватерниона q.
Пересечение луча и треугольника.
Лежит ли точка внутри полигона (2D)
Как узнать направление обхода двухмерного многоугольника.
Является ли многоугольник выпуклым.
Как узнать расстояние между двумя прямыми в 3D
Классификация двух прямых в 3D (являются ли они скрещивающимися, параллельными или пересекающимися)
Матрица поворота вокруг вектора на заданный угол
Матрица поворота по кватерниону
Векторное произведение двух векторов
Вычисление определителя матрицы 3х3
Как в скелетной анимации запаковать boneId и weight в один float
Как запаковать нормаль в один float
Как определить попадает ли сфера с усеченную пирамиду видимости
Округление вверх к степени двух
Обнуление младшего ненулевого бита
Проверить поддержку расширения 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. |
|
||
По каждому отрезку строим разницы координат - (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; } |