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

1

18.02.2010, 10:18

Parallax Occlusion Mapping mit GLSL

Hallöchen,

ich versuche das gerade mal für mich umzusetzen, auch um die Technik, die dahinter steckt, 100% zu raffen. Irgendwo im Netz hab ich jetzt schonmal diese Implementierung gefunden und versuche das ganze nachzuvollziehen:

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
uniform mat4 matView;
uniform mat3 matViewProjection;

uniform float fHeightScale;
uniform float fPerspectiveBias;
uniform vec4 vLightOffset;

varying vec2 TexCoord;
varying vec3 Normal;
varying vec3 Binormal;
varying vec3 Tangent;
varying vec3 EyeVector;
varying vec3 LightVector;
varying vec2 vParallaxXY;

attribute vec3 rm_Binormal;
attribute vec3 rm_Tangent;


void main(void)
{
    // Transform the position

    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

    // Set the texture coordinate

    TexCoord = gl_MultiTexCoord0.xy;

    // Compute the view vector in view space

    vec3 vView = -(matView * gl_Vertex);

    // Compute tangent space basis vector in view space

    vec3 vTangent = mat3(matView) * rm_Tangent;
    vec3 vBinormal = mat3(matView) * rm_Binormal;
    vec3 vNormal = mat3(matView) * Normal;

    // Normalize the view vector in tangent space

    vec3 vViewTS = mat3(vTangent, vBinormal, vNormal) * normalize(vView);

    // Compute initial parallax displacement direction

    vec2 vParallaxDirection = normalize(vViewTS.xy);

    // Compute the length of the parallax displacement vector

    float fParallaxLength = -sqrt(1.0 - vViewTS.z * vViewTS.z) / vViewTS.z;

    // Compute the parallax bias parameter

    float fParallaxBias = fPerspectiveBias + (1.0 - fPerspectiveBias) * (2.0 * vViewTS.z - 1.0);

    // Compute the actual reverse parallax displacement vector

    vParallaxXY = -vParallaxDirection * fParallaxLength * fParallaxBias * fHeightScale;

    // Compute light vector (view space):

    vec3 vLight = vView + vLightOffset;

    // Propagate the view and the light vectors (in tangent space):

    EyeVector = mat3(vTangent, vBinormal, vNormal) * vView;
    LightVector = mat3(vTangent, vBinormal, vNormal) * vLight;
}


Dazu erstmal 3 Fragen:

1) Kann man matView nicht immer durch gl_ModelViewMatrix ersetzen? Der Sinn von z.B. vec3 vView = -(matView * gl_Vertex); soll es ja offensichtlich sein, den Viewvektor im View Space zu berechnen. Da gl_Vertex im Object Space ist und die Modelviewmatrix von Object Space -> View Space mapped, müsste da doch das gleiche bei rauskommen und ich kann mir den Paramater sparen?!

2) float fParallaxLength = -sqrt(1.0 - vViewTS.z * vViewTS.z) / vViewTS.z;

Warum negiert man hier die Länge und teilt nochmal durch die z-Koordinate? Dadurch bekomme ich doch dann die negative Steigung des Viewvektors, nicht die Länge...

3) Was soll dieser fPerspectiveBias repräsentieren?

Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

2

18.02.2010, 10:27

1) Sehe ich auch so, sollte identisch sein. Sich Kamera- und Objekt-Matrix seperat zu übergeben macht bei manchen Dingen durchaus Sinn, aber das ist... da die ModelView-Matrix ja oder so so übergeben wird, ob man will oder nicht, ziemlich sinnfrei.

LG
Alyx

3

07.03.2010, 22:18

Hallo,

ich verzweifle leider immer noch an diesem verdammten Parallax Occlusion Mapping. Ich hab mal den Ausschnitt aus dem Paper zitiert, der mir Probleme bereitet (Anmerkung: Das ist ein Paper über Parallax (ohne Occlusion) Mapping, aber die POM-Paper verweisen darauf, was die Vektorberechnung angeht)

Zitat

A standard height map is used to represent the varying height of the surface. The height
map correlates to the surface's regular texture map and stores one height value per texel.
These values are in the range {0.0, 1.0}.

To compute a texture coordinate offset at a point P, the eye vector must first be normalized
to produce a normalized eye vector V. The height h at the original texture coordinate T_0 is
read from the height map. The height is scaled by a scale factor s and biased by a bias b in
order to map the height from the range {0.0, 1.0} to a range that better represents the physical properties of the surface being simulated. For example, a brick wall texture might
cover a 2x2 meter area. Also imagine the surface of the bricks and the recessed grout give
the surface a thickness of 0.02m. The correct scale factor for this material would be 0.02 /
2 = 0.01. Coupling this with a bias of 0.0 would then remap the height field to a range of
{0.0, 0.01}. Using a bias of 0.01 would remap the range to {0.99, 0.0}. The average of
these two extremes is probably best for most textures.

b = s ∙ 0.5

A bias that excludes 0.0 from the range would be impractical since that assumes that the
surface being simulated does not intersect the polygon that represents it. The new scaled
and biased height hsb is given by

h_sb = h ∙ s + b

An offset is then computed by tracing a vector parallel to the polygon from the point on the
surface directly above P to the eye vector. This new vector is the offset and can be added to
T_0 to produce the new texture coordinate Tn.
T_n = T_0 + ( h_sb ∙ V{x, y} / V{z} )
The new texture coordinate is used to index a regular texture map and any other maps
applied to the surface.



(Link)


1) Warum teile ich die 0.02 nochmal durch die 2 Meter? Wenn die Oberfläche eine Tiefe von 0.02m hat, ist es doch egal, ob die Textur 1x1 oder 200x200 groß ist, die Tiefe bleibt doch immer gleich.

2) So wie es in dem Paper (und der Skizze) beschrieben ist, soll also erst T_0 gesampled werden, die Höhe dort ausgelesen werden und anschließend von diesem Punkt eine Gerade parallel zur Oberfläche gelegt werden, um den Schnittpunkt mit dem Eye-Vektor alias T_n zu finden. Wieso hantieren die da jetzt mit ( h_sb ∙ V{x, y} / V{z} ) rum? Mal abgesehen davon, dass man zwei Vektoren nicht teilen kann, und die jeweils die Länge meinen müssen, ist doch das was vollkommen anderes oder nicht?

Ich finds irgendwie schade und erstaunlich zu gleich, dass man da so wenig Material (oder zumindest wenig noobfreundliches Material) im Netz findet, weil die Technik doch ziemlich beeindruckend ist. Man schreibt da mal ein paar Zeilen Shader und hat nen ganz anderen Realismusgrad was Texturen angeht, aber irgendwie scheinen sich nicht sonderlich viele für interessieren - warum?

Werbeanzeige