Subdivision bâtiments triangulaires.

This commit is contained in:
Georges Dupéron 2012-01-20 13:46:24 +01:00
parent 4b258d1cc6
commit 8db867a104
14 changed files with 243 additions and 49 deletions

View File

@ -41,4 +41,29 @@ public :
Triangle insetProportionnal(float prop);
};
class TriBool {
private:
bool c[3];
public :
TriBool();
TriBool(bool leftside, bool rightside, bool base) {
c[LEFTSIDE] = leftside;
c[RIGHTSIDE] = rightside;
c[BASE] = base;
};
inline bool& operator[] (CoteTriangle x) {
return c[x];
}
inline const bool& operator[] (CoteTriangle x) const {
return c[x];
}
inline TriBool operator>> (int rot) const {
return TriBool(c[LEFTSIDE - rot], c[RIGHTSIDE - rot], c[BASE - rot]);
}
inline TriBool operator<< (int rot) const {
return TriBool(c[LEFTSIDE + rot], c[RIGHTSIDE + rot], c[BASE + rot]);
}
};
#endif

View File

@ -63,7 +63,6 @@ void BatimentQuad::sousBatiments() {
}
void BatimentQuad::etages() {
// TODO : indiquer aux bâtiments où est-ce qu'ils peuvent faire des fenêtres.
float randEtages = floatInRange(seed, 0, 0.f, 1.f);
int nbEtages = 1 + (int)(randEtages * randEtages * (Dimensions::maxEtages - 1));
Quad q = c; // c.insetNESW(30)
@ -91,21 +90,92 @@ void BatimentQuad::getBoundingBoxPoints() {
addBBPoints(c, Dimensions::hauteurEtage * 2 + Dimensions::hauteurToit);
}
BatimentTri_::BatimentTri_(Triangle _c) : Chose(), c(_c) {
BatimentTri::BatimentTri(Triangle _c, bool _isSub, TriBool _w)
: Chose(), c(_c), isSub(_isSub), w(_w) {
addEntropy(c);
for (int i = 0; i < 3; i++)
addEntropy(w[LEFTSIDE+i] ? 0 : 1);
}
void BatimentTri_::split() {
// TODO : BatimentTri::split()
void BatimentTri::split() {
if (!isSub) {
bordureRouteTrottoir();
} else {
if (w[LEFTSIDE] || w[RIGHTSIDE] || w[BASE]) {
if (c.surface() > 2 * Dimensions::minSurfaceSousBatiment) {
sousBatiments();
} else {
etages();
}
} else {
addChild(new TerrainTri(c));
}
}
}
void BatimentTri_::triangulation() {
void BatimentTri::triangulation() {
Triangle th = c.offsetNormal(Dimensions::hauteurEtage * 2 + Dimensions::hauteurToit);
addGPUTriangle(th, Couleurs::toit);
for (int i = 0; i < 3; i++)
addGPUQuad(Quad(c[LEFT+i], c[TOP+i], th[TOP+i], th[LEFT+i]), Couleurs::mur);
}
void BatimentTri_::getBoundingBoxPoints() {
void BatimentTri::getBoundingBoxPoints() {
addBBPoints(c, Dimensions::hauteurEtage * 2 + Dimensions::hauteurToit);
}
void BatimentTri::bordureRouteTrottoir() {
Triangle tinterieur = c.insetLTR(Dimensions::largeurRoute + Dimensions::largeurTrottoir);
Triangle tbatiments = tinterieur.offsetNormal(Dimensions::hauteurTrottoir);
for (int i = 0; i < 4; i++) {
addChild(new RouteTrottoirQuad(Quad(c[LEFT+i],c[TOP+i],tinterieur[TOP+i],tinterieur[LEFT+i])));
}
bool anglesAcceptable = c.minAngle() > Angle::d2r(90-60) && c.maxAngle() < Angle::d2r(90+60);
if (anglesAcceptable && proba(seed, 0, 0.95f)) {
addChild(new BatimentTri(tbatiments, true));
} else {
addChild(new TerrainTri(tbatiments));
}
}
void BatimentTri::sousBatiments() {
Triangle t = c << c.minAngleCorner();
TriBool tb = w << c.minAngleCorner();
// TODO : ajuster pour que la distance c[LEFT] -- left et c[LEFT] -- base soit similaire.
Vertex left = Segment(t[LEFT], t[TOP]).randomPos(seed, 0, 1.f/3.f, 2.f/3.f);
float dLeft = Segment(t[LEFT], left).length();
float posBase = dLeft / Segment(t[LEFT], t[RIGHT]).length();
if (posBase < 0.3f) posBase = 0.2f;
else if (posBase > 0.7f) posBase = 0.8f;
Vertex base = Segment(t[RIGHT], t[LEFT]).randomPos(seed, 1, posBase - 0.1f, posBase + 0.1f);
bool small = t.surface() < 4 * Dimensions::minSurfaceSousBatiment;
if (small && (tb[LEFTSIDE] || tb[RIGHTSIDE]) && proba(seed, 2, 0.3f)) {
addChild(new TerrainTri(Triangle(base, t[LEFT], left)));
addChild(new BatimentQuad(Quad(base, left, t[TOP], t[RIGHT]), true, QuadBool(true, w[LEFTSIDE], w[RIGHTSIDE], w[BASE])));
} else if (small && (tb[LEFTSIDE] || tb[RIGHTSIDE] || tb[BASE]) && proba(seed, 2, 0.3f)) {
addChild(new BatimentTri(Triangle(base, t[LEFT], left), true, TriBool(w[BASE], w[LEFTSIDE], true)));
addChild(new TerrainQuad(Quad(base, left, t[TOP], t[RIGHT])));
} else {
addChild(new BatimentTri(Triangle(base, t[LEFT], left), true, TriBool(w[BASE], w[LEFTSIDE], false)));
addChild(new BatimentQuad(Quad(base, left, t[TOP], t[RIGHT]), true, QuadBool(false, w[LEFTSIDE], w[RIGHTSIDE], w[BASE])));
}
}
void BatimentTri::etages() {
float randEtages = floatInRange(seed, 0, 0.f, 1.f);
int nbEtages = 1 + (int)(randEtages * randEtages * (Dimensions::maxEtages - 1));
Triangle t = c; // c.insetNESW(30)
Triangle th;
for (int i = 0; i < nbEtages; i++) {
th = t.offsetNormal(floatInRange(seed, 1+i, Dimensions::hauteurEtage*0.9f, Dimensions::hauteurEtage*1.1f));
addChild(new EtageTri(t, th, w, i, nbEtages));
t = th;
}
addChild(new ToitTri(th, Dimensions::hauteurToit));
}

View File

@ -20,11 +20,17 @@ public:
BatimentQuad* isSubdivision(bool val);
};
class BatimentTri_ : public Chose {
class BatimentTri : public Chose {
private:
Triangle c;
bool isSub;
TriBool w;
void bordureRouteTrottoir();
void sousBatiments();
void etages();
public:
BatimentTri_(Triangle _c);
BatimentTri(Triangle _c, bool _isSub = false, TriBool _w = TriBool(true, true, true));
virtual void split();
virtual void triangulation();
virtual void getBoundingBoxPoints();

View File

@ -45,7 +45,7 @@ public:
static const unsigned int hauteurTrottoir = 20;
static const unsigned int hauteurMaxBatiment = hauteurTrottoir + hauteurEtage * 2 + hauteurToit;
static const unsigned int minSurfaceSousBatiment = 100 * 100*100; // 100 m²
static const unsigned int minRayonPlace = 50 * 100; // 60 m
static const unsigned int minRayonPlace = 30 * 100; // 60 m
static const unsigned int maxRayonPlace = 2 * minRayonPlace; // 60 m
// Qualité

View File

@ -68,3 +68,43 @@ void EtageQuad::triangulation() {
addGPUQuad(ch.offsetNormal(-30), Couleurs::plafond);
addGPUQuad(c, Couleurs::plancher);
}
EtageTri::EtageTri(Triangle _c, Triangle _ch, TriBool _w, int _etage, int _nbEtages) : Chose(), c(_c), ch(_ch), w(_w), etage(_etage), nbEtages(_nbEtages) {
addEntropy(c);
addEntropy(ch);
for (int i = 0; i < 3; i++)
addEntropy(w[LEFTSIDE+i] ? 0 : 1);
}
void EtageTri::getBoundingBoxPoints() {
addBBPoints(c);
addBBPoints(ch);
}
void EtageTri::split() {
Triangle small = c.insetLTR(28);
Triangle smallh = ch.insetLTR(28);
TriBool d(false,false,false);
if(etage == 0) {
if(w[LEFTSIDE]) d[LEFTSIDE] = true;
else if(w[RIGHTSIDE]) d[RIGHTSIDE] = true;
else if(w[BASE]) d[BASE] = true;
}
for (int i = 0; i < 3; i++) {
Quad q = Quad(c[TOP+i], small[TOP+i], small[LEFT+i], c[LEFT+i]);
Quad qh = Quad(ch[TOP+i], smallh[TOP+i], smallh[LEFT+i], ch[LEFT+i]);
addChild(new MurQuad(q, qh, w[LEFTSIDE+i]^d[LEFTSIDE+i],false,false,d[LEFTSIDE+i]));
}
addChild(new PlancherPlafondTri(c, PlancherPlafondTri::PLANCHER));
addChild(new PlancherPlafondTri(ch.offsetNormal(-10), PlancherPlafondTri::PLAFOND));
}
void EtageTri::triangulation() {
addGPUThreeQuads(c,ch, Couleurs::mur);
addGPUTriangle(ch.offsetNormal(-30), Couleurs::plafond);
addGPUTriangle(c, Couleurs::plancher);
}

View File

@ -3,7 +3,6 @@
#include "all_includes.hh"
class EtageQuad : public Chose {
private :
Quad c;
@ -19,4 +18,19 @@ class EtageQuad : public Chose {
virtual void getBoundingBoxPoints();
};
class EtageTri : public Chose {
private :
Triangle c;
Triangle ch;
TriBool w;
int etage;
int nbEtages;
public :
EtageTri(Triangle c, Triangle ch, TriBool _w, int _etage, int _nbEtages);
virtual void split();
virtual void triangulation();
virtual void getBoundingBoxPoints();
};
#endif

View File

@ -75,3 +75,19 @@ void PlancherPlafond::triangulation() {
void PlancherPlafond::getBoundingBoxPoints() {
addBBPoints(c);
}
PlancherPlafondTri::PlancherPlafondTri(Triangle _c, Type _type) : Chose(), c(_c), type(_type) {
addEntropy(c);
addEntropy((int)type);
}
void PlancherPlafondTri::triangulation() {
unsigned int clr = Couleurs::plancher;
if (type == PLAFOND)
clr = Couleurs::plafond;
addGPUTriangle(c, clr);
}
void PlancherPlafondTri::getBoundingBoxPoints() {
addBBPoints(c);
}

View File

@ -39,5 +39,21 @@ public:
virtual void getBoundingBoxPoints();
};
class PlancherPlafondTri: public Chose {
public:
enum Type {
PLANCHER,
PLAFOND
};
private:
Triangle c;
Type type;
public:
PlancherPlafondTri(Triangle _c, Type _type);
virtual void triangulation();
virtual void getBoundingBoxPoints();
};
#endif

View File

@ -163,8 +163,8 @@ void QuartierTri::getBoundingBoxPoints() {
}
void QuartierTri::split() {
bool small = c.minLength() < 6000;
bool big = c.maxLength() >= 10000;
bool small = c.minLength() < 80 * 100;
bool big = c.maxLength() >= 150 * 100;
float minAngle = c.minAngle();
float maxAngle = c.maxAngle();
bool equilateral = maxAngle < Angle::d2r(60+15) && minAngle > Angle::d2r(60-15);
@ -172,7 +172,7 @@ void QuartierTri::split() {
bool angleAigu = minAngle < Angle::d2r(30);
bool anglesAcceptable = !angleAigu && !angleObtus;
if (!big && proba(seed, -1, 0.05f)) {
batiments(); // TODO : addChild(new BatimentTri_(c));
addChild(new BatimentTri(c));
} else if (big && anglesAcceptable) {
switch (hash2(seed, -2) % 3) {
case 0: centre(); break;
@ -187,7 +187,7 @@ void QuartierTri::split() {
} else if (!small) {
trapeze();
} else {
batiments(); // TODO : addChild(new BatimentTri_(c));
addChild(new BatimentTri(c));
}
}
@ -228,24 +228,3 @@ void QuartierTri::trapeze() {
addChild(new QuartierTri(Triangle(base, t[LEFT], left)));
addChild(new QuartierQuad(Quad(base, left, t[TOP], t[RIGHT])));
}
void QuartierTri::batiments() {
Triangle tinterieur = c.insetLTR(Dimensions::largeurRoute + Dimensions::largeurTrottoir);
Triangle tbatiments = tinterieur.offsetNormal(Dimensions::hauteurTrottoir);
for (int i = 0; i < 3; i++) {
addChild(new RouteTrottoirQuad(Quad(c[LEFT+i],c[TOP+i],tinterieur[TOP+i],tinterieur[LEFT+i])));
}
bool small = tbatiments.minLength() < 3000;
bool big = tbatiments.maxLength() >= 5000;
bool anglesAcceptable = tbatiments.minAngle() > Angle::d2r(30) && tbatiments.maxAngle() < Angle::d2r(120);
if (!big && proba(seed, 0, 0.05f)) {
addChild(new TerrainTri(tbatiments));
} else if (small && anglesAcceptable) {
addChild(new BatimentTri_(tbatiments));
} else {
addChild(new TerrainTri(tbatiments));
}
}

View File

@ -34,7 +34,6 @@ private:
void centre();
void hauteur();
void trapeze();
void batiments();
};
#endif

View File

@ -37,10 +37,35 @@ void TerrainQuad::triangulation() {
addGPUQuad(c, Couleurs::herbe);
}
TerrainTri::TerrainTri(Triangle _c) : Chose(), c(_c) {
TerrainTri::TerrainTri(Triangle _c, bool _addTrees) : Chose(), c(_c), addTrees(_addTrees) {
addEntropy(c);
}
void TerrainTri::split() {
if (!addTrees) return;
addChild(new TerrainTri(c, false));
Vertex p[10];
int maxNArbres = std::min(10, (int)(c.surface() / (7.f*7.f*100.f*100.f)));
int pi = 0;
int nArbres = hash2(seed, -1) % (maxNArbres + 1);
for (int essai = 0; essai < nArbres * 2 && pi < nArbres; essai++) {
p[pi] = c.insetProportionnal(0.7f).randomPoint(seed, essai);
bool success = true;
for (int j = 0; j < pi; j++) {
if (Segment(p[j], p[pi]).length() < 3 * 100) {
success = false;
break;
}
}
if (success) pi++;
}
for (int i = 0; i < pi; i++) {
addChild(new Arbre(p[i], c));
}
}
void TerrainTri::getBoundingBoxPoints() {
addBBPoints(c);
}

View File

@ -3,16 +3,6 @@
#include "all_includes.hh"
class TerrainTri : public Chose {
private :
Triangle c;
public :
TerrainTri(Triangle _c);
virtual void triangulation();
virtual void getBoundingBoxPoints();
};
class TerrainQuad : public Chose {
private :
Quad c;
@ -25,4 +15,16 @@ class TerrainQuad : public Chose {
virtual void getBoundingBoxPoints();
};
class TerrainTri : public Chose {
private :
Triangle c;
bool addTrees;
public :
TerrainTri(Triangle _c, bool _addTrees = true);
virtual void split();
virtual void triangulation();
virtual void getBoundingBoxPoints();
};
#endif

View File

@ -12,6 +12,8 @@ void ToitQuad::getBoundingBoxPoints() {
}
void ToitQuad::triangulation() {
// TODO : si angles pas acceptables, plat().
// TODO : toit plat : surélever.
switch (hash2(seed, -1) % 5) {
case 0: pointCentral(); break;
case 1: quatrePoints(); break;
@ -97,6 +99,7 @@ void ToitTri::getBoundingBoxPoints() {
}
void ToitTri::triangulation() {
plat(); return;
switch (hash2(seed, -1) % 5) {
case 0: pointCentral(); break;
case 1: troisPoints(); break;

View File

@ -300,6 +300,7 @@ void Camera::keyboard(const SDL_KeyboardEvent &eventKey) {
up = true;
break;
case 'e' :
moveSensitivity = 1500;
autoPilot = true;
break;
case 'z' :
@ -350,7 +351,6 @@ void Camera::animation(int elapsedTime) {
float diff = ((float)(elapsedTime+1)/1000.f)*(float)moveSensitivity;
if (autoPilot) {
moveSensitivity = 1500;
float dx = floatInRange(frame/16, 42, -0.5, 0.5);
float olddx = floatInRange(frame/16 - 1, 42, -0.5, 0.5);
float mix = ((float)(frame % 16) / 16.f);
@ -359,7 +359,6 @@ void Camera::animation(int elapsedTime) {
cameraCenter = cameraCenter + Vertex::fromSpherical(diff, yAngle, xAngle);
cameraCenter.z = oldz;
cameraCenter.z += std::min(20.f, std::max(-20.f, 1750 - cameraCenter.z));
return;
}
if(up)