Skip to content

Commit d8f1f7b

Browse files
committed
v0.2.0
1 parent 70c71db commit d8f1f7b

File tree

3 files changed

+153
-234
lines changed

3 files changed

+153
-234
lines changed

index.html

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
<script type="importmap">
1313
{
1414
"imports": {
15-
"three": "https://unpkg.com/[email protected]/build/three.module.js",
16-
"three/webgpu": "https://unpkg.com/[email protected]/build/three.webgpu.js",
17-
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
15+
"three": "https://unpkg.com/[email protected]/build/three.webgpu.js",
16+
"three/tsl": "https://unpkg.com/[email protected]/build/three.tsl.js",
17+
"three/webgl": "https://unpkg.com/[email protected]/build/three.module.js",
18+
"three/webgpu": "https://unpkg.com/[email protected]/build/three.webgpu.js",
19+
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
1820
}
1921
}
2022
</script>

index.js

Lines changed: 148 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,175 @@
1-
import { AmbientLight, PerspectiveCamera, Scene, SRGBColorSpace, TextureLoader, WebGLRenderer } from "three";
2-
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
3-
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
1+
import { OrbitControls } from "three/addons/controls/OrbitControls.js"
2+
import { AmbientLight, Box3, ExtrudeGeometry, Mesh, MeshStandardMaterial, PerspectiveCamera, Scene, Shape, SRGBColorSpace, TextureLoader, Vector3, WebGPURenderer } from "three/webgpu"
43

5-
const reg = /Android|webOS|iPhone|iPod|BlackBerry/i;
6-
const isMobile = reg.test(navigator.userAgent);
4+
const reg = /Android|webOS|iPhone|iPod|BlackBerry/i
5+
const isMobile = reg.test(navigator.userAgent)
76

8-
const app = document.querySelector(".app");
9-
app.classList.add(isMobile ? "mobile" : "pc");
10-
const container = document.querySelector(".container");
7+
const app = document.querySelector(".app")
8+
app.classList.add(isMobile ? "mobile" : "pc")
9+
const container = document.querySelector(".container")
1110

12-
const { innerWidth, innerHeight } = window;
13-
const width = isMobile ? innerWidth : innerWidth / 2;
14-
const height = isMobile ? innerHeight / 2 : innerHeight;
11+
const { innerWidth, innerHeight } = window
12+
const width = isMobile ? innerWidth : innerWidth / 2
13+
const height = isMobile ? innerHeight / 2 : innerHeight
1514

16-
const textureLoader = new TextureLoader();
15+
const textureLoader = new TextureLoader()
1716

18-
const renderer = new WebGLRenderer({
19-
antialias: true,
20-
alpha: true,
21-
preserveDrawingBuffer: true,
22-
});
23-
renderer.setPixelRatio(window.devicePixelRatio);
24-
renderer.setSize(width, height);
25-
container.appendChild(renderer.domElement);
17+
const renderer = new WebGPURenderer({ antialias: true, alpha: true})
18+
renderer.setPixelRatio(window.devicePixelRatio)
19+
renderer.setSize(width, height)
20+
container.appendChild(renderer.domElement)
2621

27-
const aspect = width / height;
28-
const camera = new PerspectiveCamera(50, aspect);
29-
camera.position.z = 1.5;
22+
const aspect = width / height
23+
const camera = new PerspectiveCamera(50, aspect)
24+
camera.position.set(0, 0, 3)
25+
camera.lookAt(0, 0, 0)
3026

31-
const controls = new OrbitControls(camera, renderer.domElement);
32-
controls.enableDamping = true;
33-
controls.addEventListener("change", requestRender);
27+
const scene = new Scene()
28+
scene.add(new AmbientLight(0xffffff, 3.14))
3429

35-
const scene = new Scene();
36-
scene.add(new AmbientLight(0xffffff, 3.14));
37-
38-
const gltfLoader = new GLTFLoader();
39-
gltfLoader.load("model.gltf", (gltf) => {
40-
scene.add(gltf.scene);
41-
render();
42-
});
43-
44-
function render() {
45-
renderer.render(scene, camera);
30+
function animate() {
31+
const success = controls.update()
32+
renderer.render(scene, camera)
33+
if (success === false) {
34+
renderer.setAnimationLoop(null)
35+
isAnimating = false
36+
}
4637
}
4738

48-
function animate() {
49-
const success = controls.update();
50-
render();
51-
if (success === false) {
52-
renderer.setAnimationLoop(null);
53-
isAnimating = false;
54-
}
39+
let isAnimating = false
40+
function render() {
41+
if (isAnimating === true) return
42+
isAnimating = true
43+
renderer.setAnimationLoop(animate)
5544
}
5645

57-
let isAnimating = false;
58-
function requestRender() {
59-
if (isAnimating === true) return;
60-
isAnimating = true;
61-
renderer.setAnimationLoop(animate);
46+
const controls = new OrbitControls(camera, renderer.domElement)
47+
controls.enableDamping = true
48+
controls.addEventListener("change", render)
49+
50+
function createRoundedRectShape(width = 1, height = 1, radius = 0.1) {
51+
const shape = new Shape()
52+
const x = 0, y = 0
53+
54+
shape.moveTo(x + radius, y)
55+
shape.lineTo(x + width - radius, y)
56+
shape.absarc(x + width - radius, y + radius, radius, -Math.PI / 2, 0, false)
57+
shape.lineTo(x + width, y + height - radius)
58+
shape.absarc(x + width - radius, y + height - radius, radius, 0, Math.PI / 2, false)
59+
shape.lineTo(x + radius, y + height)
60+
shape.absarc(x + radius, y + height - radius, radius, Math.PI / 2, Math.PI, false)
61+
shape.lineTo(x, y + radius)
62+
shape.absarc(x + radius, y + radius, radius, Math.PI, Math.PI * 1.5, false)
63+
64+
return shape
6265
}
6366

64-
window.addEventListener("resize", resize);
67+
const shape = createRoundedRectShape(1, 1.5, 0.053)
68+
const geometry = new ExtrudeGeometry(shape, { depth: 0.01, bevelEnabled: false })
69+
geometry.clearGroups()
70+
geometry.addGroup(0, 294, 0)
71+
geometry.addGroup(294, 294, 1)
72+
geometry.addGroup(588, 600, 2)
73+
74+
const defaultMaterial = new MeshStandardMaterial()
75+
76+
const url = `./imgs/1.jpg`
77+
const texture = await textureLoader.loadAsync(url, () => render())
78+
texture.colorSpace = SRGBColorSpace
79+
const topTexture = texture.clone()
80+
81+
const bottom = new MeshStandardMaterial({ map: texture })
82+
// bottom.map.wrapS = bottom.map.wrapT = RepeatWrapping
83+
bottom.map.repeat.set(- 0.461, 0.627)
84+
bottom.map.offset.set(0.515, -0.187)
85+
bottom.map.center.set(0.315, 0.579)
86+
87+
const top = new MeshStandardMaterial({ map: topTexture })
88+
top.map.repeat.set(0.460, 0.628)
89+
top.map.offset.set(0.026, 0.029)
90+
91+
const materials = [
92+
bottom,
93+
top,
94+
defaultMaterial,
95+
]
96+
97+
const mesh = new Mesh(geometry, materials)
98+
mesh.name = "model"
99+
const box = new Box3().setFromObject(mesh)
100+
const center = box.getCenter(new Vector3())
101+
mesh.position.set(-center.x, -center.y, 0)
102+
scene.add(mesh)
103+
render()
104+
105+
window.addEventListener("resize", resize)
65106

66107
function resize() {
67-
const { innerWidth, innerHeight } = window;
68-
const width = isMobile ? innerWidth : innerWidth / 2;
69-
const height = isMobile ? innerHeight / 2 : innerHeight;
70-
renderBySize({ width, height });
108+
const { innerWidth, innerHeight } = window
109+
const width = isMobile ? innerWidth : innerWidth / 2
110+
const height = isMobile ? innerHeight / 2 : innerHeight
111+
renderBySize({ width, height })
71112
}
72113

73114
function renderBySize(options = {}) {
74-
const { width = window.innerWidth, height = window.innerHeight } = options;
75-
camera.aspect = width / height;
76-
camera.updateProjectionMatrix();
77-
renderer.setSize(width, height);
78-
render();
115+
const { width = window.innerWidth, height = window.innerHeight } = options
116+
camera.aspect = width / height
117+
camera.updateProjectionMatrix()
118+
renderer.setSize(width, height)
119+
render()
79120
}
80121

81-
let selectId = 1;
82-
const fragment = document.createDocumentFragment();
122+
let selectId = 1
123+
const fragment = document.createDocumentFragment()
83124
for (let index = 1; index <= 108; index++) {
84-
const img = document.createElement("img");
85-
img.src = `./imgs/${index}.jpg`;
86-
img.addEventListener("click", async () => {
87-
selectId = index;
88-
const mesh = scene.getObjectByName("model");
89-
const material = mesh.material;
90-
const texture = await textureLoader.loadAsync(`./imgs/${selectId}.jpg`);
91-
texture.flipY = false;
92-
texture.colorSpace = SRGBColorSpace;
93-
material.map = texture;
94-
render();
95-
});
96-
fragment.appendChild(img);
125+
const img = document.createElement("img")
126+
img.src = `./imgs/${index}.jpg`
127+
img.setAttribute("loading", "lazy")
128+
img.addEventListener("click", async () => {
129+
selectId = index
130+
const url = `./imgs/${selectId}.jpg`
131+
const texture = await textureLoader.loadAsync(url, () => render())
132+
texture.colorSpace = SRGBColorSpace
133+
const topTexture = texture.clone()
134+
const mesh = scene.getObjectByName("model")
135+
const material = mesh.material
136+
if (Array.isArray(material)) {
137+
const [bottom, top] = material
138+
bottom.map = texture
139+
bottom.map.repeat.set(0.461, 0.627)
140+
bottom.map.offset.set(0.515, 0.029)
141+
bottom.map.flipY = false
142+
bottom.map.center.set(0.315, 0.579)
143+
bottom.map.rotation = Math.PI
144+
145+
top.map = topTexture
146+
top.map.repeat.set(0.460, 0.628)
147+
top.map.offset.set(0.026, 0.029)
148+
} else {
149+
texture.flipY = false
150+
material.map = texture
151+
}
152+
render()
153+
})
154+
fragment.appendChild(img)
97155
}
98-
document.querySelector(".imgs").appendChild(fragment);
156+
document.querySelector(".imgs").appendChild(fragment)
99157

100158
document.querySelector(".button.preview").addEventListener("click", () => {
101-
container.classList.toggle("hidden");
102-
});
159+
container.classList.toggle("hidden")
160+
})
161+
162+
function screenshot(renderer, scene, camera, download = 'screenshot.png', type = 'image/png') {
163+
renderer.render(scene, camera)
164+
const canvas = renderer.domElement
165+
const link = document.createElement('a')
166+
link.href = canvas.toDataURL(type)
167+
link.download = download
168+
link.click()
169+
}
103170

104171
document.querySelector(".button.download").addEventListener("click", () => {
105-
renderBySize();
106-
const link = document.createElement("a");
107-
link.download = `水浒英雄传 ${selectId}.png`;
108-
link.href = renderer.domElement.toDataURL("image/png");
109-
link.click();
110-
resize();
111-
});
172+
renderBySize()
173+
screenshot(renderer, scene, camera, `水浒英雄传 ${selectId}.png`)
174+
resize()
175+
})

0 commit comments

Comments
 (0)