1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
| #version 330 core
precision highp float;
uniform int numberQuadric;
struct QuadricData
{
// ax^2 + by^2 + cz^2 + 2dxy + 2exz + 2fyz + gx + hy + iz + j = 0
float a, b, c, d, e, f, g, h, i, j;
// Intervalle
float xMin, xMax, yMin, yMax, zMin, zMax;
// Couleur
float rColor, gColor, bColor;
float useless;
};
uniform Camera
{
float xPos, yPos, zPos;
float xDir, yDir, zDir;
float xUp, yUp, zUp;
float cotanHalfFovY;
int width, height;
}camera;
uniform Quadric
{
QuadricData q[500];
}quadric;
out vec4 color;
// Si inférieur, c'est 0
float minZero = 0.001;
float computeDistQuadric(in vec3 ro, in vec3 rd, in QuadricData q, out vec3 pointIntersect)
{
/* Equation d'une quadric :ax² + bx² + cx² + 2dxy + 2exz + 2fyz + gx + hy + iz + j = 0
(x, y, z) = ro + dist*rd;
Objectif : Calculer la distance dist
*/
/* On se ramène à une équation en a*dist^2 + b*dist + c */
// a = partie en dist^2
float a = q.a * rd.x * rd.x + q.b * rd.y * rd.y + q.c * rd.z * rd.z + 2 * q.d * rd.x * rd.y + 2 * q.e * rd.x * rd.z + 2 * q.f * rd.y * rd.z;
// b Partie en dist
float b = 2 * (q.a * rd.x * ro.x + q.b * rd.y * ro.y + q.c * rd.z * ro.z + q.d * (rd.x * ro.y + rd.y * ro.x) + q.e * (rd.x * ro.z + rd.z + ro.x) + q.f * (rd.y * ro.z + rd.z * ro.y)) + q.g * rd.x + q.h * rd.y + q.i * rd.z;
// c Partie Constante
float c = q.a * ro.x * ro.x + q.b * ro.y * ro.y + q.c * ro.z * ro.z + 2 * q.d * ro.x * ro.y + 2 * q.e * ro.x * ro.z + 2 * q.f * ro.y * ro.z + q.g * ro.x + q.h * ro.y + q.i * ro.z + q.j;
if(abs(a) < minZero)
return -c / b;
float delta = b * b - 4.0 * a * c;
// Il n'y a pas d'intersection
if(delta < 0.0)
return -1.0;
// On récupère les distances
float disc = sqrt(delta);
float dist1 = (-b - disc) / (2.0 * a);
float dist2 = (-b + disc) / (2.0 * a);
// On récupère la bonne distance
float goodDistance;
// Les intersections sont derrières
if(dist1 < 0.0 && dist2 < 0.0)
return -1.0;
if(dist1 > 0.0)
goodDistance = dist1;
// Distance 2 plus petites que la première
if((dist2 > 0.0 && dist1 > 0.0) && dist2 < dist1)
goodDistance = dist2;
if(dist2 > 0.0 && dist1 < 0.0)
goodDistance = dist2;
pointIntersect = ro + goodDistance * rd;
// Test l'interval
if(pointIntersect.x < q.xMin || pointIntersect.x > q.xMax ||
pointIntersect.y < q.yMin || pointIntersect.y > q.yMax ||
pointIntersect.z < q.zMin || pointIntersect.z > q.zMax)
return -1.0;
return goodDistance;
}
void intersect(in vec3 ro, in vec3 rd)
{
color = vec4(0.0);
float lessDist = 100000.0;
int i;
vec3 pointIntersect;
float dist;
for(i = 0; i < numberQuadric; ++i)
{
dist = computeDistQuadric(ro, rd, quadric.q[i], pointIntersect);
// Si la distance d'intersection est plus petite que l'ancienne (z-Buffer)
if(dist > 0.0 && dist < lessDist)
{
color = vec4(quadric.q[i].rColor, quadric.q[i].gColor, quadric.q[i].bColor, 1.0);
lessDist = dist; // On met à jour la nouvelle distance
}
}
}
void main(void)
{
float i = (gl_FragCoord.x / camera.width) * 2.0 - 1.0;
float j = (gl_FragCoord.y / camera.height) * 2.0 - 1.0;
vec3 ro = vec3(camera.xPos, camera.yPos, camera.zPos);
vec3 dir = vec3(camera.xDir, camera.yDir, camera.zDir);
vec3 up = vec3(camera.xUp, camera.yUp, camera.zUp);
vec3 right = cross(dir, up);
// On recalcule le up pour avoir les 3 axes de telle sorte qu'elle forme une base orthonormal
up = cross(right, dir);
vec3 rd = normalize(camera.cotanHalfFovY * dir + i * right + j * up);
intersect(ro, rd);
} |
Partager