Skip to content

Commit e179cbc

Browse files
committed
stage:space search
1 parent fe0e35f commit e179cbc

File tree

5 files changed

+286
-0
lines changed

5 files changed

+286
-0
lines changed

package-lock.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
"vite": "^5.0.10"
1818
},
1919
"dependencies": {
20+
"@sadyx019/kd-tree": "^1.0.4",
2021
"cannon-es": "^0.20.0",
22+
"gsap": "^3.12.5",
2123
"three": "^0.159.0"
2224
}
2325
}

src/assets/models/Soldier.glb

2.06 MB
Binary file not shown.
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
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>

src/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"generic@basic",
1515
"generic@recognize_perspective_camera",
1616
"generic@orthographic_camera_in_physical_world",
17+
"generic@space_search",
1718
"shader@rawShaderMaterial",
1819
"shader@noise",
1920
"shader@web_audio_visualization",

0 commit comments

Comments
 (0)