Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

DarioFrodo

Treue Seele

  • »DarioFrodo« ist der Autor dieses Themas

Beiträge: 349

Wohnort: Kerkau, 100km nördlich von Magdeburg

Beruf: Selbstständig

  • Private Nachricht senden

1

05.10.2011, 16:04

Diamond Square Algorithmus liefert merkwürdige Ergebnisse [erledigt]

Hallo ihr lieben, ich bin es mal wieder, das verrückte Einhorn ;)

Ich habe den oben genannten Algorithmus gefunden mit dem man prima Highmaps für Terrains und auch Wolken generieren kann.
Mir wurde in einem anderem Thema zwar schon die libNoise empfohlen die das wunderbar macht, das Problem ist nur das es zu lange dauert.
Ich brauche einen schnelleren Algorithmus den ich auch abwandeln kann um ihn direkt auf meiner IcoSphere Geometrie anwenden zu können.
(siehe anderes Thema, hier)

Von daher habe ich jetzt versucht den umzusetzen mit Hilfe von verschiedenen Seiten:
wikipedia
gameprogrammer
lighthouse.3d

Das Ergebnis sollte in etwa so aussehen:
Doch es sieht so aus:

Habt ihr spontan eine Idee was ich vielleicht nicht kapiert habe, bei der Umsetzung des Algorithmus?
Und hier folgt der Quellcode:

C-/C++-Quelltext

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
const double roughness = 1.0;
const int borderSize = 1024;
const int gesSize = borderSize+1;

//! \param edges 0 = x links, 1 = x rechts, 2 = y oben, 3 = y unten (1 > 0, 3 > 2)
int mdp(double* map, double d, uint edges[4], int deep = 0)
{
    int width = edges[1] - edges[0];
    int height = edges[3] - edges[2];
    
    if(width <= 1 || height <=1)
    {
        //DRLog.writeToLog("iterationsdeep: %d", deep);
        return -1;
    }   
    //if(deep == 5) return 1;
    //diamond step
    //calculate index for middlepoint       
    DRVector2 diamondPoint(edges[0]+width/2, edges[2]+height/2);
    uint middle = diamondPoint.x + gesSize * diamondPoint.y;
    if(!middle) return 1;
    uint A = edges[0]+edges[2]*gesSize;
    uint B = edges[1]+edges[2]*gesSize;
    uint C = edges[0]+edges[3]*gesSize;
    uint D = edges[1]+edges[3]*gesSize;

    //calculate height for diamond point
    map[middle] = (map[A] + map[B] + map[C] + map[D]) / 4.0 + DRRandom::rDouble(d, -d);

    
    //square step
    uint E = middle;
    uint F = edges[0]           + (edges[2]+height/2)   *gesSize;
    uint G = edges[0] + width/2 +  edges[2]             *gesSize;
    uint H = edges[1]           + (edges[2]+height/2)   *gesSize;
    uint I = edges[0] + width/2 +  edges[3]             *gesSize;

    map[F] = (map[A] + map[C] + map[E] + map[E]) / 4.0 + DRRandom::rDouble(d, -d);
    map[G] = (map[A] + map[B] + map[E] + map[E]) / 4.0 + DRRandom::rDouble(d, -d);
    map[H] = (map[B] + map[D] + map[E] + map[E]) / 4.0 + DRRandom::rDouble(d, -d);
    map[I] = (map[C] + map[D] + map[E] + map[E]) / 4.0 + DRRandom::rDouble(d, -d);
    
    double newD = d * pow(2, -roughness);
    
    // linke obere Ecke
    uint newedges[4] = {edges[0], edges[0] + width/2, edges[2], edges[2]+height/2}; 
    mdp(map, newD, newedges, deep+1);
    
    // rechte obere Ecke
    newedges[0] = newedges[1]; newedges[1] = edges[1];
    mdp(map, newD, newedges, deep+1);
    
    // linke untere Ecke
    newedges[0] = edges[0]; newedges[1] = edges[0]+width/2; newedges[2] = edges[2]+height/2; newedges[3] = edges[3];
    mdp(map, newD, newedges, deep+1);
    
    // rechte untere Ecke
    newedges[0] = newedges[1]; newedges[1] = edges[1];
    mdp(map, newD, newedges, deep+1);
    
    return 0;
}


int main(int argc, char* argv[])
{
    double d = 0.5;
    srand(992);
    
    double* map = new double[gesSize*gesSize];
    for(int i = 0; i < (gesSize*gesSize); i++)
        map[i] = 0.5;//DRRandom::rDouble(1.0, 0.0);

        
    uint edges[4] = {0, borderSize, 0, borderSize}; 
    // rekursive midpoint deplacement methode
    mdp(map, d, edges);

    // save to image
    return 0;
}


(Hinweis: DRVector2 und DRColor sind so ähnlich wie tbColor und tbVector2 aus der TriBase-Engine)

Vielleicht sieht jemand von euch einen Fehler, was ich falsch verstanden habe von dem Algorithmus?
Hat jemand von euch schon mal diesen Algorithmus erfolgreich implementiert?
Ich freue über eure konstruktiven Antworten... ;)
Dario / dariofrodo / einhornimmond
Erst wenn der letzte Fluss vergiftet,
der letzte Baum gefällt,
der letzte Fisch gefangen,
dann werdet ihr merken, dass man Geld nicht essen kann

Man verkauft die Erde nicht, auf der die Menschen wandeln.

- Indianerweisheiten

Ich bin auch ein einhornimmond ;)

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »DarioFrodo« (07.10.2011, 10:27)


David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

2

06.10.2011, 10:39

Beim schnellen überfliegen fällt auf das der Sqare-Step falsch ist. Du musst alle Vertices berücksichtigen, die Anzahl kann variieren. Ansonsten würde ich dir raten sprechende Namen für die Variablen zu wählen!
@D13_Dreinig

DarioFrodo

Treue Seele

  • »DarioFrodo« ist der Autor dieses Themas

Beiträge: 349

Wohnort: Kerkau, 100km nördlich von Magdeburg

Beruf: Selbstständig

  • Private Nachricht senden

3

07.10.2011, 10:28

Danke David_pb das war der entscheidende Hinweis.
Erst wenn der letzte Fluss vergiftet,
der letzte Baum gefällt,
der letzte Fisch gefangen,
dann werdet ihr merken, dass man Geld nicht essen kann

Man verkauft die Erde nicht, auf der die Menschen wandeln.

- Indianerweisheiten

Ich bin auch ein einhornimmond ;)

DarioFrodo

Treue Seele

  • »DarioFrodo« ist der Autor dieses Themas

Beiträge: 349

Wohnort: Kerkau, 100km nördlich von Magdeburg

Beruf: Selbstständig

  • Private Nachricht senden

4

07.10.2011, 11:10

Mein funktionierender Code sieht nun so aus:

C-/C++-Quelltext

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
const double roughness = 1.0;
const int borderSize = 1024;
const int gesSize = borderSize+1;

int diamondStep(double* map, double d, uint x, uint y, uint width, uint height)
{
    if(width <= 1 || height <=1)
        return -1;

    // A ------ B
    // |        |
    // | middle |
    // |        |
    // C ------ D
    uint A = x+         y*gesSize;
    uint B = x+width+   y*gesSize;
    uint C = x+        (y+height)*gesSize;
    uint D = x+width+  (y+height)*gesSize;  
    
    //diamond step
    //calculate index for middlepoint   
    uint middle = x+width/2 + (y+height/2)*gesSize;
    if(!middle) return 1;

    //calculate height for diamond point
    map[middle] = (map[A] + map[B] + map[C] + map[D]) / 4.0 + DRRandom::rDouble(d, -d);
    if(map[middle] > 1.0) map[middle] = 1.0;
    
    return 0;
}

int squareStep(double* map, double d, uint x, uint y, uint width, uint height)
{
    if(width <= 1 || height <=1)
        return -1;
    
    //             ETop  (y)
    //               |    
    //      (x) A -- G -- B   
    //          |    |    |
    // ELeft -- F -- E -- H -- ERight
    //          |    |    |
    //          C -- I -- D
    //               |    
    //            EBottom 
    //                    
    uint A = x+         y*gesSize;
    uint B = x+width+   y*gesSize;
    uint C = x+        (y+height)*gesSize;
    uint D = x+width+  (y+height)*gesSize;

    uint E = x+width/2   + (y+height/2)*gesSize;
    uint F = x           + (y+height/2)*gesSize;
    uint G = x + width/2 +  y          *gesSize;
    uint H = x + width   + (y+height/2)*gesSize;
    uint I = x + width/2 + (y+height)  *gesSize;

    int ELeft = E-width;
    if(ELeft < 0) ELeft = 0;
    int ERight = E+width;
    if(ERight >= gesSize*gesSize) ERight = 0;
    int ETop = E-(height*gesSize);
    if(ETop < 0) ETop = 0;
    int EBottom = E+(height*gesSize);
    if(EBottom >= gesSize*gesSize) EBottom = 0;

    if(!ELeft)  map[F] = (map[A] + map[C] + map[E]) / 3.0 + DRRandom::rDouble(d, -d);
    else        map[F] = (map[A] + map[C] + map[E] + map[ELeft]) / 4.0 + DRRandom::rDouble(d, -d);
    
    if(!ETop)   map[G] = (map[A] + map[B] + map[E]) / 3.0 + DRRandom::rDouble(d, -d);
    else        map[G] = (map[A] + map[B] + map[E] + map[ETop]) / 4.0 + DRRandom::rDouble(d, -d);
    
    if(!ERight)  map[H] = (map[B] + map[D] + map[E]) / 3.0 + DRRandom::rDouble(d, -d);
    else         map[H] = (map[B] + map[D] + map[E] + map[ERight]) / 4.0 + DRRandom::rDouble(d, -d);
    
    if(!EBottom) map[I] = (map[C] + map[D] + map[E]) / 3.0 + DRRandom::rDouble(d, -d);
    else         map[I] = (map[C] + map[D] + map[E] + map[EBottom]) / 4.0 + DRRandom::rDouble(d, -d);

    return 0;
}

int mdp(double* map, double d, uint width, uint height)
{
    if(width <= 1 || height <=1)
        return -1;

    uint halfWidth = width;
    uint halfHeight = height;

    do
    {
        d *= pow(2, -roughness);
        halfWidth /= 2;
        halfHeight /= 2;
        if(halfHeight < 2 || halfWidth < 2) break;

        for(uint j = 0; j < gesSize-1; j+=halfHeight)
            for(uint i = 0; i < gesSize-1; i+= halfWidth)
                diamondStep(map, d, i, j, halfWidth, halfHeight);
        for(uint j = 0; j < gesSize-1; j+=halfHeight)
            for(uint i = 0; i < gesSize-1; i+= halfWidth)
                squareStep(map, d, i, j, halfWidth, halfHeight);
    } while(true);

    return 0;
}

int main(int argc, char* argv[])
{
    double d = 0.5;
    srand(182192);
    
    double* map = new double[gesSize*gesSize];
    for(int i = 0; i < (gesSize*gesSize); i++)
        map[i] = DRRandom::rDouble(1.0, 0.0);
    
    mdp(map, d, borderSize, borderSize);

    //save to image
    
    delete[] map;
    
    return 0;
}


Der Vorteil ist, er läuft nun nicht mehr rekursiv sondern nun iterativ...
Erst wenn der letzte Fluss vergiftet,
der letzte Baum gefällt,
der letzte Fisch gefangen,
dann werdet ihr merken, dass man Geld nicht essen kann

Man verkauft die Erde nicht, auf der die Menschen wandeln.

- Indianerweisheiten

Ich bin auch ein einhornimmond ;)

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

5

07.10.2011, 11:18

Noch schöner wärs, wenn die Variablen gescheite Namen bekommen würden!
@D13_Dreinig

DarioFrodo

Treue Seele

  • »DarioFrodo« ist der Autor dieses Themas

Beiträge: 349

Wohnort: Kerkau, 100km nördlich von Magdeburg

Beruf: Selbstständig

  • Private Nachricht senden

6

07.10.2011, 18:45

An welcher Stelle würdest du noch gescheitere Namen verwenden?
Die Buchstaben habe ich direkt verwendet aus dem Bild wo der Algorithmus beschrieben wird.
Und der rest spricht doch eigentlich für sich.. finde ich jedenfalls...
Erst wenn der letzte Fluss vergiftet,
der letzte Baum gefällt,
der letzte Fisch gefangen,
dann werdet ihr merken, dass man Geld nicht essen kann

Man verkauft die Erde nicht, auf der die Menschen wandeln.

- Indianerweisheiten

Ich bin auch ein einhornimmond ;)

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

7

07.10.2011, 19:47

Die Buchstaben habe ich direkt verwendet aus dem Bild wo der Algorithmus beschrieben wird.


In deiner ersten Version gabs die Kommentierung nocht nicht. Aber selbst mit dem Kommentar (der sicherlich hiflreich ist) sind sprechende Bezeichner immer vorzuziehen, wie du es bei middle ja bereits gemacht hast!
@D13_Dreinig

DarioFrodo

Treue Seele

  • »DarioFrodo« ist der Autor dieses Themas

Beiträge: 349

Wohnort: Kerkau, 100km nördlich von Magdeburg

Beruf: Selbstständig

  • Private Nachricht senden

8

08.10.2011, 13:32

Bezeichner wie leftTop, rightTop, middleTop, etc?
Hatte ich auch überlegt, aber ich war wohl auch etwas schriebfaul.. ._.
Erst wenn der letzte Fluss vergiftet,
der letzte Baum gefällt,
der letzte Fisch gefangen,
dann werdet ihr merken, dass man Geld nicht essen kann

Man verkauft die Erde nicht, auf der die Menschen wandeln.

- Indianerweisheiten

Ich bin auch ein einhornimmond ;)

Werbeanzeige