shader Terrain GPU4: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
(Die Seite wurde neu angelegt: =Shadername= Zurück zur Shadersammlung {|{{Prettytable_B1}} width=100% !width=60%|Beschreibung !width=20%|Autor !width=20%|Version |- |Shader für ein Heightmap-Te...)
 
K (Der Ausdruck ''<glsl>(.*?)</glsl>'' wurde ersetzt mit ''<source lang="glsl">$1</source>''.)
 
(5 dazwischenliegende Versionen von einem anderen Benutzer werden nicht angezeigt)
Zeile 1: Zeile 1:
=Shadername=
+
=Heightmap-Terrain=
 
Zurück zur [[Shadersammlung]]
 
Zurück zur [[Shadersammlung]]
 
{|{{Prettytable_B1}} width=100%
 
{|{{Prettytable_B1}} width=100%
Zeile 19: Zeile 19:
  
 
==Beschreibung==
 
==Beschreibung==
Ein Terrain-Shader. Das Terrain wird in Blöcken von 64x64 gerendert. Als Geometrie wird nur ein [[GL_ARB_vertex_buffer_object|VBO]] mit 65x65 minimalen 2D-Vertices und ein entsprechender Indexbuffer benötigt. Die 3D-Vertices, Normalen und Texturkoordinaten werden im Vertexshader mit Hilfe der Heightmap-Textur erzeugt. Im Fragmentshader werden drei Texturlayer mit Hilfe einer Alphamap interpoliert.
+
Ein Terrain-Shader. Das Terrain wird in Blöcken von 64x64 gerendert, da man ja sinnvollerweise sowieso einen [[Techniken_und_Algorithmen#Raumunterteilungstechniken|Quadtree]] oder ähnliches einsetzt. Als Geometrie wird daher <u>nur ein</u> [[GL_ARB_vertex_buffer_object|VBO]] mit 65x65 minimalen 2D-Vertices (keine Höhe) und ein entsprechender Indexbuffer benötigt. Die 3D-Vertices, Normalen und Texturkoordinaten werden im Vertexshader mit Hilfe der [[Heightmap|Heightmap-Textur]] erzeugt. Im Fragmentshader werden drei Texturlayer mit Hilfe einer Alphamap interpoliert.
  
Ein solcher Shader ist besonders für hochauflösende/große Terrains sinnvoll, da keine redundanten Daten im Speicher liegen müssen.
+
Ein solcher Shader ist besonders für hochauflösende/große Terrains sinnvoll, da keine redundanten Daten im Speicher der Grafikkarte liegen müssen.
  
==Besondere Vorraussetzungen==
+
==Besondere Voraussetzungen==
Ich verwende hier einige Features des ShaderModel 4.0 zwecks Performance-Optimierung, es wird also [[GL_EXT_gpu_shader4]] benötigt. Ich verwende Integer-Arithmetik und die Funktion ''texelFetch2DOffset'' für beschleunigten Texturzugriff. Es sollte aber möglich sein den Shader auch so umzuschreiben, dass er auch auf älterer Hardware funktioniert.
+
Ich verwende hier einige Features des ShaderModel 4.0 zwecks Performance-Optimierung, es wird also [[GL_EXT_gpu_shader4]] benötigt. Ich verwende Integer-Arithmetik und die Funktion ''texelFetch2DOffset'' für beschleunigten Texturzugriff. ''texelFetch2D'' ermöglicht den Texturzugriff über exakte Integer-Koordinaten, was intern die Multiplikation mit der Texturgröße sowie die Interpolation zwischen verschiedenen Texeln unnötig macht. Durch ''texelFetch2DOffset'' kann der Compiler multiple Texturzugriffe auf die selbe Textur mittels Cache beschleunigen, sofern der Offset klein und konstant ist.
 +
 
 +
Es sollte aber möglich sein den Shader auch so umzuschreiben, dass er auch auf älterer Hardware funktioniert.
 +
 
 +
{{Hinweis|Die Aussagen zur Funktionsweise von ''texelFetch2DOffset'' basieren auf Vermutungen. Die Spezifikation von [[GL_EXT_gpu_shader4]] macht leider keine Angaben was intern genau passiert. Die Tatsache das der Offset konstant sein muss und begrenzt ist legt dies aber Nahe.}}
  
 
==Code==
 
==Code==
 
Vertexshader:
 
Vertexshader:
<glsl>#extension GL_EXT_gpu_shader4 : enable
+
<source lang="glsl">#extension GL_EXT_gpu_shader4 : enable
  
 
uniform sampler2D heightmap; // heightmap texture
 
uniform sampler2D heightmap; // heightmap texture
Zeile 79: Zeile 83:
 
gl_TexCoord[0].xy = gl_Vertex.xy / leafsize;    // coords for layer texture
 
gl_TexCoord[0].xy = gl_Vertex.xy / leafsize;    // coords for layer texture
 
gl_TexCoord[1].xy = vec2(coords) / terrainsize;  // coords for alphamap
 
gl_TexCoord[1].xy = vec2(coords) / terrainsize;  // coords for alphamap
}</glsl>
+
}</source>
  
 
Fragmentshader:
 
Fragmentshader:
<glsl>uniform sampler2D layer0;
+
<source lang="glsl">uniform sampler2D layer0;
 
uniform sampler2D layer1;
 
uniform sampler2D layer1;
 
uniform sampler2D layer2;
 
uniform sampler2D layer2;
Zeile 101: Zeile 105:
 
float diffuse = max(dot(gl_LightSource[0].position.xyz, normal), 0.0);
 
float diffuse = max(dot(gl_LightSource[0].position.xyz, normal), 0.0);
 
  gl_FragColor = vec4(diffuse * color + gl_LightSource[0].ambient.xyz, 1.0);
 
  gl_FragColor = vec4(diffuse * color + gl_LightSource[0].ambient.xyz, 1.0);
}</glsl>
+
}</source>

Aktuelle Version vom 10. März 2009, 19:34 Uhr

Heightmap-Terrain

Zurück zur Shadersammlung

Beschreibung Autor Version
Shader für ein Heightmap-Terrain, benutzt GL_EXT_gpu_shader4 Coolcat 1.0

Bilder

Terrain mit 3 Texturlayern
Terrain aus Heightmap mit 2048x2048 Auflösung und 16bit Graustufen

Beschreibung

Ein Terrain-Shader. Das Terrain wird in Blöcken von 64x64 gerendert, da man ja sinnvollerweise sowieso einen Quadtree oder ähnliches einsetzt. Als Geometrie wird daher nur ein VBO mit 65x65 minimalen 2D-Vertices (keine Höhe) und ein entsprechender Indexbuffer benötigt. Die 3D-Vertices, Normalen und Texturkoordinaten werden im Vertexshader mit Hilfe der Heightmap-Textur erzeugt. Im Fragmentshader werden drei Texturlayer mit Hilfe einer Alphamap interpoliert.

Ein solcher Shader ist besonders für hochauflösende/große Terrains sinnvoll, da keine redundanten Daten im Speicher der Grafikkarte liegen müssen.

Besondere Voraussetzungen

Ich verwende hier einige Features des ShaderModel 4.0 zwecks Performance-Optimierung, es wird also GL_EXT_gpu_shader4 benötigt. Ich verwende Integer-Arithmetik und die Funktion texelFetch2DOffset für beschleunigten Texturzugriff. texelFetch2D ermöglicht den Texturzugriff über exakte Integer-Koordinaten, was intern die Multiplikation mit der Texturgröße sowie die Interpolation zwischen verschiedenen Texeln unnötig macht. Durch texelFetch2DOffset kann der Compiler multiple Texturzugriffe auf die selbe Textur mittels Cache beschleunigen, sofern der Offset klein und konstant ist.

Es sollte aber möglich sein den Shader auch so umzuschreiben, dass er auch auf älterer Hardware funktioniert.

Info DGL.png Die Aussagen zur Funktionsweise von texelFetch2DOffset basieren auf Vermutungen. Die Spezifikation von GL_EXT_gpu_shader4 macht leider keine Angaben was intern genau passiert. Die Tatsache das der Offset konstant sein muss und begrenzt ist legt dies aber Nahe.

Code

Vertexshader:

#extension GL_EXT_gpu_shader4 : enable

uniform sampler2D heightmap; // heightmap texture
uniform ivec2 leafmin; // minimum position of current block

const int tmin = 1; // minimum border for clamping
const int tmax = 2047; // maximum border for clamping
const float leafsize = 64.0; // size of terrain block
const float terrainsize = 2048.0; // size of complete terrain (heightmap size)
const float terrainscale = 100.0; // terrain height scale

varying vec3 normal;

void main()
{
	float height;
	ivec2 coords = leafmin + ivec2(gl_Vertex.xy);
	if (coords.x < tmin || coords.y < tmin || coords.x > tmax || coords.y > tmax) {
		// clamping borders
		height = 0.0;
		normal = vec3(0,-1,0);
	}
	else {
		//retrieve height
		height = terrainscale * texelFetch2DOffset(heightmap, coords, 0, ivec2(0,0)).a;
	
		//compute normal
		vec3 vector[6];
		vector[0] = vec3( 0.0, texelFetch2DOffset(heightmap, coords, 0, ivec2( 0, -1)).a, -1.0);
		vector[1] = vec3(-1.0, texelFetch2DOffset(heightmap, coords, 0, ivec2(-1, -1)).a, -1.0);
		vector[2] = vec3(-1.0, texelFetch2DOffset(heightmap, coords, 0, ivec2(-1,  0)).a,  0.0);
		vector[3] = vec3( 0.0, texelFetch2DOffset(heightmap, coords, 0, ivec2( 0,  1)).a,  1.0);
		vector[4] = vec3( 1.0, texelFetch2DOffset(heightmap, coords, 0, ivec2( 1,  1)).a,  1.0);
		vector[5] = vec3( 1.0, texelFetch2DOffset(heightmap, coords, 0, ivec2( 1,  0)).a,  0.0);
		for (int i=0; i<6; ++i) {
			vector[i].y = terrainscale * vector[i].y - height;
		}
		normal = cross(vector[5], vector[0]);
		for (int i=1; i<6; ++i) {
			normal += cross(vector[i-1], vector[i]);
		}
		normal = normalize(normal);
	}
	
	// transform position
	vec4 position = vec4(coords.x, height, coords.y, 1.0);
	gl_Position = gl_ModelViewProjectionMatrix * position;

	// generate texture coords
	gl_TexCoord[0].xy = gl_Vertex.xy / leafsize;     // coords for layer texture
	gl_TexCoord[1].xy = vec2(coords) / terrainsize;  // coords for alphamap
}

Fragmentshader:

uniform sampler2D layer0;
uniform sampler2D layer1;
uniform sampler2D layer2;
uniform sampler2D alpha;

varying vec3 normal;

void main()
{
	// compute terrain color
	vec3 tex0 = texture2D(layer0, gl_TexCoord[0].xy).rgb;
	vec3 tex1 = texture2D(layer1, gl_TexCoord[0].xy).rgb;
	vec3 tex2 = texture2D(layer2, gl_TexCoord[0].xy).rgb;
	vec3 a = texture2D(alpha, gl_TexCoord[1].xy).rgb;
	vec3 color = a.r*tex0 + a.g*tex1 + a.b*tex2;

	// compute diffuse lighting (directional lightsource only)
	float diffuse = max(dot(gl_LightSource[0].position.xyz, normal), 0.0);
 	gl_FragColor = vec4(diffuse * color + gl_LightSource[0].ambient.xyz, 1.0);
}