Améliorations sur QuadRoutes, utilisation du cm comme unité de base.

This commit is contained in:
Georges Dupéron 2011-12-03 00:51:06 +01:00
parent 11f2948558
commit 61ea30e35d
11 changed files with 136 additions and 62 deletions

View File

@ -16,12 +16,13 @@ void recursiveSubdivide(Chose* c) {
int main() {
// Générer une tile de base
int size = 50;
int size = 20000;
Vertex ne(size, size, 0);
Vertex se(size, 0, 0);
Vertex sw(0, 0, 0);
Vertex nw(0, size, 0);
Chose* c = new QuadRoutes(ne,se,sw,nw);
// c->subdivide();
recursiveSubdivide(c);
new View(c);

View File

@ -17,12 +17,13 @@ bool Batiment::subdivide() {
void Batiment::triangulation() {
triangles.reserve(12);
int h = hashInRange(seed,0,4,8);
int h = hashInRange(seed,0,minHeight,maxHeight);
int htoit = hashInRange(seed,0,minHeight/2,maxHeight/2);
Vertex neh = ne + Vertex(0,0,h);
Vertex seh = se + Vertex(0,0,h);
Vertex nwh = nw + Vertex(0,0,h);
Vertex swh = sw + Vertex(0,0,h);
Vertex toit = (neh + seh + nwh + swh) / 4 + Vertex(0,0,h/2);
Vertex toit = (neh + seh + nwh + swh) / 4 + Vertex(0,0,htoit);
// 4 Murs
addTriangle(new Triangle(neh,seh,ne,0xf1,0xe3,0xad)); addTriangle(new Triangle(seh,se,ne,0xf1,0xe3,0xad)); // ne-se-seh-neh

View File

@ -10,6 +10,9 @@ public:
Vertex se;
Vertex sw;
Vertex nw;
public:
static const int minHeight = 400;
static const int maxHeight = 800;
public:
Batiment(Vertex ne, Vertex se, Vertex sw, Vertex nw);
int width();

View File

@ -20,6 +20,6 @@ std::ostream& operator<<(std::ostream& os, const Carrefour& c) {
void Carrefour::triangulation() {
triangles.reserve(2);
addTriangle(new Triangle(ne, nw, sw, 0x80, 0x80, 0x80));
addTriangle(new Triangle(sw, se, ne, 0x80, 0x80, 0x80));
addTriangle(new Triangle(ne, nw, sw, 0x36, 0x36, 0x36));
addTriangle(new Triangle(sw, se, ne, 0x36, 0x36, 0x36));
}

View File

@ -11,25 +11,44 @@ int QuadRoutes::height() { return std::abs(this->ne.y - this->sw.y); }
bool QuadRoutes::subdivide() {
children.reserve(9);
int minchildsize = 4;
int lx = std::floor(std::min((nw-ne).norm(), (sw-se).norm()));
// constraint: lx - maxdelta*2 ≥ minchildsize
// constraint: maxdelta ≤ lx/4
int maxdelta = std::min(lx/4, (lx-minchildsize)/2);
float xpos = (lx/2.f + hashInRange(seed, 0, -maxdelta, maxdelta)) / (float)lx; // xpos \in 0..1
Vertex n = nw * xpos + ne * (1-xpos);
// TODO : faire ces calculs sur des Vertex2d.
int splitXMin = this->sw.x + std::max(4, this->width()*1/4);
int splitXMax = this->ne.x - std::max(4, this->width()*1/4);
int splitYMin = this->sw.y + std::max(4, this->height()*1/4);
int splitYMax = this->ne.y - std::max(4, this->height()*1/4);
Vertex split(
hashInRange(this->seed, 0, splitXMin, splitXMax),
hashInRange(this->seed, 1, splitYMin, splitYMax),
0 // TODO
);
// TODO : addChild(…);
addChild(new Carrefour(split + Vertex(1,1,0), split + Vertex(1,-1,0), split + Vertex(-1,-1,0), split + Vertex(-1,1,0)));
int slen = (se-sw).norm();
int nlen = (ne-nw).norm();
int minsnlen = std::min(slen,nlen);
// constraint: min(slen, nlen) - maxdelta*2 ≥ minchildsize
// constraint: maxdelta ≤ min(slen,nlen)/4
int xmaxdelta = std::min(minsnlen/4, (minsnlen-minchildsize)/2);
float sxpos = slen/2 + hashInRange(seed, 0, -xmaxdelta, xmaxdelta);
float nxpos = nlen/2 + hashInRange(seed, 0, -xmaxdelta, xmaxdelta);
Vertex s = (sw * sxpos / slen) + (se * (slen - nxpos) / slen);
Vertex n = (nw * nxpos / nlen) + (ne * (nlen - nxpos) / nlen);
int wlen = (nw-sw).norm();
int elen = (ne-se).norm();
int minwelen = std::min(wlen,elen);
// constraint: min(wlen, elen) - maxdelta*2 ≥ minchildsize
// constraint: maxdelta ≤ min(wlen,elen)/4
int ymaxdelta = std::min(minwelen/4, (minwelen-minchildsize)/2);
float wypos = wlen/2 + hashInRange(seed, 0, -ymaxdelta, ymaxdelta);
float eypos = elen/2 + hashInRange(seed, 0, -ymaxdelta, ymaxdelta);
Vertex w = (nw * wypos / wlen) + (sw * (wlen - wypos) / wlen);
Vertex e = (ne * eypos / elen) + (se * (elen - eypos) / elen);
Vertex split = intersection(s,n,w,e);
// TODO : Pour offset les points des extrémités de la route w--split :
// Vertex offset = vecteur perpendiculaire w--split, de longueur hrw.
// Projeter `offset` sur split--n, et ajouter le résultat à split.
// Projeter `offset` sur w--nw, et ajouter le résultat à w.
// Projeter u sur v : (u scalaire v) / v.norm().
// scalaire(u,v) = u.norm() * v.norm() * cos(angle(u,v))
// Donc projeter u sur v : u.norm() * cos(angle(u,v))
// TODO : comment calculer l'angle(u,v) ?
addChild(new Carrefour(split + Vertex(hrw,hrw,0), split + Vertex(hrw,-hrw,0), split + Vertex(-hrw,-hrw,0), split + Vertex(-hrw,hrw,0)));
// routes au NESW du carrefour
// TODO : la plupart des zéros en z sont faux…
Vertex roadEndN(split.x, this->ne.y, 0);
@ -37,10 +56,10 @@ bool QuadRoutes::subdivide() {
Vertex roadEndS(split.x, this->sw.y, 0);
Vertex roadEndW(this->sw.x, split.y, 0);
// TODO : addChild(…);
Route* rn = new Route(roadEndN + Vertex(+1,0,0), split + Vertex(+1,+1,0), split + Vertex(-1,+1,0), roadEndN + Vertex(-1,0,0)); // N
Route* re = new Route(roadEndE + Vertex(0,+1,0), roadEndE + Vertex(0,-1,0), split + Vertex(+1,-1,0), split + Vertex(+1,+1,0)); // E
Route* rs = new Route(split + Vertex(+1,-1,0), roadEndS + Vertex(+1,0,0), roadEndS + Vertex(-1,0,0), split + Vertex(-1,-1,0)); // S
Route* rw = new Route(split + Vertex(-1,+1,0), split + Vertex(-1,-1,0), roadEndW + Vertex(0,-1,0), roadEndW + Vertex(0,+1,0)); // W
Route* rn = new Route(roadEndN + Vertex(+hrw,0,0), split + Vertex(+hrw,+hrw,0), split + Vertex(-hrw,+hrw,0), roadEndN + Vertex(-hrw,0,0)); // N
Route* re = new Route(roadEndE + Vertex(0,+hrw,0), roadEndE + Vertex(0,-hrw,0), split + Vertex(+hrw,-hrw,0), split + Vertex(+hrw,+hrw,0)); // E
Route* rs = new Route(split + Vertex(+hrw,-hrw,0), roadEndS + Vertex(+hrw,0,0), roadEndS + Vertex(-hrw,0,0), split + Vertex(-hrw,-hrw,0)); // S
Route* rw = new Route(split + Vertex(-hrw,+hrw,0), split + Vertex(-hrw,-hrw,0), roadEndW + Vertex(0,-hrw,0), roadEndW + Vertex(0,+hrw,0)); // W
addChild(rn);
addChild(re);
addChild(rs);
@ -63,7 +82,7 @@ void QuadRoutes::triangulation() {
Chose* QuadRoutes::sub(Vertex ne, Vertex sw) {
Segment rect = Segment(ne,sw);
if (rect.width() < 10 || rect.height() < 10) {
if (rect.width() < minQuadSize || rect.height() < minQuadSize) {
return new Batiment(ne, Vertex(ne.x, sw.y, 0), sw, Vertex(sw.x, ne.y, 0));
} else {
return new QuadRoutes(ne, Vertex(ne.x, sw.y, 0), sw, Vertex(sw.x, ne.y, 0));

View File

@ -10,17 +10,20 @@ public:
Vertex se;
Vertex sw;
Vertex nw;
public:
static const int hrw = 250; // half road width : 2,50m.
static const int minchildsize = 1000;
static const int minQuadSize = 2500;
public:
QuadRoutes(Vertex ne, Vertex se, Vertex sw, Vertex nw);
int width();
int height();
virtual bool subdivide();
virtual void triangulation();
private:
Chose* sub(Vertex ne, Vertex sw);
public:
friend std::ostream& operator<<(std::ostream& os, const QuadRoutes& r);
friend std::ostream& operator<<(std::ostream& os, const QuadRoutes* r);
private:
Chose* sub(Vertex ne, Vertex sw);
};

View File

@ -21,6 +21,6 @@ std::ostream& operator<<(std::ostream& os, const Route& r) {
void Route::triangulation() {
triangles.reserve(2);
addTriangle(new Triangle(ne, nw, sw, 0x6c, 0x6c, 0x6c));
addTriangle(new Triangle(sw, se, ne, 0x6c, 0x6c, 0x6c));
addTriangle(new Triangle(ne, nw, sw, 0x36, 0x36, 0x36));
addTriangle(new Triangle(sw, se, ne, 0x36, 0x36, 0x36));
}

View File

@ -14,25 +14,8 @@ std::ostream& operator<<(std::ostream& os, const Triangle& t) {
}
Vertexf Triangle::normalVector(Vertex v1, Vertex v2, Vertex v3) {
int ax = v1.x - v2.x;
int ay = v1.y - v2.y;
int az = v1.z - v2.z;
int bx = v2.x - v3.x;
int by = v2.y - v3.y;
int bz = v2.z - v3.z;
Vertexf normal;
float x = (float)((ay * bz) - (az * by));
float y = (float)((az * bx) - (ax * bz));
float z = (float)((ax * by) - (ay * bx));
float length = sqrt(x*x + y*y + z*z);
normal.x = x/length;
normal.y = y/length;
normal.z = z/length;
return normal;
Vertexf normal = (v1 - v2)*(v2 - v3);
return normal / normal.norm();
}
void Triangle::display() {
@ -41,16 +24,16 @@ void Triangle::display() {
// glBegin(GL_LINES);
// glColor3ub(255,255,0);
// Vertex v = (v1 + v2 + v3) / 3;
// glVertex3d(v.x*10,v.y*10,v.z*10);
// glVertex3d(v.x*10+normal.x*50,v.y*10+normal.y*50,v.z*10+normal.z*50);
// glVertex3d(v.x,v.y,v.z);
// glVertex3d(v.x+normal.x*50,v.y+normal.y*50,v.z+normal.z*50);
// glEnd( );
// glEnable(GL_LIGHTING);
View::setColor(r,g,b);
glNormal3d(normal.x,normal.y,normal.z);
glBegin(GL_TRIANGLES);
glVertex3d(v1.x*10,v1.y*10,v1.z*10);
glVertex3d(v2.x*10,v2.y*10,v2.z*10);
glVertex3d(v3.x*10,v3.y*10,v3.z*10);
glEnd();
// glBegin(GL_TRIANGLES);
glVertex3d(v1.x,v1.y,v1.z);
glVertex3d(v2.x,v2.y,v2.z);
glVertex3d(v3.x,v3.y,v3.z);
// glEnd();
}

View File

@ -6,6 +6,25 @@ Vertex::Vertex(int x, int y, int z): x(x), y(y), z(z) {}
float Vertex::norm() { return std::sqrt(x*x + y*y + z*z); }
// TODO : this is 2D only, use Vertex2d.
Vertex intersection(Vertex a, Vertex b, Vertex c, Vertex d) {
// Note : si les deux lignes sont parallèles, on risque fort
// d'avoir une division par zéro.
// http://en.wikipedia.org/wiki/Line-line_intersection
long long x1 = a.x; long long y1 = a.y;
long long x2 = b.x; long long y2 = b.y;
long long x3 = c.x; long long y3 = c.y;
long long x4 = d.x; long long y4 = d.y;
long long denominator = ((x1-x2)*(y3-y4) - (y1-y2)*(x3-x4));
return Vertex(
((x1*y2-y1*x2)*(x3-x4) - (x1-x2)*(x3*y4-y3*x4)) / denominator,
((x1*y2-y1*x2)*(y3-y4) - (y1-y2)*(x3*y4-y3*x4)) / denominator,
0
);
}
Vertex::operator Vertexf() { return Vertexf(x,y,z); }
std::ostream& operator<<(std::ostream& os, const Vertex& v) {
return os << "(" << v.x << "," << v.y << "," << v.z << ")";
}
@ -34,10 +53,22 @@ Vertex operator*(const Vertex& v, const int n) {
return Vertex(v.x * n, v.y * n, v.z * n);
}
Vertex operator*(const Vertex& u, const Vertex& v) {
return Vertex(
(u.y * v.z) - (u.z * v.y),
(u.z * v.x) - (u.x * v.z),
(u.x * v.y) - (u.y * v.x)
);
}
Vertex operator/(const Vertex& v, const int n) {
return Vertex(v.x / n, v.y / n, v.z / n);
}
Vertex operator/(const Vertex& v, const float f) {
return Vertex(v.x / f, v.y / f, v.z / f);
}
Vertex Vertex::fromSpherical(float r, float xAngle, float yAngle) {
// http://electron9.phys.utk.edu/vectors/3dcoordinates.htm
return Vertex(
@ -56,6 +87,8 @@ Vertexf::Vertexf(float x, float y, float z): x(x), y(y), z(z) {}
float Vertexf::norm() { return std::sqrt(x*x + y*y + z*z); }
Vertexf::operator Vertex() { return Vertex(x,y,z); }
std::ostream& operator<<(std::ostream& os, const Vertexf& v) {
return os << "(" << v.x << "," << v.y << "," << v.z << ")";
}
@ -84,10 +117,22 @@ Vertexf operator*(const Vertexf& v, const int n) {
return Vertexf(v.x * n, v.y * n, v.z * n);
}
Vertexf operator*(const Vertexf& u, const Vertexf& v) {
return Vertexf(
(u.y * v.z) - (u.z * v.y),
(u.z * v.x) - (u.x * v.z),
(u.x * v.y) - (u.y * v.x)
);
}
Vertexf operator/(const Vertexf& v, const int n) {
return Vertexf(v.x / n, v.y / n, v.z / n);
}
Vertexf operator/(const Vertexf& v, const float f) {
return Vertexf(v.x / f, v.y / f, v.z / f);
}
Vertexf Vertexf::fromSpherical(float r, float xAngle, float yAngle) {
// http://electron9.phys.utk.edu/vectors/3dcoordinates.htm
return Vertexf(

View File

@ -15,14 +15,18 @@ class Vertex {
Vertex(int x, int y, int z);
float norm();
static Vertex fromSpherical(float r, float xAngle, float yAngle);
friend Vertex intersection(Vertex a, Vertex b, Vertex c, Vertex d); // Intersection entre (a,b) et (c,d).
public:
operator Vertexf();
friend std::ostream& operator<<(std::ostream& os, const Vertex& v);
friend Vertex operator+(const Vertex& u, const Vertex& v);
friend Vertex operator-(const Vertex& u, const Vertex& v);
friend Vertex operator-(const Vertex& v);
friend Vertex operator*(const Vertex& v, const int n);
friend Vertex operator*(const Vertex& u, const Vertex& v);
friend Vertex operator/(const Vertex& v, const int n);
friend Vertex operator/(const Vertex& v, const float f);
friend Vertex operator+(const Vertex& u, const Vertexf& v);
friend Vertex operator-(const Vertex& u, const Vertexf& v);
};
@ -40,12 +44,15 @@ class Vertexf {
static Vertexf fromSpherical(float r, float xAngle, float yAngle);
public:
operator Vertex();
friend std::ostream& operator<<(std::ostream& os, const Vertexf& v);
friend Vertexf operator+(const Vertexf& u, const Vertexf& v);
friend Vertexf operator-(const Vertexf& u, const Vertexf& v);
friend Vertexf operator-(const Vertexf& v);
friend Vertexf operator*(const Vertexf& v, const int n);
friend Vertexf operator*(const Vertexf& u, const Vertexf& v);
friend Vertexf operator/(const Vertexf& v, const int n);
friend Vertexf operator/(const Vertexf& v, const float f);
friend Vertexf operator+(const Vertexf& u, const Vertex& v);
friend Vertexf operator-(const Vertexf& u, const Vertex& v);
};

View File

@ -1,6 +1,6 @@
#include "all_includes.hh"
View::View(Chose* root) : root(root), camera(Camera(Vertexf(420,468,151),230,108,40,0.6)) {
View::View(Chose* root) : root(root), camera(Camera(Vertexf(1000,1000,2000),45,100,1000,0.6)) {
initWindow();
mainLoop();
}
@ -21,7 +21,7 @@ void View::initWindow() {
SDL_SetVideoMode(windowWidth, windowHeight, 32, SDL_OPENGL);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective(70,(double)windowWidth/windowHeight,1,10000);
gluPerspective(70,(double)windowWidth/windowHeight,1,100000); // back frustum : 1km
glEnable(GL_DEPTH_TEST);
glewInit();
@ -40,7 +40,7 @@ void View::initWindow() {
}
void View::setLight() {
float Light1Pos[4] = {0.5f, 1.0f, 1.0f, 0.0f};
float Light1Pos[4] = {-0.5f, -1.0f, 1.0f, 0.0f};
float Light1Dif[4] = {1.0f, 1.0f, 1.0f, 1.0f};
float Light1Spec[4] = {0.0f, 0.0f, 0.0f, 1.0f};
float Light1Amb[4] = {0.2f, 0.2f, 0.2f, 1.0f};
@ -88,7 +88,9 @@ void View::renderScene(int lastTime, int currentTime) {
setLight();
//displayAxes();
glBegin(GL_TRIANGLES);
root->display();
glEnd();
glFlush();
SDL_GL_SwapBuffers();
@ -189,8 +191,18 @@ void Camera::keyboard(const SDL_KeyboardEvent &eventKey) {
case 'q':
exit(0);
break;
case 's':
if (eventKey.type != SDL_KEYDOWN) break;
moveDist = std::min(50000,std::max(moveDist+1, moveDist*10/9));
break;
case 'x':
if (eventKey.type != SDL_KEYDOWN) break;
moveDist = std::max(10, moveDist*9/10);
break;
case 'p': // _Print _Position
if (eventKey.type != SDL_KEYDOWN) break;
std::cout << *this << std::endl;
break;
default:
break;
}