Skip to content

Commit

Permalink
feat(ghostCanvas): add soapbox models with accurate rotations (#363)
Browse files Browse the repository at this point in the history
  • Loading branch information
wopian authored Jun 25, 2023
1 parent 3673d88 commit be49f3c
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 26 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@unhead/vue": "1.1.27",
"@vueuse/components": "10.2.0",
"@vueuse/schema-org": "2.2.0",
"@zeepkist/gtr-api": "3.7.2",
"@zeepkist/gtr-api": "3.7.3",
"date-fns": "2.30.0",
"date-fns-tz": "2.0.0",
"ky": "0.33.3",
Expand Down
Binary file added src/assets/models/axle.stl
Binary file not shown.
Binary file added src/assets/models/character.stl
Binary file not shown.
Binary file added src/assets/models/combined_soapbox.stl
Binary file not shown.
Binary file added src/assets/models/soapbox.stl
Binary file not shown.
Binary file added src/assets/models/spoiler.stl
Binary file not shown.
Binary file added src/assets/models/wheel.stl
Binary file not shown.
36 changes: 22 additions & 14 deletions src/components/canvases/GhostCanvas.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { AxesHelper, Quaternion, Vector3 } from 'three'
import { onMounted, onUnmounted, ref } from 'vue'
import {
Expand All @@ -14,20 +15,14 @@
z: number
}
export interface Quaternion {
x: number
y: number
z: number
w: number
}
const { ghostUrls = [] } = defineProps<{
ghostUrls: string[]
}>()
const containerRef = ref()
const { camera, clock, controls, renderer, scene } = createGhostScene()
const { axesHelper, camera, clock, controls, renderer, scene } =
createGhostScene()
const { ghosts, totalDuration } = await createGhosts(scene, ghostUrls)
let longestGhost = ghosts[0]
Expand Down Expand Up @@ -62,6 +57,9 @@
containerRef.value.clientWidth / containerRef.value.clientHeight
camera.aspect = aspectRatio
camera.position.copy(center)
axesHelper.position.copy(center)
animate()
})
Expand All @@ -86,27 +84,37 @@
if (leadingPosition) {
camera.position.set(
leadingPosition.x * cameraOffsets.x,
leadingPosition.y * cameraOffsets.y,
leadingPosition.y * cameraOffsets.y + 10,
leadingPosition.z * cameraOffsets.z
)
//camera.lookAt(leadingPosition)
} else {
const position = ghosts[0].points.at(-1) ?? center
camera.position.set(
position.x * cameraOffsets.x,
position.y * cameraOffsets.y,
position.y * cameraOffsets.y + 10,
position.z * cameraOffsets.z
)
//camera.lookAt(position)
}
for (const { geometry, material, ghost } of ghosts) {
for (const { geometry, material, ghost, soapbox, points } of ghosts) {
const visiblePoints = Math.floor(
(ghost.frameCount / totalDuration) * totalDuration
)
const drawRange = Math.min(visiblePoints, currentFrame + 1)
if (soapbox) {
const position = points[currentFrame]
? (points[currentFrame] as Vector3)
: (points.at(-3) as Vector3)
const quaternion = ghost.frames[currentFrame]
? (ghost.frames[currentFrame].quaternion as Quaternion)
: (ghost.frames.at(-3)?.quaternion as Quaternion)
soapbox.position.copy(position)
soapbox.quaternion.copy(quaternion)
}
material.visible = true
geometry.setDrawRange(0, drawRange)
}
Expand Down
18 changes: 14 additions & 4 deletions src/utils/three/createGhostScene.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
AmbientLight,
AxesHelper,
Clock,
PCFSoftShadowMap,
PerspectiveCamera,
Plane,
PlaneHelper,
Expand All @@ -10,12 +12,16 @@ import {
} from 'three'
import { MapControls } from 'three/examples/jsm/controls/MapControls.js'

import { IS_DEV } from '~/configs'

export const createGhostScene = () => {
const renderer = new WebGLRenderer({ alpha: true, antialias: true })
renderer.setClearAlpha(0)
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setPixelRatio(window.devicePixelRatio)

renderer.shadowMap.enabled = true
renderer.shadowMap.type = PCFSoftShadowMap

const scene = new Scene()

Expand All @@ -31,17 +37,21 @@ export const createGhostScene = () => {
controls.enableDamping = true
controls.dampingFactor = 0.05
controls.screenSpacePanning = true
//controls.minDistance = 100
//controls.maxDistance = 500
controls.maxPolarAngle = Math.PI / 2

const ambientLight = new AmbientLight(0xff_ff_ff, 0.5)
scene.add(ambientLight)

const clock = new Clock()

const axesHelper = new AxesHelper(50)
scene.add(axesHelper)

if (IS_DEV) {
scene.add(axesHelper)
}

const plane = new Plane(new Vector3(0, 1, 0), 16)
const helper = new PlaneHelper(plane, 10_000, 0x0f_0f_0f)
helper.receiveShadow = true
scene.add(helper)

return { axesHelper, camera, clock, controls, renderer, scene }
Expand Down
40 changes: 38 additions & 2 deletions src/utils/three/createGhosts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ import {
CatmullRomCurve3,
Line,
LineBasicMaterial,
Mesh,
MeshStandardMaterial,
Quaternion,
Scene,
Vector3
} from 'three'
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js'

import soapboxUrl from '~/assets/models/combined_soapbox.stl?url'

interface GhostInstance {
ghost: Ghost
Expand All @@ -15,6 +21,7 @@ interface GhostInstance {
material: LineBasicMaterial
geometry: BufferGeometry
line: Line
soapbox?: Mesh
}

export const createGhosts = async (scene: Scene, urls: string[]) => {
Expand All @@ -31,7 +38,7 @@ export const createGhosts = async (scene: Scene, urls: string[]) => {
totalDuration = Math.max(totalDuration, ghost.frames.at(-1)?.time ?? 0)

const points = ghost.frames.map(
({ position }) => new Vector3(position.x * -1, position.y, position.z)
({ position }) => new Vector3(position.x, position.y, position.z)
)

const curve = new CatmullRomCurve3(points, false, 'catmullrom', 0)
Expand All @@ -49,9 +56,38 @@ export const createGhosts = async (scene: Scene, urls: string[]) => {

const line = new Line(geometry, material)

const loader = new STLLoader()
loader.load(soapboxUrl, geometry => {
const soapboxMaterial = new MeshStandardMaterial({
color: material.color,
metalness: 0.5,
roughness: 0.5
})

const soapbox = new Mesh(geometry, soapboxMaterial)
soapbox.position.copy(points[0])
soapbox.rotation.set(0, -Math.PI / 2, 0)
soapbox.scale.set(0.25, 0.25, 0.25)

soapbox.receiveShadow = true
soapbox.castShadow = true

scene.add(soapbox)

ghosts[index].soapbox = soapbox
})

scene.add(line)

ghosts.push({ ghost, points, curve, material, geometry, line })
ghosts.push({
ghost,
points,
curve,
material,
geometry,
line,
soapbox: undefined
})
}

return { ghosts, totalDuration }
Expand Down
10 changes: 5 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1657,17 +1657,17 @@ __metadata:
languageName: node
linkType: hard

"@zeepkist/gtr-api@npm:3.7.2":
version: 3.7.2
resolution: "@zeepkist/gtr-api@npm:3.7.2"
"@zeepkist/gtr-api@npm:3.7.3":
version: 3.7.3
resolution: "@zeepkist/gtr-api@npm:3.7.3"
dependencies:
ky: ~0.33.2
ky-universal: ~0.11.0
pako: ~2.1.0
dependenciesMeta:
esbuild:
built: true
checksum: b187299bad4b57ce5f79da8dab6ac91a4b45d43863bc60b39267682b7d42f0640b37668520107b804e8ea9f44d771a2cf5b6fa24385e1e9d23bf679a2b39a8c9
checksum: 62826c2b7ed1f4a3086133fd39005eb94bae78ea1ac9208ef5557c435286cadd96b36ce70bd8451cd5faaac1a924b60a819032a6878985535ff34da05b315842
languageName: node
linkType: hard

Expand Down Expand Up @@ -9246,7 +9246,7 @@ __metadata:
"@vue/tsconfig": 0.4.0
"@vueuse/components": 10.2.0
"@vueuse/schema-org": 2.2.0
"@zeepkist/gtr-api": 3.7.2
"@zeepkist/gtr-api": 3.7.3
cypress: 12.15.0
date-fns: 2.30.0
date-fns-tz: 2.0.0
Expand Down

0 comments on commit be49f3c

Please sign in to comment.