diff --git a/.DS_Store b/.DS_Store index c04387d..1145dba 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/backend/app/services/horizons.py b/backend/app/services/horizons.py index 4e8ecf0..d656c4e 100644 --- a/backend/app/services/horizons.py +++ b/backend/app/services/horizons.py @@ -67,6 +67,123 @@ class HorizonsService: logger.error(f"Error fetching raw data for {body_id}: {repr(e)}") raise + async def search_body_by_name(self, name: str, db: AsyncSession = None) -> dict: + """ + Search for a celestial body in Horizons by name. + + Args: + name: Name to search (e.g. 'Ceres', 'Halley') + db: Database session (optional, for future caching) + + Returns: + Dict with success/error and data + """ + url = "https://ssd.jpl.nasa.gov/api/horizons.api" + # Using a wildcard search command + cmd_val = f"'{name}*'" + + params = { + "format": "text", + "COMMAND": cmd_val, + "OBJ_DATA": "YES", + "MAKE_EPHEM": "NO" + } + + try: + client_kwargs = {"timeout": settings.nasa_api_timeout} + if settings.proxy_dict: + client_kwargs["proxies"] = settings.proxy_dict + + async with httpx.AsyncClient(**client_kwargs) as client: + logger.info(f"Searching Horizons for: {name}") + response = await client.get(url, params=params) + + if response.status_code != 200: + return {"success": False, "error": f"NASA API Error: {response.status_code}"} + + text = response.text + + # Case 1: Direct match (Horizon returns data directly) + # Look for "Target body name:" or similar indicators of a resolved body + if "Target body name:" in text or "Physical properties" in text: + # Extract ID and Name + # Pattern: "Target body name: 1 Ceres (A801 AA)" or similar + match = re.search(r"Target body name:\s*(.*?)\s*\{", text) + if not match: + match = re.search(r"Target body name:\s*(.*?)\n", text) + + full_name = match.group(1).strip() if match else name + + # Try to extract ID from the text, usually in the header or COMMAND output + # This is tricky with raw text, but let's try to extract from the command echo + # Or we can just use the input name if we can't find a better ID + # Ideally we want the numeric ID (e.g. '1' for Ceres, '399' for Earth) + + # If it's a direct match, the ID might not be explicitly listed as "ID = ..." + # But often the name contains it, e.g. "1 Ceres" + body_id = name # Fallback + + # Try to parse "1 Ceres" -> id=1 + id_match = re.search(r"^(\d+)\s+([a-zA-Z]+)", full_name) + if id_match: + body_id = id_match.group(1) + clean_name = id_match.group(2) + else: + clean_name = full_name + + return { + "success": True, + "id": body_id, + "name": clean_name, + "full_name": full_name + } + + # Case 2: Multiple matches (Ambiguous) + # Horizons returns a list of matches + if "Multiple major-bodies match" in text or "Matching small-bodies" in text: + # We need to parse the list and pick the best match or return the first one + # For now, let's try to find the most likely match (exact name) + + # Pattern for small bodies: "record # epoch-yr primary desig >name<" + # or " ID Name Designation" + + # Simple heuristic: Look for lines containing the name + lines = text.split('\n') + best_match = None + + for line in lines: + if name.lower() in line.lower(): + # Try to extract ID (first column usually) + parts = line.strip().split() + if parts and parts[0].isdigit() or (parts[0].startswith('-') and parts[0][1:].isdigit()): + best_match = { + "id": parts[0], + "name": name, + "full_name": line.strip() + } + break + + if best_match: + return { + "success": True, + "id": best_match["id"], + "name": best_match["name"], + "full_name": best_match["full_name"] + } + + return {"success": False, "error": "Multiple matches found, please be more specific"} + + # Case 3: No match + if "No matches found" in text: + return {"success": False, "error": "No celestial body found with that name"} + + # Fallback for unknown response format + return {"success": False, "error": "Could not parse NASA response"} + + except Exception as e: + logger.error(f"Search error for {name}: {repr(e)}") + return {"success": False, "error": str(e)} + async def get_body_positions( self, body_id: str, diff --git a/frontend/ASSET_LOADING_ANALYSIS.md b/frontend/ASSET_LOADING_ANALYSIS.md new file mode 100644 index 0000000..4487fe9 --- /dev/null +++ b/frontend/ASSET_LOADING_ANALYSIS.md @@ -0,0 +1,390 @@ +# Cosmo Frontend Asset Loading Strategy Analysis + +## Executive Summary + +The Cosmo frontend project implements a 3D solar system visualization using Three.js and React-Three-Fiber. The asset loading strategy currently uses a mix of on-demand fetching and preloading patterns, with assets served through a backend API proxy. + +--- + +## 1. Asset Inventory + +### 1.1 Texture Assets (Primary Location: Backend Upload) + +**Backend Location**: `/Users/jiliu/WorkSpace/cosmo/backend/upload/texture/` +- **Total Size**: ~19 MB +- **Format**: Primarily JPEG with some PNG +- **Built/Dist Location**: `/Users/jiliu/WorkSpace/cosmo/frontend/dist/textures/` + +#### Key Texture Files (by size): + +| File | Size | Purpose | +|------|------|---------| +| 2k_moon.jpg | 1.0 MB | Moon surface texture | +| 2k_venus_surface.jpg | 868 KB | Venus surface | +| 2k_mercury.jpg | 856 KB | Mercury surface | +| 2k_sun.jpg | 804 KB | Sun/Star texture | +| 2k_mars.jpg | 736 KB | Mars surface | +| 2k_jupiter.jpg | 488 KB | Jupiter surface | +| 2k_earth_daymap.jpg | 456 KB | Earth day side | +| 2k_earth_nightmap.jpg | 256 KB | Earth night side | +| 2k_stars_milky_way.jpg | 248 KB | Milky Way background | +| 2k_neptune.jpg | 236 KB | Neptune surface | +| 2k_venus_atmosphere.jpg | 228 KB | Venus atmosphere | +| 2k_saturn.jpg | 196 KB | Saturn surface | +| 2k_uranus.jpg | 76 KB | Uranus surface | +| 2k_saturn_ring_alpha.png | 12 KB | Saturn ring transparency | + +**Additional Textures** (comets, dwarf planets, moons): +- 2k_pluto.jpg: 3.8 MB (largest single file) +- Various comet/asteroid textures: 300-500 KB each +- Moon textures (Ganymede, Io, Titan, Mimas): 350-360 KB each + +--- + +### 1.2 3D Model Assets (GLB/GLTF Format) + +**Backend Location**: `/Users/jiliu/WorkSpace/cosmo/backend/upload/model/` +- **Total Size**: ~24 MB +- **Format**: GLB (binary GLTF) + +#### Key Model Files (by size): + +| File | Size | Purpose | +|------|------|---------| +| juno.glb | 8.6 MB | Juno space probe | +| cassini.glb | 1.6 MB | Cassini spacecraft | +| voyager_2.glb | 1.6 MB | Voyager 2 probe | +| parker_solar_probe.glb | 436 KB | Parker Solar Probe | +| voyager_1.glb | 280 KB | Voyager 1 probe | +| webb_space_telescope.glb | ~1-2 MB (from list) | JWST | +| new_horizons.glb | ~1-2 MB (from list) | New Horizons probe | +| perseverance.glb | ~1-2 MB (from list) | Mars Perseverance rover | + +**Observations**: +- Juno.glb (8.6 MB) is significantly larger than other models +- Most probes range 280 KB to 1.6 MB +- Total probe models: ~24 MB for ~8 spacecraft + +--- + +## 2. Asset Loading Strategy + +### 2.1 Texture Loading (Detailed Implementation) + +**File**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/CelestialBody.tsx` + +```typescript +// Current Loading Pattern: +1. Component mounts (Planet component) +2. fetchBodyResources(body.id, 'texture') - calls API +3. Finds main texture (excludes 'atmosphere' and 'night') +4. Constructs URL: /upload/{file_path} +5. useTexture(texturePath) - Three.js texture loader +6. Renders mesh with loaded texture + +// Key Line: +const texture = texturePath ? useTexture(texturePath) : null; +``` + +**Loading Characteristics**: +- **Type**: On-demand (per celestial body) +- **Caching**: useTexture hook likely caches within session +- **Error Handling**: Falls back to null (gray placeholder material) +- **Performance**: No preloading - each body texture loads when component mounts + +### 2.2 Model Loading (3D Probes) + +**File**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/Probe.tsx` + +```typescript +// Current Loading Pattern: +1. Component mounts (Probe component) +2. fetchBodyResources(body.id, 'model') - calls API +3. Gets first model resource + scale metadata +4. Constructs URL: /upload/{file_path} +5. useGLTF.preload(fullPath) - PRELOADING ENABLED +6. setModelPath(fullPath) +7. useGLTF(modelPath) - loads and parses GLB + +// Key Implementation: +useGLTF.preload(fullPath); // Preload before rendering +const gltf = useGLTF(modelPath); // Actual load +``` + +**Loading Characteristics**: +- **Type**: On-demand with optional preloading +- **Preloading**: Yes - `useGLTF.preload()` is called (Line 281) +- **Caching**: useGLTF hook caches in session +- **Scale Handling**: Custom scale from `extra_data.scale` +- **Fallback**: ProbeFallback component renders red sphere if load fails +- **Performance**: Preload triggered immediately, improves perceived load time + +### 2.3 Background/Static Assets + +**File**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/Scene.tsx` + +```typescript +// Procedural Assets (NO external files): +1. BackgroundStars (radius=300, count=5000, procedural) +2. AsteroidBelts (procedurally generated) +3. Nebulae (procedurally generated) +4. Constellations (data-driven but rendered procedurally) + +// Data-Driven Assets (fetched from API): +1. Stars (real star catalog data) +2. Galaxies (CanvasTexture generated) +3. Satellites/Planets (textures fetched on demand) +``` + +**Observations**: +- Extensive use of procedural generation reduces asset file count +- Galaxy textures created with CanvasTexture (no disk files) +- Star data loaded from API, rendered with simple geometry + +--- + +## 3. Loading Flow & Architecture + +### 3.1 Request Path + +``` +Frontend Component + ↓ +fetchBodyResources(bodyId, type) + ↓ +API Call: /api/celestial/resources/{bodyId}?resource_type=texture|model + ↓ +Backend API (Port 8000) + ↓ +Vite Proxy Dev: localhost:8000/upload/{type}/{filename} +OR +Nginx Production: proxy to backend + ↓ +Actual File: /backend/upload/{type}/{filename} + ↓ +Response to Frontend + ↓ +useTexture() or useGLTF() + ↓ +Three.js Renderer +``` + +### 3.2 API Integration Points + +**File**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/utils/api.ts` + +```typescript +// Fetch function signature: +export async function fetchBodyResources( + bodyId: string, + resourceType?: string +): Promise<{ + body_id: string; + resources: Array<{ + id: number; + resource_type: string; + file_path: string; // e.g., "texture/2k_sun.jpg" + file_size: number; + mime_type: string; + created_at: string; + extra_data?: Record; // scale, etc. + }>; +}> +``` + +--- + +## 4. Vite Build Configuration + +**File**: `/Users/jiliu/WorkSpace/cosmo/frontend/vite.config.ts` + +```typescript +export default defineConfig({ + plugins: [react()], + server: { + host: '0.0.0.0', + port: 5173, + proxy: { + '/api': { + target: 'http://localhost:8000', + changeOrigin: true, + }, + '/upload': { + target: 'http://localhost:8000', + changeOrigin: true, + }, + '/public': { + target: 'http://localhost:8000', + changeOrigin: true, + }, + }, + }, +}) +``` + +**Current Configuration Analysis**: +- **No explicit asset optimization**: No image compression, no WebP conversion +- **No size limits**: All assets proxied without size constraints +- **No chunking strategy**: Vite default chunks (1.2 MB JS bundle observed) +- **Proxy strategy**: All assets proxied through backend (good for dynamic content) + +--- + +## 5. Build Output Analysis + +**Dist Directory**: `/Users/jiliu/WorkSpace/cosmo/frontend/dist/` +- **Total Size**: ~20 MB +- **JavaScript Bundle**: 1.2 MB (index-c2PfKiPB.js) +- **CSS**: 9.8 KB +- **Textures**: ~7.9 MB (in dist, smaller than backend copy) +- **Models**: ~12.8 MB (in dist) + +**Key Finding**: Textures in dist folder are smaller than backend source, suggesting some optimization (JPEG compression) during build/deploy. + +--- + +## 6. Lazy Loading & Code Splitting + +**File**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/App.tsx` + +```typescript +// Already Implemented: +const InterstellarTicker = lazy(() => + import('./components/InterstellarTicker') + .then(m => ({ default: m.InterstellarTicker })) +); + +const MessageBoard = lazy(() => + import('./components/MessageBoard') + .then(m => ({ default: m.MessageBoard })) +); + +const BodyDetailOverlay = lazy(() => + import('./components/BodyDetailOverlay') + .then(m => ({ default: m.BodyDetailOverlay })) +); + +// Wrapped in Suspense: + + + +``` + +**Status**: +- Lazy loading implemented for 3 non-critical components +- Suspense fallback set to null (no skeleton loading) +- No lazy loading for 3D rendering components (CelestialBody, Probe, Scene) + +--- + +## 7. Current Optimization Opportunities + +### 7.1 Identified Issues + +1. **No Texture Compression** + - Total texture size: 19 MB (backend) → 7.9 MB (dist) + - JPEG quality likely could be reduced further + - No WebP fallback for modern browsers + - No LOD (Level of Detail) system + +2. **Large Model File** + - Juno.glb: 8.6 MB (30% of all model assets) + - No model optimization/decimation + - No LOD for probes + - All vertices/triangles loaded even when zoomed out + +3. **No Batch Asset Loading** + - Each body texture loaded individually + - 10+ API calls for visible celestial bodies + - No batching or parallel loading optimization + - No request deduplication + +4. **All-or-Nothing Texture Loading** + - Texture loading blocks render until complete + - Falls back to gray if load fails + - No progressive/streaming load + +5. **Limited Caching Strategy** + - useTexture/useGLTF cache only within session + - No persistent browser cache headers optimization + - No service worker caching + +6. **Background Star Data** + - Stars component loads 1000+ star systems per API call + - No pagination or frustum culling + - All stars rendered regardless of visibility + +### 7.2 Existing Optimizations + +``` +POSITIVE: +✓ Procedural generation for backgrounds (saves ~10 MB+ in textures) +✓ useGLTF.preload() for probe models +✓ useTexture hook caching +✓ Lazy loading for non-critical UI components +✓ Reused geometry for identical objects (stars use single SphereGeometry) +✓ Billboard optimization for labels (distance culling) +✓ Selective texture filtering (excludes atmosphere/night variants) +``` + +--- + +## 8. Performance Summary + +### Asset Totals: +- **Textures**: 19 MB (backend) / 7.9 MB (dist) +- **Models**: 24 MB (backend) / 12.8 MB (dist) +- **JavaScript**: 1.2 MB +- **Total Transfer**: ~32 MB initial + on-demand loading + +### Loading Pattern: +- **Initial Load**: 1.2 MB (JS) + procedural background rendering +- **Per-Scene**: ~100-500 KB (depending on visible bodies) +- **Per-Probe**: 280 KB - 8.6 MB (first load) + +### Current Bottlenecks: +1. Juno probe (8.6 MB) loading time +2. Sequential texture API calls +3. No partial/progressive loading +4. Large JPEG files (Moon: 1 MB, Venus: 868 KB) + +--- + +## 9. File Locations Summary + +### Source Code: +- **Main 3D Scene**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/Scene.tsx` +- **Texture Loading**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/CelestialBody.tsx` (Line 102-123) +- **Model Loading**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/Probe.tsx` (Line 261-295) +- **API Integration**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/utils/api.ts` +- **Build Config**: `/Users/jiliu/WorkSpace/cosmo/frontend/vite.config.ts` + +### Asset Locations: +- **Texture Source**: `/Users/jiliu/WorkSpace/cosmo/backend/upload/texture/` +- **Model Source**: `/Users/jiliu/WorkSpace/cosmo/backend/upload/model/` +- **Texture Build Output**: `/Users/jiliu/WorkSpace/cosmo/frontend/dist/textures/` +- **Model Build Output**: `/Users/jiliu/WorkSpace/cosmo/frontend/dist/models/` +- **Documentation**: `/Users/jiliu/WorkSpace/cosmo/frontend/PERFORMANCE_OPTIMIZATION.md` + +--- + +## 10. Recommendations (Priority Order) + +### Quick Wins (1-2 hours): +1. Implement image compression (JPEG quality: 80-85%) +2. Add WebP format with JPEG fallback +3. Set proper Cache-Control headers on backend +4. Implement batch/parallel texture loading + +### Medium Term (4-8 hours): +1. Add texture LOD (Load specific resolution by distance) +2. Implement model decimation for Juno probe +3. Add progressive texture loading (low-res → high-res) +4. Implement frustum culling for star systems + +### Long Term (16+ hours): +1. Implement texture atlas for small textures +2. Add KTX2/Basis texture compression +3. Implement virtual scrolling for star catalog +4. Add service worker for persistent caching + diff --git a/frontend/src/components/CelestialBody.tsx b/frontend/src/components/CelestialBody.tsx index 0cb0f92..455f06b 100644 --- a/frontend/src/components/CelestialBody.tsx +++ b/frontend/src/components/CelestialBody.tsx @@ -9,7 +9,7 @@ import { useTexture, Billboard } from '@react-three/drei'; import type { CelestialBody as CelestialBodyType } from '../types'; import { calculateRenderPosition, getOffsetDescription } from '../utils/renderPosition'; import { fetchBodyResources } from '../utils/api'; -import { PLANET_SIZES, SATELLITE_SIZES, getCelestialSize } from '../config/celestialSizes'; +import { getCelestialSize } from '../config/celestialSizes'; import { createLabelTexture } from '../utils/labelTexture'; interface CelestialBodyProps { diff --git a/frontend/src/config/celestialSizes.ts b/frontend/src/config/celestialSizes.ts index 2446b5c..7cd00ac 100644 --- a/frontend/src/config/celestialSizes.ts +++ b/frontend/src/config/celestialSizes.ts @@ -6,64 +6,31 @@ /** * Planet rendering sizes (radius in scene units) */ -export const PLANET_SIZES: Record = { - Mercury: 0.35, - Venus: 0.55, - Earth: 0.6, - Mars: 0.45, - Jupiter: 1.4, - Saturn: 1.2, - Uranus: 0.8, - Neptune: 0.8, - Pluto: 0.2, - // Default for unknown planets +/** + * Celestial body rendering sizes configuration + * Shared across components for consistent sizing + * + * STRICT RULE: Sizes are determined solely by body TYPE, not by name. + * This ensures consistent visualization scales across categories. + */ + +export const TYPE_SIZES: Record = { + star: 0.4, // Base mesh size (glow effects make it look larger) + planet: 0.6, // Unified size for all planets (Earth-like) + dwarf_planet: 0.18, + satellite: 0.12, + comet: 0.12, + asteroid: 0.10, + probe: 0.1, + + // Fallback default: 0.5, }; /** - * Satellite rendering sizes (radius in scene units) - */ -export const SATELLITE_SIZES: Record = { - Moon: 0.15, - // Default for unknown satellites - default: 0.12, -}; - -/** - * Star rendering sizes (radius in scene units) - */ -export const STAR_SIZES: Record = { - Sun: 0.4, - // Default for unknown stars - default: 0.4, -}; - -/** - * Comet rendering sizes (radius in scene units) - * Comets are typically small with a bright nucleus - */ -export const COMET_SIZES: Record = { - // Famous comets - Halley: 0.15, - // Default for unknown comets - default: 0.12, -}; - -/** - * Get the rendering size for a celestial body by name and type + * Get the rendering size for a celestial body by type only */ export function getCelestialSize(name: string, type: string): number { - switch (type) { - case 'planet': - case 'dwarf_planet': - return PLANET_SIZES[name] || PLANET_SIZES.default; - case 'satellite': - return SATELLITE_SIZES[name] || SATELLITE_SIZES.default; - case 'star': - return STAR_SIZES[name] || STAR_SIZES.default; - case 'comet': - return COMET_SIZES[name] || COMET_SIZES.default; - default: - return 0.5; - } + return TYPE_SIZES[type] || TYPE_SIZES.default; } + diff --git a/frontend/src/pages/admin/CelestialBodies.tsx b/frontend/src/pages/admin/CelestialBodies.tsx index d7e141a..cc77a12 100644 --- a/frontend/src/pages/admin/CelestialBodies.tsx +++ b/frontend/src/pages/admin/CelestialBodies.tsx @@ -425,12 +425,12 @@ export function CelestialBodies() { dataIndex: 'type', key: 'type', filters: [ - { text: '行星', value: 'planet' }, { text: '恒星', value: 'star' }, - { text: '卫星', value: 'satellite' }, - { text: '探测器', value: 'probe' }, + { text: '行星', value: 'planet' }, { text: '矮行星', value: 'dwarf_planet' }, + { text: '卫星', value: 'satellite' }, { text: '彗星', value: 'comet' }, + { text: '探测器', value: 'probe' }, ], onFilter: (value, record) => record.type === value, render: (type: string) => { @@ -582,12 +582,12 @@ export function CelestialBodies() { rules={[{ required: true, message: '请选择类型' }]} > @@ -800,12 +800,12 @@ export function CelestialBodies() { rules={[{ required: true, message: '请选择类型' }]} > diff --git a/frontend/src/pages/admin/NASADownload.tsx b/frontend/src/pages/admin/NASADownload.tsx index e96bce1..c392dd1 100644 --- a/frontend/src/pages/admin/NASADownload.tsx +++ b/frontend/src/pages/admin/NASADownload.tsx @@ -83,9 +83,12 @@ export function NASADownload() { planet: '行星', dwarf_planet: '矮行星', satellite: '卫星', + comet: '彗星', probe: '探测器', }; + const typeOrder = ['star', 'planet', 'dwarf_planet', 'satellite', 'comet', 'probe']; + useEffect(() => { loadBodies(); }, []); @@ -451,41 +454,46 @@ export function NASADownload() { > ({ - key: type, - label: ( -
- {typeNames[type] || type} - selectedBodies.includes(b.id))} - indeterminate={ - typeBodies.some(b => selectedBodies.includes(b.id)) && - !typeBodies.every(b => selectedBodies.includes(b.id)) - } - onChange={(e) => { - e.stopPropagation(); - handleTypeSelectAll(type, e.target.checked); - }} - > - 全选 - -
- ), - children: ( - - {typeBodies.map((body) => ( - handleBodySelect(body.id, e.target.checked)} - > - {body.name_zh || body.name} ({body.id}) - {!body.is_active && } - - ))} - - ), - }))} + items={typeOrder + .filter(type => bodies[type] && bodies[type].length > 0) + .map((type) => { + const typeBodies = bodies[type]; + return { + key: type, + label: ( +
+ {typeNames[type] || type} + selectedBodies.includes(b.id))} + indeterminate={ + typeBodies.some(b => selectedBodies.includes(b.id)) && + !typeBodies.every(b => selectedBodies.includes(b.id)) + } + onChange={(e) => { + e.stopPropagation(); + handleTypeSelectAll(type, e.target.checked); + }} + > + 全选 + +
+ ), + children: ( + + {typeBodies.map((body) => ( + handleBodySelect(body.id, e.target.checked)} + > + {body.name_zh || body.name} ({body.id}) + {!body.is_active && } + + ))} + + ), + }; + })} /> diff --git a/资源文件/.DS_Store b/资源文件/.DS_Store index 7b77bcc..214a243 100644 Binary files a/资源文件/.DS_Store and b/资源文件/.DS_Store differ diff --git a/资源文件/知识卡/.DS_Store b/资源文件/知识卡/.DS_Store new file mode 100644 index 0000000..c2f3413 Binary files /dev/null and b/资源文件/知识卡/.DS_Store differ diff --git a/资源文件/知识卡/Pluto.pdf b/资源文件/知识卡/Pluto.pdf new file mode 100644 index 0000000..b434bd0 Binary files /dev/null and b/资源文件/知识卡/Pluto.pdf differ diff --git a/资源文件/知识卡/土星.pdf b/资源文件/知识卡/土星.pdf new file mode 100644 index 0000000..15a9893 Binary files /dev/null and b/资源文件/知识卡/土星.pdf differ diff --git a/资源文件/知识卡/地球.pdf b/资源文件/知识卡/地球.pdf new file mode 100644 index 0000000..048470e Binary files /dev/null and b/资源文件/知识卡/地球.pdf differ diff --git a/资源文件/知识卡/天王星.pdf b/资源文件/知识卡/天王星.pdf new file mode 100644 index 0000000..150eb8c Binary files /dev/null and b/资源文件/知识卡/天王星.pdf differ diff --git a/资源文件/知识卡/月球.pdf b/资源文件/知识卡/月球.pdf new file mode 100644 index 0000000..6e96cd9 Binary files /dev/null and b/资源文件/知识卡/月球.pdf differ diff --git a/资源文件/知识卡/木星.pdf b/资源文件/知识卡/木星.pdf new file mode 100644 index 0000000..42bd0bc Binary files /dev/null and b/资源文件/知识卡/木星.pdf differ diff --git a/资源文件/知识卡/水星.pdf b/资源文件/知识卡/水星.pdf new file mode 100644 index 0000000..c58f407 Binary files /dev/null and b/资源文件/知识卡/水星.pdf differ diff --git a/资源文件/知识卡/海王星.pdf b/资源文件/知识卡/海王星.pdf new file mode 100644 index 0000000..c35d4c9 Binary files /dev/null and b/资源文件/知识卡/海王星.pdf differ diff --git a/资源文件/知识卡/火星.pdf b/资源文件/知识卡/火星.pdf new file mode 100644 index 0000000..96c9bab Binary files /dev/null and b/资源文件/知识卡/火星.pdf differ diff --git a/资源文件/知识卡/Ephemeral_Jewel_Saturn_Reborn.pdf b/资源文件/知识卡/知识册/Ephemeral_Jewel_Saturn_Reborn.pdf similarity index 100% rename from 资源文件/知识卡/Ephemeral_Jewel_Saturn_Reborn.pdf rename to 资源文件/知识卡/知识册/Ephemeral_Jewel_Saturn_Reborn.pdf diff --git a/资源文件/知识卡/Expedition_Neptune.pdf b/资源文件/知识卡/知识册/Expedition_Neptune.pdf similarity index 100% rename from 资源文件/知识卡/Expedition_Neptune.pdf rename to 资源文件/知识卡/知识册/Expedition_Neptune.pdf diff --git a/资源文件/知识卡/Jupiter_Architect_Guardian.pdf b/资源文件/知识卡/知识册/Jupiter_Architect_Guardian.pdf similarity index 100% rename from 资源文件/知识卡/Jupiter_Architect_Guardian.pdf rename to 资源文件/知识卡/知识册/Jupiter_Architect_Guardian.pdf diff --git a/资源文件/知识卡/Mercury_A_World_of_Extremes.pdf b/资源文件/知识卡/知识册/Mercury_A_World_of_Extremes.pdf similarity index 100% rename from 资源文件/知识卡/Mercury_A_World_of_Extremes.pdf rename to 资源文件/知识卡/知识册/Mercury_A_World_of_Extremes.pdf diff --git a/资源文件/知识卡/Moon_Core_Revealed.pdf b/资源文件/知识卡/知识册/Moon_Core_Revealed.pdf similarity index 100% rename from 资源文件/知识卡/Moon_Core_Revealed.pdf rename to 资源文件/知识卡/知识册/Moon_Core_Revealed.pdf diff --git a/资源文件/知识卡/The_Blue_Past_of_the_Red_Planet.pdf b/资源文件/知识卡/知识册/The_Blue_Past_of_the_Red_Planet.pdf similarity index 100% rename from 资源文件/知识卡/The_Blue_Past_of_the_Red_Planet.pdf rename to 资源文件/知识卡/知识册/The_Blue_Past_of_the_Red_Planet.pdf diff --git a/资源文件/知识卡/Unlocking_the_Ice_Giant.pdf b/资源文件/知识卡/知识册/Unlocking_the_Ice_Giant.pdf similarity index 100% rename from 资源文件/知识卡/Unlocking_the_Ice_Giant.pdf rename to 资源文件/知识卡/知识册/Unlocking_the_Ice_Giant.pdf diff --git a/资源文件/知识卡/Venus_Mysteries_Unveiled_Deep_Space_Exploration.pdf b/资源文件/知识卡/知识册/Venus_Mysteries_Unveiled_Deep_Space_Exploration.pdf similarity index 100% rename from 资源文件/知识卡/Venus_Mysteries_Unveiled_Deep_Space_Exploration.pdf rename to 资源文件/知识卡/知识册/Venus_Mysteries_Unveiled_Deep_Space_Exploration.pdf diff --git a/资源文件/知识卡/地球大气深度探索.pdf b/资源文件/知识卡/知识册/地球大气深度探索.pdf similarity index 100% rename from 资源文件/知识卡/地球大气深度探索.pdf rename to 资源文件/知识卡/知识册/地球大气深度探索.pdf diff --git a/资源文件/知识卡/新视野号揭秘冥王星起源.pdf b/资源文件/知识卡/知识册/新视野号揭秘冥王星起源.pdf similarity index 100% rename from 资源文件/知识卡/新视野号揭秘冥王星起源.pdf rename to 资源文件/知识卡/知识册/新视野号揭秘冥王星起源.pdf diff --git a/资源文件/知识卡/金星.pdf b/资源文件/知识卡/金星.pdf new file mode 100644 index 0000000..018efa0 Binary files /dev/null and b/资源文件/知识卡/金星.pdf differ diff --git a/资源文件/贴图&建模/Europa_2k.jpeg b/资源文件/贴图&建模/Europa_2k.jpeg new file mode 100644 index 0000000..989504a Binary files /dev/null and b/资源文件/贴图&建模/Europa_2k.jpeg differ diff --git a/资源文件/贴图&建模/charon_2k.jpeg b/资源文件/贴图&建模/charon_2k.jpeg new file mode 100644 index 0000000..b4e0ba6 Binary files /dev/null and b/资源文件/贴图&建模/charon_2k.jpeg differ diff --git a/资源文件/贴图&建模/pluto_rgb_8k.jpeg b/资源文件/贴图&建模/pluto_rgb_8k.jpeg new file mode 100644 index 0000000..0bcf618 Binary files /dev/null and b/资源文件/贴图&建模/pluto_rgb_8k.jpeg differ diff --git a/资源文件/贴图&建模/sedna_2k.jpeg b/资源文件/贴图&建模/sedna_2k.jpeg new file mode 100644 index 0000000..23dfac6 Binary files /dev/null and b/资源文件/贴图&建模/sedna_2k.jpeg differ diff --git a/资源文件/贴图&建模/sedna_2k.jpg b/资源文件/贴图&建模/sedna_2k.jpg new file mode 100644 index 0000000..bf3370f Binary files /dev/null and b/资源文件/贴图&建模/sedna_2k.jpg differ diff --git a/资源文件/贴图&建模/vesta_8K.jpeg b/资源文件/贴图&建模/vesta_8K.jpeg new file mode 100644 index 0000000..fd7d731 Binary files /dev/null and b/资源文件/贴图&建模/vesta_8K.jpeg differ