Vworld 3D Data를 Three.js로 출력하기

Vworld 3D Data를 Three.js로 출력하기

Vworld WebGL기반 3차원 지도

Vworld WebGL기반 3차원 지도 에 접속하시면 아래와 같은 화면을 볼 수 있습니다.

여기서 WebGL 이란

  • 웹 기반의 그래픽 라이브러리
  • 자바스크립트 프로그래밍 언어를 통해서 사용
  • 호환성이 있는 웹 브라우저에서 인터랙티브한 3D 그래픽을 사용할 수 있도록 제공

(출처: 위키피디아)

3D 데이터API 레퍼런스 소개

데이터 API는 브이월드에서 제공하는 다양한 국가공간정보를 외부(기관,기업,개인등)에서 활용할 수 있도록 XML또는 JSON형식으로 데이터를 제공하는 API서비스 입니다.

어떻게 사용해야 하나요?

어떤 데이터가 어떻게 제공 되나요?

3D 데이터API 레퍼런스

키 발급

개발자센터 > 인증키 > 인증키 발급에서 키를 발급 받을 수 있습니다. (로그인 되어 있어야 이용 가능합니다. )

1
2
3
4
// 발급 받은 키
3XE3C10E-82B7-3E7F-AC31-37175F32CDE4


개인 키를 발급 받아서 사용하시기 바랍니다.

레이어 목록 요청 API

출력 결과

각 요소별 정의

데이터 요청

발급받은 키를 사용하여 요청합니다.

URL http://xdworld.vworld.kr:8080/XDServer/3DData
Version 2.0.0.0
Request GetCapabilites
Key 3XE3C10E-82B7-3E7F-AC31-37175F32CDE4

// 요청 URL

http://xdworld.vworld.kr:8080/XDServer/3DData?Version=2.0.0.0&Request=GetCapabilities&Key=3XE3C10E-82B7-3E7F-AC31-37175F32CDE4

요청 결과

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
<GetCapabilities>
<SCRIPT id="allow-copy_script">
(function agent() { let isUnlockingCached = false const isUnlocking = () => isUnlockingCached document.addEventListener('allow_copy', event => { const { unlock } = event.detail isUnlockingCached = unlock }) const copyEvents = [ 'copy', 'cut', 'contextmenu', 'selectstart', 'mousedown', 'mouseup', 'mousemove', 'keydown', 'keypress', 'keyup', ] const rejectOtherHandlers = e => { if (isUnlocking()) { e.stopPropagation() if (e.stopImmediatePropagation) e.stopImmediatePropagation() } } copyEvents.forEach(evt => { document.documentElement.addEventListener(evt, rejectOtherHandlers, { capture: true, }) }) })()
</SCRIPT>
<Version>2.0.0.0</Version>
<Layers Count="77">
<Layer Name="tile" Type="terrainImg" MinLevel="0" MaxLevel="15"/>
<Layer Name="dem" Type="terrainDEM" MinLevel="0" MaxLevel="15"/>
<Layer Name="2015" Type="time" MinLevel="0" MaxLevel="15"/>
<Layer Name="2016" Type="time" MinLevel="0" MaxLevel="15"/>
<Layer Name="2017" Type="time" MinLevel="0" MaxLevel="15"/>
<Layer Name="2018" Type="time" MinLevel="0" MaxLevel="16"/>
<Layer Name="tile_mo" Type="terrainImg_MO" MinLevel="0" MaxLevel="18"/>
<Layer Name="tile_mo_2015" Type="terrainImg_2015" MinLevel="0" MaxLevel="18"/>
<Layer Name="tile_mo_HD" Type="terrainImg_MO_HD" MinLevel="0" MaxLevel="18"/>
<Layer Name="tile_mo2d" Type="terrainImg_MO2D" MinLevel="0" MaxLevel="15"/>
<Layer Name="tile_mo2d_HD" Type="terrainImg_MO2DHD" MinLevel="0" MaxLevel="15"/>
<Layer Name="dem_mo" Type="terrainDEM_MO" MinLevel="0" MaxLevel="15"/>
<Layer Name="indoor_build" Type="Indoor" MinLevel="0" MaxLevel="15"/>
<Layer Name="indoor_build_HD" Type="Indoor" MinLevel="0" MaxLevel="15"/>
<Layer Name="facility_build_boan" Type="boan1" MinLevel="0" MaxLevel="15"/>
<Layer Name="facility_bridge_boan" Type="boan1" MinLevel="0" MaxLevel="15"/>
<Layer Name="facility_build_lod1" Type="boan1" MinLevel="0" MaxLevel="15"/>
<Layer Name="hybrid_2017" Type="boan2" MinLevel="5" MaxLevel="15"/>
<Layer Name="facility_build" Type="Real3D" MinLevel="0" MaxLevel="15"/>
<Layer Name="facility_build_world" Type="Real3D" MinLevel="0" MaxLevel="15"/>
<Layer Name="facility_build_world_mo" Type="Real3D" MinLevel="0" MaxLevel="15"/>
<Layer Name="facility_bridge" Type="Real3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="facility_dokdo" Type="Real3D" MinLevel="0" MaxLevel="13"/>
<Layer Name="facility_build_at" Type="Real3D" MinLevel="0" MaxLevel="15"/>
<Layer Name="facility_build_mo" Type="Real3D" MinLevel="0" MaxLevel="15"/>
<Layer Name="facility_dokdo_mo" Type="Real3D" MinLevel="0" MaxLevel="13"/>
<Layer Name="facility_bridge_mo" Type="Real3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="facility_bridge_ag" Type="Real3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="facility_build_ag" Type="Real3D" MinLevel="0" MaxLevel="15"/>
<Layer Name="facility_bridge_ag_mo" Type="Real3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="facility_build_ag_mo" Type="Real3D" MinLevel="0" MaxLevel="15"/>
<Layer Name="facility_indoor" Type="Real3D" MinLevel="0" MaxLevel="15"/>
<Layer Name="facility_olympic2018" Type="Real3D" MinLevel="0" MaxLevel="15"/>
<Layer Name="tile_bridge_mo" Type="terrainImg_wgt" MinLevel="10" MaxLevel="14"/>
<Layer Name="tile_build_mo" Type="terrainImg_wgt" MinLevel="10" MaxLevel="15"/>
<Layer Name="poi_base" Type="Point3D" MinLevel="0" MaxLevel="16"/>
<Layer Name="poi_base_u8" Type="Point3D" MinLevel="0" MaxLevel="16"/>
<Layer Name="poi_base_north" Type="Point3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="poi_base_world" Type="Point3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="poi_bound" Type="Point3D" MinLevel="0" MaxLevel="11"/>
<Layer Name="poi_bound_north" Type="Point3D" MinLevel="0" MaxLevel="8"/>
<Layer Name="poi_bound_world" Type="Point3D" MinLevel="0" MaxLevel="7"/>
<Layer Name="poi_road" Type="Point3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="poi_road_north" Type="Point3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="poi_em_base" Type="Point3D" MinLevel="0" MaxLevel="16"/>
<Layer Name="poi_em_bound" Type="Point3D" MinLevel="0" MaxLevel="12"/>
<Layer Name="poi_em_dept" Type="Point3D" MinLevel="0" MaxLevel="7"/>
<Layer Name="poi_em_dokdo" Type="Point3D" MinLevel="0" MaxLevel="15"/>
<Layer Name="poi_em_embassy" Type="Point3D" MinLevel="0" MaxLevel="6"/>
<Layer Name="poi_em_issue" Type="Point3D" MinLevel="0" MaxLevel="4"/>
<Layer Name="poi_em_korea" Type="Point3D" MinLevel="0" MaxLevel="4"/>
<Layer Name="poi_em_park" Type="Point3D" MinLevel="0" MaxLevel="4"/>
<Layer Name="poi_em_whc" Type="Point3D" MinLevel="0" MaxLevel="4"/>
<Layer Name="poi_base_north_u8" Type="Point3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="poi_base_world_u8" Type="Point3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="poi_bound_u8" Type="Point3D" MinLevel="0" MaxLevel="11"/>
<Layer Name="poi_bound_north_u8" Type="Point3D" MinLevel="0" MaxLevel="8"/>
<Layer Name="poi_bound_world_u8" Type="Point3D" MinLevel="0" MaxLevel="7"/>
<Layer Name="poi_road_u8" Type="Point3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="poi_road_north_u8" Type="Point3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="poi_indoor" Type="Point3D" MinLevel="0" MaxLevel="14"/>
<Layer Name="hybrid_road" Type="HybridImg" MinLevel="5" MaxLevel="16"/>
<Layer Name="hybrid_bound" Type="HybridImg" MinLevel="0" MaxLevel="14"/>
<Layer Name="hybrid_add_sansatai" Type="HybridImg" MinLevel="5" MaxLevel="14"/>
<Layer Name="hybrid_road_mo" Type="HybridImg" MinLevel="5" MaxLevel="16"/>
<Layer Name="hybrid_silgam" Type="HybridImg" MinLevel="5" MaxLevel="15"/>
<Layer Name="hybrid_2016" Type="HybridImg" MinLevel="5" MaxLevel="15"/>
<Layer Name="bill_Tree" Type="Billboard3D" MinLevel="0" MaxLevel="16"/>
<Layer Name="timeseries" Type="TimeseriesImg" MinLevel="0" MaxLevel="16"/>
<Layer Name="T197801" Type="TimeseriesImg" MinLevel="0" MaxLevel="16"/>
<Layer Name="T198901" Type="TimeseriesImg" MinLevel="0" MaxLevel="16"/>
<Layer Name="T195001" Type="TimeseriesImg" MinLevel="0" MaxLevel="16"/>
<Layer Name="T195101" Type="TimeseriesImg" MinLevel="0" MaxLevel="16"/>
<Layer Name="T195212" Type="TimeseriesImg" MinLevel="0" MaxLevel="16"/>
<Layer Name="T199601" Type="TimeseriesImg" MinLevel="0" MaxLevel="16"/>
<Layer Name="T200601" Type="TimeseriesImg" MinLevel="0" MaxLevel="16"/>
<Layer Name="T200712" Type="TimeseriesImg" MinLevel="0" MaxLevel="14"/>
</Layers>
</GetCapabilities>

이 중에서 facility_build 를 사용하겠습니다.

1
<Layer Name="facility_build" Type="Real3D" MinLevel="0" MaxLevel="15"/>

데이터 검색 요청 API(GetLayerExists)

요청 변수

출력결과

각 요소별 정의

데이터 요청

발급받은 키를 사용하여 요청합니다.

URL http://xdworld.vworld.kr:8080/XDServer/3DData
Version 2.0.0.0
Request GetLayerExists
Key 3XE3C10E-82B7-3E7F-AC31-37175F32CDE4

추가 되는 내용들

Layer facility_build
Level 15
BBOX 126.976987,37.570187,126.979433,37.574251
CheckFlag True

http://xdworld.vworld.kr:8080/XDServer/3DData?Version=2.0.0.0&Request=GetLayerExists&Key=3XE3C10E-82B7-3E7F-AC31-37175F32CDE4&Layer=facility_build&Level=15&BBOX=126.976987,37.570187,126.979433,37.574251&CheckFlag=True

요청 결과

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
<SearchResult>
<Version>2.0.0.0</Version>
<Layer Name="facility_build">
<Nodes Level="15" NodeCount="18">
<Node IDX="279417" IDY="116117" Flag="false"/>
<Node IDX="279418" IDY="116117" Flag="false"/>
<Node IDX="279419" IDY="116117" Flag="false"/>
<Node IDX="279420" IDY="116117" Flag="false"/>
<Node IDX="279417" IDY="116118" Flag="false"/>
<Node IDX="279418" IDY="116118" Flag="false"/>
<Node IDX="279419" IDY="116118" Flag="false"/>
<Node IDX="279420" IDY="116118" Flag="false"/>
<Node IDX="279417" IDY="116119" Flag="false"/>
<Node IDX="279418" IDY="116119" Flag="false"/>
<Node IDX="279419" IDY="116119" Flag="false"/>
<Node IDX="279420" IDY="116119" Flag="false"/>
<Node IDX="279417" IDY="116120" Flag="false"/>
<Node IDX="279418" IDY="116120" Flag="false"/>
<Node IDX="279419" IDY="116120" Flag="false"/>
<Node IDX="279420" IDY="116120" Flag="false"/>
<Node IDX="279417" IDY="116121" Flag="false"/>
<Node IDX="279418" IDY="116121" Flag="false"/>
<Node IDX="279419" IDY="116121" Flag="false"/>
<Node IDX="279420" IDY="116121" Flag="false"/>
</Nodes>
</Layer>
</SearchResult>

이 중에서 가장 마지막에 있는 것을 이용해보도록 하겠습니다.

1
<Node IDX="279420" IDY="116121" Flag="false"/>

레이어 노드 및 객체 요청 API(GetLayer)

요청 URL

요청 변수

데이터 요청

URL http://xdworld.vworld.kr:8080/XDServer/3DData
Version 2.0.0.0
Request GetLayer
Key 3XE3C10E-82B7-3E7F-AC31-37175F32CDE4

추가 되는 내용들

Layer facility_build
Level 15
IDX 279420
IDY 116121

http://xdworld.vworld.kr:8080/XDServer/3DData?Version=2.0.0.0&Request=GetLayer&Key=3XE3C10E-82B7-3E7F-AC31-37175F32CDE4&Layer=facility_build&Level=15&IDX=279420&IDY=116121

위의 요청을 보내면 3DData 바이너리 파일이 리턴됩니다.

요청 결과

VWorld 3D Map Binary Data File Format을 확인하여 리턴된 바이너리 파일을 분석합니다.

Header 정보

Name Size(byte) Type 설명
Level 4 u32 레벨 (0 베이스)
IDX 4 u32 경도 ID
IDY 4 u32 위도 ID
Object Count 4 u32 객체의 총수

Model Object 정보

Name Size(byte) Type 설명
Version 4 u32 객체의 등록 버전 (XDO 파일의 버전정보)
Type 1 u8 객체의 타입 (객체의 타입정보 - 8로 고정: 예약됨)
KeyLen 1 u8 객체의 키값 크기
Key KeyLen char* 객체의 키값 (객체의 고유 ID 값)
CenterPos 16 vector2dd 객체의 중심좌표 (경위도 radian) (Model이 위치 할 공간좌표 경위도값)
altitude 4 f32 객체의 고도값 (Model이 위치 할 공간의 해발고도 높이)
box 48 aabbox3dd 객체의 바운더리 (구면 Vector) (Model 의 3차원 최대, 최소 공간 영역 좌표 정보)
ImgLevel 1 u8 이미지 레벨 (사용되는 LOD 레벨의 수)
dataFileLen 1 u8 객체의 파일이름 길이
dataFile dataFileLen char* 객체의 파일이름 (확장자 포함) (Tile 내에 실제 Model의 XDO 파일명)
imgFileNameLen 1 u8 이미지 파일이름 길이
imgFileName imgFileNameLen char* 이미지 파일이름 (XDO 파일이 사용하는 Texture 이미지 명)

Parsing

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
var idx = 279420
var idy = 116121
var layerUrl = `http://xdworld.vworld.kr:8080/XDServer/3DData?Version=2.0.0.0&Request=GetLayer&Key=3XE3C10E-82B7-3E7F-AC31-37175F32CDE4&Layer=facility_build&Level=15&IDX=${idx}&IDY=${idy}`;

var promise = $.ajax({
url: layerUrl,
dataType: "binary",
});

promise.done(function (data) {
var p = new Parser(data);

// header
_data.level = p.getUint4();
_data.idx = p.getUint4();
_data.idy = p.getUint4();
_data.objectCount = p.getUint4();

// model object
_data.version = p.getVersion();
_data.type = p.getUint1();
var lenStr = p.getLenStr();
_data.keyLen = lenStr.len;
_data.key = lenStr.str;

_data.centerPosX = p.getFloat8();
_data.centerPosY = p.getFloat8();
_data.altitude = p.getFloat4();
_data.box = p.getBox3dd();

_data.imgLevel = p.getUint1();
var lenStr = p.getLenStr();
_data.dataFileLen = lenStr.len;
_data.dataFileName = lenStr.str;

var lenStr = p.getLenStr();
_data.imgFileLen = lenStr.len;
_data.imgFileName = lenStr.str;

resolve();
});

이렇게 하면 아래와 같은 정보를 얻을 수 있습니다.

크롬 개발자 도구 캡쳐 화면

여기서 얻은 파일명을 사용하여 3D data 를 조회합니다.

  • dataFileName : a13_52.xdo
  • imgFileName: a13_52.jpg

Parser Class

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
$(document).ready(function () {
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
if (settings.dataType === 'binary') {
settings.xhr().responseType = 'blob';
}
}
});

$.ajaxTransport("+binary", function (options, originalOptions, jqXHR) {
if (window.FormData && ((options.dataType && (options.dataType == 'binary'))
|| (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer)
|| (window.Blob && options.data instanceof Blob))))) {
return {
send: function (headers, callback) {
var xhr = new XMLHttpRequest(),
url = options.url,
type = options.type,
async = options.async || true,
dataType = options.responseType || "arraybuffer",
data = options.data || null;

xhr.addEventListener('load', function () {
var data = {};
data[options.dataType] = xhr.response;
callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
});

xhr.open(type, url, async);

for (var i in headers) {
xhr.setRequestHeader(i, headers[i]);
}

xhr.responseType = dataType;
xhr.send(data);
},
abort: function () {
}
};
}
});
});

class Parser {
constructor(data) {
this.dv = new DataView(data);
this.endian = true;
this.offset = 0;
}

getUint4() {
const val = this.dv.getUint32(this.offset, this.endian);
this.offset += 4;
return val;
}

getUint1() {
const val = this.dv.getUint8(this.offset, this.endian);
this.offset += 1;
return val;
}

getUint2() {
const val = this.dv.getUint16(this.offset, this.endian);
this.offset += 2;
return val;
}

getLenStr() {
const len = this.getUint1();

var str = "";
var val = "";
for (var i = 0; i < len; i++) {
val = this.getUint1();
str += String.fromCharCode(val);
}
return {
len: len,
str: str,
};
}

getFloat8() {
const val = this.dv.getFloat64(this.offset, this.endian);
this.offset += 8;
return val;
}

getFloat4() {
const val = this.dv.getFloat32(this.offset, this.endian);
this.offset += 4;
return val;
}

getVersion() {
const val = `${this.getUint1()}.${this.getUint1()}.${this.getUint1()}.${this.getUint1()}`;
return val;
}

getBox() {
var minX = this.getFloat8();
var maxX = this.getFloat8();
var minY = this.getFloat8();
var maxY = this.getFloat8();
var minZ = this.getFloat8();
var maxZ = this.getFloat8();
return {
minX: minX,
maxX: maxX,
minY: minY,
maxY: maxY,
minZ: minZ,
maxZ: maxZ
}
}

getVector2df() {
var x = this.getFloat4();
var y = this.getFloat4();
return {
x: x,
y: y
}
}

getVector3df() {
var x = this.getFloat4();
var y = this.getFloat4();
var z = this.getFloat4();
return {
x: x,
y: y,
z: z
}
}

getVector3dd() {
var x = this.getFloat8();
var y = this.getFloat8();
var z = this.getFloat8();
return {
x: x,
y: y,
z: z
}
}

//http://irrlicht.sourceforge.net/docu/structirr_1_1video_1_1_s3_d_vertex.html
getCountVert() {
const count = this.getUint4();
var vert = [];
for (var i = 0; i < count; i++) {
const pos = this.getVector3df();
const normal = this.getVector3df();
const uv = this.getVector2df();

vert.push({
pos: pos,
normal: normal,
uv: uv
})
}
return {
count: count,
vert: vert
};
}

getCountIndex() {
const count = this.getUint4();
var index = [];
for (var i = 0; i < count; i++) {
const val = this.getUint2();
index.push(val)
}
return {
count: count,
index: index
};
}


getBox3dd() {
const min = this.getVector3dd();
const max = this.getVector3dd();
return {
min: min,
max: max
}
}
}

데이터 파일 조회

위에서 얻은 데이터 파일명을 사용하여 조회합니다.

URL http://xdworld.vworld.kr:8080/XDServer/3DData
Version 2.0.0.0
Request GetLayer
Key 3XE3C10E-82B7-3E7F-AC31-37175F32CDE4
Layer facility_build
Level 15
IDX 279420
IDY 116121
DataFile a13_52.xdo

요청 URL

http://xdworld.vworld.kr:8080/XDServer/3DData?Version=2.0.0.0&Request=GetLayer&Key=3XE3C10E-82B7-3E7F-AC31-37175F32CDE4&Layer=facility_build&Level=15&IDX=279420&IDY=116121&DataFile=a13_112.xdo

VWorld 3D Map Binary Data File Format을 확인하여 리턴된 바이너리 파일을 분석합니다.

Real3D Model Data (*.xdo) Format 구성

Object Attribute

Name Size(byte) Type 설명
Type 1 u8 객체의 타입 (객체의 형식 Real3D Model 은 8 고정으로 사용)
Object ID 4 u32 객체의 고유번호 (객체의 고유 ID 식별번호, 레이어 기준으로 객체 등록 번호)
KeyLen 1 u8 객체의 키값 길이
Key KeyLen char* 객체의 키값 (객체의 고유 식별 문자열)
Object Box 48 aabbox3dd 객체의 범위 (구면 Vector) (객체의 최대 최소 영역 범위, World Wind 구면 Vector 좌표계)
Altitude 4 f32 객체의 높이 (객체의 바닥면 기준 해발고도 높이)

3D Mesh Data

Name Size (byte) Type 설명
Vertex Count 4 u32 버텍스 총수
Vertex Vertex Count S3DVertex* 버텍스 값 (형상을 구성하는 정규화된 공간 좌표점)
Indexed Count 4 u32 인덱스 총수
Indexed Indexed Count u16* 인덱스 값 (Vertex 정점을 삼각형 그릴 시에 그리는 순서 리스트)
Color 4 u32 객체색상 (Mesh의 재질의 색상(A8R8G8B8))
ImageLevel 1 byte 이미지 LOD 총 레벨 (LOD 텍스처의 레벨 단계)
ImageNameLen 1 byte 텍스쳐 이미지명 길이
imageName ImageNameLen char* 텍스처 이미지명(확장자 제외, jpg) (LOD 텍스처 파일명)

index를 확인합니다.

vertex 를 확인합니다.

V-World 2013 Data Format Schema

S3DVertex

Name Size(byte) Type 설명
Pos 12 vector3df 버텍스 좌표
Normal 12 vector3df 버텍스 노말
UV 8 vector2df 텍스처 UV

aabbox3d

Name Size(byte) Type 설명
Min 24 vector3dd 최소 좌표점
Max 24 vector3dd 최대 좌표점

vector2df

Name Size(byte) Type 설명
x 4 float x축 값
y 4 float y축 값

vector2dd

Name Size(byte) Type 설명
x 8 double x축 값
y 8 double y축 값

vector3df

Name Size(byte) Type 설명
x 4 float x축 값
y 4 float y축 값
z 4 float z축 값

vector3dd

Name Size(byte) Type 설명
x 8 double x축 값
y 8 double y축 값
z 8 double z축 값

이미지 파일 조회

위에서 얻은 이미지 파일명을 사용하여 조회합니다.

URL http://xdworld.vworld.kr:8080/XDServer/3DData
Version 2.0.0.0
Request GetLayer
Key 3XE3C10E-82B7-3E7F-AC31-37175F32CDE4
Layer facility_build
Level 15
IDX 279420
IDY 116121
DataFile a13\_52.jpg

http://xdworld.vworld.kr:8080/XDServer/3DData?Version=2.0.0.0&Request=GetLayer&Key=3XE3C10E-82B7-3E7F-AC31-37175F32CDE4&Layer=facility_build&Level=15&IDX=279420&IDY=116121&DataFile=a13_52.jpg

다운로드 받은 파일의 확장자를 jpg로 변경하여 이미지를 확인할 수 있습니다.

여기까지 해서 오브젝트 생성을 위한 데이터를 모두 얻었습니다.

오브젝트 생성 (Three.js 사용)

기본 구조는 이렇습니다.

  1. Geometry 생성
  2. 버텍스 추가
  3. 버텍스 인덱스 추가
  4. UV 추가
  5. 이미지 파일 추가
  6. 메테리얼 생성
  7. 메시 생성

샘플 코드

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
var vert = data.vert;
var index = data.index;

// 1. Geometry 생성
var geometry = new THREE.Geometry();

for (var i = 0; i < vert.length; i += 3) {
var v1 = vert[i];
var v2 = vert[i + 1];
var v3 = vert[i + 2];

// 2. 버텍스 추가
geometry.vertices.push(new THREE.Vector3(v1.pos.x, v1.pos.y, v1.pos.z));
geometry.vertices.push(new THREE.Vector3(v2.pos.x, v2.pos.y, v2.pos.z));
geometry.vertices.push(new THREE.Vector3(v3.pos.x, v3.pos.y, v3.pos.z));

// 3. 버텍스 인덱스 추가
geometry.faces.push(new THREE.Face3(index[i], index[i + 1], index[i + 2]));

// 4. UV 추가
geometry.faceVertexUvs[0].push([
new THREE.Vector2(v1.uv.x, 1 - v1.uv.y),
new THREE.Vector2(v3.uv.x, 1 - v3.uv.y),
new THREE.Vector2(v2.uv.x, 1 - v2.uv.y)
]);
}

geometry.uvsNeedUpdate = true;

// 5. 이미지 파일 추가
const textureLoader = new THREE.TextureLoader();
textureLoader.crossOrigin = "Anonymous";
const myTexture = textureLoader.load(jpgUrl);

// 6. 메테리얼 생성
var material = new THREE.MeshBasicMaterial({
side: THREE.DoubleSide,
map: myTexture
});

// 7. 메시 생성
var build = new THREE.Mesh(geometry, material);

코드상에 잘못된 부분이 있으면 말씀해 주세요.

여기까지가 메시를 생성하는 부분이고, 이후에는 Three.js Scene에 추가합니다.

  1. Scene 생성
  2. 카메라 생성
  3. 렌더러 생성
  4. 컨테이너에 추가
  5. 메쉬 추가
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
<html>
<div id="ThreeContainer"></div>
<script>
function initThree() {
var fov = 45;
var width = window.innerWidth;
var height = window.innerHeight;
var aspect = width / height;
var near = 1;
var far = 10 * 1000 * 1000;

// 1. Scene 생성
_three.scene = new THREE.Scene();
// 2. 카메라 생성
_three.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
// 3. 렌더러 생성
_three.renderer = new THREE.WebGLRenderer({alpha: true});
// 4. 컨테이너에 추가
_ThreeContainer.appendChild(_three.renderer.domElement);
}

function init3DObject(){
// ... 위의 코드 ...

var buildGroup = new THREE.Group();
buildGroup.add(build);
// 5. 메쉬 추가
_three.scene.add(buildGroup); // don’t forget to add it to the Three.js scene manually
}

initThree(); // Initialize Three.js renderer
init3DObject(); // Initialize Three.js object mesh with Cesium Cartesian coordinate system
</script>
</html>

이렇게 하면 Vworld 로 부터 받은 3D data 를 Three.js 로 그릴 수 있습니다.

공유하기