@@ -36,64 +36,145 @@ export function createDoug(scene, gradientMap) { |
| 36 | 36 | color: eyePupil |
| 37 | 37 | }) |
| 38 | 38 | |
| 39 | | - // Body - stretched sphere |
| 40 | | - const bodyGeom = new THREE.SphereGeometry(0.5, 16, 12) |
| 41 | | - bodyGeom.scale(1.2, 0.9, 1) |
| 39 | + // Body - elongated pear shape using multiple parts |
| 40 | + // Main body (more oval, less ball) |
| 41 | + const bodyGeom = new THREE.SphereGeometry(0.42, 8, 6) // Lower poly for angular look |
| 42 | + bodyGeom.scale(1.4, 0.75, 0.9) |
| 42 | 43 | const body = new THREE.Mesh(bodyGeom, bodyMaterial) |
| 43 | | - body.position.y = 0.3 |
| 44 | + body.position.y = 0.28 |
| 45 | + body.rotation.z = 0.1 // Slight tilt forward |
| 44 | 46 | group.add(body) |
| 45 | 47 | |
| 46 | | - // Body highlight (chest area) |
| 47 | | - const chestGeom = new THREE.SphereGeometry(0.35, 12, 8) |
| 48 | | - chestGeom.scale(1, 0.8, 0.8) |
| 48 | + // Rear bump (makes it pear-shaped) |
| 49 | + const rearGeom = new THREE.SphereGeometry(0.28, 6, 5) |
| 50 | + rearGeom.scale(1, 0.8, 0.9) |
| 51 | + const rear = new THREE.Mesh(rearGeom, bodyMaterial) |
| 52 | + rear.position.set(-0.35, 0.22, 0) |
| 53 | + group.add(rear) |
| 54 | + |
| 55 | + // Chest puff (front bump) |
| 56 | + const chestGeom = new THREE.SphereGeometry(0.25, 6, 5) |
| 57 | + chestGeom.scale(0.8, 0.9, 0.85) |
| 49 | 58 | const chest = new THREE.Mesh(chestGeom, highlightMaterial) |
| 50 | | - chest.position.set(0.15, 0.35, 0.2) |
| 59 | + chest.position.set(0.25, 0.32, 0) |
| 51 | 60 | group.add(chest) |
| 52 | 61 | |
| 53 | | - // Tail feathers |
| 62 | + // Scraggly feather tufts on body |
| 63 | + const tuftMaterial = bodyMaterial |
| 64 | + const featherPositions = [ |
| 65 | + { x: -0.4, y: 0.45, z: 0.15, rx: 0.3, rz: 0.5 }, |
| 66 | + { x: -0.45, y: 0.4, z: -0.12, rx: -0.2, rz: 0.4 }, |
| 67 | + { x: -0.3, y: 0.48, z: 0, rx: 0, rz: 0.3 }, |
| 68 | + { x: 0, y: 0.5, z: 0.25, rx: 0.4, rz: -0.2 }, |
| 69 | + { x: 0, y: 0.5, z: -0.25, rx: -0.4, rz: -0.2 }, |
| 70 | + ] |
| 71 | + |
| 72 | + for (const f of featherPositions) { |
| 73 | + const featherGeom = new THREE.ConeGeometry(0.06, 0.18, 4) |
| 74 | + const feather = new THREE.Mesh(featherGeom, tuftMaterial) |
| 75 | + feather.position.set(f.x, f.y, f.z) |
| 76 | + feather.rotation.x = f.rx |
| 77 | + feather.rotation.z = f.rz |
| 78 | + group.add(feather) |
| 79 | + } |
| 80 | + |
| 81 | + // Tail feathers - more prominent and scraggly |
| 54 | 82 | const tailGroup = new THREE.Group() |
| 55 | | - for (let i = 0; i < 3; i++) { |
| 56 | | - const tailGeom = new THREE.ConeGeometry(0.08, 0.3, 6) |
| 83 | + const tailFeathers = [ |
| 84 | + { x: -0.58, y: 0.38, z: 0, rx: 1.8, rz: 0, scale: 1.2 }, |
| 85 | + { x: -0.62, y: 0.42, z: 0.1, rx: 1.6, rz: 0.3, scale: 1.0 }, |
| 86 | + { x: -0.62, y: 0.42, z: -0.1, rx: 1.6, rz: -0.3, scale: 1.0 }, |
| 87 | + { x: -0.55, y: 0.48, z: 0.05, rx: 1.4, rz: 0.15, scale: 0.8 }, |
| 88 | + { x: -0.55, y: 0.48, z: -0.05, rx: 1.4, rz: -0.15, scale: 0.8 }, |
| 89 | + ] |
| 90 | + |
| 91 | + for (const t of tailFeathers) { |
| 92 | + const tailGeom = new THREE.ConeGeometry(0.05, 0.25, 4) |
| 57 | 93 | const tail = new THREE.Mesh(tailGeom, bodyMaterial) |
| 58 | | - tail.rotation.x = Math.PI / 2 + (i - 1) * 0.15 |
| 59 | | - tail.rotation.z = (i - 1) * 0.2 |
| 60 | | - tail.position.set(-0.55 - i * 0.05, 0.35, (i - 1) * 0.08) |
| 94 | + tail.position.set(t.x, t.y, t.z) |
| 95 | + tail.rotation.x = t.rx |
| 96 | + tail.rotation.z = t.rz |
| 97 | + tail.scale.setScalar(t.scale) |
| 61 | 98 | tailGroup.add(tail) |
| 62 | 99 | } |
| 63 | 100 | group.add(tailGroup) |
| 64 | 101 | |
| 65 | | - // Wings |
| 66 | | - const wingGeom = new THREE.SphereGeometry(0.25, 8, 6) |
| 67 | | - wingGeom.scale(0.6, 1, 0.3) |
| 102 | + // Wings - more angular, feather-like |
| 103 | + const wingGeom = new THREE.ConeGeometry(0.18, 0.4, 4) |
| 68 | 104 | |
| 69 | 105 | const leftWing = new THREE.Mesh(wingGeom, bodyMaterial) |
| 70 | | - leftWing.position.set(-0.1, 0.35, 0.45) |
| 71 | | - leftWing.rotation.x = 0.2 |
| 106 | + leftWing.position.set(-0.1, 0.32, 0.38) |
| 107 | + leftWing.rotation.x = 1.2 |
| 108 | + leftWing.rotation.z = 0.4 |
| 72 | 109 | group.add(leftWing) |
| 73 | 110 | |
| 74 | 111 | const rightWing = new THREE.Mesh(wingGeom, bodyMaterial) |
| 75 | | - rightWing.position.set(-0.1, 0.35, -0.45) |
| 76 | | - rightWing.rotation.x = -0.2 |
| 112 | + rightWing.position.set(-0.1, 0.32, -0.38) |
| 113 | + rightWing.rotation.x = -1.2 |
| 114 | + rightWing.rotation.z = 0.4 |
| 77 | 115 | group.add(rightWing) |
| 78 | 116 | |
| 79 | | - // Head |
| 80 | | - const headGeom = new THREE.SphereGeometry(0.32, 16, 12) |
| 117 | + // Wing feather details |
| 118 | + const wingFeatherGeom = new THREE.ConeGeometry(0.08, 0.22, 3) |
| 119 | + |
| 120 | + const leftWingFeather = new THREE.Mesh(wingFeatherGeom, bodyMaterial) |
| 121 | + leftWingFeather.position.set(-0.2, 0.28, 0.42) |
| 122 | + leftWingFeather.rotation.x = 1.4 |
| 123 | + leftWingFeather.rotation.z = 0.6 |
| 124 | + group.add(leftWingFeather) |
| 125 | + |
| 126 | + const rightWingFeather = new THREE.Mesh(wingFeatherGeom, bodyMaterial) |
| 127 | + rightWingFeather.position.set(-0.2, 0.28, -0.42) |
| 128 | + rightWingFeather.rotation.x = -1.4 |
| 129 | + rightWingFeather.rotation.z = 0.6 |
| 130 | + group.add(rightWingFeather) |
| 131 | + |
| 132 | + // Head - slightly egg-shaped, not perfectly round |
| 133 | + const headGeom = new THREE.SphereGeometry(0.28, 7, 6) |
| 134 | + headGeom.scale(1.1, 1.0, 0.95) |
| 81 | 135 | const head = new THREE.Mesh(headGeom, bodyMaterial) |
| 82 | | - head.position.set(0.45, 0.7, 0) |
| 136 | + head.position.set(0.42, 0.68, 0) |
| 83 | 137 | group.add(head) |
| 84 | 138 | |
| 85 | | - // Head tuft (little feather on top) |
| 86 | | - const tuftGeom = new THREE.ConeGeometry(0.05, 0.15, 6) |
| 87 | | - const tuft = new THREE.Mesh(tuftGeom, bodyMaterial) |
| 88 | | - tuft.position.set(0.4, 1.0, 0) |
| 89 | | - tuft.rotation.z = -0.3 |
| 90 | | - group.add(tuft) |
| 91 | | - |
| 92 | | - // Beak - cone pointing forward |
| 93 | | - const beakGeom = new THREE.ConeGeometry(0.1, 0.35, 8) |
| 139 | + // Cheek puffs |
| 140 | + const cheekGeom = new THREE.SphereGeometry(0.1, 5, 4) |
| 141 | + const leftCheek = new THREE.Mesh(cheekGeom, highlightMaterial) |
| 142 | + leftCheek.position.set(0.48, 0.62, 0.18) |
| 143 | + leftCheek.scale.set(0.8, 0.7, 0.6) |
| 144 | + group.add(leftCheek) |
| 145 | + |
| 146 | + const rightCheek = new THREE.Mesh(cheekGeom, highlightMaterial) |
| 147 | + rightCheek.position.set(0.48, 0.62, -0.18) |
| 148 | + rightCheek.scale.set(0.8, 0.7, 0.6) |
| 149 | + group.add(rightCheek) |
| 150 | + |
| 151 | + // Head tuft - messier, multiple feathers |
| 152 | + const tuftGeom = new THREE.ConeGeometry(0.04, 0.14, 4) |
| 153 | + const tuft1 = new THREE.Mesh(tuftGeom, bodyMaterial) |
| 154 | + tuft1.position.set(0.35, 0.95, 0) |
| 155 | + tuft1.rotation.z = -0.4 |
| 156 | + group.add(tuft1) |
| 157 | + |
| 158 | + const tuft2 = new THREE.Mesh(tuftGeom, bodyMaterial) |
| 159 | + tuft2.position.set(0.32, 0.92, 0.06) |
| 160 | + tuft2.rotation.z = -0.2 |
| 161 | + tuft2.rotation.x = 0.3 |
| 162 | + tuft2.scale.setScalar(0.8) |
| 163 | + group.add(tuft2) |
| 164 | + |
| 165 | + const tuft3 = new THREE.Mesh(tuftGeom, bodyMaterial) |
| 166 | + tuft3.position.set(0.32, 0.92, -0.06) |
| 167 | + tuft3.rotation.z = -0.2 |
| 168 | + tuft3.rotation.x = -0.3 |
| 169 | + tuft3.scale.setScalar(0.7) |
| 170 | + group.add(tuft3) |
| 171 | + |
| 172 | + // Beak - flatter, more duck-like |
| 173 | + const beakGeom = new THREE.ConeGeometry(0.09, 0.32, 6) |
| 174 | + beakGeom.scale(1, 1, 0.6) // Flatten it |
| 94 | 175 | const beak = new THREE.Mesh(beakGeom, beakMaterial) |
| 95 | 176 | beak.rotation.z = -Math.PI / 2 |
| 96 | | - beak.position.set(0.8, 0.65, 0) |
| 177 | + beak.position.set(0.75, 0.62, 0) |
| 97 | 178 | group.add(beak) |
| 98 | 179 | |
| 99 | 180 | // Eyes - big and expressive Wind Waker style |