1+ <!DOCTYPE html>
2+ < html lang ="en ">
3+
4+ < head >
5+ < meta charset ="UTF-8 " />
6+ < meta name ="viewport " content ="width=device-width, initial-scale=1.0 " />
7+ < title > space search</ title >
8+ < link type ="text/css " rel ="stylesheet " href ="../main.css " />
9+ </ head >
10+
11+ < body >
12+ <!-- scripts -->
13+ < script type ="module ">
14+ import * as THREE from "three" ;
15+ import * as dat from "dat.gui" ;
16+ import { OrbitControls } from "three/examples/jsm/controls/OrbitControls" ;
17+ import Stats from "three/examples/jsm/libs/stats.module" ;
18+ import { KdTree } from '@sadyx019/kd-tree' ;
19+
20+ let screenWidth = window . innerWidth ;
21+ let screenHeight = window . innerHeight ;
22+
23+ // three
24+ let container , stats , scene , renderer , camera , orbitControl , directionalLight , ambientLight ;
25+ let planeMesh , modelMesh , tree ;
26+ let pointIndexCache = new Set ( ) ;
27+
28+ const distanceFn = ( a , b ) => {
29+ return Math . sqrt (
30+ Math . pow ( ( a [ 0 ] - b [ 0 ] ) , 2 )
31+ + Math . pow ( ( a [ 1 ] - b [ 1 ] ) , 2 )
32+ + Math . pow ( ( a [ 2 ] - b [ 2 ] ) , 2 )
33+ ) ;
34+ }
35+
36+ // gui
37+ const params = {
38+ 'kd-tree' : false ,
39+ range : 10 ,
40+ wireframe : false ,
41+ } ;
42+
43+ const gui = new dat . GUI ( ) ;
44+ gui . add ( params , 'kd-tree' ) ;
45+ gui . add ( params , 'range' , 3 , 30 ) ;
46+ gui . add ( params , 'wireframe' ) . onChange ( ( ) => {
47+ if ( planeMesh ) {
48+ planeMesh . material . wireframe = params . wireframe ;
49+ }
50+ } ) ;
51+
52+ //
53+ const initThree = ( ) => {
54+ container = document . createElement ( "div" ) ;
55+ document . body . appendChild ( container ) ;
56+
57+ // stats
58+ stats = new Stats ( ) ;
59+ container . appendChild ( stats . dom ) ;
60+
61+ // scene
62+ scene = new THREE . Scene ( ) ;
63+
64+ // renderer
65+ renderer = new THREE . WebGLRenderer ( {
66+ antialias : true ,
67+ } ) ;
68+ renderer . setPixelRatio ( window . devicePixelRatio ) ;
69+ renderer . setSize ( screenWidth , screenHeight ) ;
70+ container . appendChild ( renderer . domElement ) ;
71+
72+ // cameras
73+ camera = new THREE . PerspectiveCamera (
74+ 50 ,
75+ screenWidth / screenHeight ,
76+ 0.01 ,
77+ 10000
78+ ) ;
79+ camera . position . set ( 100 , 100 , 100 ) ;
80+
81+ // control
82+ orbitControl = new OrbitControls ( camera , renderer . domElement ) ;
83+ // orbitControl.enableDamping = true;
84+
85+ // light
86+ directionalLight = new THREE . DirectionalLight ( 0xffffff , 0.3 ) ;
87+ directionalLight . position . set ( - 7 , 8 , 9 ) ;
88+ scene . add ( directionalLight ) ;
89+
90+ ambientLight = new THREE . AmbientLight ( 0x404040 ) ;
91+ scene . add ( ambientLight ) ;
92+
93+ // helper
94+ const helper = new THREE . AxesHelper ( 3 ) ;
95+ scene . add ( helper ) ;
96+ } ;
97+
98+ //
99+ const startTime = performance . now ( ) ;
100+ const render = ( ) => {
101+ orbitControl . update ( ) ;
102+ renderer . render ( scene , camera ) ;
103+ } ;
104+
105+ const animate = ( ) => {
106+ requestAnimationFrame ( animate ) ;
107+
108+ const time = ( performance . now ( ) - startTime ) / 1000 ;
109+
110+ // set color
111+ if ( planeMesh && modelMesh && tree ) {
112+ const colors = planeMesh . geometry . attributes . color . array ;
113+ const newPosition = [
114+ 40 * Math . sin ( time ) ,
115+ 0.5 ,
116+ 40 * Math . cos ( time ) ,
117+ ] ;
118+
119+ modelMesh . position . set ( ...newPosition ) ;
120+
121+ // use kd tree
122+ if ( params [ 'kd-tree' ] ) {
123+ const points = tree . getNearestByDistance ( newPosition , params . range ) ;
124+
125+ const newIndex = new Set ( ) ;
126+ points . forEach ( ( { data } ) => {
127+ const index = data [ 3 ] ;
128+
129+ newIndex . add ( index ) ;
130+
131+ // already include
132+ if ( pointIndexCache . has ( index ) ) {
133+ pointIndexCache . delete ( index ) ;
134+ return ;
135+ }
136+
137+ // should be colored
138+ colors [ index ] = 1 ;
139+ colors [ index + 1 ] = 0 ;
140+ colors [ index + 2 ] = 0 ;
141+ } ) ;
142+
143+ // reset color
144+ pointIndexCache . forEach ( ( index ) => {
145+ colors [ index ] = 0.4 ;
146+ colors [ index + 1 ] = 0.7 ;
147+ colors [ index + 2 ] = 0.8 ;
148+ } ) ;
149+
150+ pointIndexCache = newIndex ;
151+ }
152+ // simple iterate
153+ else {
154+ const count = planeMesh . geometry . attributes . color . count ;
155+ const positions = planeMesh . geometry . attributes . position . array ;
156+
157+ for ( let i = 0 ; i < count ; i ++ ) {
158+ const index = i * 3 ;
159+
160+ const distance = distanceFn (
161+ newPosition ,
162+ [
163+ positions [ index ] ,
164+ positions [ index + 1 ] ,
165+ positions [ index + 2 ] ,
166+ ]
167+ ) ;
168+
169+ if ( distance <= params . range ) {
170+ // should be colored
171+ colors [ index ] = 1 ;
172+ colors [ index + 1 ] = 0 ;
173+ colors [ index + 2 ] = 0 ;
174+ }
175+ else {
176+ // reset color
177+ colors [ index ] = 0.4 ;
178+ colors [ index + 1 ] = 0.7 ;
179+ colors [ index + 2 ] = 0.8 ;
180+ }
181+ }
182+ }
183+
184+ planeMesh . geometry . attributes . color . needsUpdate = true ;
185+ }
186+
187+ render ( ) ;
188+ stats . update ( ) ;
189+ } ;
190+
191+ //
192+ const resize = ( ) => {
193+ screenWidth = window . innerWidth ;
194+ screenHeight = window . innerHeight ;
195+
196+ renderer . setSize ( screenWidth , screenHeight ) ;
197+
198+ camera . aspect = screenWidth / screenHeight ;
199+ camera . updateProjectionMatrix ( ) ;
200+ } ;
201+
202+
203+ //
204+ const addPlane = ( ) => {
205+ const geometry = new THREE . PlaneGeometry ( 100 , 100 , 2000 , 2000 ) ;
206+ geometry . rotateX ( - Math . PI / 2 ) ;
207+
208+ const position = geometry . attributes . position ;
209+ const positionArray = position . array ;
210+ const count = position . count ;
211+
212+ const colors = new Float32Array ( count * 3 ) ;
213+ const points = [ ] ;
214+
215+ for ( let i = 0 ; i < count ; i ++ ) {
216+ const index = i * 3 ;
217+
218+ // colors
219+ colors [ index ] = 0.4 ;
220+ colors [ index + 1 ] = 0.7 ;
221+ colors [ index + 2 ] = 0.8 ;
222+
223+ // points
224+ points . push ( [
225+ positionArray [ index ] ,
226+ positionArray [ index + 1 ] ,
227+ positionArray [ index + 2 ] ,
228+ index
229+ ] ) ;
230+ }
231+
232+ geometry . setAttribute ( 'color' , new THREE . BufferAttribute ( colors , 3 ) ) ;
233+
234+ // init kd tree
235+ tree = new KdTree (
236+ points ,
237+ distanceFn ,
238+ [ '0' , '1' , '2' ] ,
239+ ) ;
240+
241+ const material = new THREE . MeshBasicMaterial ( {
242+ color : 0xffffff ,
243+ vertexColors : true ,
244+ wireframe : false ,
245+ } ) ;
246+ planeMesh = new THREE . Mesh ( geometry , material ) ;
247+ scene . add ( planeMesh ) ;
248+ }
249+
250+ //
251+ const addModel = ( ) => {
252+ const geometry = new THREE . BoxGeometry ( 1 , 1 , 1 ) ;
253+ const material = new THREE . MeshStandardMaterial ( { color : 0x049ef4 } ) ;
254+
255+ modelMesh = new THREE . Mesh ( geometry , material ) ;
256+ modelMesh . position . set ( 0 , 0.5 , 0 ) ;
257+ scene . add ( modelMesh ) ;
258+ }
259+
260+ // invoke
261+ initThree ( ) ;
262+ window . addEventListener ( "resize" , resize ) ;
263+ animate ( ) ;
264+
265+ // stuff
266+ addPlane ( ) ;
267+ addModel ( ) ;
268+ </ script >
269+ </ body >
270+
271+ </ html >
0 commit comments