Initial commit

This commit is contained in:
natuka committed 2025-06-05 09:25:26 +08:00
commit 84061c9a18
243 files changed
+63148

No files matched your search

+109
View File
@@ -0,0 +1,109 @@
<script setup lang="ts">
import { useTranslation } from "i18next-vue";
import * as i18n from '@/lang/utils'
import { Locale } from 'vant';
// 引入英文语言包
import enUS from 'vant/es/locale/lang/en-US';
import zhCN from 'vant/es/locale/lang/zh-CN';
import zhTW from 'vant/es/locale/lang/zh-TW';
import ko from 'vant/es/locale/lang/ko-KR';
// import { zhCN } from "element-plus/es/locale";
const { i18next, t } = useTranslation();
i18n.set(t);
watch(
() => i18next.language,
(val: any) => {
console.log("val", val);
},
{ immediate: true }
);
// function getLocaleName() {
// switch (i18next.language) {
// case 'zh':
// case "zh-CN":
// return 'zh-CN';
// case "en-US":
// case "en":
// return 'en-US';
// case "es":
// case "es-AR":
// case "es-BO":
// case "es-CL":
// case "es-ES":
// case "es-MX":
// case "es-AR":
// return 'es';
// case "zh-TW":
// case "zh-HK":
// return 'zh-TW';
// default:
// return 'en';
// }
// }
function getLocale() {
switch (i18next.language) {
case "zh-CN":
return zhCN;
case "en":
return enUS;
case "es":
case "es-AR":
case "es-BO":
case "es-CL":
case "es-ES":
case "es-MX":
case "es-AR":
return enUS;
case "zh-TW":
case "zh-HK":
return zhTW;
case "ko":
return ko;
default:
return enUS;
}
}
onMounted(() => {
let obj = filterUrl(window.location.href)
// console.log(obj)
let urlLan = obj.lang;
// 浏览器缓存判断
let cookieLan = localStorage.getItem("i18nextLng")
// 浏览器语言判断
let userLan = navigator.language;
let lang = urlLan || cookieLan || userLan || "zh-CN";
Locale.use(lang || i18next.language, getLocale())
})
function filterUrl(url) {
let filter = url.split("?")[1]?.split("&");
var obj = {};
for (var i = 0; i < filter?.length; i++) {
var item = filter[i].split('=');
var key = item[0];
var value = item[1];
obj[key] = value;
}
return obj
}
</script>
<template>
<router-view v-slot="{ Component }">
<Suspense>
<div>
<component :is="Component" />
</div>
</Suspense>
</router-view>
</template>
+30
View File
@@ -0,0 +1,30 @@
<script setup lang="ts">
import type { ConfigProviderTheme } from 'vant'
import { localStorage } from '@/utils/local-storage'
import { useStore } from '@/stores'
const store = useStore()
const theme = ref<ConfigProviderTheme>('light')
const mode = computed(() => store.mode)
watch(mode, (val) => {
if (val === 'dark' || localStorage.get('theme') === 'dark') {
theme.value = 'dark'
document.querySelector('html')
.setAttribute('data-theme', 'dark')
}
else {
theme.value = 'light'
document.querySelector('html')
.setAttribute('data-theme', 'light')
}
}, { immediate: true })
provide('isRealDark', computed(() => theme.value === 'dark'))
</script>
<template>
<van-config-provider :theme="theme">
<router-view />
</van-config-provider>
</template>
+8
View File
@@ -0,0 +1,8 @@
import request from '@/utils/request'
export const getUser = (data: any) => {
return request<String>('auth/getUser', {
method: 'POST',
data,
})
}
+15
View File
@@ -0,0 +1,15 @@
import request from '@/utils/request'
// export const calc = (data: any) => {
// return request('queue/calc', {
// method: 'POST',
// data,
// })
// }
// export const attr = (params: any) => {
// return request('queue/attr', {
// method: 'GET',
// params,
// })
// }
+7
View File
@@ -0,0 +1,7 @@
import request from '@/utils/request'
// 品牌信息
export const brand = (brand_id: any) => {
return request('/config/brand/info', { params: { brand_id }, method: 'GET' })
}
+5
View File
@@ -0,0 +1,5 @@
import request from '@/utils/request'
export async function queryProse(): Promise<any> {
return request('/project/prose')
}
+32
View File
@@ -0,0 +1,32 @@
import request from '@/utils/request'
// 参数为 page, size, pid
export const page = (params: any) => {
return request('/printBatchOrder/page', { params, method: 'GET' })
}
// 批次详情
export const detailPage = (data: any) => {
return request('/printBatchOrder/detailPage', { data, method: 'POST' })
}
// 主要参数为pid
export const add = (params: any) => {
return request('/printBatchOrder/grossWeight', { params, method: 'POST' })
}
// 签名
export const getPutSignURL = (data: any) => {
return request('/printBatchOrder/putSignURL', { data, method: 'POST' })
}
// oss
export const uploadToOss = (putSignUrl: any, file: any) => {
return request({
url: putSignUrl,
headers: {
"Content-Type": "application/octet-stream"
},
data: file, method: 'PUT', withCredentials: false, })
}
+12
View File
@@ -0,0 +1,12 @@
import request from '@/utils/request'
// 参数为 page, size, pid
export const page = (params: any) => {
return request('/myOrder/page', { params, method: 'GET' })
}
// 主要参数为pid
export const detail = (pid: number) => {
return request('/myOrder/detail', { params: { pid }, method: 'GET' })
}
+33
View File
@@ -0,0 +1,33 @@
import request from '@/utils/request'
import requestWx from '@/utils/requestWx'
export const glb = (id: number, file_type: string,isShare: string, extParams?: any) => {
return request('model/glb', {
method: 'GET',
params: Object.assign({}, {
file_type,
s: isShare,
id,
type: 1,
without_head: 1,
}, extParams),
})
}
export const get3dBgList = (pid: number) => {
return request('material/bg', {
method: 'GET',
params: {
pid,
},
})
}
export const getWechatConfig = (url: string) => {
return requestWx('wechatConfig/config', {
method: 'GET',
data: {
url: url.split('#')[0],
},
})
}
+20
View File
@@ -0,0 +1,20 @@
import request from '@/utils/request'
// 参数为 page, size
export const list = (params: any) => {
return request('/picVideo/list', { params, method: 'GET' })
}
// 参数为 id, print_id, from_u
export const info = (id: number) => {
return request('/picVideo/info', { params: { id }, method: 'GET' })
}
// 参数为 id, print_id, from_u
export const share = (id: number) => {
return request('/picVideo/share', { params: { id }, method: 'GET' })
}
// 参数为 id, print_id
export const downloadUrl = (id: number) => {
return request('/picVideo/downloadUrl', { params: { id }, method: 'GET' })
}
+28
View File
@@ -0,0 +1,28 @@
import request from '@/utils/request'
export const calc = (data: any) => {
return request('queue/calc', {
method: 'POST',
data,
})
}
export const queueAdd = (data: any) => {
return request('queue/addNew', {
method: 'POST',
data,
})
}
// export const queueAdd = (data: any) => {
// return request('queue/add', {
// method: 'POST',
// data,
// })
// }
export const attr = (params: any) => {
return request('queue/attr', {
method: 'GET',
params,
})
}
+41
View File
@@ -0,0 +1,41 @@
import request from '@/utils/request'
// 参数为 shop_id, pid
export const list = (params: any) => {
return request('/receiveAddress/list', { params, method: 'GET' })
}
// 参数为 id
export const info = (id: number) => {
return request('/receiveAddress/info', { params: { id }, method: 'GET' })
}
// 无参数
export const Default = () => {
return request('/receiveAddress/default', { method: 'GET' })
}
// add
/**
* @param data
* @returns
*/
export const add = (data: any) => {
return request('/receiveAddress/add', { data, method: 'POST' })
}
/**
* 修改收货地址
* @param data
* @returns
*/
export const edit = (data: any) => {
return request('/receiveAddress/update', { data, method: 'POST' })
}
/**
* 删除收获地址
* @param data
* @returns
*/
export const del = (params: any) => {
return request('/receiveAddress/delete', { params, method: 'POST' })
}
+22
View File
@@ -0,0 +1,22 @@
import request from '@/utils/request'
// 参数为 code
export const actions = (code: string) => {
return request('/shortUrl/actions', { params: { code }, method: 'GET' })
}
// 参数为 code, 订单履历
export const orderTrack = (code: string) => {
return request('/shortUrl/orderTrack', { params: { code }, method: 'GET' })
}
// 参数为 code, 订单信息
export const orderInfo = (code: string) => {
return request('/shortUrl/orderInfo', { params: { code }, method: 'GET' })
}
// 参数为 code, 打印信息
export const printOrderInfo = (code: string) => {
return request('/shortUrl/printOrderInfo', { params: { code }, method: 'GET' })
}
+16
View File
@@ -0,0 +1,16 @@
export interface ResponseBody<T = any> {
message?: string
code?: number
data?: T
success: boolean
}
/** 统一返回结构体 */
export interface PageResult<T = any> {
data: T[]
current?: number
pageSize?: number
total?: number
success: boolean
}
+31
View File
@@ -0,0 +1,31 @@
*,
*::before,
*::after {
box-sizing: border-box;
}
[data-theme='dark'],
[data-theme='dark'] * {
color-scheme: dark !important;
}
[data-theme='light'],
[data-theme='light'] * {
color-scheme: light !important;
}
[data-theme='light'] body {
background-color: #eff2f5;
}
:root {
--van-checkbox-checked-icon-color: #07c160;
--van-radio-checked-icon-color: #07c160;
}
.agree-dialog {
top: 50%!important;
max-width: 100vw!important;
}
canvas {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
}
+46
View File
@@ -0,0 +1,46 @@
#app {
// height: 100%;
// overflow-x: hidden;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
[data-theme='dark'] {
&,
* {
color-scheme: dark !important;
}
}
[data-theme='light'] {
&,
* {
color-scheme: light !important;
}
body {
background-color: #eff2f5;
}
}
:root{
--van-checkbox-checked-icon-color: #07c160;
--van-radio-checked-icon-color: #07c160;
}
.agree-dialog{
top: 50%!important;
max-width: 100vw!important;
// height: 100vh;
}
canvas {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

+38
View File
@@ -0,0 +1,38 @@
@font-face {
font-family: "iconfont"; /* Project id 4436817 */
src: url('./iconfont.woff2?t=v.0.0.1') format('woff2'),
url('./iconfont.woff?t=v.0.0.1') format('woff'),
url('./iconfont.ttf?t=v.0.0.1') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.iconfont-twitter:before {
content: "\e61d";
}
.iconfont-googleplus:before {
content: "\e87a";
}
.iconfont-wechat:before {
content: "\e661";
}
.iconfont-facebook:before {
content: "\e605";
}
.iconfont-apple:before {
content: "\e881";
}
.iconfont-microsoft:before {
content: "\e611";
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.
@@ -0,0 +1,147 @@
%PDF-1.5␍%âãÏÓ
1 0 obj␍<</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R]/Order 6 0 R/RBGroups[]>>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>>␍endobj␍2 0 obj␍<</Length 17644/Subtype/XML/Type/Metadata>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.0-c060 61.134777, 2010/02/12-17:32:00 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
<xmp:CreateDate>2015-05-27T12:23:34+12:00</xmp:CreateDate>
<xmp:CreatorTool>Adobe Illustrator CS5</xmp:CreatorTool>
<xmp:MetadataDate>2015-05-27T12:23:34+12:00</xmp:MetadataDate>
<xmp:ModifyDate>2015-05-27T12:23:34+12:00</xmp:ModifyDate>
<xmp:Thumbnails>
<rdf:Alt>
<rdf:li rdf:parseType="Resource">
<xmpGImg:width>256</xmpGImg:width>
<xmpGImg:height>256</xmpGImg:height>
<xmpGImg:format>JPEG</xmpGImg:format>
<xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq+S/z9/P380fK&#xA;H5o6poOg6pHbaXbR2zQwtbW8pBlt0kf45EZjVmJ3OKvPP+hrfzv/AOr3F/0hWn/VLFXf9DW/nf8A&#xA;9XuL/pCtP+qWKu/6Gt/O/wD6vcX/AEhWn/VLFXf9DW/nf/1e4v8ApCtP+qWKu/6Gt/O//q9xf9IV&#xA;p/1SxV3/AENb+d//AFe4v+kK0/6pYq7/AKGt/O//AKvcX/SFaf8AVLFXf9DW/nf/ANXuL/pCtP8A&#xA;qlirv+hrfzv/AOr3F/0hWn/VLFXf9DW/nf8A9XuL/pCtP+qWKu/6Gt/O/wD6vcX/AEhWn/VLFXf9&#xA;DW/nf/1e4v8ApCtP+qWKu/6Gt/O//q9xf9IVp/1SxV3/AENb+d//AFe4v+kK0/6pYq7/AKGt/O//&#xA;AKvcX/SFaf8AVLFXf9DW/nf/ANXuL/pCtP8Aqlirv+hrfzv/AOr3F/0hWn/VLFXf9DW/nf8A9XuL&#xA;/pCtP+qWKu/6Gt/O/wD6vcX/AEhWn/VLFXf9DW/nf/1e4v8ApCtP+qWKu/6Gt/O//q9xf9IVp/1S&#xA;xV3/AENb+d//AFe4v+kK0/6pYq7/AKGt/O//AKvcX/SFaf8AVLFXf9DW/nf/ANXuL/pCtP8Aqlir&#xA;v+hrfzv/AOr3F/0hWn/VLFXf9DW/nf8A9XuL/pCtP+qWKu/6Gt/O/wD6vcX/AEhWn/VLFXf9DW/n&#xA;f/1e4v8ApCtP+qWKvQ/yC/P380fN/wCaOl6Dr2qR3Ol3Mdy00K21vESYrd5E+ONFYUZQdjir60xV&#xA;2Kvgj/nK3/yd+t/8YrL/AKhIsVeRYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXrv/OKX/k79E/4xXv8A1CS4q+98Vdir4I/5yt/8nfrf/GKy/wCoSLFX&#xA;kWKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV67/zi&#xA;l/5O/RP+MV7/ANQkuKvvfFXYq+CP+crf/J363/xisv8AqEixV5FirsVdirsVdirsVdirsVdirsVd&#xA;irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeu/84pf+Tv0T/jFe/wDUJLir73xV2Kvg&#xA;j/nK3/yd+t/8YrL/AKhIsVeRYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXrv/OKX/k79E/4xXv8A1CS4q+98Vdir4I/5yt/8nfrf/GKy/wCoSLFXkWKu&#xA;xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV67/zil/5O&#xA;/RP+MV7/ANQkuKvvfFXYq+CP+crf/J363/xisv8AqEixV5FirsVdirsVdirsVdirsVdirsVdirsV&#xA;dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeu/84pf+Tv0T/jFe/wDUJLir73xV2Kvgj/nK&#xA;3/yd+t/8YrL/AKhIsVeRYq7FXYq7FXYq7FWUfl1+XXmDz/5gbQtCaBb1YHuSbl2jThGyq3xKrmtX&#xA;HbFXpv8A0Jt+bn+/tK/6SZf+qOKu/wChNvzc/wB/aV/0ky/9UcVd/wBCbfm5/v7Sv+kmX/qjirv+&#xA;hNvzc/39pX/STL/1RxV3/Qm35uf7+0r/AKSZf+qOKu/6E2/Nz/f2lf8ASTL/ANUcVd/0Jt+bn+/t&#xA;K/6SZf8Aqjirv+hNvzc/39pX/STL/wBUcVd/0Jt+bn+/tK/6SZf+qOKu/wChNvzc/wB/aV/0ky/9&#xA;UcVd/wBCbfm5/v7Sv+kmX/qjirv+hNvzc/39pX/STL/1RxV3/Qm35uf7+0r/AKSZf+qOKu/6E2/N&#xA;z/f2lf8ASTL/ANUcVeZfmL+XXmDyB5gXQtdaBr1oEuQbZ2kThIzKvxMqGtUPbFWL4q7FXYq7FXYq&#xA;7FXrv/OKX/k79E/4xXv/AFCS4q+98Vdir4I/5yt/8nfrf/GKy/6hIsVeRYq7FXYq7FXYq7FXuv8A&#xA;zht/5Nyb/tlXP/J2HFX2/irsVdirsVdirsVdirsVdirsVdirsVdirsVfEH/OZP8A5NyH/tlW3/J2&#xA;bFXhWKuxV2KuxV2KuxV67/zil/5O/RP+MV7/ANQkuKvvfFXYq+CP+crf/J363/xisv8AqEixV5Fi&#xA;rsVdirsVdirsVe6/84bf+Tcm/wC2Vc/8nYcVfb+KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV8Qf&#xA;85k/+Tch/wC2Vbf8nZsVeFYq7FXYq7FXYq7FXrv/ADil/wCTv0T/AIxXv/UJLir73xV2Kvgj/nK3&#xA;/wAnfrf/ABisv+oSLFXkWKuxV2KuxV2KuxV7r/zht/5Nyb/tlXP/ACdhxV9v4q7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXxB/zmT/5NyH/tlW3/ACdmxV4VirsVdirsVdirsVeu/wDOKX/k79E/4xXv&#xA;/UJLir73xV2Kvgj/AJyt/wDJ363/AMYrL/qEixV5FirsVdirsVdirsVe6/8AOG3/AJNyb/tlXP8A&#xA;ydhxV9v4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXxB/wA5k/8Ak3If+2Vbf8nZsVeFYq7FXYq7&#xA;FXYq7FXrv/OKX/k79E/4xXv/AFCS4q+98Vdir4I/5yt/8nfrf/GKy/6hIsVeRYq7FXYq7FXYq7FX&#xA;uv8Azht/5Nyb/tlXP/J2HFX2/irsVdirsVdirsVdirsVdirsVdirsVdirsVfEH/OZP8A5NyH/tlW&#xA;3/J2bFXhWKuxV2KuxV2KuxV67/zil/5O/RP+MV7/ANQkuKvvfFXYq+CP+crf/J363/xisv8AqEix&#xA;V5FirsVdirsVdirsVe6/84bf+Tcm/wC2Vc/8nYcVfb+KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux&#xA;V8Qf85k/+Tch/wC2Vbf8nZsVeFYq7FXYq7FXYq7FXrv/ADil/wCTv0T/AIxXv/UJLir73xV2Kvgj&#xA;/nK3/wAnfrf/ABisv+oSLFXkWKuxV2KuxV2KuxV7r/zht/5Nyb/tlXP/ACdhxV9v4q7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXxB/zmT/5NyH/tlW3/ACdmxV4VirsVdirsVdirsVeu/wDOKX/k79E/&#xA;4xXv/UJLir73xV2Kvgj/AJyt/wDJ363/AMYrL/qEixV5FirsVdirsVdirsVe6/8AOG3/AJNyb/tl&#xA;XP8AydhxV9v4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXxB/wA5k/8Ak3If+2Vbf8nZsVeFYq7F&#xA;XYq7FXYq7FXrv/OKX/k79E/4xXv/AFCS4q+98Vdir4I/5yt/8nfrf/GKy/6hIsVeRYq7FXYq7FXY&#xA;q7FXuv8Azht/5Nyb/tlXP/J2HFWTfmz/AM5N/mf5Y/MbXdA0uSyXT9PuPStxJb8348FPxNy33OKv&#xA;c/yB896954/Lm21/XDEdQkuLiJzAnpoViei/DU9sVejYq+Y/+cg/+cg/zD8jfmG+g6C9otgtpBMB&#xA;NB6j85OXL4uQ8MVZz/zjT+afmr8w/L+sX3mJoGuLG7SGA28fpDg0YY1FTXfFXnX56/8AORf5j+S/&#xA;zM1Ly7oklmunWsds0Qmt/UestLine truncated
</rdf:li>
</rdf:Alt>
</xmp:Thumbnails>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
<pdf:Producer>Adobe PDF library 9.90</pdf:Producer>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:format>application/pdf</dc:format>
<dc:title>
<rdf:Alt>
<rdf:li xml:lang="x-default">Hiro pattern with border</rdf:li>
</rdf:Alt>
</dc:title>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
<xmpTPg:NPages>1</xmpTPg:NPages>
<xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
<xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
<xmpTPg:MaxPageSize rdf:parseType="Resource">
<stDim:w>246.764648</stDim:w>
<stDim:h>246.769043</stDim:h>
<stDim:unit>Pixels</stDim:unit>
</xmpTPg:MaxPageSize>
<xmpTPg:PlateNames>
<rdf:Seq>
<rdf:li>Cyan</rdf:li>
<rdf:li>Magenta</rdf:li>
<rdf:li>Yellow</rdf:li>
<rdf:li>Black</rdf:li>
</rdf:Seq>
</xmpTPg:PlateNames>
<xmpTPg:SwatchGroups>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Default Swatch Group</xmpG:groupName>
<xmpG:groupType>0</xmpG:groupType>
</rdf:li>
</rdf:Seq>
</xmpTPg:SwatchGroups>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#">
<xmpMM:DocumentID>xmp.did:F87F1174072068118C149E02DD6A777A</xmpMM:DocumentID>
<xmpMM:InstanceID>uuid:b2f181f8-2596-5940-b349-9cc46b3a6435</xmpMM:InstanceID>
<xmpMM:OriginalDocumentID>xmp.did:F77F1174072068118C149E02DD6A777A</xmpMM:OriginalDocumentID>
<xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
<xmpMM:DerivedFrom rdf:parseType="Resource">
<stRef:instanceID>xmp.iid:F77F1174072068118C149E02DD6A777A</stRef:instanceID>
<stRef:documentID>xmp.did:F77F1174072068118C149E02DD6A777A</stRef:documentID>
<stRef:originalDocumentID>xmp.did:F77F1174072068118C149E02DD6A777A</stRef:originalDocumentID>
<stRef:renditionClass>proof:pdf</stRef:renditionClass>
</xmpMM:DerivedFrom>
<xmpMM:History>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<stEvt:action>saved</stEvt:action>
<stEvt:instanceID>xmp.iid:F77F1174072068118C149E02DD6A777A</stEvt:instanceID>
<stEvt:when>2015-05-27T12:22:47+12:00</stEvt:when>
<stEvt:softwareAgent>Adobe Illustrator CS5</stEvt:softwareAgent>
<stEvt:changed>/</stEvt:changed>
</rdf:li>
<rdf:li rdf:parseType="Resource">
<stEvt:action>saved</stEvt:action>
<stEvt:instanceID>xmp.iid:F87F1174072068118C149E02DD6A777A</stEvt:instanceID>
<stEvt:when>2015-05-27T12:23:30+12:00</stEvt:when>
<stEvt:softwareAgent>Adobe Illustrator CS5</stEvt:softwareAgent>
<stEvt:changed>/</stEvt:changed>
</rdf:li>
</rdf:Seq>
</xmpMM:History>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>␍endstream␍endobj␍3 0 obj␍<</Count 1/Kids[7 0 R]/Type/Pages>>␍endobj␍7 0 obj␍<</ArtBox[0.0 0.0 246.765 246.769]/BleedBox[0.0 0.0 246.765 246.769]/Contents 8 0 R/MediaBox[0.0 0.0 246.765 246.769]/Parent 3 0 R/Resources<</ExtGState<</GS0 9 0 R>>/Properties<</MC0 5 0 R>>>>/Thumb 10 0 R/TrimBox[0.0 0.0 246.765 246.769]/Type/Page>>␍endobj␍8 0 obj␍<</Filter/FlateDecode/Length 526>>stream
H‰ÜUKŽ1 Ý×)|�òØù8ɶ4R ␍³à#€4Ãq{ž“TU·8µT¶“÷ü‹“¾{¦»ËYèôæL‹’ÿ^Ÿ—»ûG¡ç‹�PHÆÅò”�^?-Ÿû†8r(îa‘B?)Ð;8-xƒ¾¥óOG$3¶½‚_*©FŽÕhÝ”ŽÞ£½€äªRQ– „À­¦DOß:Ì¿kúºÔC†Ò•Òwb8S¬šsJ_þ‚²þj2óxDª‚ðmD/�*·gBg‹7„Ü ¢\AB¾�” 퀼,²Ÿü6 ëÕ(|¤ïW=ч±Fª…³¶|Ó“Æ* ·„ jœ@}�¶ÛO ¼³d==ã°ó§)�ºïmÄγÝó4�‘§-“%Ý“­rB³/ô?Ô3‡d»eWYåPFEÞëzPª9מ]ê#a›…˜·¤û.Rê¥Lê4{)Sßv:íÆçîrl³ŠA8NåM}ÀþpáA¼¬¨8­š¨e–šÛQ�r†XZÂWs ‰J îcñ�J\[%C/kô|ÅBÆŽ�Âu�—>EUYëÆð6Mc1Ì–°Á@é×R°aùwè˜Ï½P ®L±Ç]�dH¹âéX[,ž¿ï$î�ú�JrŸÙ¯DåRÜð ðäwÜ }{{Á¿ÑÃò[€„TCÎ␍endstream␍endobj␍10 0 obj␍<</BitsPerComponent 8/ColorSpace 11 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 30/Length 61/Width 30>>stream
8;Xp,*A:g9#DTK7ej()#Z4Ie#=U:!U()nAsp,WuN`6(ten'I1##VZ7GGD_U~>␍endstream␍endobj␍11 0 obj␍[/Indexed/DeviceRGB 255 12 0 R]␍endobj␍12 0 obj␍<</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream
8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>␍endstream␍endobj␍5 0 obj␍<</Intent 13 0 R/Name(Layer 1)/Type/OCG/Usage 14 0 R>>␍endobj␍13 0 obj␍[/View/Design]␍endobj␍14 0 obj␍<</CreatorInfo<</Creator(Adobe Illustrator 15.0)/Subtype/Artwork>>>>␍endobj␍9 0 obj␍<</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>>␍endobj␍6 0 obj␍[5 0 R]␍endobj␍15 0 obj␍<</CreationDate(D:20150527122334+12'00')/Creator(Adobe Illustrator CS5)/ModDate(D:20150527122334+12'00')/Producer(Adobe PDF library 9.90)/Title(Hiro pattern with border)>>␍endobj␍xref␍0 16␍0000000000 65535 f
0000000016 00000 n
0000000144 00000 n
0000017865 00000 n
0000000000 00000 f
0000019539 00000 n
0000019837 00000 n
0000017916 00000 n
0000018183 00000 n
0000019725 00000 n
0000018777 00000 n
0000018978 00000 n
0000019026 00000 n
0000019609 00000 n
0000019640 00000 n
0000019860 00000 n
trailer␍<</Size 16/Root 1 0 R/Info 15 0 R/ID[<79BC151AAC4D410B8FE29EA60F76EB2E><5ACE1FE7797442838B94A4D48F7D3704>]>>␍startxref␍20048␍%%EOF␍
Binary file not shown.
Binary file not shown.
+196
View File
@@ -0,0 +1,196 @@
234 235 240 233 240 234 240 235 240 237 240 238 240 240 240 232
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 228
227 240 240 240 240 240 240 240 240 240 240 240 240 240 240 239
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
234 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
231 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
225 149 240 240 186 216 225 174 240 240 240 237 238 240 240 240
150 107 238 231 75 208 115 147 238 228 223 226 237 180 226 240
150 62 181 213 62 187 113 169 197 72 29 237 120 50 53 207
149 63 47 78 53 184 113 101 142 5 150 150 45 217 186 83
121 84 220 222 58 180 121 92 128 109 237 124 155 232 161 64
149 71 240 240 76 210 98 109 122 108 240 129 51 119 161 155
149 186 240 240 98 219 135 152 207 191 236 227 152 77 175 209
235 235 240 233 240 234 240 235 240 236 240 238 240 240 240 240
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
227 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
234 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
232 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
225 156 240 240 186 216 225 186 240 240 240 240 240 240 240 240
150 117 240 231 72 206 115 162 240 232 223 237 240 180 226 240
150 74 187 213 51 184 103 168 197 78 29 237 120 50 53 216
144 77 51 74 61 184 106 101 142 5 150 152 52 217 186 85
117 89 219 219 65 184 121 92 128 100 236 125 156 240 170 73
148 71 240 240 76 210 109 109 121 99 240 137 51 120 166 164
140 186 240 240 98 220 150 156 207 192 236 230 152 77 176 212
234 235 240 233 240 234 240 235 240 236 240 238 240 240 240 233
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 239
227 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
234 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
232 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
235 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
232 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
228 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
225 156 240 240 182 212 225 180 240 240 240 240 240 240 240 240
150 116 238 228 66 205 115 151 238 236 225 240 240 180 226 240
156 84 186 211 47 184 109 170 200 92 30 240 120 50 53 216
147 83 51 73 50 184 106 110 148 17 151 150 45 217 186 85
127 98 219 219 58 179 109 101 128 107 237 125 155 240 163 72
155 86 240 240 76 201 85 108 121 95 232 137 51 118 153 155
149 189 240 240 98 220 141 154 206 178 235 230 152 77 175 209
232 228 239 240 240 240 240 240 240 240 240 207 83 64 155 209
240 240 240 240 240 240 240 240 240 240 226 53 186 161 161 175
240 240 240 240 240 240 240 240 240 240 180 50 217 232 119 77
240 240 240 240 240 240 240 240 240 238 237 120 45 155 51 152
238 240 240 240 240 240 240 240 240 237 226 237 150 124 129 227
240 240 240 240 240 240 240 240 240 240 223 29 150 237 240 236
237 240 240 240 240 240 240 240 240 240 228 72 5 109 108 191
240 240 240 240 240 240 240 240 240 240 238 197 142 128 122 207
235 240 240 240 240 240 240 240 240 174 147 169 101 92 109 152
240 240 240 240 240 240 240 240 240 225 115 113 113 121 98 135
234 240 240 240 240 240 240 240 240 216 208 187 184 180 210 219
240 240 240 240 240 240 240 240 240 186 75 62 53 58 76 98
233 240 240 240 240 240 240 240 240 240 231 213 78 222 240 240
240 240 240 240 240 240 240 240 240 240 238 181 47 220 240 240
235 240 240 240 240 240 240 240 240 149 107 62 63 84 71 186
234 229 227 240 236 234 236 231 229 225 150 150 149 121 149 149
240 240 240 240 240 240 240 240 240 240 240 216 85 73 164 212
240 240 240 240 240 240 240 240 240 240 226 53 186 170 166 176
240 240 240 240 240 240 240 240 240 240 180 50 217 240 120 77
240 240 240 240 240 240 240 240 240 240 240 120 52 156 51 152
238 240 240 240 240 240 240 240 240 240 237 237 152 125 137 230
240 240 240 240 240 240 240 240 240 240 223 29 150 236 240 236
236 240 240 240 240 240 240 240 240 240 232 78 5 100 99 192
240 240 240 240 240 240 240 240 240 240 240 197 142 128 121 207
235 240 240 240 240 240 240 240 240 186 162 168 101 92 109 156
240 240 240 240 240 240 240 240 240 225 115 103 106 121 109 150
234 240 240 240 240 240 240 240 240 216 206 184 184 184 210 220
240 240 240 240 240 240 240 240 240 186 72 51 61 65 76 98
233 240 240 240 240 240 240 240 240 240 231 213 74 219 240 240
240 240 240 240 240 240 240 240 240 240 240 187 51 219 240 240
235 240 240 240 240 240 240 240 240 156 117 74 77 89 71 186
235 229 227 240 236 234 236 232 229 225 150 150 144 117 148 140
233 239 240 240 240 240 240 240 240 240 240 216 85 72 155 209
240 240 240 240 240 240 240 240 240 240 226 53 186 163 153 175
240 240 240 240 240 240 240 240 240 240 180 50 217 240 118 77
240 240 240 240 240 240 240 240 240 240 240 120 45 155 51 152
238 240 240 240 240 240 240 240 240 240 240 240 150 125 137 230
240 240 240 240 240 240 240 240 240 240 225 30 151 237 232 235
236 240 240 240 240 240 240 240 240 240 236 92 17 107 95 178
240 240 240 240 240 240 240 240 240 240 238 200 148 128 121 206
235 240 240 240 240 240 240 240 240 180 151 170 110 101 108 154
240 240 240 240 240 240 240 240 240 225 115 109 106 109 85 141
234 240 240 240 240 240 240 240 240 212 205 184 184 179 201 220
240 240 240 240 240 240 240 240 240 182 66 47 50 58 76 98
233 240 240 240 240 240 240 240 240 240 228 211 73 219 240 240
240 240 240 240 240 240 240 240 240 240 238 186 51 219 240 240
235 240 240 240 240 240 240 240 240 156 116 84 83 98 86 189
234 229 227 240 234 232 235 232 228 225 150 156 147 127 155 149
209 175 77 152 227 236 191 207 152 135 219 98 240 240 186 149
155 161 119 51 129 240 108 122 109 98 210 76 240 240 71 149
64 161 232 155 124 237 109 128 92 121 180 58 222 220 84 121
83 186 217 45 150 150 5 142 101 113 184 53 78 47 63 149
207 53 50 120 237 29 72 197 169 113 187 62 213 181 62 150
240 226 180 237 226 223 228 238 147 115 208 75 231 238 107 150
240 240 240 238 237 240 240 240 174 225 216 186 240 240 149 225
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 231
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 234
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
239 240 240 240 240 240 240 240 240 240 240 240 240 240 240 227
228 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
232 240 240 240 238 240 237 240 235 240 234 240 233 240 235 234
212 176 77 152 230 236 192 207 156 150 220 98 240 240 186 140
164 166 120 51 137 240 99 121 109 109 210 76 240 240 71 148
73 170 240 156 125 236 100 128 92 121 184 65 219 219 89 117
85 186 217 52 152 150 5 142 101 106 184 61 74 51 77 144
216 53 50 120 237 29 78 197 168 103 184 51 213 187 74 150
240 226 180 240 237 223 232 240 162 115 206 72 231 240 117 150
240 240 240 240 240 240 240 240 186 225 216 186 240 240 156 225
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 232
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 234
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 227
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
240 240 240 240 238 240 236 240 235 240 234 240 233 240 235 235
209 175 77 152 230 235 178 206 154 141 220 98 240 240 189 149
155 153 118 51 137 232 95 121 108 85 201 76 240 240 86 155
72 163 240 155 125 237 107 128 101 109 179 58 219 219 98 127
85 186 217 45 150 151 17 148 110 106 184 50 73 51 83 147
216 53 50 120 240 30 92 200 170 109 184 47 211 186 84 156
240 226 180 240 240 225 236 238 151 115 205 66 228 238 116 150
240 240 240 240 240 240 240 240 180 225 212 182 240 240 156 225
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 228
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 232
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 235
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 232
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 234
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 227
239 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
233 240 240 240 238 240 236 240 235 240 234 240 233 240 235 234
149 149 121 149 150 150 225 229 231 236 234 236 240 227 229 234
186 71 84 63 62 107 149 240 240 240 240 240 240 240 240 235
240 240 220 47 181 238 240 240 240 240 240 240 240 240 240 240
240 240 222 78 213 231 240 240 240 240 240 240 240 240 240 233
98 76 58 53 62 75 186 240 240 240 240 240 240 240 240 240
219 210 180 184 187 208 216 240 240 240 240 240 240 240 240 234
135 98 121 113 113 115 225 240 240 240 240 240 240 240 240 240
152 109 92 101 169 147 174 240 240 240 240 240 240 240 240 235
207 122 128 142 197 238 240 240 240 240 240 240 240 240 240 240
191 108 109 5 72 228 240 240 240 240 240 240 240 240 240 237
236 240 237 150 29 223 240 240 240 240 240 240 240 240 240 240
227 129 124 150 237 226 237 240 240 240 240 240 240 240 240 238
152 51 155 45 120 237 238 240 240 240 240 240 240 240 240 240
77 119 232 217 50 180 240 240 240 240 240 240 240 240 240 240
175 161 161 186 53 226 240 240 240 240 240 240 240 240 240 240
209 155 64 83 207 240 240 240 240 240 240 240 240 239 228 232
140 148 117 144 150 150 225 229 232 236 234 236 240 227 229 235
186 71 89 77 74 117 156 240 240 240 240 240 240 240 240 235
240 240 219 51 187 240 240 240 240 240 240 240 240 240 240 240
240 240 219 74 213 231 240 240 240 240 240 240 240 240 240 233
98 76 65 61 51 72 186 240 240 240 240 240 240 240 240 240
220 210 184 184 184 206 216 240 240 240 240 240 240 240 240 234
150 109 121 106 103 115 225 240 240 240 240 240 240 240 240 240
156 109 92 101 168 162 186 240 240 240 240 240 240 240 240 235
207 121 128 142 197 240 240 240 240 240 240 240 240 240 240 240
192 99 100 5 78 232 240 240 240 240 240 240 240 240 240 236
236 240 236 150 29 223 240 240 240 240 240 240 240 240 240 240
230 137 125 152 237 237 240 240 240 240 240 240 240 240 240 238
152 51 156 52 120 240 240 240 240 240 240 240 240 240 240 240
77 120 240 217 50 180 240 240 240 240 240 240 240 240 240 240
176 166 170 186 53 226 240 240 240 240 240 240 240 240 240 240
212 164 73 85 216 240 240 240 240 240 240 240 240 240 240 240
149 155 127 147 156 150 225 228 232 235 232 234 240 227 229 234
189 86 98 83 84 116 156 240 240 240 240 240 240 240 240 235
240 240 219 51 186 238 240 240 240 240 240 240 240 240 240 240
240 240 219 73 211 228 240 240 240 240 240 240 240 240 240 233
98 76 58 50 47 66 182 240 240 240 240 240 240 240 240 240
220 201 179 184 184 205 212 240 240 240 240 240 240 240 240 234
141 85 109 106 109 115 225 240 240 240 240 240 240 240 240 240
154 108 101 110 170 151 180 240 240 240 240 240 240 240 240 235
206 121 128 148 200 238 240 240 240 240 240 240 240 240 240 240
178 95 107 17 92 236 240 240 240 240 240 240 240 240 240 236
235 232 237 151 30 225 240 240 240 240 240 240 240 240 240 240
230 137 125 150 240 240 240 240 240 240 240 240 240 240 240 238
152 51 155 45 120 240 240 240 240 240 240 240 240 240 240 240
77 118 240 217 50 180 240 240 240 240 240 240 240 240 240 240
175 153 163 186 53 226 240 240 240 240 240 240 240 240 240 240
209 155 72 85 216 240 240 240 240 240 240 240 240 240 239 233
+195
View File
@@ -0,0 +1,195 @@
40 37 56 45 45 49 53 81 97 56 48 42 26 37 46 31
38 48 43 35 110 16 101 109 99 81 74 46 36 47 42 39
40 44 36 53 87 73 0 112 112 90 64 60 38 43 54 46
41 44 151 136 114 106 119 4 112 101 70 41 61 58 55 39
39 44 43 73 115 101 87 77 103 84 59 46 57 60 56 44
45 52 45 97 208 99 73 46 4 26 60 43 41 59 56 50
32 11 115 115 206 63 56 3 196 65 12 47 40 71 55 49
61 109 117 110 215 93 108 228 54 49 0 44 50 83 65 39
66 70 113 54 222 232 234 12 0 181 60 55 88 70 61 57
68 70 123 47 32 234 206 207 234 234 99 95 89 79 78 62
68 20 71 39 14 234 188 199 199 158 69 92 99 111 71 50
73 78 82 33 41 41 44 194 206 234 234 226 74 77 79 74
81 84 78 48 106 66 204 213 66 234 234 234 103 78 69 57
80 91 93 53 136 120 234 97 113 132 220 234 228 103 93 70
89 85 120 67 99 234 234 21 101 99 228 234 234 237 69 59
78 75 79 118 230 234 106 37 234 234 234 234 234 234 82 57
41 39 61 50 50 54 51 81 95 56 44 51 31 35 46 31
42 53 48 40 106 16 103 107 103 80 72 53 41 49 42 39
41 43 41 53 86 76 0 110 110 87 62 62 42 48 52 46
46 46 163 140 109 104 118 4 112 98 65 50 61 63 60 44
44 50 49 70 115 100 91 75 104 82 57 46 55 65 61 49
50 55 50 99 211 97 77 50 8 26 65 44 40 66 61 55
37 12 116 113 208 64 54 3 205 58 12 50 38 69 58 54
66 109 118 107 223 51 112 239 56 50 3 44 50 83 65 44
70 74 111 52 224 236 239 20 1 187 57 55 91 70 61 57
73 73 124 47 33 236 211 208 236 238 104 95 89 79 78 62
68 20 78 45 19 236 188 200 200 160 70 92 99 111 71 50
73 78 87 35 41 41 51 195 208 236 236 239 74 77 79 74
81 84 79 48 106 68 210 214 72 236 236 236 108 78 69 57
80 91 96 53 136 120 236 103 113 140 229 236 230 103 93 70
89 85 127 67 99 236 236 21 108 101 237 236 236 239 69 64
78 75 80 118 236 236 106 34 236 236 236 236 236 236 82 62
37 33 59 48 48 52 50 75 86 50 43 48 29 34 40 25
37 49 46 38 101 15 95 106 92 75 71 50 39 45 36 33
32 41 39 51 85 68 0 109 109 83 61 56 40 46 51 40
44 39 101 103 107 103 113 4 106 94 64 47 61 61 58 42
42 47 43 69 108 99 86 73 94 81 56 46 54 63 59 47
48 50 48 93 221 96 72 38 3 26 63 34 40 65 59 53
35 5 98 103 220 62 53 3 194 51 12 48 37 68 56 52
64 87 102 99 232 5 74 243 50 46 0 44 50 83 65 42
65 71 110 51 234 231 239 20 0 186 56 55 89 70 61 57
71 72 115 47 33 246 220 222 246 243 100 95 89 79 78 62
68 20 73 42 16 246 206 214 214 169 68 92 99 111 71 50
73 78 85 33 41 41 46 209 218 246 246 237 74 77 79 74
81 84 77 48 106 69 217 228 67 246 246 246 106 78 69 57
80 91 94 53 136 120 246 98 113 139 239 246 240 103 93 70
89 85 122 67 99 246 246 21 109 101 241 246 246 249 69 62
78 75 71 118 240 246 106 30 246 246 246 246 246 246 82 60
31 39 46 39 44 51 50 39 57 63 50 75 58 71 60 58
47 42 55 56 56 56 55 65 62 78 72 79 69 94 70 83
38 47 44 59 61 60 72 84 71 79 111 78 79 104 238 234
27 36 39 62 57 41 41 50 89 89 100 75 103 228 234 234
42 47 61 41 47 44 47 44 55 95 92 227 234 234 234 234
48 75 65 71 60 61 12 0 60 99 70 234 234 221 229 234
57 81 91 101 84 26 66 49 182 235 159 234 234 132 100 234
97 100 113 112 103 5 196 54 0 235 199 206 66 113 101 234
81 110 113 4 77 47 4 228 13 208 199 194 214 97 21 38
54 101 0 119 88 73 57 108 234 206 189 44 204 234 234 107
49 16 74 106 101 99 63 94 233 234 234 41 66 121 234 234
45 110 87 115 115 208 207 216 222 32 14 41 107 136 100 230
45 36 54 137 74 97 115 110 55 48 40 34 48 54 67 118
56 43 36 151 43 46 115 118 113 123 72 82 79 93 120 79
37 49 44 44 45 52 12 110 71 71 21 78 84 91 85 75
41 39 40 42 39 45 33 61 66 69 69 73 81 80 90 78
31 39 46 44 49 56 55 44 57 63 50 75 58 71 65 63
47 42 53 61 61 61 58 65 62 78 72 79 69 94 70 83
36 50 49 64 65 67 70 84 71 79 111 78 79 104 240 236
32 41 43 62 55 41 39 50 92 89 100 75 109 230 236 236
51 53 63 50 47 45 50 44 55 95 92 240 236 236 236 236
44 73 63 66 58 66 12 3 57 105 71 236 236 229 238 236
57 81 88 98 82 26 59 50 188 239 160 236 236 140 101 236
96 103 111 112 104 9 206 56 1 237 200 208 72 113 109 236
81 108 111 4 76 51 4 239 21 209 200 195 215 103 21 35
52 103 0 118 92 77 55 113 239 211 189 51 210 236 236 107
54 17 76 104 101 97 64 51 237 236 236 41 68 121 236 236
50 106 87 110 115 211 208 224 224 33 20 41 107 136 100 237
50 41 53 140 71 99 113 107 53 48 46 36 48 54 67 118
61 48 41 163 50 51 117 119 111 124 79 87 80 96 127 80
39 53 43 46 50 56 13 110 74 74 21 78 84 91 85 75
42 42 41 47 44 50 38 66 70 74 69 73 81 80 90 78
25 33 40 42 47 54 53 42 57 63 50 75 58 71 63 61
41 36 52 59 59 59 56 65 62 78 72 79 69 94 70 83
35 46 47 62 63 66 69 84 71 79 111 78 79 104 250 246
30 39 41 62 54 41 38 50 90 89 100 75 107 240 246 246
48 50 57 47 47 35 48 44 55 95 92 238 246 246 246 246
43 71 62 65 57 64 12 0 56 101 69 246 246 240 242 246
51 76 84 94 81 26 52 46 187 244 170 246 246 139 101 246
86 93 110 106 94 4 194 50 0 247 214 218 67 113 110 246
75 107 110 4 73 39 4 243 21 223 214 209 229 98 21 31
51 95 0 114 87 72 53 74 240 220 206 46 218 246 246 107
52 15 68 103 99 96 62 6 232 246 246 41 69 121 246 246
48 102 86 108 109 221 221 233 234 33 16 41 107 136 100 241
48 38 52 104 70 94 103 99 52 48 42 34 48 54 67 118
59 46 39 101 44 49 98 103 110 115 74 85 78 94 122 71
33 49 42 39 48 50 6 88 72 72 21 78 84 91 85 75
38 38 32 45 42 48 36 64 65 72 69 73 81 80 90 78
58 83 234 234 234 234 234 234 38 107 234 230 118 79 75 78
60 70 238 234 234 229 100 101 21 234 234 100 67 120 85 90
71 94 104 228 234 221 132 113 97 234 121 136 54 93 91 80
58 69 79 103 234 234 234 66 214 204 66 107 48 79 84 81
75 79 78 75 227 234 234 206 194 44 41 41 34 82 78 73
50 72 111 100 92 70 159 199 199 189 234 14 40 72 21 69
63 78 79 89 95 99 235 235 208 206 234 32 48 123 71 69
57 62 71 89 55 60 182 0 13 234 233 222 55 113 71 66
39 65 84 50 44 0 49 54 228 108 94 216 110 118 110 61
50 55 72 41 47 12 66 196 4 57 63 207 115 115 12 33
51 56 60 41 44 61 26 5 47 73 99 208 97 46 52 45
44 56 61 57 47 60 84 103 77 88 101 115 74 43 45 39
39 56 59 62 41 71 101 112 4 119 106 115 137 151 44 42
46 55 44 39 61 65 91 113 113 0 74 87 54 36 44 40
39 42 47 36 47 75 81 100 110 101 16 110 36 43 49 39
31 47 38 27 42 48 57 97 81 54 49 45 45 56 37 41
63 83 236 236 236 236 236 236 35 107 236 237 118 80 75 78
65 70 240 236 236 238 101 109 21 236 236 100 67 127 85 90
71 94 104 230 236 229 140 113 103 236 121 136 54 96 91 80
58 69 79 109 236 236 236 72 215 210 68 107 48 80 84 81
75 79 78 75 240 236 236 208 195 51 41 41 36 87 78 73
50 72 111 100 92 71 160 200 200 189 236 20 46 79 21 69
63 78 79 89 95 105 239 237 209 211 236 33 48 124 74 74
57 62 71 92 55 57 188 1 21 239 237 224 53 111 74 70
44 65 84 50 44 3 50 56 239 113 51 224 107 119 110 66
55 58 70 39 50 12 59 206 4 55 64 208 113 117 13 38
56 61 67 41 45 66 26 9 51 77 97 211 99 51 56 50
49 61 65 55 47 58 82 104 76 92 101 115 71 50 50 44
44 61 64 62 50 66 98 112 4 118 104 110 140 163 46 47
46 53 49 43 63 63 88 111 111 0 76 87 53 41 43 41
39 42 50 41 53 73 81 103 108 103 17 106 41 48 53 42
31 47 36 32 51 44 57 96 81 52 54 50 50 61 39 42
61 83 246 246 246 246 246 246 31 107 246 241 118 71 75 78
63 70 250 246 246 242 101 110 21 246 246 100 67 122 85 90
71 94 104 240 246 240 139 113 98 246 121 136 54 94 91 80
58 69 79 107 246 246 246 67 229 218 69 107 48 78 84 81
75 79 78 75 238 246 246 218 209 46 41 41 34 85 78 73
50 72 111 100 92 69 170 214 214 206 246 16 42 74 21 69
63 78 79 89 95 101 244 247 223 220 246 33 48 115 72 72
57 62 71 90 55 56 187 0 21 240 232 234 52 110 72 65
42 65 84 50 44 0 46 50 243 74 6 233 99 103 88 64
53 56 69 38 48 12 52 194 4 53 62 221 103 98 6 36
54 59 66 41 35 64 26 4 39 72 96 221 94 49 50 48
47 59 63 54 47 57 81 94 73 87 99 109 70 44 48 42
42 59 62 62 47 65 94 106 4 114 103 108 104 101 39 45
40 52 47 41 57 62 84 110 110 0 68 86 52 39 42 32
33 36 46 39 50 71 76 93 107 95 15 102 38 46 49 38
25 41 35 30 48 43 51 86 75 51 52 48 48 59 33 38
78 90 80 81 73 69 69 66 61 33 45 39 42 40 39 41
75 85 91 84 78 21 71 71 110 12 52 45 44 44 49 37
79 120 93 79 82 72 123 113 118 115 46 43 151 36 43 56
118 67 54 48 34 40 48 55 110 115 97 74 137 54 36 45
230 100 136 107 41 14 32 222 216 207 208 115 115 87 110 45
234 234 121 66 41 234 234 233 94 63 99 101 106 74 16 49
107 234 234 204 44 189 206 234 108 57 73 88 119 0 101 54
38 21 97 214 194 199 208 13 228 4 47 77 4 113 110 81
234 101 113 66 206 199 235 0 54 196 5 103 112 113 100 97
234 100 132 234 234 159 235 182 49 66 26 84 101 91 81 57
234 229 221 234 234 70 99 60 0 12 61 60 71 65 75 48
234 234 234 234 227 92 95 55 44 47 44 47 41 61 47 42
234 234 228 103 75 100 89 89 50 41 41 57 62 39 36 27
234 238 104 79 78 111 79 71 84 72 60 61 59 44 47 38
83 70 94 69 79 72 78 62 65 55 56 56 56 55 42 47
58 60 71 58 75 50 63 57 39 50 51 44 39 46 39 31
78 90 80 81 73 69 74 70 66 38 50 44 47 41 42 42
75 85 91 84 78 21 74 74 110 13 56 50 46 43 53 39
80 127 96 80 87 79 124 111 119 117 51 50 163 41 48 61
118 67 54 48 36 46 48 53 107 113 99 71 140 53 41 50
237 100 136 107 41 20 33 224 224 208 211 115 110 87 106 50
236 236 121 68 41 236 236 237 51 64 97 101 104 76 17 54
107 236 236 210 51 189 211 239 113 55 77 92 118 0 103 52
35 21 103 215 195 200 209 21 239 4 51 76 4 111 108 81
236 109 113 72 208 200 237 1 56 206 9 104 112 111 103 96
236 101 140 236 236 160 239 188 50 59 26 82 98 88 81 57
236 238 229 236 236 71 105 57 3 12 66 58 66 63 73 44
236 236 236 236 240 92 95 55 44 50 45 47 50 63 53 51
236 236 230 109 75 100 89 92 50 39 41 55 62 43 41 32
236 240 104 79 78 111 79 71 84 70 67 65 64 49 50 36
83 70 94 69 79 72 78 62 65 58 61 61 61 53 42 47
63 65 71 58 75 50 63 57 44 55 56 49 44 46 39 31
78 90 80 81 73 69 72 65 64 36 48 42 45 32 38 38
75 85 91 84 78 21 72 72 88 6 50 48 39 42 49 33
71 122 94 78 85 74 115 110 103 98 49 44 101 39 46 59
118 67 54 48 34 42 48 52 99 103 94 70 104 52 38 48
241 100 136 107 41 16 33 234 233 221 221 109 108 86 102 48
246 246 121 69 41 246 246 232 6 62 96 99 103 68 15 52
107 246 246 218 46 206 220 240 74 53 72 87 114 0 95 51
31 21 98 229 209 214 223 21 243 4 39 73 4 110 107 75
246 110 113 67 218 214 247 0 50 194 4 94 106 110 93 86
246 101 139 246 246 170 244 187 46 52 26 81 94 84 76 51
246 242 240 246 246 69 101 56 0 12 64 57 65 62 71 43
246 246 246 246 238 92 95 55 44 48 35 47 47 57 50 48
246 246 240 107 75 100 89 90 50 38 41 54 62 41 39 30
246 250 104 79 78 111 79 71 84 69 66 63 62 47 46 35
83 70 94 69 79 72 78 62 65 56 59 59 59 52 36 41
61 63 71 58 75 50 63 57 42 53 54 47 42 40 33 25
Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1011 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

+456
View File
@@ -0,0 +1,456 @@
<template>
<div id="webGL3d" ref="container"></div>
<video ref="videoRef" id="video" autoplay playsinline></video>
</template>
<script lang="ts" setup>
import * as THREE from "three";
import "aframe";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
import { localStorage } from "@/utils/local-storage";
// 导入lil.gui
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
const props = defineProps({
modelFile: { type: String, default: () => "" },
bgModel: { type: String, default: "" },
pid: { type: Number, default: 0 },
});
import { showSuccessToast, showToast } from "vant";
const container = ref(null);
const STATE = {
NONE: -1,
MOVE: 0,
ZOOM_OR_PAN: 1,
POSITION_MOVE: 1,
};
const mouseInfo = ref({
startX: 0,
startY: 0,
isDown: false,
startPointerDistance: 0,
state: STATE.NONE,
});
let model, scene, camera, renderer, controls;
const videoRef = ref();
const twoFirst = ref(true);
const lastPoint = ref({
touchStartX1: 0,
touchStartY1: 0,
touchStartX2: 0,
touchStartY2: 0,
});
const emit = defineEmits([
"handleProgress",
"handleLoaded",
]);
onMounted(() => {
isDevices();
});
// 监听组件销毁事件
onBeforeUnmount(() => {
// 销毁 Three.js 模型
scene.remove(model);
model.traverse((child) => {
if (child.isMesh) {
child.geometry.dispose();
child.material.dispose();
}
});
// 清理渲染器
renderer.dispose();
});
watch(
() => props.modelFile,
(val, oldVal) => {
if (val) {
// 加载模型
Init();
}
},
{
immediate: true,
}
);
const modelContainer = new THREE.Object3D();
const loader = new GLTFLoader();
const Init = async () => {
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./draco/");
// 创建场景
scene = new THREE.Scene();
// 创建一个包含模型的父对象
// 旋转缩放相关配置
// 创建相机
camera = new THREE.OrthographicCamera(
window.innerWidth / -10.5,
window.innerWidth / 10.5,
window.innerHeight / 10.5,
window.innerHeight / -10.5,
0.1,
1000
// 90,
// window.innerWidth / window.innerHeight,
// .1,
// 1000
);
// 添加环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 2);
scene.add(ambientLight);
// 从上方照射的白色平行光,强度为 0.5。
const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
// directionalLight.castShadow = true;
directionalLight.position.x = 1;
directionalLight.position.y = 1;
directionalLight.position.z = 80;
directionalLight.target = modelContainer;
scene.add(directionalLight);
let renderParam = {
antialias: true, // true/false表示是否开启反锯齿
alpha: true, // true/false 表示是否可以设置背景色透明
precision: "highp", // highp/mediump/lowp 表示着色精度选择
premultipliedAlpha: false,
maxLights: 3,
};
// 创建渲染器
renderer = new THREE.WebGLRenderer(renderParam);
renderer.setSize(window.innerWidth, window.innerHeight);
// renderer.setClearColor(0x000000, 0);
renderer.setPixelRatio(window.devicePixelRatio); // 设置画布分辨率 提高画质
container.value.appendChild(renderer.domElement);
await startCamera();
var videoElement = document.getElementById("video");
var videoTexture = new THREE.VideoTexture(videoElement);
videoTexture.minFilter = THREE.LinearFilter;
scene.background = videoTexture;
// 加载hdr贴图
// let rgbeLoader = new RGBELoader();
// const rgbUrl = props.bgModel || "src/assets/bg.hdr";
// rgbeLoader.load(rgbUrl, envMap => {
// // 设置球形贴图
// envMap.mapping = THREE.EquirectangularReflectionMapping;
// // 设置环境贴图
// scene.background = envMap;
// scene.environment = envMap;
// })
// 创建点光源
var pointLight = new THREE.PointLight(0xffffff, 500); // 设置点光源的颜色和强度
pointLight.position.set(0, 0, 100); // 设置点光源的位置
scene.add(pointLight);
// 相机位置
camera.position.z = 200;
camera.position.y = 0;
camera.position.x = 0;
camera.lookAt(0, 0, 0);
// 监听缩放\旋转操作
renderer.domElement.addEventListener("touchstart", (event) => {
console.log("touchstart", event);
handleTouchStart(event);
});
const handleTouchStart = (event) => {
mouseInfo.value.isDown = true;
// 双指
const touch0 = event.touches[0];
const touch1 = event.touches[1];
// 单点触控
if (event.touches.length === 1) {
mouseInfo.value.startX = touch0.pageX;
mouseInfo.value.startY = touch0.pageY;
mouseInfo.value.state = STATE.MOVE; // 这边换成rorate会比较好点
} else if (event.touches.length === 2) {
// 双指,计算两指距离
// 一般是平移或者缩放
const dx = touch0.pageX - touch1.pageX;
const dy = touch0.pageY - touch1.pageY;
mouseInfo.value.startPointerDistance = Math.sqrt(dx * dx + dy * dy);
mouseInfo.value.startX = (touch0.pageX + touch1.pageX) / 2;
mouseInfo.value.startY = (touch0.pageY + touch1.pageY) / 2;
mouseInfo.value.state = STATE.ZOOM_OR_PAN;
}
};
renderer.domElement.addEventListener("touchmove", (event) => {
if(isModel) {
handleTouchMove(event);
}
event.stopPropagation();
event.preventDefault();
}, { passive: false });
renderer.domElement.addEventListener('click', (event) => {
onMouseClick(event)
});
function onMouseClick(event) {
var mouse = new THREE.Vector2();
// 计算鼠标点击位置的归一化设备坐标
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
if(isModel.value) {
modelContainer.position.x = mouse.x * 40;
modelContainer.position.y = mouse.y * 100;
}else {
loadModel(mouse);
}
}
const isModel = ref(false); // 是否创建模型
function loadModel(position) {
// 加载 glb 格式的 3D 模型
loader.setDRACOLoader(dracoLoader);
loader.load(
props.modelFile,
(gltf) => {
// 加载成功后的回调函数
emit("handleLoaded");
model = gltf.scene;
// model.position.set(0, 0, 0);
const box = new THREE.Box3().setFromObject(model);
// sizeBox.expandByObject(gltf.scene)
// sizeBox.getSize(v3)
// console.log("gltf", gltf)
// console.log("volume", volume)
// 获取包围盒中心点
const center = box.getCenter(new THREE.Vector3());
model.position.sub(center); // 将模型位置移到原点处
// 将模型添加到父对象中
modelContainer.add(model);
// modelGeometry.center(); // 这个等同于上面这行代码
// model.translateX(-80)
scene.add(modelContainer);
modelContainer.position.x = position.x * 40;
modelContainer.position.y = position.y * 100;
console.log("modelContainer", modelContainer.position)
isModel.value = true;
},
(xhr) => {
// 加载过程中的回调函数
emit("handleProgress", Math.floor((xhr.loaded / xhr.total) * 100));
},
(error) => {
// 加载失败的回调函数
console.error("Failed to load model", error);
}
);
}
// 开始触碰
const handleTouchMove = (event) => {
if (!mouseInfo.value.isDown) {
return;
}
switch (mouseInfo.value.state) {
case STATE.MOVE:
if (event.touches.length === 1) {
handleRotate(event);
} else if (event.touches.length === 2) {
// 兼容处理,如果是移动过程中出现双指时,需要取消单指,然后再重新计算
renderer.domElement.removeEventListener(
"touchmove",
handleTouchMove,
false
);
renderer.domElement.removeEventListener(
"touchend",
handleTouchEnd,
false
);
handleTouchStart(event);
}
break;
case STATE.ZOOM_OR_PAN:
if (event.touches.length === 1) {
} else if (event.touches.length === 2) {
handleZoomOrPan(event);
}
break;
default:
break;
}
};
let rotateSpeed = 0.01;
// 模型旋转
const handleRotate = (event) => {
const x = event.touches[0].pageX;
const y = event.touches[0].pageY;
const { startX, startY } = mouseInfo.value;
const deltaX = x - startX;
const deltaY = y - startY;
modelContainer.rotation.y += deltaX * rotateSpeed;
modelContainer.rotation.x += deltaY * rotateSpeed;
mouseInfo.value.startX = x;
mouseInfo.value.startY = y;
};
// 模型缩放
const handleZoomOrPan = (event) => {
let { touchStartX1, touchStartY1, touchStartX2, touchStartY2 } =
lastPoint.value;
let initialScale = modelContainer.scale.x;
const touch0 = event.touches[0];
const touch1 = event.touches[1];
const dx = touch0.pageX - touch1.pageX;
const dy = touch0.pageY - touch1.pageY;
const distance = Math.sqrt(dx * dx + dy * dy);
let obj = {
touchStartX1: touch0.pageX,
touchStartY1: touch0.pageY,
touchStartX2: touch1.pageX,
touchStartY2: touch1.pageY,
};
if (twoFirst.value) {
twoFirst.value = false;
lastPoint.value = { ...obj };
} else {
let deltaScale =
initialScale * (distance / mouseInfo.value.startPointerDistance);
// 限制缩放距离
if (deltaScale < 0.25) {
deltaScale = 0.25;
} else if (deltaScale > 2) {
deltaScale = 2;
}
mouseInfo.value.startPointerDistance = distance;
modelContainer.scale.set(deltaScale, deltaScale, deltaScale);
const avgX = (touch0.pageX + touch1.pageX) / 2;
const avgY = (touch0.pageY + touch1.pageY) / 2;
const deltaX = avgX - (touchStartX1 + touchStartX2) / 2;
const deltaY = avgY - (touchStartY1 + touchStartY2) / 2;
modelContainer.position.x += deltaX * 0.3;
modelContainer.position.y -= deltaY * 0.3;
lastPoint.value = {
touchStartX1: touch0.pageX,
touchStartY1: touch0.pageY,
touchStartX2: touch1.pageX,
touchStartY2: touch1.pageY,
};
}
};
const handleTouchEnd = () => {
mouseInfo.value.isDown = false;
mouseInfo.value.state = STATE.NONE;
twoFirst.value = true;
lastPoint.value.touchStartX1 = 0;
lastPoint.value.touchStartY1 = 0;
lastPoint.value.touchStartX2 = 0;
lastPoint.value.touchStartY2 = 0;
// 取消移动事件监听
renderer.domElement.removeEventListener(
"touchmove",
handleTouchMove,
false
);
renderer.domElement.removeEventListener(
"touchstart",
handleTouchStart,
false
);
};
renderer.domElement.addEventListener("touchend", (event) => {
handleTouchEnd();
});
// 渲染场景
const animate = () => {
// controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
videoTexture.needsUpdate = true;
};
animate();
// 监听窗口缩放
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
};
const isDevices = () => {
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
var getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia ||
navigator.oGetUserMedia;
if (!getUserMedia) {
return Promise.reject(
new Error("getUserMedia is not implemented in this browser")
);
}
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
};
}
};
const cameraStream = ref(null)
const startCamera = async () => {
isDevices();
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
facingMode: { exact: "environment" },
},
});
cameraStream.value = stream;
videoRef.value.srcObject = stream;
} catch (error) {
console.error(error);
}
};
</script>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
+591
View File
@@ -0,0 +1,591 @@
<template>
<div class="container">
<a-scene
xr-mode-ui="enabled: false"
arjs="sourceType: webcam;"
style="width: 100%; height: 100vh;"
@click="onSceneClick"
>
<a-camera position="0 1.6 0">
<a-cursor></a-cursor>
</a-camera>
<a-light type="directional" position="0 1 0.5" intensity="1"></a-light>
<a-light type="ambient" color="#ffffff"></a-light>
<a-plane id="ground" position="0 0 0" rotation="-90 0 0" width="200" height="200" color="#7BC8A4" opacity="0.5"></a-plane>
<a-entity id="model" :gltf-model="modelFile" position="0 1 -.5" scale="0.005 0.005 0.005" ></a-entity>
</a-scene>
</div>
</template>
<script setup lang="ts">
import * as THREE from "three";
import "aframe";
// import '@/utils/threex/ar.min.js'
// import "@ar-js-org/ar.js"
// import * as THREEx from "@ar-js-org/ar.js/three.js/build/ar-threex"
import "@ar-js-org/ar.js/three.js/build/ar"
// import "@ar-js-org/ar.js/aframe/build/aframe-ar";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
// import {ARToolkit, ARController} from "@ar-js-org/artoolkit5-js"
let model, scene, camera, renderer, controls;
const container = ref(null);
var onRenderFcts = [];
const STATE = {
NONE: -1,
MOVE: 0,
ZOOM_OR_PAN: 1,
POSITION_MOVE: 1,
};
const mouseInfo = ref({
startX: 0,
startY: 0,
isDown: false,
startPointerDistance: 0,
state: STATE.NONE,
});
const twoFirst = ref(true);
const lastPoint = ref({
touchStartX1: 0,
touchStartY1: 0,
touchStartX2: 0,
touchStartY2: 0,
});
const emit = defineEmits(["rotateControl", "handleProgress", "handleLoaded"]);
const props = defineProps({
modelFile: { type: String, default: () => "" },
pid: { type: Number, default: 0 },
});
onMounted(() => {
isDevices();
document.addEventListener('click', onSceneClick, false);
// animate();
});
// 监听组件销毁事件
onBeforeUnmount(() => {
// 销毁 Three.js 模型
scene.remove(model);
model.traverse((child) => {
if (child.isMesh) {
child.geometry.dispose();
child.material.dispose();
}
});
// 清理渲染器
renderer.dispose();
});
watch(
() => props.modelFile,
(val, oldVal) => {
if (val) {
// init();
test();
}
},
{ immediate: true }
);
const modelContainer = new THREE.Object3D();
const loader = new GLTFLoader();
const test = () => {
}
const init = () => {
let renderParam = {
antialias: true, // true/false表示是否开启反锯齿
alpha: true, // true/false 表示是否可以设置背景色透明
precision: "highp", // highp/mediump/lowp 表示着色精度选择
premultipliedAlpha: false,
maxLights: 3,
};
// 创建渲染器
renderer = new THREE.WebGLRenderer(renderParam);
renderer.setSize(window.innerWidth, window.innerHeight);
// renderer.setClearColor(0x000000, 0);
renderer.setPixelRatio(window.devicePixelRatio); // 设置画布分辨率 提高画质
container.value.appendChild(renderer.domElement);
// 创建场景
scene = new THREE.Scene();
// const {width, height} = scene
// 创建一个包含模型的父对象
// 旋转缩放相关配置
// 创建相机
camera = new THREE.OrthographicCamera(
window.innerWidth / -10.5,
window.innerWidth / 10.5,
window.innerHeight / 10.5,
window.innerHeight / -10.5,
0.1,
1000
// 90,
// window.innerWidth / window.innerHeight,
// .1,
// 1000
);
// 相机位置
camera.position.z = 200;
camera.position.y = 0;
camera.position.x = 0;
camera.lookAt(0, 0, 0);
// 添加环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 2);
scene.add(ambientLight);
// 从上方照射的白色平行光,强度为 0.5。
const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
// directionalLight.castShadow = true;
directionalLight.position.x = 1;
directionalLight.position.y = 1;
directionalLight.position.z = 80;
directionalLight.target = modelContainer;
scene.add(directionalLight);
// 加载hdr贴图
// let rgbeLoader = new RGBELoader();
// const rgbUrl = props.bgModel || "src/assets/bg.hdr";
// rgbeLoader.load(rgbUrl, envMap => {
// // 设置球形贴图
// envMap.mapping = THREE.EquirectangularReflectionMapping;
// // 设置环境贴图
// scene.background = envMap;
// scene.environment = envMap;
// })
// 创建点光源
var pointLight = new THREE.PointLight(0xffffff, 500); // 设置点光源的颜色和强度
pointLight.position.set(0, 0, 100); // 设置点光源的位置
scene.add(pointLight);
// 坐标轴
// const axesHelper = new THREE.AxesHelper(5)
// scene.add( axesHelper );
// // 添加轨道控制器
// controls = new OrbitControls(camera, renderer.domElement);
// controls.autoRotate = true;
// controls.autoRotateSpeed = 5;
runAR();
};
var arToolkitSource, arToolkitContext;
const runAR = () => {
// 创建AR场景和渲染器
arToolkitSource = new THREEx.ArToolkitSource({
sourceType: "webcam",
// sourceWidth: window.innerWidth,
// sourceHeight: window.innerHeight,
displayWidth: window.innerWidth,
displayHeight: window.innerHeight,
});
arToolkitContext = new THREEx.ArToolkitContext({
cameraParametersUrl: "src/assets/model/camera_para.dat",
detectionMode: "mono",
// canvasWidth: window.innerWidth,
// canvasHeight: window.innerHeight,
});
const markerControls = new THREEx.ArMarkerControls(arToolkitContext, camera, { type: 'pattern', patternUrl: 'src/assets/model/patt.hiro' });
const marker = document.createElement('a-marker');
container.value.appendChild(marker);
arToolkitContext.init(function onCompleted() {
arToolkitSource.onResizeElement();
arToolkitSource.copyElementSizeTo(renderer.domElement);
camera.projectionMatrix.copy(arToolkitContext.getProjectionMatrix());
});
arToolkitSource.init(() => {
setTimeout(() => {
arToolkitContext.arController.setPatternDetectionMode(artoolkit.AR_TEMPLATE_MATCHING_MONO_AND_MATRIX);
}, 2000);
});
// arToolkitContext.addEventListener('artoolkit-mat', (event) => {
// var detectedPlanes = event.data;
// if (detectedPlanes.length > 0) {
// // 检测到平面,执行相应的操作
// var plane = detectedPlanes[0];
// console.log("Detected plane: ", plane);
// }
// });
// 创建AR追踪器
// var markerControls = new THREEx.ArMarkerControls(arToolkitContext, camera, {
// type: "pattern",
// patternUrl: "src/assets/model/pattern-marker.patt",
// });
// function onMarkerFound(event) {
// var markerRoot = event.data.markerRoot;
// // 获取平面的位置
// var position = new THREE.Vector3();
// markerRoot.matrixWorld.decompose(
// position,
// new THREE.Quaternion(),
// new THREE.Vector3()
// );
// // 添加标记物体
// addMarker(position);
// }
// markerControls.addEventListener("markerFound", onMarkerFound);
// function addMarker(position) {
// var markerGeometry = new THREE.BoxGeometry(0.1, 0.1, 0.1);
// var markerMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
// var marker = new THREE.Mesh(markerGeometry, markerMaterial);
// marker.position.copy(position);
// scene.add(marker);
// }
// build a smoothedControls
// var smoothedRoot = new THREE.Group()
// scene.add(smoothedRoot)
// var smoothedControls = new THREEx.ArSmoothedControls(smoothedRoot, {
// lerpPosition: 0.4,
// lerpQuaternion: 0.3,
// lerpScale: 1,
// // minVisibleDelay: 1,
// // minUnvisibleDelay: 1,
// })
// onRenderFcts.push(function(delta){
// smoothedControls.update(markerRoot)
// })
// 加载模型
// loadModel(props.modelFile)
animate();
};
const loadModel = async (modelPath) => {
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./draco/");
// 加载 glb 格式的 3D 模型
loader.setDRACOLoader(dracoLoader);
loader.load(
modelPath,
(gltf) => {
// 加载成功后的回调函数
// emit("handleLoaded")
model = gltf.scene;
// model.position.set(0, 0, 0);
const box = new THREE.Box3().setFromObject(model);
let sizeBox = new THREE.Box3();
sizeBox.expandByObject(gltf.scene);
const v3 = new THREE.Vector3();
sizeBox.getSize(v3);
// console.log('size', v3)
// console.log("gltf", gltf)
// console.log("volume", volume)
// 获取包围盒中心点
const center = box.getCenter(new THREE.Vector3());
model.position.sub(center); // 将模型位置移到原点处
// 将模型添加到父对象中
modelContainer.add(model);
// modelGeometry.center(); // 这个等同于上面这行代码
// model.translateX(-80)
scene.add(modelContainer);
},
(xhr) => {
// 加载过程中的回调函数
// emit("handleProgress",Math.floor((xhr.loaded / xhr.total) * 100))
},
(error) => {
// 加载失败的回调函数
console.error("Failed to load model", error);
}
);
// 监听缩放\旋转操作
renderer.domElement.addEventListener("touchstart", (event) => {
handleTouchStart(event);
});
const handleTouchStart = (event) => {
mouseInfo.value.isDown = true;
// 双指
const touch0 = event.touches[0];
const touch1 = event.touches[1];
// 单点触控
if (event.touches.length === 1) {
mouseInfo.value.startX = touch0.pageX;
mouseInfo.value.startY = touch0.pageY;
mouseInfo.value.state = STATE.MOVE; // 这边换成rorate会比较好点
} else if (event.touches.length === 2) {
// 双指,计算两指距离
// 一般是平移或者缩放
const dx = touch0.pageX - touch1.pageX;
const dy = touch0.pageY - touch1.pageY;
mouseInfo.value.startPointerDistance = Math.sqrt(dx * dx + dy * dy);
mouseInfo.value.startX = (touch0.pageX + touch1.pageX) / 2;
mouseInfo.value.startY = (touch0.pageY + touch1.pageY) / 2;
mouseInfo.value.state = STATE.ZOOM_OR_PAN;
}
};
renderer.domElement.addEventListener("touchmove", (event) => {
// console.log("touchmove",event )
handleTouchMove(event);
});
// 开始触碰
const handleTouchMove = (event) => {
if (!mouseInfo.value.isDown) {
return;
}
switch (mouseInfo.value.state) {
case STATE.MOVE:
if (event.touches.length === 1) {
handleRotate(event);
} else if (event.touches.length === 2) {
// 兼容处理,如果是移动过程中出现双指时,需要取消单指,然后再重新计算
renderer.domElement.removeEventListener(
"touchmove",
handleTouchMove,
false
);
renderer.domElement.removeEventListener(
"touchend",
handleTouchEnd,
false
);
handleTouchStart(event);
}
break;
case STATE.ZOOM_OR_PAN:
if (event.touches.length === 1) {
} else if (event.touches.length === 2) {
handleZoomOrPan(event);
}
break;
default:
break;
}
};
let rotateSpeed = 0.01;
// 模型旋转
const handleRotate = (event) => {
const x = event.touches[0].pageX;
const y = event.touches[0].pageY;
const { startX, startY } = mouseInfo.value;
const deltaX = x - startX;
const deltaY = y - startY;
modelContainer.rotation.y += deltaX * rotateSpeed;
modelContainer.rotation.x += deltaY * rotateSpeed;
// const theta = (x - startX) / radius * (-rotateSpeed)
// const phi = (y - startY) / radius * (-rotateSpeed)
// const maxRotationAngle = Math.PI / 2;
// // 没有变化那么停止
// if (Math.abs(theta) < .01 && Math.abs(phi) < .01) {
// return
// }
// // 移动位置判断
// if (Math.abs(x - startX) >= Math.abs(y - startY)) {
// // 旋转角度
// model.rotation.y -= theta
// } else {
// model.rotation.x -= phi
// model.rotation.x = Math.max(-maxRotationAngle, Math.min(maxRotationAngle, model.rotation.x))
// // this.gltfItemLights.rotation.x -= phi
// // this.gltfItemLights.rotation.x = Math.max(-maxRotationAngle, Math.min(maxRotationAngle, model.rotation.x));
// }
mouseInfo.value.startX = x;
mouseInfo.value.startY = y;
// console.log("mouseInfo.value.startY", y)
};
// 模型缩放
const handleZoomOrPan = (event) => {
let { touchStartX1, touchStartY1, touchStartX2, touchStartY2 } =
lastPoint.value;
let initialScale = modelContainer.scale.x;
const touch0 = event.touches[0];
const touch1 = event.touches[1];
const dx = touch0.pageX - touch1.pageX;
const dy = touch0.pageY - touch1.pageY;
const distance = Math.sqrt(dx * dx + dy * dy);
let obj = {
touchStartX1: touch0.pageX,
touchStartY1: touch0.pageY,
touchStartX2: touch1.pageX,
touchStartY2: touch1.pageY,
};
if (twoFirst.value) {
twoFirst.value = false;
lastPoint.value = { ...obj };
} else {
let deltaScale =
initialScale * (distance / mouseInfo.value.startPointerDistance);
// 限制缩放距离
if (deltaScale < -2) {
deltaScale = -2;
} else if (deltaScale > 2) {
deltaScale = 2;
}
mouseInfo.value.startPointerDistance = distance;
modelContainer.scale.set(deltaScale, deltaScale, deltaScale);
const avgX = (touch0.pageX + touch1.pageX) / 2;
const avgY = (touch0.pageY + touch1.pageY) / 2;
const deltaX = avgX - (touchStartX1 + touchStartX2) / 2;
const deltaY = avgY - (touchStartY1 + touchStartY2) / 2;
// modelContainer.position.x += deltaX * 0.3;
// modelContainer.position.y -= deltaY * 0.3;
lastPoint.value = {
touchStartX1: touch0.pageX,
touchStartY1: touch0.pageY,
touchStartX2: touch1.pageX,
touchStartY2: touch1.pageY,
};
}
};
const handleTouchEnd = () => {
mouseInfo.value.isDown = false;
mouseInfo.value.state = STATE.NONE;
twoFirst.value = true;
lastPoint.value.touchStartX1 = 0;
lastPoint.value.touchStartY1 = 0;
lastPoint.value.touchStartX2 = 0;
lastPoint.value.touchStartY2 = 0;
// 取消移动事件监听
renderer.domElement.removeEventListener(
"touchmove",
handleTouchMove,
false
);
renderer.domElement.removeEventListener(
"touchstart",
handleTouchStart,
false
);
};
renderer.domElement.addEventListener("touchend", (event) => {
handleTouchEnd();
});
animate();
// 监听窗口缩放
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
};
const isDevices = () => {
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
var getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia ||
navigator.oGetUserMedia;
if (!getUserMedia) {
return Promise.reject(
new Error("getUserMedia is not implemented in this browser")
);
}
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
};
}
};
const onSceneClick = (event) => {
const sceneEl = document.querySelector('a-scene');
let Camera = sceneEl.querySelector('[camera]');
let Model = sceneEl.querySelector('#model');
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, Camera.getObject3D('camera'));
const intersects = raycaster.intersectObjects([sceneEl.querySelector('#ground').object3D], true);
if (intersects.length > 0) {
const intersect = intersects[0];
console.log("--------onSceneClick-------",intersect)
Model.setAttribute('position', intersect.point);
Model.setAttribute('visible', 'true');
}
};
var lastTimeMsec = null;
// 渲染场景
const animate = () => {
// controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
// videoTexture.needsUpdate = true;
if (arToolkitSource.ready) {
arToolkitContext.update(arToolkitSource.domElement);
}
// measure time
// lastTimeMsec = lastTimeMsec || nowMsec-1000/60
// var deltaMsec = Math.min(200, nowMsec - lastTimeMsec)
// lastTimeMsec = nowMsec
// // call each update function
// onRenderFcts.forEach(function(onRenderFct){
// onRenderFct(deltaMsec/1000, nowMsec/1000)
// })
};
</script>
<style scoped>
.container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
body {
margin: 0;
overflow: hidden;
}
</style>
+13
View File
@@ -0,0 +1,13 @@
<template>
<div>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
+499
View File
@@ -0,0 +1,499 @@
<template>
<div ref="container" class="container">
<video ref="video" class="fullscreen-video" autoplay playsinline muted></video>
<canvas ref="canvas" class="fullscreen-canvas"></canvas>
</div>
</template>
<script setup lang="ts">
import * as tf from '@tensorflow/tfjs';
import * as cocoSsd from '@tensorflow-models/coco-ssd';
import * as THREE from "three";
// import "aframe";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
let model, scene, camera, renderer, controls;
const video = ref(null);
const canvas = ref(null);
const container = ref(null);
const STATE = {
NONE: -1,
MOVE: 0,
ZOOM_OR_PAN: 1,
POSITION_MOVE: 1,
};
const mouseInfo = ref({
startX: 0,
startY: 0,
isDown: false,
startPointerDistance: 0,
state: STATE.NONE,
});
const twoFirst = ref(true);
const lastPoint = ref({
touchStartX1: 0,
touchStartY1: 0,
touchStartX2: 0,
touchStartY2: 0,
});
const emit = defineEmits(["handleProgress", "handleLoaded", "closeHint"]);
const props = defineProps({
modelFile: { type: String, default: () => "" },
pid: { type: Number, default: 0 },
});
onMounted(async() => {
await tf.setBackend('webgl'); // 或者'cpu',根据你的需求选择
await tf.ready();
const model = await cocoSsd.load();
const videoElement = video.value;
const canvasElement = canvas.value;
const context = canvasElement.getContext('2d');
const detectFrame = async () => {
const predictions = await model.detect(videoElement);
context.clearRect(0, 0, canvasElement.width, canvasElement.height);
context.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
predictions.forEach((prediction) => {
if(prediction.class == "keyboard" && !isModel.value) {
loadModel(props.modelFile);
emit("closeHint")
}
// context.beginPath();
// context.rect(
// prediction.bbox[0],
// prediction.bbox[1],
// prediction.bbox[2],
// prediction.bbox[3]
// );
// context.lineWidth = 2;
// context.strokeStyle = 'green';
// context.fillStyle = 'green';
// context.stroke();
// context.fillText(
// prediction.class + ': ' + Math.round(prediction.score * 100) + '%',
// prediction.bbox[0],
// prediction.bbox[1] > 10 ? prediction.bbox[1] - 5 : 10
// );
});
requestAnimationFrame(detectFrame);
};
await setupCamera(videoElement);
resizeCanvas(canvasElement);
detectFrame();
window.addEventListener('resize', resizeCanvas);
});
// 监听组件销毁事件
onBeforeUnmount(() => {
// Clean up TensorFlow.js resources
if (model) {
model.dispose();
model = null;
}
tf.engine().disposeVariables();
console.log('TensorFlow.js resources disposed.');
});
const resizeCanvas = (canvasElement) => {
canvasElement.width = window.innerWidth;
canvasElement.height = window.innerHeight;
};
const setupCamera = async (videoElement) => {
isDevices();
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: { exact: "environment" }, },
});
videoElement.srcObject = stream;
await new Promise((resolve) => {
videoElement.onloadedmetadata = () => {
resolve(videoElement);
};
});
};
watch(
() => props.modelFile,
(val, oldVal) => {
if (val) {
init();
}
},
{ immediate: true }
);
const modelContainer = new THREE.Object3D();
const loader = new GLTFLoader();
const init = () => {
let renderParam = {
antialias: true, // true/false表示是否开启反锯齿
alpha: true, // true/false 表示是否可以设置背景色透明
precision: "highp", // highp/mediump/lowp 表示着色精度选择
premultipliedAlpha: false,
maxLights: 3,
};
// 创建渲染器
renderer = new THREE.WebGLRenderer(renderParam);
renderer.setSize(window.innerWidth, window.innerHeight);
// renderer.setClearColor(0x000000, 0);
renderer.setPixelRatio(window.devicePixelRatio); // 设置画布分辨率 提高画质
container.value.appendChild(renderer.domElement);
// 创建场景
scene = new THREE.Scene();
// const {width, height} = scene
// 创建一个包含模型的父对象
// 旋转缩放相关配置
// 创建相机
camera = new THREE.OrthographicCamera(
window.innerWidth / -10.5,
window.innerWidth / 10.5,
window.innerHeight / 10.5,
window.innerHeight / -10.5,
0.1,
1000
// 90,
// window.innerWidth / window.innerHeight,
// .1,
// 1000
);
// 相机位置
camera.position.z = 200;
camera.position.y = 0;
camera.position.x = 0;
camera.lookAt(0, 0, 0);
// 添加环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 2);
scene.add(ambientLight);
// 从上方照射的白色平行光,强度为 0.5。
const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
// directionalLight.castShadow = true;
directionalLight.position.x = 1;
directionalLight.position.y = 1;
directionalLight.position.z = 80;
directionalLight.target = modelContainer;
scene.add(directionalLight);
// 加载hdr贴图
// let rgbeLoader = new RGBELoader();
// const rgbUrl = props.bgModel || "src/assets/bg.hdr";
// rgbeLoader.load(rgbUrl, envMap => {
// // 设置球形贴图
// envMap.mapping = THREE.EquirectangularReflectionMapping;
// // 设置环境贴图
// scene.background = envMap;
// scene.environment = envMap;
// })
// 创建点光源
var pointLight = new THREE.PointLight(0xffffff, 500); // 设置点光源的颜色和强度
pointLight.position.set(0, 0, 100); // 设置点光源的位置
scene.add(pointLight);
// 坐标轴
// const axesHelper = new THREE.AxesHelper(5)
// scene.add( axesHelper );
// // 添加轨道控制器
// controls = new OrbitControls(camera, renderer.domElement);
// controls.autoRotate = true;
// controls.autoRotateSpeed = 5;
};
const isModel = ref(false); // 是否创建模型
const loadModel = async (modelPath) => {
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./draco/");
// 加载 glb 格式的 3D 模型
loader.setDRACOLoader(dracoLoader);
loader.load(
modelPath,
(gltf) => {
// 加载成功后的回调函数
emit("handleLoaded")
model = gltf.scene;
// model.position.set(0, 0, 0);
const box = new THREE.Box3().setFromObject(model);
// console.log("gltf", gltf)
// console.log("volume", volume)
// 获取包围盒中心点
const center = box.getCenter(new THREE.Vector3());
model.position.sub(center); // 将模型位置移到原点处
// 将模型添加到父对象中
modelContainer.add(model);
// modelGeometry.center(); // 这个等同于上面这行代码
// model.translateX(-80)
scene.add(modelContainer);
isModel.value = true;
},
(xhr) => {
// 加载过程中的回调函数
emit("handleProgress",Math.floor((xhr.loaded / xhr.total) * 100))
},
(error) => {
// 加载失败的回调函数
console.error("Failed to load model", error);
}
);
// 监听缩放\旋转操作
renderer.domElement.addEventListener("touchstart", (event) => {
handleTouchStart(event);
});
const handleTouchStart = (event) => {
mouseInfo.value.isDown = true;
// 双指
const touch0 = event.touches[0];
const touch1 = event.touches[1];
// 单点触控
if (event.touches.length === 1) {
mouseInfo.value.startX = touch0.pageX;
mouseInfo.value.startY = touch0.pageY;
mouseInfo.value.state = STATE.MOVE; // 这边换成rorate会比较好点
} else if (event.touches.length === 2) {
// 双指,计算两指距离
// 一般是平移或者缩放
const dx = touch0.pageX - touch1.pageX;
const dy = touch0.pageY - touch1.pageY;
mouseInfo.value.startPointerDistance = Math.sqrt(dx * dx + dy * dy);
mouseInfo.value.startX = (touch0.pageX + touch1.pageX) / 2;
mouseInfo.value.startY = (touch0.pageY + touch1.pageY) / 2;
mouseInfo.value.state = STATE.ZOOM_OR_PAN;
}
};
renderer.domElement.addEventListener("touchmove", (event) => {
// console.log("touchmove",event )
handleTouchMove(event);
});
// 开始触碰
const handleTouchMove = (event) => {
if (!mouseInfo.value.isDown) {
return;
}
switch (mouseInfo.value.state) {
case STATE.MOVE:
if (event.touches.length === 1) {
handleRotate(event);
} else if (event.touches.length === 2) {
// 兼容处理,如果是移动过程中出现双指时,需要取消单指,然后再重新计算
renderer.domElement.removeEventListener(
"touchmove",
handleTouchMove,
false
);
renderer.domElement.removeEventListener(
"touchend",
handleTouchEnd,
false
);
handleTouchStart(event);
}
break;
case STATE.ZOOM_OR_PAN:
if (event.touches.length === 1) {
} else if (event.touches.length === 2) {
handleZoomOrPan(event);
}
break;
default:
break;
}
};
let rotateSpeed = 0.01;
// 模型旋转
const handleRotate = (event) => {
const x = event.touches[0].pageX;
const y = event.touches[0].pageY;
const { startX, startY } = mouseInfo.value;
const deltaX = x - startX;
const deltaY = y - startY;
modelContainer.rotation.y += deltaX * rotateSpeed;
modelContainer.rotation.x += deltaY * rotateSpeed;
mouseInfo.value.startX = x;
mouseInfo.value.startY = y;
};
// 模型缩放
const handleZoomOrPan = (event) => {
let { touchStartX1, touchStartY1, touchStartX2, touchStartY2 } =
lastPoint.value;
let initialScale = modelContainer.scale.x;
const touch0 = event.touches[0];
const touch1 = event.touches[1];
const dx = touch0.pageX - touch1.pageX;
const dy = touch0.pageY - touch1.pageY;
const distance = Math.sqrt(dx * dx + dy * dy);
let obj = {
touchStartX1: touch0.pageX,
touchStartY1: touch0.pageY,
touchStartX2: touch1.pageX,
touchStartY2: touch1.pageY,
};
if (twoFirst.value) {
twoFirst.value = false;
lastPoint.value = { ...obj };
} else {
let deltaScale =
initialScale * (distance / mouseInfo.value.startPointerDistance);
// 限制缩放距离
if (deltaScale < 0.25) {
deltaScale = 0.25;
} else if (deltaScale > 2) {
deltaScale = 2;
}
mouseInfo.value.startPointerDistance = distance;
modelContainer.scale.set(deltaScale, deltaScale, deltaScale);
const avgX = (touch0.pageX + touch1.pageX) / 2;
const avgY = (touch0.pageY + touch1.pageY) / 2;
const deltaX = avgX - (touchStartX1 + touchStartX2) / 2;
const deltaY = avgY - (touchStartY1 + touchStartY2) / 2;
modelContainer.position.x += deltaX * 0.3;
modelContainer.position.y -= deltaY * 0.3;
lastPoint.value = {
touchStartX1: touch0.pageX,
touchStartY1: touch0.pageY,
touchStartX2: touch1.pageX,
touchStartY2: touch1.pageY,
};
}
};
const handleTouchEnd = () => {
mouseInfo.value.isDown = false;
mouseInfo.value.state = STATE.NONE;
twoFirst.value = true;
lastPoint.value.touchStartX1 = 0;
lastPoint.value.touchStartY1 = 0;
lastPoint.value.touchStartX2 = 0;
lastPoint.value.touchStartY2 = 0;
// 取消移动事件监听
renderer.domElement.removeEventListener(
"touchmove",
handleTouchMove,
false
);
renderer.domElement.removeEventListener(
"touchstart",
handleTouchStart,
false
);
};
renderer.domElement.addEventListener("touchend", (event) => {
handleTouchEnd();
});
animate();
// 监听窗口缩放
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
};
const isDevices = () => {
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
var getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia ||
navigator.oGetUserMedia;
if (!getUserMedia) {
return Promise.reject(
new Error("getUserMedia is not implemented in this browser")
);
}
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
};
}
};
var lastTimeMsec = null;
// 渲染场景
const animate = () => {
// controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
// videoTexture.needsUpdate = true;
// if (arToolkitSource.ready) {
// arToolkitContext.update(arToolkitSource.domElement);
// }
// measure time
// lastTimeMsec = lastTimeMsec || nowMsec-1000/60
// var deltaMsec = Math.min(200, nowMsec - lastTimeMsec)
// lastTimeMsec = nowMsec
// // call each update function
// onRenderFcts.forEach(function(onRenderFct){
// onRenderFct(deltaMsec/1000, nowMsec/1000)
// })
};
</script>
<style lang="less" scoped>
body {
margin: 0;
overflow: hidden;
}
.container {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.fullscreen-video, .fullscreen-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
object-fit: cover;
}
.fullscreen-video {
opacity: 0;
}
.fullscreen-canvas {
pointer-events: none; /* 避免画布阻挡视频的鼠标事件 */
}
</style>
+498
View File
@@ -0,0 +1,498 @@
<template>
<div ref="container" class="container">
<video ref="video" class="fullscreen-video" autoplay playsinline muted></video>
<canvas ref="canvas" class="fullscreen-canvas"></canvas>
</div>
</template>
<script setup lang="ts">
import * as tf from '@tensorflow/tfjs';
import * as cocoSsd from '@tensorflow-models/coco-ssd';
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
let model, scene, camera, renderer, controls;
const video = ref(null);
const canvas = ref(null);
const container = ref(null);
const STATE = {
NONE: -1,
MOVE: 0,
ZOOM_OR_PAN: 1,
POSITION_MOVE: 1,
};
const mouseInfo = ref({
startX: 0,
startY: 0,
isDown: false,
startPointerDistance: 0,
state: STATE.NONE,
});
const twoFirst = ref(true);
const lastPoint = ref({
touchStartX1: 0,
touchStartY1: 0,
touchStartX2: 0,
touchStartY2: 0,
});
const emit = defineEmits(["handleProgress", "handleLoaded", "closeHint"]);
const props = defineProps({
modelFile: { type: String, default: () => "" },
pid: { type: Number, default: 0 },
});
onMounted(async() => {
await tf.setBackend('webgl'); // 或者'cpu',根据你的需求选择
await tf.ready();
const model = await cocoSsd.load();
const videoElement = video.value;
const canvasElement = canvas.value;
const context = canvasElement.getContext('2d');
const detectFrame = async () => {
const predictions = await model.detect(videoElement);
context.clearRect(0, 0, canvasElement.width, canvasElement.height);
context.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
predictions.forEach((prediction) => {
if(prediction.class == "keyboard" && !isModel.value) {
loadModel(props.modelFile);
emit("closeHint")
}
// context.beginPath();
// context.rect(
// prediction.bbox[0],
// prediction.bbox[1],
// prediction.bbox[2],
// prediction.bbox[3]
// );
// context.lineWidth = 2;
// context.strokeStyle = 'green';
// context.fillStyle = 'green';
// context.stroke();
// context.fillText(
// prediction.class + ': ' + Math.round(prediction.score * 100) + '%',
// prediction.bbox[0],
// prediction.bbox[1] > 10 ? prediction.bbox[1] - 5 : 10
// );
});
requestAnimationFrame(detectFrame);
};
await setupCamera(videoElement);
resizeCanvas(canvasElement);
detectFrame();
window.addEventListener('resize', resizeCanvas);
});
// 监听组件销毁事件
onBeforeUnmount(() => {
// Clean up TensorFlow.js resources
if (model) {
model.dispose();
model = null;
}
tf.engine().disposeVariables();
console.log('TensorFlow.js resources disposed.');
});
const resizeCanvas = (canvasElement) => {
canvasElement.width = window.innerWidth;
canvasElement.height = window.innerHeight;
};
const setupCamera = async (videoElement) => {
isDevices();
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: { exact: "environment" }, },
});
videoElement.srcObject = stream;
await new Promise((resolve) => {
videoElement.onloadedmetadata = () => {
resolve(videoElement);
};
});
};
watch(
() => props.modelFile,
(val, oldVal) => {
if (val) {
init();
}
},
{ immediate: true }
);
const modelContainer = new THREE.Object3D();
const loader = new GLTFLoader();
const init = () => {
let renderParam = {
antialias: true, // true/false表示是否开启反锯齿
alpha: true, // true/false 表示是否可以设置背景色透明
precision: "highp", // highp/mediump/lowp 表示着色精度选择
premultipliedAlpha: false,
maxLights: 3,
};
// 创建渲染器
renderer = new THREE.WebGLRenderer(renderParam);
renderer.setSize(window.innerWidth, window.innerHeight);
// renderer.setClearColor(0x000000, 0);
renderer.setPixelRatio(window.devicePixelRatio); // 设置画布分辨率 提高画质
container.value.appendChild(renderer.domElement);
// 创建场景
scene = new THREE.Scene();
// const {width, height} = scene
// 创建一个包含模型的父对象
// 旋转缩放相关配置
// 创建相机
camera = new THREE.OrthographicCamera(
window.innerWidth / -10.5,
window.innerWidth / 10.5,
window.innerHeight / 10.5,
window.innerHeight / -10.5,
0.1,
1000
// 90,
// window.innerWidth / window.innerHeight,
// .1,
// 1000
);
// 相机位置
camera.position.z = 200;
camera.position.y = 0;
camera.position.x = 0;
camera.lookAt(0, 0, 0);
// 添加环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 2);
scene.add(ambientLight);
// 从上方照射的白色平行光,强度为 0.5。
const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
// directionalLight.castShadow = true;
directionalLight.position.x = 1;
directionalLight.position.y = 1;
directionalLight.position.z = 80;
directionalLight.target = modelContainer;
scene.add(directionalLight);
// 加载hdr贴图
// let rgbeLoader = new RGBELoader();
// const rgbUrl = props.bgModel || "src/assets/bg.hdr";
// rgbeLoader.load(rgbUrl, envMap => {
// // 设置球形贴图
// envMap.mapping = THREE.EquirectangularReflectionMapping;
// // 设置环境贴图
// scene.background = envMap;
// scene.environment = envMap;
// })
// 创建点光源
var pointLight = new THREE.PointLight(0xffffff, 500); // 设置点光源的颜色和强度
pointLight.position.set(0, 0, 100); // 设置点光源的位置
scene.add(pointLight);
// 坐标轴
// const axesHelper = new THREE.AxesHelper(5)
// scene.add( axesHelper );
// // 添加轨道控制器
// controls = new OrbitControls(camera, renderer.domElement);
// controls.autoRotate = true;
// controls.autoRotateSpeed = 5;
};
const isModel = ref(false); // 是否创建模型
const loadModel = async (modelPath) => {
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./draco/");
// 加载 glb 格式的 3D 模型
loader.setDRACOLoader(dracoLoader);
loader.load(
modelPath,
(gltf) => {
// 加载成功后的回调函数
emit("handleLoaded")
model = gltf.scene;
// model.position.set(0, 0, 0);
const box = new THREE.Box3().setFromObject(model);
// console.log("gltf", gltf)
// console.log("volume", volume)
// 获取包围盒中心点
const center = box.getCenter(new THREE.Vector3());
model.position.sub(center); // 将模型位置移到原点处
// 将模型添加到父对象中
modelContainer.add(model);
// modelGeometry.center(); // 这个等同于上面这行代码
// model.translateX(-80)
scene.add(modelContainer);
isModel.value = true;
},
(xhr) => {
// 加载过程中的回调函数
emit("handleProgress",Math.floor((xhr.loaded / xhr.total) * 100))
},
(error) => {
// 加载失败的回调函数
console.error("Failed to load model", error);
}
);
// 监听缩放\旋转操作
renderer.domElement.addEventListener("touchstart", (event) => {
handleTouchStart(event);
});
const handleTouchStart = (event) => {
mouseInfo.value.isDown = true;
// 双指
const touch0 = event.touches[0];
const touch1 = event.touches[1];
// 单点触控
if (event.touches.length === 1) {
mouseInfo.value.startX = touch0.pageX;
mouseInfo.value.startY = touch0.pageY;
mouseInfo.value.state = STATE.MOVE; // 这边换成rorate会比较好点
} else if (event.touches.length === 2) {
// 双指,计算两指距离
// 一般是平移或者缩放
const dx = touch0.pageX - touch1.pageX;
const dy = touch0.pageY - touch1.pageY;
mouseInfo.value.startPointerDistance = Math.sqrt(dx * dx + dy * dy);
mouseInfo.value.startX = (touch0.pageX + touch1.pageX) / 2;
mouseInfo.value.startY = (touch0.pageY + touch1.pageY) / 2;
mouseInfo.value.state = STATE.ZOOM_OR_PAN;
}
};
renderer.domElement.addEventListener("touchmove", (event) => {
// console.log("touchmove",event )
handleTouchMove(event);
});
// 开始触碰
const handleTouchMove = (event) => {
if (!mouseInfo.value.isDown) {
return;
}
switch (mouseInfo.value.state) {
case STATE.MOVE:
if (event.touches.length === 1) {
handleRotate(event);
} else if (event.touches.length === 2) {
// 兼容处理,如果是移动过程中出现双指时,需要取消单指,然后再重新计算
renderer.domElement.removeEventListener(
"touchmove",
handleTouchMove,
false
);
renderer.domElement.removeEventListener(
"touchend",
handleTouchEnd,
false
);
handleTouchStart(event);
}
break;
case STATE.ZOOM_OR_PAN:
if (event.touches.length === 1) {
} else if (event.touches.length === 2) {
handleZoomOrPan(event);
}
break;
default:
break;
}
};
let rotateSpeed = 0.01;
// 模型旋转
const handleRotate = (event) => {
const x = event.touches[0].pageX;
const y = event.touches[0].pageY;
const { startX, startY } = mouseInfo.value;
const deltaX = x - startX;
const deltaY = y - startY;
modelContainer.rotation.y += deltaX * rotateSpeed;
modelContainer.rotation.x += deltaY * rotateSpeed;
mouseInfo.value.startX = x;
mouseInfo.value.startY = y;
};
// 模型缩放
const handleZoomOrPan = (event) => {
let { touchStartX1, touchStartY1, touchStartX2, touchStartY2 } =
lastPoint.value;
let initialScale = modelContainer.scale.x;
const touch0 = event.touches[0];
const touch1 = event.touches[1];
const dx = touch0.pageX - touch1.pageX;
const dy = touch0.pageY - touch1.pageY;
const distance = Math.sqrt(dx * dx + dy * dy);
let obj = {
touchStartX1: touch0.pageX,
touchStartY1: touch0.pageY,
touchStartX2: touch1.pageX,
touchStartY2: touch1.pageY,
};
if (twoFirst.value) {
twoFirst.value = false;
lastPoint.value = { ...obj };
} else {
let deltaScale =
initialScale * (distance / mouseInfo.value.startPointerDistance);
// 限制缩放距离
if (deltaScale < 0.25) {
deltaScale = 0.25;
} else if (deltaScale > 2) {
deltaScale = 2;
}
mouseInfo.value.startPointerDistance = distance;
modelContainer.scale.set(deltaScale, deltaScale, deltaScale);
const avgX = (touch0.pageX + touch1.pageX) / 2;
const avgY = (touch0.pageY + touch1.pageY) / 2;
const deltaX = avgX - (touchStartX1 + touchStartX2) / 2;
const deltaY = avgY - (touchStartY1 + touchStartY2) / 2;
modelContainer.position.x += deltaX * 0.3;
modelContainer.position.y -= deltaY * 0.3;
lastPoint.value = {
touchStartX1: touch0.pageX,
touchStartY1: touch0.pageY,
touchStartX2: touch1.pageX,
touchStartY2: touch1.pageY,
};
}
};
const handleTouchEnd = () => {
mouseInfo.value.isDown = false;
mouseInfo.value.state = STATE.NONE;
twoFirst.value = true;
lastPoint.value.touchStartX1 = 0;
lastPoint.value.touchStartY1 = 0;
lastPoint.value.touchStartX2 = 0;
lastPoint.value.touchStartY2 = 0;
// 取消移动事件监听
renderer.domElement.removeEventListener(
"touchmove",
handleTouchMove,
false
);
renderer.domElement.removeEventListener(
"touchstart",
handleTouchStart,
false
);
};
renderer.domElement.addEventListener("touchend", (event) => {
handleTouchEnd();
});
animate();
// 监听窗口缩放
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
};
const isDevices = () => {
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
var getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia ||
navigator.oGetUserMedia;
if (!getUserMedia) {
return Promise.reject(
new Error("getUserMedia is not implemented in this browser")
);
}
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
};
}
};
var lastTimeMsec = null;
// 渲染场景
const animate = () => {
// controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
// videoTexture.needsUpdate = true;
// if (arToolkitSource.ready) {
// arToolkitContext.update(arToolkitSource.domElement);
// }
// measure time
// lastTimeMsec = lastTimeMsec || nowMsec-1000/60
// var deltaMsec = Math.min(200, nowMsec - lastTimeMsec)
// lastTimeMsec = nowMsec
// // call each update function
// onRenderFcts.forEach(function(onRenderFct){
// onRenderFct(deltaMsec/1000, nowMsec/1000)
// })
};
</script>
<style lang="less" scoped>
body {
margin: 0;
overflow: hidden;
}
.container {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.fullscreen-video, .fullscreen-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
object-fit: cover;
}
.fullscreen-video {
opacity: 0;
}
.fullscreen-canvas {
pointer-events: none; /* 避免画布阻挡视频的鼠标事件 */
}
</style>
Loaded 100 of 243 files, more files were not shown because too many files have changed in this diff. Show more