Vann - grunnleggende
Funksjonen for å laste gråskalabildene i klassen HeightImageLoader har to parametere "level" som bestemmer hvor på z-aksen (høyde) laveste punkt til høydekartet skal være. Og "diff" som bestemmer høydeforskjellen mellom høyeste og laveste punkt i høydekartet.
public void setData(float diff, float level)
Ved å sette disse verdiene kan en bestemme hvor høyt over bakken vannet skal være og bølgestørrelsen. Bølgene blir generert ved å bruke gråskalabilder tilsvarende de som blir brukt for å generere terrenget.
Hvis f.eks. terrenget har level = 0 og diff = 1000 og vannet har level = 500 og diff = 50 vil kun de delene av terrenget som har høyere z-verdi en 500 syns over vannoverflaten og vannet vil ha små bølger.
Opptegningen foregår på samme måte som med terrenget:
HeightField waterhf = new HeightField(SIZE, stride); for (int x = 1; x < waterhf.getSize()-2; x++) { gl.glBegin(GL_TRIANGLE_STRIP); for (int y = 1; y < waterhf.getSize()-2; y++) { gl.glNormal3f(normalsWater[x][y][0], normalsWater[x][y][1], normalsWater[x][y][2]); gl.glVertex3f(waterhf.getLength(x,y), waterhf.getWidth(x, y), waterhf.getHeight(x, y)); gl.glVertex3f(waterhf.getLength(x+1,y), waterhf.getWidth(x+1, y), waterhf.getHeight(x+1, y)); } } gl.glEnd();
Siden vannet benytter samme HeightField klassen som terrenget blir teksturkoordiantene automatisk generert og kan hentes ut med med metoden:
public float[][][] getTeksturKoor()
Normal kan beregnes med samme klassen Normals som brukes til å generere normaler for terrenget, men det er viktig og huske på å sende med riktig HeightField klasse. Normalene kan hentes ut med metoden:
public float[][][] getNormals()
Det er viktig at terrenget får eksakt lik SIZE og stride som terrenget slik at det dekker hele overflaten. Størrelsen på bildet som brukes til å generere bølger må også være like stor som bildet som brukes til å generere landskap for å få bølger over hele overflaten.
P.S. Denne måten og generere vann med vil også rendre vann under fjelltoppene men det vil ikke syns nå man er over overflaten. En kan lage metoder for å hindre at vannet ikke rendres der det ikke vil syns, men det er fort gjort at vannkanten som er inntill toppene da blir hakkete og stygg.
Gjennomsiktig vann
Og få vannet gjennomsiktig for å kunne se bunnen er ganske enkelt. En trenger kun og slå på blending med metoden:
gl.glEnable(GL_BLEND)
Deretter velge måten man vil blende vannet med bakgrunnen med f.eks.
gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Så må man sette alpha verdiene i materialet som skal bli brukt til overflaten til mindre en 1, f.eks.
public void setMaterialWater() { float amb[] = {0.0f, 1.0f, 1.0f, 0.7f}; float diff[] = {0.0f, 1.0f, 1.0f, 0.7f}; float spec[] = {0.0f, 0.0f, 1.0f, 0.7f}; float shine = 90f; gl.glMaterialfv(GL_FRONT, GL_AMBIENT, amb); gl.glMaterialfv(GL_FRONT, GL_DIFFUSE, diff); gl.glMaterialfv(GL_FRONT, GL_SPECULAR, spec); gl.glMaterialf(GL_FRONT, GL_SHININESS, shine); }
Så tegne vannet med dette materialet på overflaten. Vannet vil da bli turkisaktig. Så slå av blending når opptegning er ferdig med metoden:
gl.glDisable(GL_BLEND)
Og vips, så har du en gjennomsiktig vannoverflate.
OBS! Koden som er presentert her tegner selvfølgelig kun ut vannoverflaten, hvis man kikker under vann vil det ikke lenger se realistisk ut. Dette kan løses på mange forskjellige måter med det vil jeg ikke gå inn på her.
- Modulen Høydekart
- Terreng.java