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

28.11.2011, 14:15

GLSL Shader spinnt auf NVidia Grafikkarte, funktioniert aber bei ATI

Hallo Ihr liebe,

ich bins mal wieder..
Für meinen Realtime-Fractal-Planet Renderer habe ich es jetzt geschafft den Beispiel-Code von libnoise in einen GLSL Shader zu übertragen.
Der Beispielcode ruft eine ganze Reihe von libnoise modulen auf um eine realistische Planetenoberfläche zu generieren.
libnoise-Beispielcode

Ich habe nun den Code und aller erforderlichen Funktionen in einem FragmentShader implementiert.

Der Beispielcode benötigt zum generieren einer 4096x2048 Pixel Textur ca. 8 minuten auf meinem Rechner (Intel Core 2 Quad CPU Q8200 @ 2.33 GHz, 3 GB RAM, NVIDIA GeForce GTS 250, Win XP Professional SP 3).
Der Shadercode bringt es auf etwa 1 Frame per Second, benötigt also nur noch ca 1 sekunde, bei einer gefühlt höheren Auflösung. Soweit also schonmal ein Erfolg. Doch sieht das Resultat nicht so aus wie erwartet. Ich dachte erst ich hätte einen Fehler gemacht und habe es einfach mal auf meinem 2. PC getestet (Intel Core 2 Duo CPU E8400 @ 3.00 GHz, 6 GB RAM, ATI Radeon HD 5700, Window Vista Professional 64 Bit).
Doch hier sah das Ergebnis genau so aus wie ich es erwartet habe und wie es auch mit libnoise aussah.

Dazu ein Screenshot:

(Link)

Auf der linken Seite sieht es richtig aus (oben farbe, unten als heighmap),
auf der rechten Seite merkwürdig. Das rechte wurde auf der NVIDIA Grafikkarte gerendert.

Wer möchte kann es auch mal selbst probieren:
Prototyp ca. 2,6 MByte, MinGW Build
Die Shader befinden sich im Ordner data/shader.

Habt ihr eine Idee in wie weit sich die Grafikkarten unterscheiden, das solche unterschiedlichen Effekte dabei herauskommen?
Ich habe die Ahnung das es vielleicht etwas mit unterschiedlicher Typen-überlaufs-behandlung zu tun haben könnte.
Aber ich wüsste nicht genau wo.

Den ganzen Shader poste ich hier nicht, das wäre zu viel.. (ca. 1500 Zeilen),
aber ich habe einen kleinen Ausschnitt erstellt.
GLSL Vertex-Shader:

HLSL-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
#version 120

varying vec3 v_texCoord3D;

void main( void )
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;

    const int seed =99;
    v_texCoord3D = normalize(gl_Vertex).xyz + seed; 
}

GLSL-Fragment-Shader

HLSL-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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// basierend auf: 
//
// Description : Array and textureless GLSL 3D simplex noise function.
//      Author : Ian McEwan, Ashima Arts.
//  Maintainer : ijm
//     Lastmod : 20110409 (stegu)
//     License : Copyright (C) 2011 Ashima Arts. All rights reserved.
//               Distributed under the MIT License. See LICENSE file.
//

#version 120

varying vec3 v_texCoord3D;

float f_lacunarity;
float f_persistence;

struct GradientColor
{
    float pos;
    vec4 color;
};

//libnoise helper

vec4 LinearInterpColor (vec4 color0, vec4 color1, float alpha)
{
    return (color1 * alpha) + (color0 * (1.0 - alpha));
}
int clampi(int x, int minVal, int maxVal) 
{
    if(x < minVal) return minVal;
    else if (x > maxVal) return maxVal;
    else return x;
}
// noise helper
vec4 permute(vec4 x) {return mod(((x*34.0)+1.0)*x, 289.0);}
vec4 taylorInvSqrt(vec4 r) {return 1.79284291400159 - 0.85373472095314 * r;}
vec3 fade(vec3 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);}

float snoise(vec3 v)
  { 
  const vec2  C = vec2(1.0/6.0, 1.0/3.0) ;
  const vec4  D = vec4(0.0, 0.5, 1.0, 2.0);

// First corner
  vec3 i  = floor(v + dot(v, C.yyy) );
  vec3 x0 =   v - i + dot(i, C.xxx) ;

// Other corners
  vec3 g = step(x0.yzx, x0.xyz);
  vec3 l = 1.0 - g;
  vec3 i1 = min( g.xyz, l.zxy );
  vec3 i2 = max( g.xyz, l.zxy );

  //  x0 = x0 - 0. + 0.0 * C 
  vec3 x1 = x0 - i1 + 1.0 * C.xxx;
  vec3 x2 = x0 - i2 + 2.0 * C.xxx;
  vec3 x3 = x0 - 1. + 3.0 * C.xxx;

// Permutations
  i = mod(i, 289.0 ); 
  vec4 p = permute( permute( permute( 
             i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
           + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) 
           + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));

// Gradients
// ( N*N points uniformly over a square, mapped onto an octahedron.)
  float n_ = 1.0/7.0; // N=7
  vec3  ns = n_ * D.wyz - D.xzx;

  vec4 j = p - 49.0 * floor(p * ns.z *ns.z);  //  mod(p,N*N)

  vec4 x_ = floor(j * ns.z);
  vec4 y_ = floor(j - 7.0 * x_ );    // mod(j,N)

  vec4 x = x_ *ns.x + ns.yyyy;
  vec4 y = y_ *ns.x + ns.yyyy;
  vec4 h = 1.0 - abs(x) - abs(y);

  vec4 b0 = vec4( x.xy, y.xy );
  vec4 b1 = vec4( x.zw, y.zw );

  //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
  //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
  vec4 s0 = floor(b0)*2.0 + 1.0;
  vec4 s1 = floor(b1)*2.0 + 1.0;
  vec4 sh = -step(h, vec4(0.0));

  vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
  vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;

  vec3 p0 = vec3(a0.xy,h.x);
  vec3 p1 = vec3(a0.zw,h.y);
  vec3 p2 = vec3(a1.xy,h.z);
  vec3 p3 = vec3(a1.zw,h.w);

//Normalise gradients
  vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
  p0 *= norm.x;
  p1 *= norm.y;
  p2 *= norm.z;
  p3 *= norm.w;

// Mix final noise value
  vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
  m = m * m;
  return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), 
                                dot(p2,x2), dot(p3,x3) ) );
  }
float sOctaveNoise(vec3 p, float frequenzy, int octaveCount)
{
    float value = 0.0;
    float curPersistence = 1.0;
//  cnoise(p*frequenzy);
    for(int curOctave = 0; curOctave < octaveCount; curOctave++)
    {
        value += snoise(p*frequenzy) * curPersistence;
        p *= f_lacunarity;
        curPersistence *= f_persistence;
    }
    return value;
}

vec4 gradientColor(float value, GradientColor points[10], int pointsCount)
{
  // Find the first element in the control point array that has a value
  // larger than the output value from the source module.
  int indexPos;
  for (indexPos = 0; indexPos < pointsCount; indexPos++) {
    if (value < points[indexPos].pos) {
      break;
    }
  }

  // Find the two nearest control points so that we can map their values
  // onto a quadratic curve.
  ivec2 index = ivec2(clampi(indexPos - 1, 0, pointsCount - 1),
                      clampi(indexPos    , 0, pointsCount - 1));

  // If some control points are missing (which occurs if the output value from
  // the source module is greater than the largest value or less than the
  // smallest value of the control point array), get the value of the nearest
  // control point and exit now.
  if (index.x == index.y) 
    return points[index.y].color;

  // Compute the alpha value used for linear interpolation.
  vec2 inputv = vec2(points[index.x].pos, points[index.y].pos);
  float alpha = (value - inputv.x) / (inputv.y - inputv.x);

  vec4 color0 = points[index.x].color;
  vec4 color1 = points[index.y].color;

  // Now perform the linear interpolation given the alpha value.
  return LinearInterpColor (color0, color1, alpha);
}

void main( void )
{
    //Default
    const float DEFAULT_LACUNARTITY = 2.0;

    f_lacunarity = DEFAULT_LACUNARTITY;
    f_persistence = 0.5;

    vec2 curveTemp[10];
    float terraceTemp[6];
    float n = 0;
    
    f_lacunarity = 2.208984375;
    float baseContinentDef_pe0 = sOctaveNoise(v_texCoord3D, 1.0, 14);


    if(n == 0.0)
        n = baseContinentDef_pe0;
    float seaLevel = 0.0;
    GradientColor gradient[10];
    gradient[0] =  GradientColor(-2.0           + seaLevel, vec4(0.0,     0.0,     0.0,     1.0));
    gradient[1] =  GradientColor(-0.03125       + seaLevel, vec4(0.02353, 0.22745, 0.49804, 1.0));
    gradient[2] =  GradientColor(-0.0001220703  + seaLevel, vec4(0.05490, 0.43922, 0.75294, 1.0));
    gradient[3] =  GradientColor( 0.0           + seaLevel, vec4(0.27451, 0.47059, 0.23529, 1.0));
    gradient[4] =  GradientColor( 0.125         + seaLevel, vec4(0.43137, 0.54902, 0.29412, 1.0));
    gradient[5] =  GradientColor( 0.25          + seaLevel, vec4(0.62745, 0.54902, 0.43529, 1.0));
    gradient[6] =  GradientColor( 0.375         + seaLevel, vec4(0.72157, 0.63921, 0.55294, 1.0));
    gradient[7] =  GradientColor( 0.5           + seaLevel, vec4(1.0));
    gradient[8] =  GradientColor( 0.75          + seaLevel, vec4(0.5,     1.0,     1.0,     1.0));
    gradient[9] =  GradientColor( 2.0           + seaLevel, vec4(0.0,     0.0,     1.0,     1.0));

    gl_FragColor = gradientColor(n, gradient, 10);//vec4(0.5 + 0.5*vec3(n, n, n), 1.0);
//  gl_FragColor = vec4(0.5 + 0.5*vec3(n,n,n), 1.0);
}


Der obige Code generiert auf einer Kugel ebenfalls ein sehr nach Planeten aussehende Oberfläche (zumindest auf einer ATI-Grafikkarte)
unterverwendung der selben Basisfunktionen wie mein eigentlicher Shader. Die schwarzweiß Variante (Zeile 192 wieder auskommentieren)
sieht bei beiden Grafikkarten gleich aus. Demnach müsste der Fehler in der gradientColor Funktion liegen. Diese habe ich fast ohne Änderung aus libnoise (C++) übernommen.

Ich würde mich freuen wenn einer von euch mir einen kleinen Hinweis geben könnte, wonach ich gucken könnte um den Fehler zu beheben.
Liebe Grüße
Dario
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 ;)

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

28.11.2011, 14:30

Sieht mir in der Tat stark nach Überläufen aus. Kannst du nicht einfach im Shader clampen wo es zu einem Überlauf kommen könnte? Schau mal ob das einen Unterschied macht!?
Ansonsten haben ATI und NVIDIA natürlich jeweils ihren eigenen GLSL Compiler im Treiber, mit jeweils eigenen Bugs/Macken...

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

28.11.2011, 15:08

Ich habe an verschiedenen stellen clamp verwendet, keine Änderung.
Ich habe auch nicht wirklich eine Stelle mit Überlauf gefunden.

Ich habe aber eine neue Vermutung.
Vielleicht beherrscht GLSL die Parameterübergabe von arrays gar nicht, oder nicht überall gleich.

Ich habe die Funktion:

HLSL-Quelltext

1
2
3
4
5
6
7
8
9
10
struct GradientColor
{
    float pos;
    vec4 color;
}; 

vec4 gradientColor(float value, GradientColor points[10], int pointsCount)
{
//Funktion
}


und rufe sie mit diesen Parametern auf:

HLSL-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//float n = ...

    GradientColor gradient[10];
    gradient[0] =  GradientColor(-2.0           , vec4(0.0,        0.0,        0.0,        1.0));
    gradient[1] =  GradientColor(-0.03125       , vec4(0.02353, 0.22745, 0.49804, 1.0));
    gradient[2] =  GradientColor(-0.0001220703  , vec4(0.05490, 0.43922, 0.75294, 1.0));
    gradient[3] =  GradientColor( 0.0           , vec4(0.27451, 0.47059, 0.23529, 1.0));
    gradient[4] =  GradientColor( 0.125         , vec4(0.43137, 0.54902, 0.29412, 1.0));
    gradient[5] =  GradientColor( 0.25          , vec4(0.62745, 0.54902, 0.43529, 1.0));
    gradient[6] =  GradientColor( 0.375         , vec4(0.72157, 0.63921, 0.55294, 1.0));
    gradient[7] =  GradientColor( 0.5           , vec4(1.0));
    gradient[8] =  GradientColor( 0.75          , vec4(0.5,     1.0,     1.0,     1.0));
    gradient[9] =  GradientColor( 2.0           , vec4(0.0,     0.0,     1.0,     1.0));

   gl_FragColor = gradientColor(n, gradient, 10);


Ich habe das Gefühl das die Daten nicht so ankommen wie ich es erwarte, zumindest bei der NVIDIA Grafikkarte.
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 ;)

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

4

28.11.2011, 15:15

Kannst das Array ja mal so in der Funktion definieren und schaun ob das was ändert ;)

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

5

28.11.2011, 15:24

Wenn ich das Array direkt in der Funktion deklariere, gibt es keine Änderung bei NVIDIA, aber bei ATI compilert der Shader nicht mehr (10 compiler-fehler: "Cannot convert from 'structure' to 'structure')

Was merkwürdig ist, im DGL Wiki steht das bei glsl in Funktionen arrays ohne Größenangaben deklariert werden müssen,

Zitat von »http://wiki.delphigl.com/index.php/Tutorial_glsl#Arrays«

Wenn ein Array als Parameter einer Funktion deklariert wird, so darf dieses keine Dimensionierung erhalten.


Aber wenn ich das so mache, bekomme ich einen Compilerfehler:

HLSL-Quelltext

1
2
3
4
vec4 gradientColor(float value, GradientColor points[], int pointsCount)
{
//funktion
}

0(148) : error C7523: OpenGL requires array parameters of constant size
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 ;)

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

6

28.11.2011, 15:36

Wenn ich das Array direkt in der Funktion deklariere, gibt es keine Änderung bei NVIDIA, aber bei ATI compilert der Shader nicht mehr (10 compiler-fehler: "Cannot convert from 'structure' to 'structure')

Wie sieht der Code denn aus?

Was merkwürdig ist, im DGL Wiki steht das bei glsl in Funktionen arrays ohne Größenangaben deklariert werden müssen, [...]

Zitat von »GLSL Specification«

Arrays declared as formal parameters in a function declaration must specify a size.

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

7

28.11.2011, 15:48

Ups, ATI mag

HLSL-Quelltext

1
GradientColor points[];
nicht.
also jetzt gehts auch auf der ATI Grafikkarte...
aber wie gesagt.. keine Änderung.. bei NVIDIA sieht es immer noch komisch aus und bei ATI korrekt.
das kann es also nicht gewesen sein.

Ich habe bemerkt wenn ich das hier clampe:

HLSL-Quelltext

1
float alpha = clamp((value - inputv.x) / (inputv.y - inputv.x), 0.0, 1.0);


ändert sich das Ergebnis bei NVIDIA, aber nicht bei ATI.

Dabei befindet sich der Wert value zwischen den Werten inputv.x und inputv.y, wobei inputv.x kleiner ist als value.
Demnach müsste ja eigentlich immer ein Wert zwischen [0;1] herauskommen.
Oder beherrscht die NVIDIA Grafikkarte nicht einmal die Grundrechenarten?

(nochmal der ganze Code der gradientColorFunktion)

HLSL-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
vec4 gradientColor(float value, GradientColor points[10], int pointsCount)
{

  // Find the first element in the control point array that has a value
  // larger than the output value from the source module.
  int indexPos;
  for (indexPos = 0; indexPos < pointsCount; indexPos++) {
    if (value < points[indexPos].pos) {
      break;
    }
  }


  // Find the two nearest control points so that we can map their values
  // onto a quadratic curve.
  ivec2 index = ivec2(clampi(indexPos - 1, 0, pointsCount - 1),
                      clampi(indexPos    , 0, pointsCount - 1));

  // If some control points are missing (which occurs if the output value from
  // the source module is greater than the largest value or less than the
  // smallest value of the control point array), get the value of the nearest
  // control point and exit now.
 if (index.x == index.y) 
    return points[index.y].color;

  // Compute the alpha value used for linear interpolation.
  vec2 inputv = vec2(points[index.x].pos, points[index.y].pos);
  float alpha = clamp((value - inputv.x) / (inputv.y - inputv.x), 0.0, 1.0);
  

  vec4 color0 = points[index.x].color;
  vec4 color1 = points[index.y].color;

  // Now perform the linear interpolation given the alpha value.
  return LinearInterpColor (color0, color1, alpha);
}
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 ;)

Tobiking

1x Rätselkönig

  • Private Nachricht senden

8

28.11.2011, 16:48

Ich hab deinen Prototyp grad mal bei mir auf einer GeForce GTX 570 mit aktuellen Treiber (285.62) probiert und es sieht richtig aus.

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

9

28.11.2011, 17:34

Danke Tobiking das war der entscheidende Hinweis. Ich habe jetzt auch die aktuellen Treiber installiert und jetzt gehts auch bei mir.. sogar auf meinem Laptop.. :)

Nur interessenhalber.. was hattest du für eine Framerate?
Ich habe auf meinem Haupt PC 5 FPS und auf meinem 2. PC 10 FPS gehabt..
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 ;)

Tobiking

1x Rätselkönig

  • Private Nachricht senden

10

29.11.2011, 02:40

Wenn ich es einfach nur starte ohne die Kamra zu drehen sind es 6 FPS. Es geht aber schnell rauf oder runter wenn man den Blickwinkel ändert.

Werbeanzeige

Ähnliche Themen