Главная Статьи Ссылки Скачать Скриншоты Юмор Почитать 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
Как повернуть вектор при помощи кватерниона
Как получить 2D AABB при проектировании сферы
Как перевести единичный 3D вектор в две компоненты и потом восстановить
Gradient from noise Jorge Jimenez's presentation
|
||
Пусть заданы две точки a и b тогда прямая, проходящая через них задается уравнением: \( p = a+t \cdot (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 \cdot l \) и плоскость \( (p,n)=d \). Тогда прямая лежит в плоскости, если выполнены следующие два условия: \( (p-a,n) = d \) и \( (l,n)=0 \). |
|
||
По каждому отрезку строим разницы координат - \( (dx_1,dy_1) \) и \( (dx_2,dy_2) \). Если один из отрезков имеет нулевую длину, то он параллелен любому отрезку. Если dx1==0, то отрезки параллельны тогда и только тогда, когда dx2==0. Иначе у отрезков должны совпадать соотношения приращений по x и y, т.е. должно быть выполнено соотношение: \( dy_1 \cdot dx_2 = dy_2 \cdot dx_1 \).
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;
}
В трехмерном случае появляется еще одно соотношение - \( dz_1 \cdot dx_2 = dz_2 \cdot dx_1 \). |
|
||
Число 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 = u_0 + t \cdot l \). Тогда для произвольного значения параметра t квадрат расстояния от P до u(t) задается следующей формулой (считая, что l - единичный вектор): \( (P - u_0, P - u_0 ) + 2 \cdot t \cdot ( P - u_0, l ) + t^2 \) Минимальное значение эта функция принимает при \( t' = (P - u_0, 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 |
|
Пересечение луча и плоскости |
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) |
|
Площадь многоугольника со знаком (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 |
|
Пересечение луча и треугольника |
#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 = p_1 + t \cdot l_1 \) и \( p = p_2 + t \cdot l_2 \). Тогда нормаль плоскости, параллельной этим двум прямым будет задаваться формулой \( n = [l_1, l_2] \). Если вектор n нулевой (или почти нулевой), то прямые параллельны. В противном случае они либо пересекаются (и тогда лежат в одной плоскости) или скрещивающиеся. Чтобы проверить лежат ли они в одной плоскости достаточно проверить лежат ли точки \( p_1 \) и \( p_2 \) в плоскости с нормалью n. Это выполнено тогда и только тогда, когда \( ( n, p_1) = (n, p_2) \). |
Матрица поворота вокруг вектора на заданный угол |
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 - точка лежащая внутри мэша. Тогда для нахождения объема мэша для каждого треугольника \( A_iB_iC_i \) находится ориентированный объем тетраэдра \( OA_iB_iC_i \) как 1/6 смешанного произведения \( (A_i - O)(B_i - O)(C_i - 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; } |
|
||
// rotate 3D vector by quaternion q
vec3 rotateQuat ( vec3 v, vec4 q )
{
return v + 2.0 * cross ( q.xyz, cross ( q.xyz, v ) + q.w * v );
}
|
|
||
// 2D Polyhedral Bounds of a Clipped, Perspective-Projected 3D Sphere. Michael Mara, Morgan McGuire. 2013
bool projectSphere ( vec3 c, float r, float zNear, float P00, float P11, out vec4 aabb )
{
if ( c.z < r + zNear )
return false;
vec3 cr = c * r;
float czr2 = c.z * c.z - r * r;
float vx = sqrt ( c.x * c.x + czr2 );
float minx = ( vx * c.x - cr.z ) / ( vx * c.z + cr.x );
float maxx = ( vx * c.x + cr.z ) / ( vx * c.z - cr.x );
float vy = sqrt ( c.y * c.y + czr2 );
float miny = ( vy * c.y - cr.z ) / ( vy * c.z + cr.y );
float maxy = ( vy * c.y + cr.z ) / ( vy * c.z - cr.y );
aabb = vec4 ( minx * P00, miny * P11, maxx * P00, maxy * P11 );
aabb = aabb.xwzy * vec4 ( 0.5, -0.5, 0.5, -0.5 ) + vec4 ( 0.5 ); // clip space -> uv space
return true;
}
|
|
||
// A Survey of Efficient Representations for Independent Unit Vectors
vec2 encodeOct ( vec3 v )
{
vec2 p = v.xy * (1.0 / (abs(v.x) + abs(v.y) + abs(v.z)));
vec2 s = vec2 ((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);
vec2 r = (v.z <= 0.0) ? ((1.0 - abs(p.yx)) * s) : p;
return r;
}
vec3 decodeOct ( vec2 e )
{
vec3 v = vec3 ( e.xy, 1.0 - abs ( e.x ) - abs ( e.y ));
vec2 s = vec2 ((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);
v.xy = v.z < 0 ? (1.0 - abs ( v.yx ) ) * s : v.xy;
return normalize ( v );
}
|
Gradient from noise Jorge Jimenez's presentation: http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare |
float gradientNoise(vec2 uv)
{
return fract ( 52.9829189 * fract ( dot ( uv, vec2 ( 0.06711056, 0.00583715 ))));
}
|