Init
This commit is contained in:
		
							
								
								
									
										24
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					# Logs
 | 
				
			||||||
 | 
					logs
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					npm-debug.log*
 | 
				
			||||||
 | 
					yarn-debug.log*
 | 
				
			||||||
 | 
					yarn-error.log*
 | 
				
			||||||
 | 
					pnpm-debug.log*
 | 
				
			||||||
 | 
					lerna-debug.log*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					node_modules
 | 
				
			||||||
 | 
					dist
 | 
				
			||||||
 | 
					dist-ssr
 | 
				
			||||||
 | 
					*.local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Editor directories and files
 | 
				
			||||||
 | 
					.vscode/*
 | 
				
			||||||
 | 
					!.vscode/extensions.json
 | 
				
			||||||
 | 
					.idea
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					*.suo
 | 
				
			||||||
 | 
					*.ntvs*
 | 
				
			||||||
 | 
					*.njsproj
 | 
				
			||||||
 | 
					*.sln
 | 
				
			||||||
 | 
					*.sw?
 | 
				
			||||||
							
								
								
									
										3
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "recommendations": ["Vue.volar"]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					# Vue 3 + TypeScript + Vite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
 | 
				
			||||||
							
								
								
									
										13
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					<!doctype html>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					  <head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8" />
 | 
				
			||||||
 | 
					    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
 | 
				
			||||||
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
				
			||||||
 | 
					    <title>Vite + Vue + TS</title>
 | 
				
			||||||
 | 
					  </head>
 | 
				
			||||||
 | 
					  <body>
 | 
				
			||||||
 | 
					    <div id="app"></div>
 | 
				
			||||||
 | 
					    <script type="module" src="/src/main.ts"></script>
 | 
				
			||||||
 | 
					  </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										29
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "material-editor",
 | 
				
			||||||
 | 
					  "private": true,
 | 
				
			||||||
 | 
					  "version": "0.0.0",
 | 
				
			||||||
 | 
					  "type": "module",
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "dev": "vite",
 | 
				
			||||||
 | 
					    "build": "vue-tsc -b && vite build",
 | 
				
			||||||
 | 
					    "preview": "vite preview"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "vue": "^3.5.13",
 | 
				
			||||||
 | 
					    "three": "npm:three-cf@^0.122.9",
 | 
				
			||||||
 | 
					    "js-angusj-clipper": "^1.2.1",
 | 
				
			||||||
 | 
					    "polylabel": "^1.1.0",
 | 
				
			||||||
 | 
					    "@jscad/modeling": "^2.11.0",
 | 
				
			||||||
 | 
					    "flatbush": "^3.3.0",
 | 
				
			||||||
 | 
					    "xaop": "^2.0.0",
 | 
				
			||||||
 | 
					    "webcad_ue4_api": "http://gitea.cf/cx/webcad-ue4-api/archive/3.20.0.tar.gz"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "@vitejs/plugin-vue": "^5.2.1",
 | 
				
			||||||
 | 
					    "@vue/tsconfig": "^0.7.0",
 | 
				
			||||||
 | 
					    "typescript": "~5.7.2",
 | 
				
			||||||
 | 
					    "vite": "^6.2.0",
 | 
				
			||||||
 | 
					    "vue-tsc": "^2.2.4"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "packageManager": "pnpm@9.1.1+sha1.09ada6cd05003e0ced25fb716f9fda4063ec2e3b"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										960
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										960
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,960 @@
 | 
				
			|||||||
 | 
					lockfileVersion: '9.0'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					settings:
 | 
				
			||||||
 | 
					  autoInstallPeers: true
 | 
				
			||||||
 | 
					  excludeLinksFromLockfile: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					importers:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@jscad/modeling':
 | 
				
			||||||
 | 
					        specifier: ^2.11.0
 | 
				
			||||||
 | 
					        version: 2.12.5
 | 
				
			||||||
 | 
					      flatbush:
 | 
				
			||||||
 | 
					        specifier: ^3.3.0
 | 
				
			||||||
 | 
					        version: 3.3.1
 | 
				
			||||||
 | 
					      js-angusj-clipper:
 | 
				
			||||||
 | 
					        specifier: ^1.2.1
 | 
				
			||||||
 | 
					        version: 1.3.1
 | 
				
			||||||
 | 
					      polylabel:
 | 
				
			||||||
 | 
					        specifier: ^1.1.0
 | 
				
			||||||
 | 
					        version: 1.1.0
 | 
				
			||||||
 | 
					      three:
 | 
				
			||||||
 | 
					        specifier: npm:three-cf@^0.122.9
 | 
				
			||||||
 | 
					        version: three-cf@0.122.9
 | 
				
			||||||
 | 
					      vue:
 | 
				
			||||||
 | 
					        specifier: ^3.5.13
 | 
				
			||||||
 | 
					        version: 3.5.13(typescript@5.7.3)
 | 
				
			||||||
 | 
					      webcad_ue4_api:
 | 
				
			||||||
 | 
					        specifier: http://gitea.cf/cx/webcad-ue4-api/archive/3.20.0.tar.gz
 | 
				
			||||||
 | 
					        version: http://gitea.cf/cx/webcad-ue4-api/archive/3.20.0.tar.gz
 | 
				
			||||||
 | 
					      xaop:
 | 
				
			||||||
 | 
					        specifier: ^2.0.0
 | 
				
			||||||
 | 
					        version: 2.1.0
 | 
				
			||||||
 | 
					    devDependencies:
 | 
				
			||||||
 | 
					      '@vitejs/plugin-vue':
 | 
				
			||||||
 | 
					        specifier: ^5.2.1
 | 
				
			||||||
 | 
					        version: 5.2.3(vite@6.2.5)(vue@3.5.13(typescript@5.7.3))
 | 
				
			||||||
 | 
					      '@vue/tsconfig':
 | 
				
			||||||
 | 
					        specifier: ^0.7.0
 | 
				
			||||||
 | 
					        version: 0.7.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))
 | 
				
			||||||
 | 
					      typescript:
 | 
				
			||||||
 | 
					        specifier: ~5.7.2
 | 
				
			||||||
 | 
					        version: 5.7.3
 | 
				
			||||||
 | 
					      vite:
 | 
				
			||||||
 | 
					        specifier: ^6.2.0
 | 
				
			||||||
 | 
					        version: 6.2.5
 | 
				
			||||||
 | 
					      vue-tsc:
 | 
				
			||||||
 | 
					        specifier: ^2.2.4
 | 
				
			||||||
 | 
					        version: 2.2.8(typescript@5.7.3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					packages:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@babel/helper-string-parser@7.25.9':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=6.9.0'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@babel/helper-validator-identifier@7.25.9':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
 | 
				
			||||||
 | 
					    engines: {node: '>=6.9.0'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@babel/parser@7.27.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==}
 | 
				
			||||||
 | 
					    engines: {node: '>=6.0.0'}
 | 
				
			||||||
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@babel/types@7.27.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==}
 | 
				
			||||||
 | 
					    engines: {node: '>=6.9.0'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/aix-ppc64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [ppc64]
 | 
				
			||||||
 | 
					    os: [aix]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/android-arm64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [android]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/android-arm@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [arm]
 | 
				
			||||||
 | 
					    os: [android]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/android-x64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [android]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/darwin-arm64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [darwin]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/darwin-x64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [darwin]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/freebsd-arm64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [freebsd]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/freebsd-x64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [freebsd]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-arm64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-arm@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [arm]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-ia32@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [ia32]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-loong64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [loong64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-mips64el@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [mips64el]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-ppc64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [ppc64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-riscv64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [riscv64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-s390x@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [s390x]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-x64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/netbsd-arm64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [netbsd]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/netbsd-x64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [netbsd]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/openbsd-arm64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [openbsd]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/openbsd-x64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [openbsd]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/sunos-x64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [sunos]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/win32-arm64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [win32]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/win32-ia32@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [ia32]
 | 
				
			||||||
 | 
					    os: [win32]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/win32-x64@0.25.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [win32]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@jridgewell/sourcemap-codec@1.5.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@jscad/modeling@2.12.5':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-7deHWmE+CKBx2RyxDxl9Pie0bDOHHtcsh4V0gKViu27abYXKGl8+myoddwIvxLczwnw31ZZXDdUdm0Ef51YwQg==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-android-arm-eabi@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==}
 | 
				
			||||||
 | 
					    cpu: [arm]
 | 
				
			||||||
 | 
					    os: [android]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-android-arm64@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [android]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-darwin-arm64@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [darwin]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-darwin-x64@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [darwin]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-freebsd-arm64@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [freebsd]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-freebsd-x64@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [freebsd]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-arm-gnueabihf@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==}
 | 
				
			||||||
 | 
					    cpu: [arm]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					    libc: [glibc]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-arm-musleabihf@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==}
 | 
				
			||||||
 | 
					    cpu: [arm]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					    libc: [musl]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-arm64-gnu@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					    libc: [glibc]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-arm64-musl@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					    libc: [musl]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-loongarch64-gnu@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==}
 | 
				
			||||||
 | 
					    cpu: [loong64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					    libc: [glibc]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-powerpc64le-gnu@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==}
 | 
				
			||||||
 | 
					    cpu: [ppc64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					    libc: [glibc]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-riscv64-gnu@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==}
 | 
				
			||||||
 | 
					    cpu: [riscv64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					    libc: [glibc]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-riscv64-musl@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==}
 | 
				
			||||||
 | 
					    cpu: [riscv64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					    libc: [musl]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-s390x-gnu@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==}
 | 
				
			||||||
 | 
					    cpu: [s390x]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					    libc: [glibc]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-x64-gnu@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					    libc: [glibc]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-x64-musl@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [linux]
 | 
				
			||||||
 | 
					    libc: [musl]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-win32-arm64-msvc@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==}
 | 
				
			||||||
 | 
					    cpu: [arm64]
 | 
				
			||||||
 | 
					    os: [win32]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-win32-ia32-msvc@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==}
 | 
				
			||||||
 | 
					    cpu: [ia32]
 | 
				
			||||||
 | 
					    os: [win32]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-win32-x64-msvc@4.39.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==}
 | 
				
			||||||
 | 
					    cpu: [x64]
 | 
				
			||||||
 | 
					    os: [win32]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/estree@1.0.7':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vitejs/plugin-vue@5.2.3':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-IYSLEQj4LgZZuoVpdSUCw3dIynTWQgPlaRP6iAvMle4My0HdYwr5g5wQAfwOeHQBmYwEkqF70nRpSilr6PoUDg==}
 | 
				
			||||||
 | 
					    engines: {node: ^18.0.0 || >=20.0.0}
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      vite: ^5.0.0 || ^6.0.0
 | 
				
			||||||
 | 
					      vue: ^3.2.25
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@volar/language-core@2.4.12':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-RLrFdXEaQBWfSnYGVxvR2WrO6Bub0unkdHYIdC31HzIEqATIuuhRRzYu76iGPZ6OtA4Au1SnW0ZwIqPP217YhA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@volar/source-map@2.4.12':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-bUFIKvn2U0AWojOaqf63ER0N/iHIBYZPpNGogfLPQ68F5Eet6FnLlyho7BS0y2HJ1jFhSif7AcuTx1TqsCzRzw==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@volar/typescript@2.4.12':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-HJB73OTJDgPc80K30wxi3if4fSsZZAOScbj2fcicMuOPoOkcf9NNAINb33o+DzhBdF9xTKC1gnPmIRDous5S0g==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/compiler-core@3.5.13':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/compiler-dom@3.5.13':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/compiler-sfc@3.5.13':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/compiler-ssr@3.5.13':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/compiler-vue2@2.7.16':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/language-core@2.2.8':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-rrzB0wPGBvcwaSNRriVWdNAbHQWSf0NlGqgKHK5mEkXpefjUlVRP62u03KvwZpvKVjRnBIQ/Lwre+Mx9N6juUQ==}
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      typescript: '*'
 | 
				
			||||||
 | 
					    peerDependenciesMeta:
 | 
				
			||||||
 | 
					      typescript:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/reactivity@3.5.13':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/runtime-core@3.5.13':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/runtime-dom@3.5.13':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/server-renderer@3.5.13':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==}
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      vue: 3.5.13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/shared@3.5.13':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/tsconfig@0.7.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==}
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      typescript: 5.x
 | 
				
			||||||
 | 
					      vue: ^3.4.0
 | 
				
			||||||
 | 
					    peerDependenciesMeta:
 | 
				
			||||||
 | 
					      typescript:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					      vue:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  alien-signals@1.0.13:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  balanced-match@1.0.2:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  brace-expansion@2.0.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  csstype@3.1.3:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  de-indent@1.0.2:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  entities@4.5.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
 | 
				
			||||||
 | 
					    engines: {node: '>=0.12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  esbuild@0.25.2:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18'}
 | 
				
			||||||
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  estree-walker@2.0.2:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  flatbush@3.3.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-oKuPbtT+DS2CxH+9Vhbsq8HifmSCuOw+3Cy5zt/vCIrZl5KyengoTHDBLmtpZoBhcwa7/biNjgL1DwdLMJYm1A==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  flatqueue@1.2.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-X86TpWS1rGuY7m382HuA9vngLeDuWA9lJvhEG+GfgKMV5onSvx5a71cl7GMbXzhWtlN9dGfqOBrpfqeOtUfGYQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fsevents@2.3.3:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
 | 
				
			||||||
 | 
					    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
 | 
				
			||||||
 | 
					    os: [darwin]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  he@1.2.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
 | 
				
			||||||
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  js-angusj-clipper@1.3.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-/qru4QXxN/gBbQjL4WaFl296YSM8kh5XKpNuNqfZhJ4t4Hw3KeLc5ERj3XHAeLi6pBrqeh6o9PFZUpS3QThEEQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  magic-string@0.30.17:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  minimatch@9.0.5:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
 | 
				
			||||||
 | 
					    engines: {node: '>=16 || 14 >=14.17'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  muggle-string@0.4.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  nanoid@3.3.11:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
 | 
				
			||||||
 | 
					    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
 | 
				
			||||||
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  path-browserify@1.0.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  picocolors@1.1.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  polylabel@1.1.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-bxaGcA40sL3d6M4hH72Z4NdLqxpXRsCFk8AITYg6x1rn1Ei3izf00UMLklerBZTO49aPA3CYrIwVulx2Bce2pA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  postcss@8.5.3:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
 | 
				
			||||||
 | 
					    engines: {node: ^10 || ^12 || >=14}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rollup@4.39.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18.0.0', npm: '>=8.0.0'}
 | 
				
			||||||
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  source-map-js@1.2.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=0.10.0'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  three-cf@0.122.9:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-y+bvPYKI0yMNGF2flNsTbqloPiMAL4OKbIbR9QaQLRjNlz15Th+69ZtirU5ZASGXF/vQIvIrv+6OkxdSjiN89Q==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  tinyqueue@2.0.3:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  typescript@5.7.3:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==}
 | 
				
			||||||
 | 
					    engines: {node: '>=14.17'}
 | 
				
			||||||
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  vite@6.2.5:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==}
 | 
				
			||||||
 | 
					    engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
 | 
				
			||||||
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
 | 
				
			||||||
 | 
					      jiti: '>=1.21.0'
 | 
				
			||||||
 | 
					      less: '*'
 | 
				
			||||||
 | 
					      lightningcss: ^1.21.0
 | 
				
			||||||
 | 
					      sass: '*'
 | 
				
			||||||
 | 
					      sass-embedded: '*'
 | 
				
			||||||
 | 
					      stylus: '*'
 | 
				
			||||||
 | 
					      sugarss: '*'
 | 
				
			||||||
 | 
					      terser: ^5.16.0
 | 
				
			||||||
 | 
					      tsx: ^4.8.1
 | 
				
			||||||
 | 
					      yaml: ^2.4.2
 | 
				
			||||||
 | 
					    peerDependenciesMeta:
 | 
				
			||||||
 | 
					      '@types/node':
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					      jiti:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					      less:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					      lightningcss:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					      sass:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					      sass-embedded:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					      stylus:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					      sugarss:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					      terser:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					      tsx:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					      yaml:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  vscode-uri@3.1.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  vue-tsc@2.2.8:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-jBYKBNFADTN+L+MdesNX/TB3XuDSyaWynKMDgR+yCSln0GQ9Tfb7JS2lr46s2LiFUT1WsmfWsSvIElyxzOPqcQ==}
 | 
				
			||||||
 | 
					    hasBin: true
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      typescript: '>=5.0.0'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  vue@3.5.13:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==}
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      typescript: '*'
 | 
				
			||||||
 | 
					    peerDependenciesMeta:
 | 
				
			||||||
 | 
					      typescript:
 | 
				
			||||||
 | 
					        optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  webcad_ue4_api@http://gitea.cf/cx/webcad-ue4-api/archive/3.20.0.tar.gz:
 | 
				
			||||||
 | 
					    resolution: {tarball: http://gitea.cf/cx/webcad-ue4-api/archive/3.20.0.tar.gz}
 | 
				
			||||||
 | 
					    version: 0.3.19
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  xaop@2.1.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-/ovWCaQIet3a3VnoVeN1/pNPqCrS/JifF28N7crPhq8BXEWx4Da2o+LYCCxnTWGAjGp5+2W2hd0HIpVESounSQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					snapshots:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@babel/helper-string-parser@7.25.9': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@babel/helper-validator-identifier@7.25.9': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@babel/parser@7.27.0':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@babel/types': 7.27.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@babel/types@7.27.0':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@babel/helper-string-parser': 7.25.9
 | 
				
			||||||
 | 
					      '@babel/helper-validator-identifier': 7.25.9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/aix-ppc64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/android-arm64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/android-arm@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/android-x64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/darwin-arm64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/darwin-x64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/freebsd-arm64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/freebsd-x64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-arm64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-arm@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-ia32@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-loong64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-mips64el@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-ppc64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-riscv64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-s390x@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/linux-x64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/netbsd-arm64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/netbsd-x64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/openbsd-arm64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/openbsd-x64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/sunos-x64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/win32-arm64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/win32-ia32@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@esbuild/win32-x64@0.25.2':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@jridgewell/sourcemap-codec@1.5.0': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@jscad/modeling@2.12.5': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-android-arm-eabi@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-android-arm64@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-darwin-arm64@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-darwin-x64@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-freebsd-arm64@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-freebsd-x64@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-arm-gnueabihf@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-arm-musleabihf@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-arm64-gnu@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-arm64-musl@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-loongarch64-gnu@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-powerpc64le-gnu@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-riscv64-gnu@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-riscv64-musl@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-s390x-gnu@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-x64-gnu@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-linux-x64-musl@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-win32-arm64-msvc@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-win32-ia32-msvc@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@rollup/rollup-win32-x64-msvc@4.39.0':
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/estree@1.0.7': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vitejs/plugin-vue@5.2.3(vite@6.2.5)(vue@3.5.13(typescript@5.7.3))':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      vite: 6.2.5
 | 
				
			||||||
 | 
					      vue: 3.5.13(typescript@5.7.3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@volar/language-core@2.4.12':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@volar/source-map': 2.4.12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@volar/source-map@2.4.12': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@volar/typescript@2.4.12':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@volar/language-core': 2.4.12
 | 
				
			||||||
 | 
					      path-browserify: 1.0.1
 | 
				
			||||||
 | 
					      vscode-uri: 3.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/compiler-core@3.5.13':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@babel/parser': 7.27.0
 | 
				
			||||||
 | 
					      '@vue/shared': 3.5.13
 | 
				
			||||||
 | 
					      entities: 4.5.0
 | 
				
			||||||
 | 
					      estree-walker: 2.0.2
 | 
				
			||||||
 | 
					      source-map-js: 1.2.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/compiler-dom@3.5.13':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@vue/compiler-core': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/shared': 3.5.13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/compiler-sfc@3.5.13':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@babel/parser': 7.27.0
 | 
				
			||||||
 | 
					      '@vue/compiler-core': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/compiler-dom': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/compiler-ssr': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/shared': 3.5.13
 | 
				
			||||||
 | 
					      estree-walker: 2.0.2
 | 
				
			||||||
 | 
					      magic-string: 0.30.17
 | 
				
			||||||
 | 
					      postcss: 8.5.3
 | 
				
			||||||
 | 
					      source-map-js: 1.2.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/compiler-ssr@3.5.13':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@vue/compiler-dom': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/shared': 3.5.13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/compiler-vue2@2.7.16':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      de-indent: 1.0.2
 | 
				
			||||||
 | 
					      he: 1.2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/language-core@2.2.8(typescript@5.7.3)':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@volar/language-core': 2.4.12
 | 
				
			||||||
 | 
					      '@vue/compiler-dom': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/compiler-vue2': 2.7.16
 | 
				
			||||||
 | 
					      '@vue/shared': 3.5.13
 | 
				
			||||||
 | 
					      alien-signals: 1.0.13
 | 
				
			||||||
 | 
					      minimatch: 9.0.5
 | 
				
			||||||
 | 
					      muggle-string: 0.4.1
 | 
				
			||||||
 | 
					      path-browserify: 1.0.1
 | 
				
			||||||
 | 
					    optionalDependencies:
 | 
				
			||||||
 | 
					      typescript: 5.7.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/reactivity@3.5.13':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@vue/shared': 3.5.13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/runtime-core@3.5.13':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@vue/reactivity': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/shared': 3.5.13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/runtime-dom@3.5.13':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@vue/reactivity': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/runtime-core': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/shared': 3.5.13
 | 
				
			||||||
 | 
					      csstype: 3.1.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.3))':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@vue/compiler-ssr': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/shared': 3.5.13
 | 
				
			||||||
 | 
					      vue: 3.5.13(typescript@5.7.3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/shared@3.5.13': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@vue/tsconfig@0.7.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))':
 | 
				
			||||||
 | 
					    optionalDependencies:
 | 
				
			||||||
 | 
					      typescript: 5.7.3
 | 
				
			||||||
 | 
					      vue: 3.5.13(typescript@5.7.3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  alien-signals@1.0.13: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  balanced-match@1.0.2: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  brace-expansion@2.0.1:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      balanced-match: 1.0.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  csstype@3.1.3: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  de-indent@1.0.2: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  entities@4.5.0: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  esbuild@0.25.2:
 | 
				
			||||||
 | 
					    optionalDependencies:
 | 
				
			||||||
 | 
					      '@esbuild/aix-ppc64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/android-arm': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/android-arm64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/android-x64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/darwin-arm64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/darwin-x64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/freebsd-arm64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/freebsd-x64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/linux-arm': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/linux-arm64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/linux-ia32': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/linux-loong64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/linux-mips64el': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/linux-ppc64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/linux-riscv64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/linux-s390x': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/linux-x64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/netbsd-arm64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/netbsd-x64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/openbsd-arm64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/openbsd-x64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/sunos-x64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/win32-arm64': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/win32-ia32': 0.25.2
 | 
				
			||||||
 | 
					      '@esbuild/win32-x64': 0.25.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  estree-walker@2.0.2: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  flatbush@3.3.1:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      flatqueue: 1.2.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  flatqueue@1.2.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fsevents@2.3.3:
 | 
				
			||||||
 | 
					    optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  he@1.2.0: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  js-angusj-clipper@1.3.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  magic-string@0.30.17:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@jridgewell/sourcemap-codec': 1.5.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  minimatch@9.0.5:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      brace-expansion: 2.0.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  muggle-string@0.4.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  nanoid@3.3.11: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  path-browserify@1.0.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  picocolors@1.1.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  polylabel@1.1.0:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      tinyqueue: 2.0.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  postcss@8.5.3:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      nanoid: 3.3.11
 | 
				
			||||||
 | 
					      picocolors: 1.1.1
 | 
				
			||||||
 | 
					      source-map-js: 1.2.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rollup@4.39.0:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@types/estree': 1.0.7
 | 
				
			||||||
 | 
					    optionalDependencies:
 | 
				
			||||||
 | 
					      '@rollup/rollup-android-arm-eabi': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-android-arm64': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-darwin-arm64': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-darwin-x64': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-freebsd-arm64': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-freebsd-x64': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-linux-arm-gnueabihf': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-linux-arm-musleabihf': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-linux-arm64-gnu': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-linux-arm64-musl': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-linux-loongarch64-gnu': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-linux-powerpc64le-gnu': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-linux-riscv64-gnu': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-linux-riscv64-musl': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-linux-s390x-gnu': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-linux-x64-gnu': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-linux-x64-musl': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-win32-arm64-msvc': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-win32-ia32-msvc': 4.39.0
 | 
				
			||||||
 | 
					      '@rollup/rollup-win32-x64-msvc': 4.39.0
 | 
				
			||||||
 | 
					      fsevents: 2.3.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  source-map-js@1.2.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  three-cf@0.122.9: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  tinyqueue@2.0.3: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  typescript@5.7.3: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  vite@6.2.5:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      esbuild: 0.25.2
 | 
				
			||||||
 | 
					      postcss: 8.5.3
 | 
				
			||||||
 | 
					      rollup: 4.39.0
 | 
				
			||||||
 | 
					    optionalDependencies:
 | 
				
			||||||
 | 
					      fsevents: 2.3.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  vscode-uri@3.1.0: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  vue-tsc@2.2.8(typescript@5.7.3):
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@volar/typescript': 2.4.12
 | 
				
			||||||
 | 
					      '@vue/language-core': 2.2.8(typescript@5.7.3)
 | 
				
			||||||
 | 
					      typescript: 5.7.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  vue@3.5.13(typescript@5.7.3):
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@vue/compiler-dom': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/compiler-sfc': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/runtime-dom': 3.5.13
 | 
				
			||||||
 | 
					      '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.7.3))
 | 
				
			||||||
 | 
					      '@vue/shared': 3.5.13
 | 
				
			||||||
 | 
					    optionalDependencies:
 | 
				
			||||||
 | 
					      typescript: 5.7.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  webcad_ue4_api@http://gitea.cf/cx/webcad-ue4-api/archive/3.20.0.tar.gz: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  xaop@2.1.0: {}
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/App.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/App.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import MaterialView from './components/MaterialView.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <MaterialView></MaterialView>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/assets/vue.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/assets/vue.svg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 496 B  | 
							
								
								
									
										251
									
								
								src/common/CameraControls.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								src/common/CameraControls.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,251 @@
 | 
				
			|||||||
 | 
					import * as THREE from 'three';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Vector3 } from 'three';
 | 
				
			||||||
 | 
					import { Viewer } from './Viewer';
 | 
				
			||||||
 | 
					import { KeyBoard, MouseKey } from './KeyEnum';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//相机控制状态
 | 
				
			||||||
 | 
					export enum CameraControlState
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Null = 0, Pan = 1, Rotate = 2, Scale = 3
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class CameraControls
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    m_TouthTypeList = [CameraControlState.Rotate, CameraControlState.Scale, CameraControlState.Pan];
 | 
				
			||||||
 | 
					    m_domElement: HTMLElement;//HTMLDocument
 | 
				
			||||||
 | 
					    //起始点击
 | 
				
			||||||
 | 
					    m_StartClickPoint: THREE.Vector3 = new THREE.Vector3();
 | 
				
			||||||
 | 
					    m_EndClickPoint: THREE.Vector3 = new THREE.Vector3();
 | 
				
			||||||
 | 
					    m_DollyStart: THREE.Vector2 = new THREE.Vector2();
 | 
				
			||||||
 | 
					    m_DollyEnd: THREE.Vector2 = new THREE.Vector2();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m_KeyDown = new Map<KeyBoard, boolean>();
 | 
				
			||||||
 | 
					    m_MouseDown = new Map<MouseKey, boolean>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //状态
 | 
				
			||||||
 | 
					    m_State: CameraControlState = CameraControlState.Null;
 | 
				
			||||||
 | 
					    m_Viewer: Viewer;
 | 
				
			||||||
 | 
					    //左键使用旋转
 | 
				
			||||||
 | 
					    m_LeftUseRotate: boolean = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(viewer: Viewer)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.m_Viewer = viewer;
 | 
				
			||||||
 | 
					        this.m_domElement = viewer.Renderer.domElement.parentElement;
 | 
				
			||||||
 | 
					        this.RegisterEvent();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RegisterEvent()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (this.m_domElement)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.m_domElement.addEventListener("mousedown", this.onMouseDown, false)
 | 
				
			||||||
 | 
					            this.m_domElement.addEventListener("mousemove", this.onMouseMove, false)
 | 
				
			||||||
 | 
					            this.m_domElement.addEventListener("mouseup", this.onMouseUp, false)
 | 
				
			||||||
 | 
					            window.addEventListener("keydown", this.onKeyDown, false);
 | 
				
			||||||
 | 
					            window.addEventListener("keyup", this.onKeyUp, false);
 | 
				
			||||||
 | 
					            this.m_domElement.addEventListener('wheel', this.onMouseWheel, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.m_domElement.addEventListener('touchstart', this.onTouchStart, false);
 | 
				
			||||||
 | 
					            this.m_domElement.addEventListener('touchend', this.onTouchEnd, false);
 | 
				
			||||||
 | 
					            this.m_domElement.addEventListener('touchmove', this.onTouchMove, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            window.addEventListener("blur", this.onBlur, false);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 窗体失去焦点时.
 | 
				
			||||||
 | 
					     * @memberof CameraControls
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    onBlur = () =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.m_KeyDown.clear();
 | 
				
			||||||
 | 
					        this.m_MouseDown.clear();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //触屏开始事件
 | 
				
			||||||
 | 
					    onTouchStart = (event: TouchEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.m_Viewer.UpdateLockTarget();
 | 
				
			||||||
 | 
					        this.m_StartClickPoint.set(event.touches[0].pageX, event.touches[0].pageY, 0);
 | 
				
			||||||
 | 
					        if (event.touches.length < 4)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (event.touches.length == 2)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var dx = event.touches[0].pageX - event.touches[1].pageX;
 | 
				
			||||||
 | 
					                var dy = event.touches[0].pageY - event.touches[1].pageY;
 | 
				
			||||||
 | 
					                var distance = Math.sqrt(dx * dx + dy * dy);
 | 
				
			||||||
 | 
					                this.m_DollyStart.set(0, distance);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            this.m_State = this.m_TouthTypeList[event.touches.length - 1];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    onTouchEnd = (event: TouchEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.m_State = CameraControlState.Null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    onTouchMove = (event: TouchEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        event.preventDefault();
 | 
				
			||||||
 | 
					        event.stopPropagation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.m_EndClickPoint.set(event.touches[0].pageX, event.touches[0].pageY, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let vec = this.m_EndClickPoint.clone().sub(this.m_StartClickPoint);
 | 
				
			||||||
 | 
					        switch (this.m_State)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case CameraControlState.Pan:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    this.m_Viewer.Pan(vec);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            case CameraControlState.Scale:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var dx = event.touches[0].pageX - event.touches[1].pageX;
 | 
				
			||||||
 | 
					                    var dy = event.touches[0].pageY - event.touches[1].pageY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var distance = Math.sqrt(dx * dx + dy * dy);
 | 
				
			||||||
 | 
					                    this.m_DollyEnd.set(0, distance);
 | 
				
			||||||
 | 
					                    if (distance > this.m_DollyStart.y)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        this.m_Viewer.Zoom(0.95);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        this.m_Viewer.Zoom(1.05)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    this.m_DollyStart.copy(this.m_DollyEnd);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            case CameraControlState.Rotate:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    this.m_Viewer.Rotate(vec.multiplyScalar(2));
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.m_StartClickPoint.copy(this.m_EndClickPoint);
 | 
				
			||||||
 | 
					        this.m_Viewer.UpdateRender();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    beginRotate()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.m_State = CameraControlState.Rotate;
 | 
				
			||||||
 | 
					        this.m_Viewer.UpdateLockTarget();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //最后一次按中键的时间
 | 
				
			||||||
 | 
					    lastMiddleClickTime = 0;
 | 
				
			||||||
 | 
					    //鼠标
 | 
				
			||||||
 | 
					    onMouseDown = (event: MouseEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        event.preventDefault();
 | 
				
			||||||
 | 
					        let key: MouseKey = event.button;
 | 
				
			||||||
 | 
					        this.m_MouseDown.set(key, true);
 | 
				
			||||||
 | 
					        this.m_StartClickPoint.set(event.offsetX, event.offsetY, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (key)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case MouseKey.Left:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (this.m_LeftUseRotate)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        this.beginRotate();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            case MouseKey.Middle:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    let curTime = Date.now();
 | 
				
			||||||
 | 
					                    let t = curTime - this.lastMiddleClickTime;
 | 
				
			||||||
 | 
					                    this.lastMiddleClickTime = curTime;
 | 
				
			||||||
 | 
					                    if (t < 350)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        this.m_Viewer.ZoomAll();
 | 
				
			||||||
 | 
					                        return;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (this.m_KeyDown.get(KeyBoard.Control))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        this.beginRotate();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        this.m_State = CameraControlState.Pan;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            case MouseKey.Right:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    onMouseUp = (event: MouseEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        event.preventDefault();
 | 
				
			||||||
 | 
					        this.m_State = CameraControlState.Null;
 | 
				
			||||||
 | 
					        this.m_MouseDown.set(event.button, false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    onMouseMove = (event: MouseEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        event.preventDefault();
 | 
				
			||||||
 | 
					        this.m_EndClickPoint.set(event.offsetX, event.offsetY, 0);
 | 
				
			||||||
 | 
					        let changeVec = this.m_EndClickPoint.clone().sub(this.m_StartClickPoint);
 | 
				
			||||||
 | 
					        this.m_StartClickPoint.copy(this.m_EndClickPoint);
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					            (this.m_LeftUseRotate ||
 | 
				
			||||||
 | 
					                (this.m_KeyDown.get(KeyBoard.Control))
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            && this.m_State == CameraControlState.Rotate
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.m_Viewer.Rotate(changeVec);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        switch (this.m_State)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case CameraControlState.Pan:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    this.m_Viewer.Pan(changeVec);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            case CameraControlState.Rotate:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            case CameraControlState.Scale:
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 鼠标滚轮事件
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @memberof CameraControls
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    onMouseWheel = (event: WheelEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        event.stopPropagation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let pt = new THREE.Vector3(event.offsetX, event.offsetY, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.m_Viewer.ScreenToWorld(pt, new Vector3().setFromMatrixColumn(this.m_Viewer.m_Camera.Camera.matrixWorld, 2));
 | 
				
			||||||
 | 
					        if (event.deltaY < 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.m_Viewer.Zoom(0.6, pt);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (event.deltaY > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.m_Viewer.Zoom(1.4, pt);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //按键
 | 
				
			||||||
 | 
					    onKeyDown = (event: KeyboardEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.m_KeyDown.set(event.keyCode, true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    onKeyUp = (event: KeyboardEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.m_KeyDown.set(event.keyCode, false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										290
									
								
								src/common/GeUtils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								src/common/GeUtils.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,290 @@
 | 
				
			|||||||
 | 
					import { Box3, Geometry, Line, Matrix4, Mesh, Object3D, Vector2, Vector3, type Vector } from 'three';
 | 
				
			||||||
 | 
					import { Matrix2 } from './Matrix2';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const cZeroVec = new Vector3();
 | 
				
			||||||
 | 
					export const cXAxis = new Vector3(1, 0, 0);
 | 
				
			||||||
 | 
					export const cYAxis = new Vector3(0, 1, 0);
 | 
				
			||||||
 | 
					export const cZAxis = new Vector3(0, 0, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 旋转一个点,旋转中心在原点
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @export
 | 
				
			||||||
 | 
					 * @param {Vector3} pt 点
 | 
				
			||||||
 | 
					 * @param {number} ang 角度.
 | 
				
			||||||
 | 
					 * @returns {Vector3} 返回pt不拷贝.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function rotatePoint(pt: Vector3, ang: number): Vector3
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    new Matrix2().setRotate(ang).applyVector(pt);
 | 
				
			||||||
 | 
					    return pt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function equaln(v1: number, v2: number, fuzz = 1e-3)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return Math.abs(v1 - v2) < fuzz;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function equalv3(v1: Vector3, v2: Vector3, fuzz = 1e-8)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return equaln(v1.x, v2.x, fuzz) && equaln(v1.y, v2.y, fuzz) && equaln(v1.z, v2.z, fuzz);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function equal<T extends Vector>(v1: T, v2: T)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return v1.distanceToSquared(v2) < 1e-8;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function fixAngle(an: number, fixAngle: number, fuzz: number = 0.1)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (an < 0)
 | 
				
			||||||
 | 
					        an += Math.PI * 2;
 | 
				
			||||||
 | 
					    an += fuzz;
 | 
				
			||||||
 | 
					    let rem = an % fixAngle;
 | 
				
			||||||
 | 
					    if (rem < fuzz * 2)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        an -= rem;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        an -= fuzz;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return an;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 按照极坐标的方式移动一个点
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @export
 | 
				
			||||||
 | 
					 * @template
 | 
				
			||||||
 | 
					 * @param {T} v 向量(2d,3d)
 | 
				
			||||||
 | 
					 * @param {number} an 角度
 | 
				
			||||||
 | 
					 * @param {number} dis 距离
 | 
				
			||||||
 | 
					 * @returns {T}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function polar<T extends Vector2 | Vector3>(v: T, an: number, dis: number): T
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    v.x += Math.cos(an) * dis;
 | 
				
			||||||
 | 
					    v.y += Math.sin(an) * dis;
 | 
				
			||||||
 | 
					    return v;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function angle(v: Vector3 | Vector2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (equaln(v.y, 0) && v.x > 0)
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    let angle = Math.atan2(v.y, v.x);
 | 
				
			||||||
 | 
					    if (angle < 0) angle += Math.PI * 2;
 | 
				
			||||||
 | 
					    return angle;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 求两个向量的夹角,顺时针为负,逆时针为正
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Vector3} v1
 | 
				
			||||||
 | 
					 * @param {Vector3} v2
 | 
				
			||||||
 | 
					 * @param {Vector3} [ref] 参考向量,如果为世界坐标系则为0,0,1
 | 
				
			||||||
 | 
					 * @returns
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function angleTo(v1: Vector3, v2: Vector3, ref: Vector3 = new Vector3(0, 0, 1))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!ref.equals(new Vector3(0, 0, 1)))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        //任意轴坐标系. 使用相机的构造矩阵.
 | 
				
			||||||
 | 
					        ref.multiplyScalar(-1);
 | 
				
			||||||
 | 
					        let up = getLoocAtUpVec(ref);
 | 
				
			||||||
 | 
					        let refOcs = new Matrix4();
 | 
				
			||||||
 | 
					        refOcs.lookAt(cZeroVec, ref, up);
 | 
				
			||||||
 | 
					        let refOcsInv = new Matrix4().getInverse(refOcs);
 | 
				
			||||||
 | 
					        v1.applyMatrix4(refOcsInv);
 | 
				
			||||||
 | 
					        v2.applyMatrix4(refOcsInv);
 | 
				
			||||||
 | 
					        v1.z = 0;
 | 
				
			||||||
 | 
					        v2.z = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (v1.equals(cZeroVec) || v2.equals(cZeroVec))
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    let cv = new Vector3().crossVectors(v1, v2).normalize();
 | 
				
			||||||
 | 
					    return cv.z === 0 ? v1.angleTo(v2) : v1.angleTo(v2) * cv.z;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function getLoocAtUpVec(dir: Vector3): Vector3
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (dir.equals(cZeroVec))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        throw ("zero vector");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let norm = dir.clone().normalize();
 | 
				
			||||||
 | 
					    if (norm.equals(cZAxis))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return new Vector3(0, 1, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (norm.equals(cZAxis.clone().negate()))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return new Vector3(0, -1, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let xv: Vector3 = new Vector3();
 | 
				
			||||||
 | 
					        xv.crossVectors(cZAxis, norm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let up = new Vector3();
 | 
				
			||||||
 | 
					        up.crossVectors(norm, xv);
 | 
				
			||||||
 | 
					        return up;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function createLookAtMat4(dir: Vector3): Matrix4
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let up = getLoocAtUpVec(dir);
 | 
				
			||||||
 | 
					    let mat = new Matrix4();
 | 
				
			||||||
 | 
					    mat.lookAt(cZeroVec, dir, up);
 | 
				
			||||||
 | 
					    return mat;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function isParallelTo(v1: Vector3, v2: Vector3)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return v1.clone().cross(v2).lengthSq() < 1e-9;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function ptToString(v: Vector3, fractionDigits: number = 3): string
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return v.toArray().map(o =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return o.toFixed(fractionDigits);
 | 
				
			||||||
 | 
					    }).join(",");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function midPoint(v1: Vector3, v2: Vector3): Vector3
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return v1.clone().add(v2).multiplyScalar(0.5);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export function midPoint2(v1: Vector2, v2: Vector2): Vector2
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return v1.clone().add(v2).multiplyScalar(0.5);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function midPtCir(v1: Vector3, v2: Vector3)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let baseline = new Vector3(1, 0, 0);
 | 
				
			||||||
 | 
					    let outLine = v2.clone().sub(v1);
 | 
				
			||||||
 | 
					    let ang = angleTo(baseline, outLine) / 2;
 | 
				
			||||||
 | 
					    let midLine = rotatePoint(outLine, -ang);
 | 
				
			||||||
 | 
					    return v1.clone().add(midLine);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 获得Three对象的包围盒.
 | 
				
			||||||
 | 
					 * @param obj
 | 
				
			||||||
 | 
					 * @param [updateMatrix] 是否应该更新对象矩阵
 | 
				
			||||||
 | 
					 * @returns box
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function GetBox(obj: Object3D, updateMatrix?: boolean): Box3
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let box = new Box3();
 | 
				
			||||||
 | 
					    if (updateMatrix) obj.updateMatrixWorld(false);
 | 
				
			||||||
 | 
					    if (!obj.visible) return box;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    obj.traverse(o =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        //因为实体Erase时,实体仍然保存在Scene中.
 | 
				
			||||||
 | 
					        if (o.visible === false)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //@ts-ignore
 | 
				
			||||||
 | 
					        let geo = o.geometry as BufferGeometry;
 | 
				
			||||||
 | 
					        if (geo)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (!geo.boundingBox)
 | 
				
			||||||
 | 
					                geo.computeBoundingBox();
 | 
				
			||||||
 | 
					            box.union(geo.boundingBox.clone().applyMatrix4(o.matrixWorld));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return box;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function GetBoxArr(arr: Array<Object3D>): Box3
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let box = new Box3();
 | 
				
			||||||
 | 
					    for (let o of arr)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let b = GetBox(o);
 | 
				
			||||||
 | 
					        if (!b.isEmpty())
 | 
				
			||||||
 | 
					            box.union(b);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return box;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function MoveMatrix(v: Vector3): Matrix4
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let mat = new Matrix4();
 | 
				
			||||||
 | 
					    mat.makeTranslation(v.x, v.y, v.z);
 | 
				
			||||||
 | 
					    return mat;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function getProjectDist(v1: Vector3, v2: Vector3)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let ang = v1.angleTo(v2);
 | 
				
			||||||
 | 
					    let dist = v1.length();
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        h: dist * Math.cos(ang),
 | 
				
			||||||
 | 
					        v: dist * Math.sin(ang)
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					//获得输入点在2线组成的4个区间的位置
 | 
				
			||||||
 | 
					export function getPtPostion(sp: Vector3, ep: Vector3, c: Vector3, inPt: Vector3)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let l1 = sp.clone().sub(c);
 | 
				
			||||||
 | 
					    let l2 = ep.clone().sub(c);
 | 
				
			||||||
 | 
					    let l3 = l1.clone().negate();
 | 
				
			||||||
 | 
					    let l4 = l2.clone().negate();
 | 
				
			||||||
 | 
					    let inputLine = inPt.clone().sub(c);
 | 
				
			||||||
 | 
					    let ang1 = angleTo(l1, l2);
 | 
				
			||||||
 | 
					    let ang2 = Math.PI;
 | 
				
			||||||
 | 
					    let ang3 = ang2 + Math.abs(ang1);
 | 
				
			||||||
 | 
					    let inputAng = angleTo(l1, inputLine);
 | 
				
			||||||
 | 
					    if (ang1 * inputAng < 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        inputAng = (Math.PI * 2 - Math.abs(inputAng));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ang1 = Math.abs(ang1);
 | 
				
			||||||
 | 
					    inputAng = Math.abs(inputAng);
 | 
				
			||||||
 | 
					    if (inputAng <= ang1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return { sp, ep };
 | 
				
			||||||
 | 
					    } else if (inputAng > ang1 && inputAng <= ang2)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return { sp: c.clone().add(l3), ep };
 | 
				
			||||||
 | 
					    } else if (inputAng > ang2 && inputAng <= ang3)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return { sp: c.clone().add(l3), ep: c.clone().add(l4) };
 | 
				
			||||||
 | 
					    } else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return { sp, ep: c.clone().add(l4) };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export function angleAndX(v: Vector3 | Vector2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return v.x ? Math.atan(v.y / v.x) : Math.PI / 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 将角度调整为0-2pi之间
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @export
 | 
				
			||||||
 | 
					 * @param {number} an
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function angleTo2Pi(an: number)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    an = an % (Math.PI * 2);
 | 
				
			||||||
 | 
					    if (an < 0) an += Math.PI * 2;
 | 
				
			||||||
 | 
					    return an;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export function updateGeometry(l: Line | Mesh, geometry: Geometry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let geo = l.geometry as Geometry;
 | 
				
			||||||
 | 
					    geo.dispose();
 | 
				
			||||||
 | 
					    l.geometry = geometry;
 | 
				
			||||||
 | 
					    geometry.verticesNeedUpdate = true;
 | 
				
			||||||
 | 
					    geometry.computeBoundingSphere();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										164
									
								
								src/common/KeyEnum.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/common/KeyEnum.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
				
			|||||||
 | 
					//鼠标类型
 | 
				
			||||||
 | 
					export enum MouseKey
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Left = 0,
 | 
				
			||||||
 | 
					    Middle = 1,
 | 
				
			||||||
 | 
					    Right = 2,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum KeyBoard
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // 数字
 | 
				
			||||||
 | 
					    Digit1 = 49,
 | 
				
			||||||
 | 
					    Digit2 = 50,
 | 
				
			||||||
 | 
					    Digit3 = 51,
 | 
				
			||||||
 | 
					    Digit4 = 52,
 | 
				
			||||||
 | 
					    Digit5 = 53,
 | 
				
			||||||
 | 
					    Digit6 = 54,
 | 
				
			||||||
 | 
					    Digit7 = 55,
 | 
				
			||||||
 | 
					    Digit8 = 56,
 | 
				
			||||||
 | 
					    Digit9 = 57,
 | 
				
			||||||
 | 
					    Digit0 = 58,
 | 
				
			||||||
 | 
					    // 字母
 | 
				
			||||||
 | 
					    KeyA = 65,
 | 
				
			||||||
 | 
					    KeyB = 66,
 | 
				
			||||||
 | 
					    KeyC = 67,
 | 
				
			||||||
 | 
					    KeyD = 68,
 | 
				
			||||||
 | 
					    KeyE = 69,
 | 
				
			||||||
 | 
					    KeyF = 70,
 | 
				
			||||||
 | 
					    KeyG = 71,
 | 
				
			||||||
 | 
					    KeyH = 72,
 | 
				
			||||||
 | 
					    KeyI = 73,
 | 
				
			||||||
 | 
					    KeyJ = 74,
 | 
				
			||||||
 | 
					    KeyK = 75,
 | 
				
			||||||
 | 
					    KeyL = 76,
 | 
				
			||||||
 | 
					    KeyM = 77,
 | 
				
			||||||
 | 
					    KeyN = 78,
 | 
				
			||||||
 | 
					    KeyO = 79,
 | 
				
			||||||
 | 
					    KeyP = 80,
 | 
				
			||||||
 | 
					    KeyQ = 81,
 | 
				
			||||||
 | 
					    KeyR = 82,
 | 
				
			||||||
 | 
					    KeyS = 83,
 | 
				
			||||||
 | 
					    KeyT = 84,
 | 
				
			||||||
 | 
					    KeyU = 85,
 | 
				
			||||||
 | 
					    KeyV = 86,
 | 
				
			||||||
 | 
					    KeyW = 87,
 | 
				
			||||||
 | 
					    KeyX = 88,
 | 
				
			||||||
 | 
					    KeyY = 89,
 | 
				
			||||||
 | 
					    KeyZ = 90,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 符号
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 逗号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Comma = 188,
 | 
				
			||||||
 | 
					    CommaChrome = 229,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 句号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Period = 190,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 分号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Semicolon = 186,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 引号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Quote = 222,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 左括号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    BracketLeft = 219,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 右括号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    BracketRight = 220,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 反引号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Backquote = 192,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 反斜杠
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Backslash = 220,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 减号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Minus = 189,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 等号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Equal = 187,
 | 
				
			||||||
 | 
					    IntlRo = 193,
 | 
				
			||||||
 | 
					    IntlYen = 255,
 | 
				
			||||||
 | 
					    // 功能键
 | 
				
			||||||
 | 
					    Alt = 18,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 大写锁定
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    CapsLock = 20,
 | 
				
			||||||
 | 
					    Control = 17,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * win左键
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    OSLeft = 91,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * win右键
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    OSRight = 92,
 | 
				
			||||||
 | 
					    Shift = 16,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ContextMenu = 93,
 | 
				
			||||||
 | 
					    Enter = 13,
 | 
				
			||||||
 | 
					    Space = 32,
 | 
				
			||||||
 | 
					    Backspace = 8,
 | 
				
			||||||
 | 
					    Tab = 9,
 | 
				
			||||||
 | 
					    Delete = 46,
 | 
				
			||||||
 | 
					    End = 35,
 | 
				
			||||||
 | 
					    Home = 36,
 | 
				
			||||||
 | 
					    Insert = 45,
 | 
				
			||||||
 | 
					    PageDown = 34,
 | 
				
			||||||
 | 
					    PageUp = 33,
 | 
				
			||||||
 | 
					    ArrowDown = 40,
 | 
				
			||||||
 | 
					    ArrowLeft = 37,
 | 
				
			||||||
 | 
					    ArrowRight = 39,
 | 
				
			||||||
 | 
					    ArrowUp = 38,
 | 
				
			||||||
 | 
					    Escape = 27,
 | 
				
			||||||
 | 
					    PrintScreen = 44,
 | 
				
			||||||
 | 
					    ScrollLock = 145,
 | 
				
			||||||
 | 
					    Pause = 19,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // F数字
 | 
				
			||||||
 | 
					    F1 = 112,
 | 
				
			||||||
 | 
					    F2 = 113,
 | 
				
			||||||
 | 
					    F3 = 114,
 | 
				
			||||||
 | 
					    F5 = 116,
 | 
				
			||||||
 | 
					    F6 = 117,
 | 
				
			||||||
 | 
					    F7 = 118,
 | 
				
			||||||
 | 
					    F8 = 119,
 | 
				
			||||||
 | 
					    F9 = 120,
 | 
				
			||||||
 | 
					    F10 = 121,
 | 
				
			||||||
 | 
					    F11 = 122,
 | 
				
			||||||
 | 
					    F12 = 123,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //数字键盘
 | 
				
			||||||
 | 
					    NumLock = 114,
 | 
				
			||||||
 | 
					    Numpad0 = 96,
 | 
				
			||||||
 | 
					    Numpad1 = 97,
 | 
				
			||||||
 | 
					    Numpad2 = 98,
 | 
				
			||||||
 | 
					    Numpad3 = 99,
 | 
				
			||||||
 | 
					    Numpad4 = 100,
 | 
				
			||||||
 | 
					    Numpad5 = 101,
 | 
				
			||||||
 | 
					    Numpad6 = 102,
 | 
				
			||||||
 | 
					    Numpad7 = 103,
 | 
				
			||||||
 | 
					    Numpad8 = 104,
 | 
				
			||||||
 | 
					    Numpad9 = 105,
 | 
				
			||||||
 | 
					    NumpadAdd = 107,
 | 
				
			||||||
 | 
					    NumpadDivide = 111,
 | 
				
			||||||
 | 
					    NumpadEqual = 12,
 | 
				
			||||||
 | 
					    NumpadMultiply = 106,
 | 
				
			||||||
 | 
					    NumpadSubtract = 109,
 | 
				
			||||||
 | 
					    NumpadDot = 110,
 | 
				
			||||||
 | 
					    NumpadDot1 = 190
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										236
									
								
								src/common/MaterialEditor.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								src/common/MaterialEditor.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,236 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					import { AmbientLight, BoxBufferGeometry, BufferGeometry, ConeBufferGeometry, CubeRefractionMapping, CubeTextureLoader, Geometry, Mesh, MeshPhysicalMaterial, Object3D, SphereBufferGeometry, sRGBEncoding, Texture, TorusBufferGeometry, TorusKnotBufferGeometry } from 'three';
 | 
				
			||||||
 | 
					import { Singleton } from './Singleton';
 | 
				
			||||||
 | 
					import { Viewer } from './Viewer';
 | 
				
			||||||
 | 
					import { PMREMGenerator3 } from './PMREMGenerator2';
 | 
				
			||||||
 | 
					import type { PhysicalMaterialRecord, TextureTableRecord } from 'webcad_ue4_api';
 | 
				
			||||||
 | 
					import { MaterialEditorCamerControl } from './MaterialMouseControl';
 | 
				
			||||||
 | 
					import { ref } from 'vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function textureRenderUpdate(textureRecord:TextureTableRecord){
 | 
				
			||||||
 | 
					    const texture = textureRecord['texture'] as Texture;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    texture.wrapS = textureRecord.WrapS;
 | 
				
			||||||
 | 
					    texture.wrapT = textureRecord.WrapT;
 | 
				
			||||||
 | 
					    texture.anisotropy = 16;
 | 
				
			||||||
 | 
					    texture.rotation = textureRecord.rotation;
 | 
				
			||||||
 | 
					    texture.repeat.set(textureRecord.repeatX, textureRecord.repeatY);
 | 
				
			||||||
 | 
					    texture.offset.set(textureRecord.moveX, textureRecord.moveY);
 | 
				
			||||||
 | 
					    texture.needsUpdate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//     for (let f of this.waits)
 | 
				
			||||||
 | 
					//         f();
 | 
				
			||||||
 | 
					//     this.waits.length = 0;
 | 
				
			||||||
 | 
					// 
 | 
				
			||||||
 | 
					//     this.AsyncUpdated();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 材质编辑器
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export class MaterialEditor extends Singleton
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Geometrys: Map<string, Geometry | BufferGeometry>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CurGeometryName = ref("球");
 | 
				
			||||||
 | 
					    Canvas: HTMLElement;
 | 
				
			||||||
 | 
					    ShowObject: Object3D;
 | 
				
			||||||
 | 
					    ShowMesh: Mesh;
 | 
				
			||||||
 | 
					    Viewer: Viewer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private _MeshMaterial: MeshPhysicalMaterial = new MeshPhysicalMaterial({});
 | 
				
			||||||
 | 
					    //构造
 | 
				
			||||||
 | 
					    private constructor()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        super();
 | 
				
			||||||
 | 
					        this.initGeometrys();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.LoadDefaultExr();
 | 
				
			||||||
 | 
					        this.LoadMetalEnv();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    initGeometrys()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.Geometrys = new Map<string, Geometry | BufferGeometry>(
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                ["球", new SphereBufferGeometry(1000, 32, 32)],
 | 
				
			||||||
 | 
					                ["圆环", new TorusBufferGeometry(0.8 * 1e3, 0.4 * 1e3, 32, 64)],
 | 
				
			||||||
 | 
					                ["立方体", new BoxBufferGeometry(1e3, 1e3, 1e3, 1, 1, 1)],
 | 
				
			||||||
 | 
					                ["环面纽结", new TorusKnotBufferGeometry(0.7 * 1e3, 0.3 * 1e3, 128, 64)],
 | 
				
			||||||
 | 
					                ["圆锥体", new ConeBufferGeometry(1 * 1e3, 2 * 1e3, 32)],
 | 
				
			||||||
 | 
					                // ["球(多面)", new SphereBufferGeometry(1 * 1e3, 64, 64)],
 | 
				
			||||||
 | 
					                // ["立方体(多面)", new BoxBufferGeometry(1 * 1e3, 1 * 1e3, 1 * 1e3, 128, 128, 128)]
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    initViewer()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!this.Viewer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.Viewer = new Viewer(this.Canvas);
 | 
				
			||||||
 | 
					            // this.Viewer.PreViewer.Cursor.CursorObject.visible = false;
 | 
				
			||||||
 | 
					            // this.Viewer.CameraCtrl.CameraType = CameraType.PerspectiveCamera;
 | 
				
			||||||
 | 
					            // this.Viewer.UsePass = false;
 | 
				
			||||||
 | 
					            this.initScene();
 | 
				
			||||||
 | 
					            new MaterialEditorCamerControl(this.Viewer);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.Canvas.appendChild(this.Viewer.Renderer.domElement);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    SetViewer(canvas: HTMLElement)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.Canvas = canvas;
 | 
				
			||||||
 | 
					        this.initViewer();
 | 
				
			||||||
 | 
					        this.CurGeometryName.value = "球";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    initScene()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let scene = this.Viewer.Scene;
 | 
				
			||||||
 | 
					        this.ShowObject = new Object3D();
 | 
				
			||||||
 | 
					        let geo = this.Geometrys.get(this.CurGeometryName.value);
 | 
				
			||||||
 | 
					        this.ShowMesh = new Mesh(geo, this._MeshMaterial);
 | 
				
			||||||
 | 
					        this.ShowMesh.scale.set(1000, 1000, 1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.ShowObject.add(this.ShowMesh);
 | 
				
			||||||
 | 
					        scene.add(this.ShowObject);
 | 
				
			||||||
 | 
					        // let remove = autorun(() =>
 | 
				
			||||||
 | 
					        // {
 | 
				
			||||||
 | 
					        //     let geo = this.Geometrys.get(this.CurGeometryName.get());
 | 
				
			||||||
 | 
					        //     if (geo)
 | 
				
			||||||
 | 
					        //     {
 | 
				
			||||||
 | 
					        //         this.ShowMesh.geometry = geo;
 | 
				
			||||||
 | 
					        //         this.Viewer.UpdateRender();
 | 
				
			||||||
 | 
					        //     }
 | 
				
			||||||
 | 
					        // });
 | 
				
			||||||
 | 
					        // end(this as MaterialEditor, this.dispose, remove);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //环境光
 | 
				
			||||||
 | 
					        let ambient = new AmbientLight();
 | 
				
			||||||
 | 
					        ambient.intensity = 0.7;
 | 
				
			||||||
 | 
					        scene.add(ambient);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    metaTexture: Texture;
 | 
				
			||||||
 | 
					    metaPromise: Promise<Texture>;
 | 
				
			||||||
 | 
					    async LoadMetalEnv(): Promise<Texture>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (this.metaTexture) return this.metaTexture;
 | 
				
			||||||
 | 
					        if (this.metaPromise) return this.metaPromise;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new Promise((res, rej) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            let urls = ['right.webp', 'left.webp', 'top.webp', 'bottom.webp', 'front.webp', 'back.webp'];
 | 
				
			||||||
 | 
					            new CubeTextureLoader().setPath('https://cdn.cfcad.cn/t/house/')
 | 
				
			||||||
 | 
					                .load(urls, (t) =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    t.encoding = sRGBEncoding;
 | 
				
			||||||
 | 
					                    t.mapping = CubeRefractionMapping;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let pmremGenerator = new PMREMGenerator3(this.Viewer.Renderer);
 | 
				
			||||||
 | 
					                    let ldrCubeRenderTarget = pmremGenerator.fromCubemap(t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    this.metaTexture = ldrCubeRenderTarget.texture;
 | 
				
			||||||
 | 
					                    res(this.metaTexture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    this.Viewer.Scene.background = this.metaTexture;
 | 
				
			||||||
 | 
					                    // this.Viewer.Scene.background = new Color(255,0,0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    this.Viewer.UpdateRender();
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    exrPromise: Promise<Texture>;
 | 
				
			||||||
 | 
					    exrTexture: Texture;
 | 
				
			||||||
 | 
					    async LoadDefaultExr(): Promise<Texture>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (this.exrTexture) return this.exrTexture;
 | 
				
			||||||
 | 
					        if (this.exrPromise) return this.exrPromise;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.exrPromise = new Promise<Texture>((res, rej) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            let urls = ['right.webp', 'left.webp', 'top.webp', 'bottom.webp', 'front.webp', 'back.webp'];
 | 
				
			||||||
 | 
					            new CubeTextureLoader().setPath('https://cdn.cfcad.cn/t/house_gray/')
 | 
				
			||||||
 | 
					                .load(urls, (t) =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    t.encoding = sRGBEncoding;
 | 
				
			||||||
 | 
					                    t.mapping = CubeRefractionMapping;
 | 
				
			||||||
 | 
					                    let pmremGenerator = new PMREMGenerator3(this.Viewer.Renderer);
 | 
				
			||||||
 | 
					                    let target = pmremGenerator.fromCubemap(t);
 | 
				
			||||||
 | 
					                    this.exrTexture = target.texture;
 | 
				
			||||||
 | 
					                    res(this.exrTexture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    this.Viewer.UpdateRender();
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return this.exrPromise;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private Material: PhysicalMaterialRecord;
 | 
				
			||||||
 | 
					    setMaterial(mat: PhysicalMaterialRecord)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.Material = mat;
 | 
				
			||||||
 | 
					        this._MeshMaterial.copy(mat.Material);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mtl = this._MeshMaterial;
 | 
				
			||||||
 | 
					        if (mtl.metalness > 0.8)
 | 
				
			||||||
 | 
					            this.LoadMetalEnv().then(env =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                mtl.envMap = env;
 | 
				
			||||||
 | 
					                mtl.needsUpdate = true;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            this.LoadDefaultExr().then(exr =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                mtl.envMap = exr;
 | 
				
			||||||
 | 
					                mtl.needsUpdate = true;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.Update();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async Update()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let mat = this.ShowMesh.material as MeshPhysicalMaterial;
 | 
				
			||||||
 | 
					        if (this.Material.map && this.Material.map.Object && this.Material.useMap)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            let texture = this.Material.map.Object as TextureTableRecord;
 | 
				
			||||||
 | 
					            await textureRenderUpdate(texture);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (this.Material.bumpMap && this.Material.bumpMap.Object)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            let texture = this.Material.bumpMap.Object as TextureTableRecord;
 | 
				
			||||||
 | 
					            await textureRenderUpdate(texture);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (this.Material.roughnessMap && this.Material.roughnessMap.Object)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            let texture = this.Material.roughnessMap.Object as TextureTableRecord;
 | 
				
			||||||
 | 
					            await textureRenderUpdate(texture);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        mat.needsUpdate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._MeshMaterial.copy(this.Material.Material);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mtl = this._MeshMaterial;
 | 
				
			||||||
 | 
					        if (mtl.metalness > 0.8)
 | 
				
			||||||
 | 
					            this.LoadMetalEnv().then(env =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                mtl.envMap = env;
 | 
				
			||||||
 | 
					                mtl.needsUpdate = true;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            this.LoadDefaultExr().then(exr =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                mtl.envMap = exr;
 | 
				
			||||||
 | 
					                mtl.needsUpdate = true;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.Viewer.UpdateRender();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										85
									
								
								src/common/MaterialMouseControl.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/common/MaterialMouseControl.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
				
			|||||||
 | 
					import { Vector3 } from 'three';
 | 
				
			||||||
 | 
					import type { Viewer } from './Viewer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 材质编辑器的场景鼠标控制.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export class MaterialEditorCamerControl
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private Viewer: Viewer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //State.
 | 
				
			||||||
 | 
					    private _MouseIsDown: boolean = false;
 | 
				
			||||||
 | 
					    private _StartPoint: Vector3 = new Vector3();
 | 
				
			||||||
 | 
					    private _EndPoint = new Vector3();
 | 
				
			||||||
 | 
					    private pointId: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(view: Viewer)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.Viewer = view;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.initMouseControl();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    initMouseControl()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let el = this.Viewer.Renderer.domElement;
 | 
				
			||||||
 | 
					        el.addEventListener("pointerdown", (e) => { this.pointId = e.pointerId; }, false);
 | 
				
			||||||
 | 
					        el.addEventListener("mousedown", this.onMouseDown, false);
 | 
				
			||||||
 | 
					        el.addEventListener("mousemove", this.onMouseMove, false);
 | 
				
			||||||
 | 
					        el.addEventListener("mouseup", this.onMouseUp, false);
 | 
				
			||||||
 | 
					        el.addEventListener('wheel', this.onMouseWheel, false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    onMouseDown = (event: MouseEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.requestPointerLock();
 | 
				
			||||||
 | 
					        this._MouseIsDown = true;
 | 
				
			||||||
 | 
					        this._StartPoint.set(event.offsetX, event.offsetY, 0);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    onMouseUp = (event: MouseEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this._MouseIsDown = false;
 | 
				
			||||||
 | 
					        this.exitPointerLock();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    onMouseMove = (event: MouseEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        event.preventDefault();
 | 
				
			||||||
 | 
					        if (this._MouseIsDown)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this._EndPoint.set(event.offsetX, event.offsetY, 0);
 | 
				
			||||||
 | 
					            let changeVec: Vector3 = new Vector3();
 | 
				
			||||||
 | 
					            changeVec.subVectors(this._EndPoint, this._StartPoint);
 | 
				
			||||||
 | 
					            this._StartPoint.copy(this._EndPoint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Viewer.Rotate(changeVec);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    onMouseWheel = (event: WheelEvent) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (event.deltaY < 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.Viewer.Zoom(0.6);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (event.deltaY > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.Viewer.Zoom(1.4);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    requestPointerLock()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (this.Viewer.Renderer.domElement.setPointerCapture)
 | 
				
			||||||
 | 
					            this.Viewer.Renderer.domElement.setPointerCapture(this.pointId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    exitPointerLock()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (this.Viewer.Renderer.domElement.releasePointerCapture && this.pointId !== undefined)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                this.Viewer.Renderer.domElement.releasePointerCapture(this.pointId);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (error) { }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								src/common/Matrix2.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/common/Matrix2.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					import { Vector2, Vector3 } from "three";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class Matrix2
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private el = [1, 0, 0, 1];
 | 
				
			||||||
 | 
					    set(n11: number, n12: number, n21: number, n22: number)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let te = this.el;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        te[0] = n11; te[1] = n21;
 | 
				
			||||||
 | 
					        te[2] = n12; te[3] = n22;
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    applyVector(vec: Vector2 | Vector3)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let x = vec.x, y = vec.y;
 | 
				
			||||||
 | 
					        let e = this.el;
 | 
				
			||||||
 | 
					        vec.x = e[0] * x + e[2] * y;
 | 
				
			||||||
 | 
					        vec.y = e[1] * x + e[3] * y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setRotate(theta: number): Matrix2
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // let el = this.el;
 | 
				
			||||||
 | 
					        let c = Math.cos(theta), s = Math.sin(theta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.set(c, -s,
 | 
				
			||||||
 | 
					            s, c);
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										997
									
								
								src/common/PMREMGenerator2.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										997
									
								
								src/common/PMREMGenerator2.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,997 @@
 | 
				
			|||||||
 | 
					import { BufferAttribute, BufferGeometry, CubeUVReflectionMapping, GammaEncoding, LinearEncoding, Mesh, NearestFilter, NoBlending, NoToneMapping, OrthographicCamera, PerspectiveCamera, RawShaderMaterial, RGBDEncoding, RGBEEncoding, RGBEFormat, RGBM16Encoding, RGBM7Encoding, sRGBEncoding, UnsignedByteType, Vector2, Vector3, WebGLRenderer, WebGLRenderTarget } from "three";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const LOD_MIN = 4;
 | 
				
			||||||
 | 
					const LOD_MAX = 8;
 | 
				
			||||||
 | 
					const SIZE_MAX = Math.pow(2, LOD_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The standard deviations (radians) associated with the extra mips. These are
 | 
				
			||||||
 | 
					// chosen to approximate a Trowbridge-Reitz distribution function times the
 | 
				
			||||||
 | 
					// geometric shadowing function. These sigma values squared must match the
 | 
				
			||||||
 | 
					// variance #defines in cube_uv_reflection_fragment.glsl.js.
 | 
				
			||||||
 | 
					const EXTRA_LOD_SIGMA = [0.125, 0.215, 0.35, 0.446, 0.526, 0.582];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TOTAL_LODS = LOD_MAX - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The maximum length of the blur for loop. Smaller sigmas will use fewer
 | 
				
			||||||
 | 
					// samples and exit early, but not recompile the shader.
 | 
				
			||||||
 | 
					const MAX_SAMPLES = 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ENCODINGS = {
 | 
				
			||||||
 | 
					    [LinearEncoding]: 0,
 | 
				
			||||||
 | 
					    [sRGBEncoding]: 1,
 | 
				
			||||||
 | 
					    [RGBEEncoding]: 2,
 | 
				
			||||||
 | 
					    [RGBM7Encoding]: 3,
 | 
				
			||||||
 | 
					    [RGBM16Encoding]: 4,
 | 
				
			||||||
 | 
					    [RGBDEncoding]: 5,
 | 
				
			||||||
 | 
					    [GammaEncoding]: 6
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//@ts-ignore
 | 
				
			||||||
 | 
					const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
 | 
				
			||||||
 | 
					const { _lodPlanes, _sizeLods, _sigmas } = /*@__PURE__*/ _createPlanes();
 | 
				
			||||||
 | 
					let _oldTarget = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Golden Ratio
 | 
				
			||||||
 | 
					const PHI = (1 + Math.sqrt(5)) / 2;
 | 
				
			||||||
 | 
					const INV_PHI = 1 / PHI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Vertices of a dodecahedron (except the opposites, which represent the
 | 
				
			||||||
 | 
					// same axis), used as axis directions evenly spread on a sphere.
 | 
				
			||||||
 | 
					const _axisDirections = [
 | 
				
			||||||
 | 
						/*@__PURE__*/ new Vector3(1, 1, 1),
 | 
				
			||||||
 | 
						/*@__PURE__*/ new Vector3(- 1, 1, 1),
 | 
				
			||||||
 | 
						/*@__PURE__*/ new Vector3(1, 1, - 1),
 | 
				
			||||||
 | 
						/*@__PURE__*/ new Vector3(- 1, 1, - 1),
 | 
				
			||||||
 | 
						/*@__PURE__*/ new Vector3(0, PHI, INV_PHI),
 | 
				
			||||||
 | 
						/*@__PURE__*/ new Vector3(0, PHI, - INV_PHI),
 | 
				
			||||||
 | 
						/*@__PURE__*/ new Vector3(INV_PHI, 0, PHI),
 | 
				
			||||||
 | 
						/*@__PURE__*/ new Vector3(- INV_PHI, 0, PHI),
 | 
				
			||||||
 | 
						/*@__PURE__*/ new Vector3(PHI, INV_PHI, 0),
 | 
				
			||||||
 | 
						/*@__PURE__*/ new Vector3(- PHI, INV_PHI, 0)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This class generates a Prefiltered, Mipmapped Radiance Environment Map
 | 
				
			||||||
 | 
					 * (PMREM) from a cubeMap environment texture. This allows different levels of
 | 
				
			||||||
 | 
					 * blur to be quickly accessed based on material roughness. It is packed into a
 | 
				
			||||||
 | 
					 * special CubeUV format that allows us to perform custom interpolation so that
 | 
				
			||||||
 | 
					 * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap
 | 
				
			||||||
 | 
					 * chain, it only goes down to the LOD_MIN level (above), and then creates extra
 | 
				
			||||||
 | 
					 * even more filtered 'mips' at the same LOD_MIN resolution, associated with
 | 
				
			||||||
 | 
					 * higher roughness levels. In this way we maintain resolution to smoothly
 | 
				
			||||||
 | 
					 * interpolate diffuse lighting while limiting sampling computation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class PMREMGenerator3
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    _renderer: WebGLRenderer;
 | 
				
			||||||
 | 
					    _pingPongRenderTarget: any;
 | 
				
			||||||
 | 
					    _blurMaterial: RawShaderMaterial;
 | 
				
			||||||
 | 
					    _equirectShader: any;
 | 
				
			||||||
 | 
					    _cubemapShader: any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(renderer: WebGLRenderer)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._renderer = renderer;
 | 
				
			||||||
 | 
					        this._pingPongRenderTarget = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._blurMaterial = _getBlurShader(MAX_SAMPLES);
 | 
				
			||||||
 | 
					        this._equirectShader = null;
 | 
				
			||||||
 | 
					        this._cubemapShader = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._compileMaterial(this._blurMaterial);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Generates a PMREM from a supplied Scene, which can be faster than using an
 | 
				
			||||||
 | 
					     * image if networking bandwidth is low. Optional sigma specifies a blur radius
 | 
				
			||||||
 | 
					     * in radians to be applied to the scene before PMREM generation. Optional near
 | 
				
			||||||
 | 
					     * and far planes ensure the scene is rendered in its entirety (the cubeCamera
 | 
				
			||||||
 | 
					     * is placed at the origin).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fromScene(scene, sigma = 0, near = 0.1, far = 100)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _oldTarget = this._renderer.getRenderTarget();
 | 
				
			||||||
 | 
					        const cubeUVRenderTarget = this._allocateTargets();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._sceneToCubeUV(scene, near, far, cubeUVRenderTarget);
 | 
				
			||||||
 | 
					        if (sigma > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this._blur(cubeUVRenderTarget, 0, 0, sigma);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._applyPMREM(cubeUVRenderTarget);
 | 
				
			||||||
 | 
					        this._cleanup(cubeUVRenderTarget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return cubeUVRenderTarget;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Generates a PMREM from an equirectangular texture, which can be either LDR
 | 
				
			||||||
 | 
					     * (RGBFormat) or HDR (RGBEFormat). The ideal input image size is 1k (1024 x 512),
 | 
				
			||||||
 | 
					     * as this matches best with the 256 x 256 cubemap output.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fromEquirectangular(equirectangular)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this._fromTexture(equirectangular);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Generates a PMREM from an cubemap texture, which can be either LDR
 | 
				
			||||||
 | 
					     * (RGBFormat) or HDR (RGBEFormat). The ideal input cube size is 256 x 256,
 | 
				
			||||||
 | 
					     * as this matches best with the 256 x 256 cubemap output.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fromCubemap(cubemap)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this._fromTexture(cubemap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
 | 
				
			||||||
 | 
					     * your texture's network fetch for increased concurrency.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    compileCubemapShader()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this._cubemapShader === null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this._cubemapShader = _getCubemapShader();
 | 
				
			||||||
 | 
					            this._compileMaterial(this._cubemapShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
 | 
				
			||||||
 | 
					     * your texture's network fetch for increased concurrency.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    compileEquirectangularShader()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this._equirectShader === null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this._equirectShader = _getEquirectShader();
 | 
				
			||||||
 | 
					            this._compileMaterial(this._equirectShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
 | 
				
			||||||
 | 
					     * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
 | 
				
			||||||
 | 
					     * one of them will cause any others to also become unusable.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._blurMaterial.dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this._cubemapShader !== null) this._cubemapShader.dispose();
 | 
				
			||||||
 | 
					        if (this._equirectShader !== null) this._equirectShader.dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let i = 0; i < _lodPlanes.length; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _lodPlanes[i].dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // private interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _cleanup(outputTarget)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._pingPongRenderTarget.dispose();
 | 
				
			||||||
 | 
					        this._renderer.setRenderTarget(_oldTarget);
 | 
				
			||||||
 | 
					        outputTarget.scissorTest = false;
 | 
				
			||||||
 | 
					        _setViewport(outputTarget, 0, 0, outputTarget.width, outputTarget.height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _fromTexture(texture)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _oldTarget = this._renderer.getRenderTarget();
 | 
				
			||||||
 | 
					        const cubeUVRenderTarget = this._allocateTargets(texture);
 | 
				
			||||||
 | 
					        this._textureToCubeUV(texture, cubeUVRenderTarget);
 | 
				
			||||||
 | 
					        this._applyPMREM(cubeUVRenderTarget);
 | 
				
			||||||
 | 
					        this._cleanup(cubeUVRenderTarget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return cubeUVRenderTarget;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _allocateTargets(texture?)
 | 
				
			||||||
 | 
					    { // warning: null texture is valid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const params = {
 | 
				
			||||||
 | 
					            magFilter: NearestFilter,
 | 
				
			||||||
 | 
					            minFilter: NearestFilter,
 | 
				
			||||||
 | 
					            generateMipmaps: false,
 | 
				
			||||||
 | 
					            type: UnsignedByteType,
 | 
				
			||||||
 | 
					            format: RGBEFormat,
 | 
				
			||||||
 | 
					            encoding: _isLDR(texture) ? texture.encoding : RGBEEncoding,
 | 
				
			||||||
 | 
					            depthBuffer: false
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const cubeUVRenderTarget = _createRenderTarget(params);
 | 
				
			||||||
 | 
					        cubeUVRenderTarget.depthBuffer = texture ? false : true;
 | 
				
			||||||
 | 
					        this._pingPongRenderTarget = _createRenderTarget(params);
 | 
				
			||||||
 | 
					        return cubeUVRenderTarget;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _compileMaterial(material)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const tmpMesh = new Mesh(_lodPlanes[0], material);
 | 
				
			||||||
 | 
					        this._renderer.compile(tmpMesh, _flatCamera);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _sceneToCubeUV(scene, near, far, cubeUVRenderTarget)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const fov = 90;
 | 
				
			||||||
 | 
					        const aspect = 1;
 | 
				
			||||||
 | 
					        const cubeCamera = new PerspectiveCamera(fov, aspect, near, far);
 | 
				
			||||||
 | 
					        const upSign = [1, - 1, 1, 1, 1, 1];
 | 
				
			||||||
 | 
					        const forwardSign = [1, 1, 1, - 1, - 1, - 1];
 | 
				
			||||||
 | 
					        const renderer = this._renderer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const outputEncoding = renderer.outputEncoding;
 | 
				
			||||||
 | 
					        const toneMapping = renderer.toneMapping;
 | 
				
			||||||
 | 
					        const clearColor = renderer.getClearColor();
 | 
				
			||||||
 | 
					        const clearAlpha = renderer.getClearAlpha();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        renderer.toneMapping = NoToneMapping;
 | 
				
			||||||
 | 
					        renderer.outputEncoding = LinearEncoding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let background = scene.background;
 | 
				
			||||||
 | 
					        if (background && background.isColor)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            background.convertSRGBToLinear();
 | 
				
			||||||
 | 
					            // Convert linear to RGBE
 | 
				
			||||||
 | 
					            const maxComponent = Math.max(background.r, background.g, background.b);
 | 
				
			||||||
 | 
					            const fExp = Math.min(Math.max(Math.ceil(Math.log2(maxComponent)), - 128.0), 127.0);
 | 
				
			||||||
 | 
					            background = background.multiplyScalar(Math.pow(2.0, - fExp));
 | 
				
			||||||
 | 
					            const alpha = (fExp + 128.0) / 255.0;
 | 
				
			||||||
 | 
					            renderer.setClearColor(background, alpha);
 | 
				
			||||||
 | 
					            scene.background = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let i = 0; i < 6; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const col = i % 3;
 | 
				
			||||||
 | 
					            if (col == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                cubeCamera.up.set(0, upSign[i], 0);
 | 
				
			||||||
 | 
					                cubeCamera.lookAt(forwardSign[i], 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            } else if (col == 1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                cubeCamera.up.set(0, 0, upSign[i]);
 | 
				
			||||||
 | 
					                cubeCamera.lookAt(0, forwardSign[i], 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            } else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                cubeCamera.up.set(0, upSign[i], 0);
 | 
				
			||||||
 | 
					                cubeCamera.lookAt(0, 0, forwardSign[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _setViewport(cubeUVRenderTarget,
 | 
				
			||||||
 | 
					                col * SIZE_MAX, i > 2 ? SIZE_MAX : 0, SIZE_MAX, SIZE_MAX);
 | 
				
			||||||
 | 
					            renderer.setRenderTarget(cubeUVRenderTarget);
 | 
				
			||||||
 | 
					            renderer.render(scene, cubeCamera);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        renderer.toneMapping = toneMapping;
 | 
				
			||||||
 | 
					        renderer.outputEncoding = outputEncoding;
 | 
				
			||||||
 | 
					        renderer.setClearColor(clearColor, clearAlpha);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _textureToCubeUV(texture, cubeUVRenderTarget)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const renderer = this._renderer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (texture.isCubeTexture)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (this._cubemapShader == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                this._cubemapShader = _getCubemapShader();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (this._equirectShader == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                this._equirectShader = _getEquirectShader();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const material = texture.isCubeTexture ? this._cubemapShader : this._equirectShader;
 | 
				
			||||||
 | 
					        const mesh = new Mesh(_lodPlanes[0], material);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const uniforms = material.uniforms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uniforms['envMap'].value = texture;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!texture.isCubeTexture)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uniforms['texelSize'].value.set(1.0 / texture.image.width, 1.0 / texture.image.height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uniforms['inputEncoding'].value = ENCODINGS[texture.encoding];
 | 
				
			||||||
 | 
					        uniforms['outputEncoding'].value = ENCODINGS[cubeUVRenderTarget.texture.encoding];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _setViewport(cubeUVRenderTarget, 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        renderer.setRenderTarget(cubeUVRenderTarget);
 | 
				
			||||||
 | 
					        renderer.render(mesh, _flatCamera);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _applyPMREM(cubeUVRenderTarget)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const renderer = this._renderer;
 | 
				
			||||||
 | 
					        const autoClear = renderer.autoClear;
 | 
				
			||||||
 | 
					        renderer.autoClear = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let i = 1; i < TOTAL_LODS; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const sigma = Math.sqrt(_sigmas[i] * _sigmas[i] - _sigmas[i - 1] * _sigmas[i - 1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const poleAxis = _axisDirections[(i - 1) % _axisDirections.length];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this._blur(cubeUVRenderTarget, i - 1, i, sigma, poleAxis);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        renderer.autoClear = autoClear;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * This is a two-pass Gaussian blur for a cubemap. Normally this is done
 | 
				
			||||||
 | 
					     * vertically and horizontally, but this breaks down on a cube. Here we apply
 | 
				
			||||||
 | 
					     * the blur latitudinally (around the poles), and then longitudinally (towards
 | 
				
			||||||
 | 
					     * the poles) to approximate the orthogonally-separable blur. It is least
 | 
				
			||||||
 | 
					     * accurate at the poles, but still does a decent job.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    _blur(cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis?)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const pingPongRenderTarget = this._pingPongRenderTarget;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._halfBlur(
 | 
				
			||||||
 | 
					            cubeUVRenderTarget,
 | 
				
			||||||
 | 
					            pingPongRenderTarget,
 | 
				
			||||||
 | 
					            lodIn,
 | 
				
			||||||
 | 
					            lodOut,
 | 
				
			||||||
 | 
					            sigma,
 | 
				
			||||||
 | 
					            'latitudinal',
 | 
				
			||||||
 | 
					            poleAxis);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._halfBlur(
 | 
				
			||||||
 | 
					            pingPongRenderTarget,
 | 
				
			||||||
 | 
					            cubeUVRenderTarget,
 | 
				
			||||||
 | 
					            lodOut,
 | 
				
			||||||
 | 
					            lodOut,
 | 
				
			||||||
 | 
					            sigma,
 | 
				
			||||||
 | 
					            'longitudinal',
 | 
				
			||||||
 | 
					            poleAxis);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _halfBlur(targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const renderer = this._renderer;
 | 
				
			||||||
 | 
					        const blurMaterial = this._blurMaterial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (direction !== 'latitudinal' && direction !== 'longitudinal')
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            console.error(
 | 
				
			||||||
 | 
					                'blur direction must be either latitudinal or longitudinal!');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Number of standard deviations at which to cut off the discrete approximation.
 | 
				
			||||||
 | 
					        const STANDARD_DEVIATIONS = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const blurMesh = new Mesh(_lodPlanes[lodOut], blurMaterial);
 | 
				
			||||||
 | 
					        const blurUniforms = blurMaterial.uniforms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const pixels = _sizeLods[lodIn] - 1;
 | 
				
			||||||
 | 
					        const radiansPerPixel = isFinite(sigmaRadians) ? Math.PI / (2 * pixels) : 2 * Math.PI / (2 * MAX_SAMPLES - 1);
 | 
				
			||||||
 | 
					        const sigmaPixels = sigmaRadians / radiansPerPixel;
 | 
				
			||||||
 | 
					        const samples = isFinite(sigmaRadians) ? 1 + Math.floor(STANDARD_DEVIATIONS * sigmaPixels) : MAX_SAMPLES;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (samples > MAX_SAMPLES)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            console.warn(`sigmaRadians, ${sigmaRadians}, is too large and will clip, as it requested ${samples} samples when the maximum is set to ${MAX_SAMPLES}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const weights = [];
 | 
				
			||||||
 | 
					        let sum = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let i = 0; i < MAX_SAMPLES; ++i)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const x = i / sigmaPixels;
 | 
				
			||||||
 | 
					            const weight = Math.exp(- x * x / 2);
 | 
				
			||||||
 | 
					            weights.push(weight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (i == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                sum += weight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            } else if (i < samples)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                sum += 2 * weight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let i = 0; i < weights.length; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            weights[i] = weights[i] / sum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        blurUniforms['envMap'].value = targetIn.texture;
 | 
				
			||||||
 | 
					        blurUniforms['samples'].value = samples;
 | 
				
			||||||
 | 
					        blurUniforms['weights'].value = weights;
 | 
				
			||||||
 | 
					        blurUniforms['latitudinal'].value = direction === 'latitudinal';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (poleAxis)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            blurUniforms['poleAxis'].value = poleAxis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        blurUniforms['dTheta'].value = radiansPerPixel;
 | 
				
			||||||
 | 
					        blurUniforms['mipInt'].value = LOD_MAX - lodIn;
 | 
				
			||||||
 | 
					        blurUniforms['inputEncoding'].value = ENCODINGS[targetIn.texture.encoding];
 | 
				
			||||||
 | 
					        blurUniforms['outputEncoding'].value = ENCODINGS[targetIn.texture.encoding];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const outputSize = _sizeLods[lodOut];
 | 
				
			||||||
 | 
					        const x = 3 * Math.max(0, SIZE_MAX - 2 * outputSize);
 | 
				
			||||||
 | 
					        const y = (lodOut === 0 ? 0 : 2 * SIZE_MAX) + 2 * outputSize * (lodOut > LOD_MAX - LOD_MIN ? lodOut - LOD_MAX + LOD_MIN : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _setViewport(targetOut, x, y, 3 * outputSize, 2 * outputSize);
 | 
				
			||||||
 | 
					        renderer.setRenderTarget(targetOut);
 | 
				
			||||||
 | 
					        renderer.render(blurMesh, _flatCamera);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _isLDR(texture)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (texture === undefined || texture.type !== UnsignedByteType) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return texture.encoding === LinearEncoding || texture.encoding === sRGBEncoding || texture.encoding === GammaEncoding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _createPlanes()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const _lodPlanes = [];
 | 
				
			||||||
 | 
					    const _sizeLods = [];
 | 
				
			||||||
 | 
					    const _sigmas = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let lod = LOD_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (let i = 0; i < TOTAL_LODS; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const sizeLod = Math.pow(2, lod);
 | 
				
			||||||
 | 
					        _sizeLods.push(sizeLod);
 | 
				
			||||||
 | 
					        let sigma = 1.0 / sizeLod;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (i > LOD_MAX - LOD_MIN)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            sigma = EXTRA_LOD_SIGMA[i - LOD_MAX + LOD_MIN - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else if (i == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            sigma = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _sigmas.push(sigma);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const texelSize = 1.0 / (sizeLod - 1);
 | 
				
			||||||
 | 
					        const min = - texelSize / 2;
 | 
				
			||||||
 | 
					        const max = 1 + texelSize / 2;
 | 
				
			||||||
 | 
					        const uv1 = [min, min, max, min, max, max, min, min, max, max, min, max];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const cubeFaces = 6;
 | 
				
			||||||
 | 
					        const vertices = 6;
 | 
				
			||||||
 | 
					        const positionSize = 3;
 | 
				
			||||||
 | 
					        const uvSize = 2;
 | 
				
			||||||
 | 
					        const faceIndexSize = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const position = new Float32Array(positionSize * vertices * cubeFaces);
 | 
				
			||||||
 | 
					        const uv = new Float32Array(uvSize * vertices * cubeFaces);
 | 
				
			||||||
 | 
					        const faceIndex = new Float32Array(faceIndexSize * vertices * cubeFaces);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let face = 0; face < cubeFaces; face++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const x = (face % 3) * 2 / 3 - 1;
 | 
				
			||||||
 | 
					            const y = face > 2 ? 0 : - 1;
 | 
				
			||||||
 | 
					            const coordinates = [
 | 
				
			||||||
 | 
					                x, y, 0,
 | 
				
			||||||
 | 
					                x + 2 / 3, y, 0,
 | 
				
			||||||
 | 
					                x + 2 / 3, y + 1, 0,
 | 
				
			||||||
 | 
					                x, y, 0,
 | 
				
			||||||
 | 
					                x + 2 / 3, y + 1, 0,
 | 
				
			||||||
 | 
					                x, y + 1, 0
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					            position.set(coordinates, positionSize * vertices * face);
 | 
				
			||||||
 | 
					            uv.set(uv1, uvSize * vertices * face);
 | 
				
			||||||
 | 
					            const fill = [face, face, face, face, face, face];
 | 
				
			||||||
 | 
					            faceIndex.set(fill, faceIndexSize * vertices * face);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const planes = new BufferGeometry();
 | 
				
			||||||
 | 
					        planes.setAttribute('position', new BufferAttribute(position, positionSize));
 | 
				
			||||||
 | 
					        planes.setAttribute('uv', new BufferAttribute(uv, uvSize));
 | 
				
			||||||
 | 
					        planes.setAttribute('faceIndex', new BufferAttribute(faceIndex, faceIndexSize));
 | 
				
			||||||
 | 
					        _lodPlanes.push(planes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (lod > LOD_MIN)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            lod--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return { _lodPlanes, _sizeLods, _sigmas };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _createRenderTarget(params)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const cubeUVRenderTarget = new WebGLRenderTarget(3 * SIZE_MAX, 3 * SIZE_MAX, params);
 | 
				
			||||||
 | 
					    cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;
 | 
				
			||||||
 | 
					    cubeUVRenderTarget.texture.name = 'PMREM.cubeUv';
 | 
				
			||||||
 | 
					    cubeUVRenderTarget.scissorTest = true;
 | 
				
			||||||
 | 
					    return cubeUVRenderTarget;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _setViewport(target, x, y, width, height)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    target.viewport.set(x, y, width, height);
 | 
				
			||||||
 | 
					    target.scissor.set(x, y, width, height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _getBlurShader(maxSamples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const weights = new Float32Array(maxSamples);
 | 
				
			||||||
 | 
					    const poleAxis = new Vector3(0, 1, 0);
 | 
				
			||||||
 | 
					    const shaderMaterial = new RawShaderMaterial({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        name: 'SphericalGaussianBlur',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        defines: { 'n': maxSamples },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uniforms: {
 | 
				
			||||||
 | 
					            'envMap': { value: null },
 | 
				
			||||||
 | 
					            'samples': { value: 1 },
 | 
				
			||||||
 | 
					            'weights': { value: weights },
 | 
				
			||||||
 | 
					            'latitudinal': { value: false },
 | 
				
			||||||
 | 
					            'dTheta': { value: 0 },
 | 
				
			||||||
 | 
					            'mipInt': { value: 0 },
 | 
				
			||||||
 | 
					            'poleAxis': { value: poleAxis },
 | 
				
			||||||
 | 
					            'inputEncoding': { value: ENCODINGS[LinearEncoding] },
 | 
				
			||||||
 | 
					            'outputEncoding': { value: ENCODINGS[LinearEncoding] }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        vertexShader: _getCommonVertexShader(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fragmentShader: /* glsl */`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								precision mediump float;
 | 
				
			||||||
 | 
								precision mediump int;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								varying vec3 vOutputDirection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								uniform sampler2D envMap;
 | 
				
			||||||
 | 
								uniform int samples;
 | 
				
			||||||
 | 
								uniform float weights[ n ];
 | 
				
			||||||
 | 
								uniform bool latitudinal;
 | 
				
			||||||
 | 
								uniform float dTheta;
 | 
				
			||||||
 | 
								uniform float mipInt;
 | 
				
			||||||
 | 
								uniform vec3 poleAxis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								${_getEncodings()}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								#define ENVMAP_TYPE_CUBE_UV
 | 
				
			||||||
 | 
								#include <cube_uv_reflection_fragment>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								vec3 getSample( float theta, vec3 axis ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									float cosTheta = cos( theta );
 | 
				
			||||||
 | 
									// Rodrigues' axis-angle rotation
 | 
				
			||||||
 | 
									vec3 sampleDirection = vOutputDirection * cosTheta
 | 
				
			||||||
 | 
										+ cross( axis, vOutputDirection ) * sin( theta )
 | 
				
			||||||
 | 
										+ axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return bilinearCubeUV( envMap, sampleDirection, mipInt );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								void main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if ( all( equal( axis, vec3( 0.0 ) ) ) ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									axis = normalize( axis );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
 | 
				
			||||||
 | 
									gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for ( int i = 1; i < n; i++ ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if ( i >= samples ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										float theta = dTheta * float( i );
 | 
				
			||||||
 | 
										gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );
 | 
				
			||||||
 | 
										gl_FragColor.rgb += weights[ i ] * getSample( theta, axis );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									gl_FragColor = linearToOutputTexel( gl_FragColor );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							`,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        blending: NoBlending,
 | 
				
			||||||
 | 
					        depthTest: false,
 | 
				
			||||||
 | 
					        depthWrite: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return shaderMaterial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _getEquirectShader()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const texelSize = new Vector2(1, 1);
 | 
				
			||||||
 | 
					    const shaderMaterial = new RawShaderMaterial({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        name: 'EquirectangularToCubeUV',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uniforms: {
 | 
				
			||||||
 | 
					            'envMap': { value: null },
 | 
				
			||||||
 | 
					            'texelSize': { value: texelSize },
 | 
				
			||||||
 | 
					            'inputEncoding': { value: ENCODINGS[LinearEncoding] },
 | 
				
			||||||
 | 
					            'outputEncoding': { value: ENCODINGS[LinearEncoding] }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        vertexShader: _getCommonVertexShader(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fragmentShader: /* glsl */`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								precision mediump float;
 | 
				
			||||||
 | 
								precision mediump int;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								varying vec3 vOutputDirection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								uniform sampler2D envMap;
 | 
				
			||||||
 | 
								uniform vec2 texelSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								${_getEncodings()}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								#include <common>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								void main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									vec3 outputDirection = normalize( vOutputDirection );
 | 
				
			||||||
 | 
									vec2 uv = equirectUv( outputDirection );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									vec2 f = fract( uv / texelSize - 0.5 );
 | 
				
			||||||
 | 
									uv -= f * texelSize;
 | 
				
			||||||
 | 
									vec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
 | 
				
			||||||
 | 
									uv.x += texelSize.x;
 | 
				
			||||||
 | 
									vec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
 | 
				
			||||||
 | 
									uv.y += texelSize.y;
 | 
				
			||||||
 | 
									vec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
 | 
				
			||||||
 | 
									uv.x -= texelSize.x;
 | 
				
			||||||
 | 
									vec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									vec3 tm = mix( tl, tr, f.x );
 | 
				
			||||||
 | 
									vec3 bm = mix( bl, br, f.x );
 | 
				
			||||||
 | 
									gl_FragColor.rgb = mix( tm, bm, f.y );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									gl_FragColor = linearToOutputTexel( gl_FragColor );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							`,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        blending: NoBlending,
 | 
				
			||||||
 | 
					        depthTest: false,
 | 
				
			||||||
 | 
					        depthWrite: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return shaderMaterial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _getCubemapShader()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const shaderMaterial = new RawShaderMaterial({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        name: 'CubemapToCubeUV',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uniforms: {
 | 
				
			||||||
 | 
					            'envMap': { value: null },
 | 
				
			||||||
 | 
					            'inputEncoding': { value: ENCODINGS[LinearEncoding] },
 | 
				
			||||||
 | 
					            'outputEncoding': { value: ENCODINGS[LinearEncoding] }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        vertexShader: _getCommonVertexShader(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fragmentShader: /* glsl */`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								precision mediump float;
 | 
				
			||||||
 | 
								precision mediump int;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								varying vec3 vOutputDirection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								uniform samplerCube envMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								${_getEncodings()}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								void main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
 | 
				
			||||||
 | 
									gl_FragColor.rgb = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ).rgb;
 | 
				
			||||||
 | 
									gl_FragColor = linearToOutputTexel( gl_FragColor );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							`,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        blending: NoBlending,
 | 
				
			||||||
 | 
					        depthTest: false,
 | 
				
			||||||
 | 
					        depthWrite: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return shaderMaterial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _getCommonVertexShader()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return /* glsl */`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							precision mediump float;
 | 
				
			||||||
 | 
							precision mediump int;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							attribute vec3 position;
 | 
				
			||||||
 | 
							attribute vec2 uv;
 | 
				
			||||||
 | 
							attribute float faceIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							varying vec3 vOutputDirection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// RH coordinate system; PMREM face-indexing convention
 | 
				
			||||||
 | 
							vec3 getDirection( vec2 uv, float face ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								uv = 2.0 * uv - 1.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								vec3 direction = vec3( uv, 1.0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if ( face == 0.0 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									direction = direction.zyx; // ( 1, v, u ) pos x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( face == 1.0 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									direction = direction.xzy;
 | 
				
			||||||
 | 
									direction.xz *= -1.0; // ( -u, 1, -v ) pos y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( face == 2.0 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									direction.x *= -1.0; // ( -u, v, 1 ) pos z
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( face == 3.0 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									direction = direction.zyx;
 | 
				
			||||||
 | 
									direction.xz *= -1.0; // ( -1, v, -u ) neg x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( face == 4.0 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									direction = direction.xzy;
 | 
				
			||||||
 | 
									direction.xy *= -1.0; // ( -u, -1, v ) neg y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( face == 5.0 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									direction.z *= -1.0; // ( u, v, -1 ) neg z
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return direction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								vOutputDirection = getDirection( uv, faceIndex );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // //从xz->z-up坐标系变换到 threejs坐标系
 | 
				
			||||||
 | 
					            mat3 ro = mat3(
 | 
				
			||||||
 | 
					                        1.0, 0.0, 0.0,
 | 
				
			||||||
 | 
					                        0.0, 0.0, -1.0,
 | 
				
			||||||
 | 
					                        0.0, 1.0, 0
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					            vOutputDirection = ro * vOutputDirection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								gl_Position = vec4( position, 1.0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _getEncodings()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return /* glsl */`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uniform int inputEncoding;
 | 
				
			||||||
 | 
							uniform int outputEncoding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#include <encodings_pars_fragment>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vec4 inputTexelToLinear( vec4 value ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if ( inputEncoding == 0 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( inputEncoding == 1 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return sRGBToLinear( value );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( inputEncoding == 2 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return RGBEToLinear( value );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( inputEncoding == 3 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return RGBMToLinear( value, 7.0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( inputEncoding == 4 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return RGBMToLinear( value, 16.0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( inputEncoding == 5 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return RGBDToLinear( value, 256.0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return GammaToLinear( value, 2.2 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vec4 linearToOutputTexel( vec4 value ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if ( outputEncoding == 0 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( outputEncoding == 1 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return LinearTosRGB( value );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( outputEncoding == 2 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return LinearToRGBE( value );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( outputEncoding == 3 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return LinearToRGBM( value, 7.0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( outputEncoding == 4 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return LinearToRGBM( value, 16.0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else if ( outputEncoding == 5 ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return LinearToRGBD( value, 256.0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return LinearToGamma( value, 2.2 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vec4 envMapTexelToLinear( vec4 color ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return inputTexelToLinear( color );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								src/common/PlaneExt.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/common/PlaneExt.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					import * as THREE from 'three';
 | 
				
			||||||
 | 
					import { Vector3, Line3, Plane } from "three";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class PlaneExt extends Plane
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    constructor(normal?: Vector3, constant?: number)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        super(normal, constant);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    intersectLine(line: Line3, optionalTarget?: Vector3, extendLine?: boolean): Vector3
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let v1 = new Vector3();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let result = optionalTarget || new Vector3();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let direction = line.delta(v1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let denominator = this.normal.dot(direction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (denominator === 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // line is coplanar, return origin
 | 
				
			||||||
 | 
					            if (this.distanceToPoint(line.start) === 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return result.copy(line.start);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // Unsure if this is the correct method to handle this case.
 | 
				
			||||||
 | 
					            return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let t = - (line.start.dot(this.normal) + this.constant) / denominator;
 | 
				
			||||||
 | 
					        //If you not extendLine,check intersect point in Line
 | 
				
			||||||
 | 
					        if (!extendLine && (t < 0 || t > 1))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return result.copy(direction).multiplyScalar(t).add(line.start);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    intersectRay(ray: THREE.Ray, optionalTarget?: Vector3, extendLine?: boolean): Vector3
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // 从射线初始位置
 | 
				
			||||||
 | 
					        let line = new THREE.Line3(ray.origin.clone(), ray.origin.clone().add(ray.direction));
 | 
				
			||||||
 | 
					        return this.intersectLine(line, optionalTarget, extendLine);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								src/common/Singleton.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/common/Singleton.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let instanceMap = new Map();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface PrototypeType<T> extends Function
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    prototype: T;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ConstructorFunctionType<T = any> extends PrototypeType<T>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    new(...args: any[]): T;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type ConstructorType<T = unknown, Static extends Record<string, any> = PrototypeType<T>> = (ConstructorFunctionType<T> | PrototypeType<T>) & {
 | 
				
			||||||
 | 
					    [Key in keyof Static]: Static[Key];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 构造单例类的静态类.
 | 
				
			||||||
 | 
					 * # Example:
 | 
				
			||||||
 | 
					 *     class A extends Singleton(){};
 | 
				
			||||||
 | 
					 *     //获得单例
 | 
				
			||||||
 | 
					 *     let a = A.GetInstance();
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export class Singleton
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected constructor() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //ref:https://github.com/Microsoft/TypeScript/issues/5863
 | 
				
			||||||
 | 
					    static GetInstance<T extends Singleton>(this: ConstructorType<T, typeof Singleton>): T
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (instanceMap.has(this))
 | 
				
			||||||
 | 
					            return instanceMap.get(this);
 | 
				
			||||||
 | 
					        //@ts-ignore
 | 
				
			||||||
 | 
					        let __instance__ = new this.prototype.constructor();
 | 
				
			||||||
 | 
					        instanceMap.set(this, __instance__);
 | 
				
			||||||
 | 
					        return __instance__;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										168
									
								
								src/common/Viewer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								src/common/Viewer.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
				
			|||||||
 | 
					import { Raycaster, Scene, Vector3, WebGLRenderer, type WebGLRendererParameters } from "three";
 | 
				
			||||||
 | 
					import { cZeroVec, GetBox, GetBoxArr } from "./GeUtils";
 | 
				
			||||||
 | 
					import { PlaneExt } from "./PlaneExt";
 | 
				
			||||||
 | 
					import { CameraUpdate } from "webcad_ue4_api";
 | 
				
			||||||
 | 
					import { CameraControls } from "./CameraControls";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class Viewer {
 | 
				
			||||||
 | 
					    m_LookTarget: any;
 | 
				
			||||||
 | 
					    m_Camera: CameraUpdate = new CameraUpdate();
 | 
				
			||||||
 | 
					    CameraCtrl: CameraControls;
 | 
				
			||||||
 | 
					    protected NeedUpdate: boolean = true;
 | 
				
			||||||
 | 
					    Renderer: WebGLRenderer;//渲染器  //暂时只用这个类型
 | 
				
			||||||
 | 
					    m_DomEl: HTMLElement;    //画布容器
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _Height: number = 0;
 | 
				
			||||||
 | 
					    _Width: number = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _Scene: Scene = new Scene();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get Scene() {
 | 
				
			||||||
 | 
					        return this._Scene;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UpdateRender()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.NeedUpdate = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {HTMLElement} canvasContainer 可以传入一个div或者一个画布
 | 
				
			||||||
 | 
					     * @memberof Viewer
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    constructor(canvasContainer: HTMLElement) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.m_DomEl = canvasContainer;
 | 
				
			||||||
 | 
					        this.initRender(canvasContainer);
 | 
				
			||||||
 | 
					        this.OnSize();
 | 
				
			||||||
 | 
					        this.StartRender();
 | 
				
			||||||
 | 
					        this.CameraCtrl = new CameraControls(this);
 | 
				
			||||||
 | 
					        window.addEventListener("resize", () => {
 | 
				
			||||||
 | 
					            this.OnSize();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //初始化render
 | 
				
			||||||
 | 
					    initRender(canvasContainer: HTMLElement) {
 | 
				
			||||||
 | 
					        let params: WebGLRendererParameters = {
 | 
				
			||||||
 | 
					            antialias: true,//antialias:true/false是否开启反锯齿
 | 
				
			||||||
 | 
					            precision: "highp",//precision:highp/mediump/lowp着色精度选择
 | 
				
			||||||
 | 
					            alpha: true//alpha:true/false是否可以设置背景色透明
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        this.Renderer = new WebGLRenderer(params);
 | 
				
			||||||
 | 
					        //加到画布
 | 
				
			||||||
 | 
					        canvasContainer.appendChild(this.Renderer.domElement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.Renderer.autoClear = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //如果设置,那么它希望所有的纹理和颜色都是预乘的伽玛。默认值为false。
 | 
				
			||||||
 | 
					        // this.Renderer.gammaInput = true;
 | 
				
			||||||
 | 
					        // this.Renderer.gammaOutput = true;
 | 
				
			||||||
 | 
					        // this.Renderer.shadowMap.enabled = true;
 | 
				
			||||||
 | 
					        // this.Renderer.toneMapping = ReinhardToneMapping;
 | 
				
			||||||
 | 
					        //设置设备像素比。 这通常用于HiDPI设备,以防止模糊输出画布。
 | 
				
			||||||
 | 
					        this.Renderer.setPixelRatio(window.devicePixelRatio);
 | 
				
			||||||
 | 
					        this.Renderer.physicallyCorrectLights = true;
 | 
				
			||||||
 | 
					        //this.Renderer.toneMappingExposure = Math.pow(1, 5.0); // to allow for very bright scenes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //设置它的背景色为黑色
 | 
				
			||||||
 | 
					        this.Renderer.setClearColor(0xffffff, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.OnSize();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OnSize = (width?: number, height?: number) => {
 | 
				
			||||||
 | 
					        this._Width = width ? width : this.m_DomEl.clientWidth;
 | 
				
			||||||
 | 
					        this._Height = height ? height : this.m_DomEl.clientHeight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //校验.成为2的倍数 避免外轮廓错误.
 | 
				
			||||||
 | 
					        if (this._Width % 2 == 1)
 | 
				
			||||||
 | 
					            this._Width -= 1;
 | 
				
			||||||
 | 
					        if (this._Height % 2 == 1)
 | 
				
			||||||
 | 
					            this._Height -= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.Renderer.setSize(this._Width, this._Height);
 | 
				
			||||||
 | 
					        this.m_Camera.SetSize(this._Width, this._Height);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    StartRender = () => {
 | 
				
			||||||
 | 
					        requestAnimationFrame(this.StartRender);
 | 
				
			||||||
 | 
					        if (this._Scene != null && this.NeedUpdate) {
 | 
				
			||||||
 | 
					            this.Render();
 | 
				
			||||||
 | 
					            this.NeedUpdate = false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    Render() {
 | 
				
			||||||
 | 
					        this.Renderer.render(this._Scene, this.m_Camera.Camera);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ScreenToWorld(pt: Vector3, planVec?: Vector3) {
 | 
				
			||||||
 | 
					        //变换和求交点
 | 
				
			||||||
 | 
					        let plan = new PlaneExt(planVec || new Vector3(0, 0, 1));
 | 
				
			||||||
 | 
					        let raycaster = new Raycaster();
 | 
				
			||||||
 | 
					        // 射线从相机射线向屏幕点位置
 | 
				
			||||||
 | 
					        raycaster.setFromCamera(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                x: (pt.x / this._Width) * 2 - 1,
 | 
				
			||||||
 | 
					                y: - (pt.y / this._Height) * 2 + 1
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            , this.m_Camera.Camera
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        plan.intersectRay(raycaster.ray, pt, true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    WorldToScreen(pt: Vector3) {
 | 
				
			||||||
 | 
					        let widthHalf = this._Width * 0.5;
 | 
				
			||||||
 | 
					        let heightHalf = this._Height * 0.5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pt.project(this.m_Camera.Camera);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pt.x = (pt.x * widthHalf) + widthHalf;
 | 
				
			||||||
 | 
					        pt.y = - (pt.y * heightHalf) + heightHalf;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 更新视角观测目标(物体中心)
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @memberof Viewer
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    UpdateLockTarget() {
 | 
				
			||||||
 | 
					        let renderList = this.Renderer.renderLists.get(this._Scene, this.m_Camera.Camera);
 | 
				
			||||||
 | 
					        let box = GetBoxArr(renderList.opaque.map(o => o.object));
 | 
				
			||||||
 | 
					        if (box)
 | 
				
			||||||
 | 
					            this.m_LookTarget = box.getCenter(new Vector3());
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            this.m_LookTarget = cZeroVec;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Rotate(mouseMove: Vector3) {
 | 
				
			||||||
 | 
					        this.m_Camera.Rotate(mouseMove, this.m_LookTarget);
 | 
				
			||||||
 | 
					        this.NeedUpdate = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Pan(mouseMove: Vector3) {
 | 
				
			||||||
 | 
					        this.m_Camera.Pan(mouseMove);
 | 
				
			||||||
 | 
					        this.NeedUpdate = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Zoom(scale: number, center?: Vector3) {
 | 
				
			||||||
 | 
					        this.m_Camera.Zoom(scale, center);
 | 
				
			||||||
 | 
					        this.NeedUpdate = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ZoomAll()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.m_Camera.ZoomExtentsBox3(GetBox(this._Scene, true));
 | 
				
			||||||
 | 
					        this.NeedUpdate = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ViewToTop() {
 | 
				
			||||||
 | 
					        this.m_Camera.LookAt(new Vector3(0, 0, -1));
 | 
				
			||||||
 | 
					        this.NeedUpdate = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ViewToFront() {
 | 
				
			||||||
 | 
					        this.m_Camera.LookAt(new Vector3(0, 1, 0));
 | 
				
			||||||
 | 
					        this.NeedUpdate = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ViewToSwiso() {
 | 
				
			||||||
 | 
					        this.m_Camera.LookAt(new Vector3(1, 1, -1));
 | 
				
			||||||
 | 
					        this.NeedUpdate = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										41
									
								
								src/components/MaterialView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/components/MaterialView.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div ref="container" style="width: 800px;height: 800px;"></div>
 | 
				
			||||||
 | 
					    {{ CurGeometryName }}
 | 
				
			||||||
 | 
					    <div v-for="geo in geometries">
 | 
				
			||||||
 | 
					        <button @click="changeGeometry(geo[0])">{{ geo[0] }}</button>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { onMounted, useTemplateRef } from 'vue';
 | 
				
			||||||
 | 
					import { MaterialEditor } from '../common/MaterialEditor';
 | 
				
			||||||
 | 
					import { PhysicalMaterialRecord } from 'webcad_ue4_api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const container = useTemplateRef<HTMLElement>('container');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let editor:MaterialEditor = MaterialEditor.GetInstance();
 | 
				
			||||||
 | 
					const geometries = editor.Geometrys;
 | 
				
			||||||
 | 
					const material = new PhysicalMaterialRecord();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const CurGeometryName = editor.CurGeometryName;
 | 
				
			||||||
 | 
					onMounted(() => {
 | 
				
			||||||
 | 
					    editor.SetViewer(container.value);
 | 
				
			||||||
 | 
					    editor.setMaterial(material);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const view = editor.Viewer;
 | 
				
			||||||
 | 
					    view.OnSize(800, 800);
 | 
				
			||||||
 | 
					    view.ZoomAll();
 | 
				
			||||||
 | 
					    view.Zoom(2.1);
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function changeGeometry(geoName:string) {
 | 
				
			||||||
 | 
					    CurGeometryName.value = geoName;
 | 
				
			||||||
 | 
					    let geo = editor.Geometrys.get(CurGeometryName.value);
 | 
				
			||||||
 | 
					    if (geo) {
 | 
				
			||||||
 | 
					        editor.ShowMesh.geometry = geo;
 | 
				
			||||||
 | 
					        editor.Viewer.UpdateRender();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
							
								
								
									
										6
									
								
								src/main.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/main.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					import { createApp } from 'vue'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import App from './App.vue'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					createApp(App).mount('#app')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/vite-env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/vite-env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					/// <reference types="vite/client" />
 | 
				
			||||||
							
								
								
									
										14
									
								
								tsconfig.app.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tsconfig.app.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "extends": "@vue/tsconfig/tsconfig.dom.json",
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Linting */
 | 
				
			||||||
 | 
					    "strict": false,
 | 
				
			||||||
 | 
					    // "noUnusedLocals": true,
 | 
				
			||||||
 | 
					    // "noUnusedParameters": true,
 | 
				
			||||||
 | 
					    // "noFallthroughCasesInSwitch": true,
 | 
				
			||||||
 | 
					    // "noUncheckedSideEffectImports": true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "files": [],
 | 
				
			||||||
 | 
					  "references": [
 | 
				
			||||||
 | 
					    { "path": "./tsconfig.app.json" },
 | 
				
			||||||
 | 
					    { "path": "./tsconfig.node.json" }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								tsconfig.node.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								tsconfig.node.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
 | 
				
			||||||
 | 
					    "target": "ES2022",
 | 
				
			||||||
 | 
					    "lib": ["ES2023"],
 | 
				
			||||||
 | 
					    "module": "ESNext",
 | 
				
			||||||
 | 
					    "skipLibCheck": true,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Bundler mode */
 | 
				
			||||||
 | 
					    "moduleResolution": "bundler",
 | 
				
			||||||
 | 
					    "allowImportingTsExtensions": true,
 | 
				
			||||||
 | 
					    "isolatedModules": true,
 | 
				
			||||||
 | 
					    "moduleDetection": "force",
 | 
				
			||||||
 | 
					    "noEmit": true,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Linting */
 | 
				
			||||||
 | 
					    "strict": true,
 | 
				
			||||||
 | 
					    "noUnusedLocals": true,
 | 
				
			||||||
 | 
					    "noUnusedParameters": true,
 | 
				
			||||||
 | 
					    "noFallthroughCasesInSwitch": true,
 | 
				
			||||||
 | 
					    "noUncheckedSideEffectImports": true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "include": ["vite.config.ts"]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								vite.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vite.config.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					import { defineConfig } from 'vite'
 | 
				
			||||||
 | 
					import vue from '@vitejs/plugin-vue'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://vite.dev/config/
 | 
				
			||||||
 | 
					export default defineConfig({
 | 
				
			||||||
 | 
					  plugins: [vue()],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
		Reference in New Issue
	
	Block a user