2011-10-03 12 views
12

Próbuję utworzyć teren 3D przy użyciu WebGL. Mam jpg z teksturą dla terenu i inny jpg z wartościami wysokości (-1 do 1).WebGL - Teksturowany teren z mapą wysokości

Przeglądałem różne biblioteki opakowujące (takie jak SpiderGL i Three.js), ale nie mogę znaleźć odpowiedniego przykładu, a jeśli to zrobię (jak w Three.js), kod nie jest udokumentowany i mogę nie wiem, jak to zrobić.

Czy ktoś może podać mi dobry samouczek lub przykład?

Jest przykład na Three.js http://mrdoob.github.com/three.js/examples/webgl_geometry_terrain.html, który jest prawie tym, czego chcę. Problem polega na tym, że losowo tworzą kolor gór i wartości wysokości. Chcę odczytać te wartości z 2 różnych plików graficznych.

Każda pomoc byłaby przydatna. Dzięki

+0

Po prostu informacja, że ​​JPEG może nie być najlepszym formatem dla terenu, ponieważ jest stratny, a artefakty JPEG staną się subtelnymi uderzeniami w terenie, czego prawdopodobnie nie spodziewałbyś się znaleźć. – izb

Odpowiedz

5

dwie metody, które można myślę:

  1. Załóż wierzchołki krajobrazowych w postaci płaskiej siatki. Użyj Vertex Texture Lookups, aby zapytać o mapę wysokości i zmodyfikuj wysokość (prawdopodobnie Twój komponent Y) każdego punktu. Prawdopodobnie byłoby to najprostsze, ale nie sądzę, że obsługa przeglądarki jest teraz bardzo dobra. (W rzeczywistości nie mogę znaleźć żadnych przykładów)
  2. Załaduj obraz, wyrenderuj go na płótnie i użyj go do odczytania wartości wysokości. Zbuduj na tej podstawie statyczną siatkę. Prawdopodobnie będzie to szybsze renderowanie, ponieważ moduły cieniujące wykonują mniej pracy. Jednak do budowy siatki wymagane jest więcej kodu.

Na przykład czytanie danych obrazu, można sprawdzić this SO question.

+1

Opcja 2 sprawdzi się lepiej w niemal każdym przypadku. Opcja 1 jest odpowiednia tylko wtedy, gdy renderujesz tylko teren, ponieważ wszystkie dane elewacji będą znane tylko przez moduł cieniujący i będziesz potrzebował innych środków do umieszczenia (prawdopodobnie) innych obiektów sceny. – Chiguireitor

12

sprawdź ten post nad na GitHub:

https://github.com/mrdoob/three.js/issues/1003

Ten przykład umieszczonego tam przez florianf pomógł mi być w stanie to zrobić.

function getHeightData(img) { 
    var canvas = document.createElement('canvas'); 
    canvas.width = 128; 
    canvas.height = 128; 
    var context = canvas.getContext('2d'); 

    var size = 128 * 128, data = new Float32Array(size); 

    context.drawImage(img,0,0); 

    for (var i = 0; i < size; i ++) { 
     data[i] = 0 
    } 

    var imgd = context.getImageData(0, 0, 128, 128); 
    var pix = imgd.data; 

    var j=0; 
    for (var i = 0, n = pix.length; i < n; i += (4)) { 
     var all = pix[i]+pix[i+1]+pix[i+2]; 
     data[j++] = all/30; 
    } 

    return data; 
} 

Demo: http://oos.moxiecode.com/js_webgl/terrain/index.html

2

Możesz być zainteresowany w moim blogu na temat: http://www.pheelicks.com/2014/03/rendering-large-terrains/

I skupić się na jak skutecznie tworzyć geometrię terenu tak, że masz odpowiedni poziom szczegółowości zarówno w polu bliskim, jak i daleko.

można zobaczyć prezentację wyniku tutaj: http://felixpalmer.github.io/lod-terrain/ i cały kod jest maksymalnie na github: https://github.com/felixpalmer/lod-terrain

Aby zastosować teksturę terenu, trzeba zrobić odnośnika tekstury w fragment shader, mapowanie położenie w przestrzeni do pozycji w twojej fakturze. Na przykład.

vec2 st = vPosition.xy/1024.0; 
vec3 color = texture2D(uColorTexture, st) 
0

W zależności od twoich umiejętności GLSL, można napisać shaderów GLSL wierzchołków, przypisać tekstury do jednego z kanałów tekstury i odczytać wartość w vertex shader (wierzę trzeba nowoczesną kartę do odczytu tekstur w module cieniującym wierzchołków, ale to może być po prostu pokazanie mojego wieku: P)

W wierzchołku modułu cieniującego przetłumaczyć wartość z wierzchołka na podstawie wartości odczytanej z tekstury.

0

Babylon.js czyni to niezwykle łatwym do wdrożenia. Możesz zobaczyć przykład na: Heightmap Playground

Oni nawet realizowane silnik fizyki Cannon.js z nim, więc można obsługiwać kolizje: Heightmap with collisions

Uwaga: W chwili pisania tego działa tylko z armaty Wtyczka fizyczna .js i tarcie nie działa (musi być ustawione na 0). Upewnij się też, że ustawiłeś lokalizację siatki/oszusta PRZED ustawieniem stanu fizyki, lub uzyskasz dziwne zachowanie.