瀏覽代碼

CapsuleGeometry: Change length param to height, fix UVs (#30915)

* CapsuleGeometry: Fix prop name

Change length to height; matching heightSegments and other geometries

* CapsuleGeometry: improve UVs, fix capSegments parameter

* Remove noop section check

* Fix extend test
Michael Blix 10 月之前
父節點
當前提交
92bd89f2cc

+ 2 - 2
docs/api/ar/geometries/CapsuleGeometry.html

@@ -47,11 +47,11 @@
 		<h2>المنشئ (Constructor)</h2>
 		<h2>المنشئ (Constructor)</h2>
 
 
  		<h3>
  		<h3>
- 		[name]([param:Float radius], [param:Float length], [param:Integer capSegments], [param:Integer radialSegments])
+ 		[name]([param:Float radius], [param:Float height], [param:Integer capSegments], [param:Integer radialSegments], [param:Integer heightSegments])
  		</h3>
  		</h3>
  		<p>
  		<p>
  		radius — نصف قطر الكبسولة. اختياري؛ الافتراضي هو 1.<br />
  		radius — نصف قطر الكبسولة. اختياري؛ الافتراضي هو 1.<br />
- 		length — طول القسم الأوسط. اختياري؛ الافتراضي هو 1.<br />
+ 		height — ارتفاع القسم الأوسط. اختياري؛ الافتراضي هو 1.<br />
  		capSegments — عدد قطاعات المنحنى المستخدمة لبناء الأغطية. اختياري؛
  		capSegments — عدد قطاعات المنحنى المستخدمة لبناء الأغطية. اختياري؛
  		الافتراضي هو 4.<br />
  		الافتراضي هو 4.<br />
  		radialSegments — عدد الوجوه المقسمة حول محيط
  		radialSegments — عدد الوجوه المقسمة حول محيط

+ 2 - 2
docs/api/en/geometries/CapsuleGeometry.html

@@ -48,11 +48,11 @@ const capsule = new THREE.Mesh( geometry, material ); scene.add( capsule );
 		<h2>Constructor</h2>
 		<h2>Constructor</h2>
 
 
 		<h3>
 		<h3>
-			[name]([param:Float radius], [param:Float length], [param:Integer capSegments], [param:Integer radialSegments], [param:Integer heightSegments])
+			[name]([param:Float radius], [param:Float height], [param:Integer capSegments], [param:Integer radialSegments], [param:Integer heightSegments])
 		</h3>
 		</h3>
 		<p>
 		<p>
 			radius — Radius of the capsule. Optional; defaults to `1`.<br />
 			radius — Radius of the capsule. Optional; defaults to `1`.<br />
-			length — Length of the middle section. Optional; defaults to `1`.<br />
+			height — Height of the middle section. Optional; defaults to `1`.<br />
 			capSegments — Number of curve segments used to build the caps. Optional;
 			capSegments — Number of curve segments used to build the caps. Optional;
 			defaults to `4`.<br />
 			defaults to `4`.<br />
 			radialSegments — Number of segmented faces around the circumference of the
 			radialSegments — Number of segmented faces around the circumference of the

+ 2 - 2
docs/api/fr/geometries/CapsuleGeometry.html

@@ -44,11 +44,11 @@
 
 
 		<h2>Constructeur</h2>
 		<h2>Constructeur</h2>
 
 
-		<h3>[name]([param:Float radius], [param:Float length], [param:Integer capSegments], [param:Integer radialSegments])</h3>
+		<h3>[name]([param:Float radius], [param:Float height], [param:Integer capSegments], [param:Integer radialSegments], [param:Integer heightSegments])</h3>
 		<p>
 		<p>
 
 
 		radius — Rayon de la capsule. Optionnel; par défaut à 1.<br />
 		radius — Rayon de la capsule. Optionnel; par défaut à 1.<br />
-		length — Longueur de la section médiane. Optionnel; par défaut à 1.<br />
+		height — Hauteur de la section médiane. Optionnel; par défaut à 1.<br />
 		capSegments — Nombre de segments de courbe utilisés pour construire les demi-sphères. Optionnel; par défaut à 4.<br />
 		capSegments — Nombre de segments de courbe utilisés pour construire les demi-sphères. Optionnel; par défaut à 4.<br />
 		radialSegments — Nombre de faces segmentées autour de la circonférence de la capsule. Optionnel; par défaut à 8.<br />
 		radialSegments — Nombre de faces segmentées autour de la circonférence de la capsule. Optionnel; par défaut à 8.<br />
 		heightSegments — Nombre de faces rectangulaires segmentées sur la hauteur de la capsule. Optionnel; par défaut à 1.<br />
 		heightSegments — Nombre de faces rectangulaires segmentées sur la hauteur de la capsule. Optionnel; par défaut à 1.<br />

+ 2 - 2
docs/api/it/geometries/CapsuleGeometry.html

@@ -44,11 +44,11 @@
 
 
 		<h2>Costruttore</h2>
 		<h2>Costruttore</h2>
 
 
-		<h3>[name]([param:Float radius], [param:Float length], [param:Integer capSegments], [param:Integer radialSegments])</h3>
+		<h3>[name]([param:Float radius], [param:Float height], [param:Integer capSegments], [param:Integer radialSegments], [param:Integer heightSegments])</h3>
 		<p>
 		<p>
 
 
 		radius — Raggio della capsula. Opzionale; il valore predefinito è 1.<br />
 		radius — Raggio della capsula. Opzionale; il valore predefinito è 1.<br />
-		length — Lunghezza della sezione centrale. Opzionale; il valore predefinito è 1.<br />
+		height — Altezza della sezione centrale. Opzionale; il valore predefinito è 1.<br />
 		capSegments — Numero di segmenti curvi utilizzato per costruire i tappi della capsula. Opzionale; il valore predefinito è 4.<br />
 		capSegments — Numero di segmenti curvi utilizzato per costruire i tappi della capsula. Opzionale; il valore predefinito è 4.<br />
 		radialSegments — Numero di facce segmentate attorno alla circonferenza della capsula. Opzionale; il valore predefinito è 8.<br />
 		radialSegments — Numero di facce segmentate attorno alla circonferenza della capsula. Opzionale; il valore predefinito è 8.<br />
 		heightSegments — Numero di facce rettangolari segmentate sull'altezza della capsula. Opzionale; il valore predefinito è 1.<br />
 		heightSegments — Numero di facce rettangolari segmentate sull'altezza della capsula. Opzionale; il valore predefinito è 1.<br />

+ 2 - 2
docs/api/ko/geometries/CapsuleGeometry.html

@@ -45,11 +45,11 @@
 
 
 		<h2>생성자</h2>
 		<h2>생성자</h2>
 
 
-		<h3>[name]([param:Float radius], [param:Float length], [param:Integer capSegments], [param:Integer radialSegments])</h3>
+		<h3>[name]([param:Float radius], [param:Float height], [param:Integer capSegments], [param:Integer radialSegments], [param:Integer heightSegments])</h3>
 		<p>
 		<p>
 
 
 		radius — 캡슐의 반경입니다. Optional; 기본값은 1 입니다.<br />
 		radius — 캡슐의 반경입니다. Optional; 기본값은 1 입니다.<br />
-		length — 중간 구역의 길이입니다. Optional; 기본값은 1 입니다.<br />
+		height — 중간 구역의 높이입니다. Optional; 기본값은 1 입니다.<br />
 		capSegments — 캡을 구성하는 데 사용된 곡선 면의 수입니다. Optional; 기본값은 4 입니다.<br />
 		capSegments — 캡을 구성하는 데 사용된 곡선 면의 수입니다. Optional; 기본값은 4 입니다.<br />
 		radialSegments — 캡슐 둘레 주변의 분할된 면의 수입니다. Optional; 기본값은 8 입니다.<br />
 		radialSegments — 캡슐 둘레 주변의 분할된 면의 수입니다. Optional; 기본값은 8 입니다.<br />
 		heightSegments — 캡슐의 높이에 따라 분할된 면의 수입니다. Optional; 기본값은 1 입니다.<br />
 		heightSegments — 캡슐의 높이에 따라 분할된 면의 수입니다. Optional; 기본값은 1 입니다.<br />

+ 2 - 2
docs/api/zh/geometries/CapsuleGeometry.html

@@ -47,11 +47,11 @@ const capsule = new THREE.Mesh( geometry, material ); scene.add( capsule );
 		<h2>构造函数</h2>
 		<h2>构造函数</h2>
 
 
 		<h3>
 		<h3>
-			[name]([param:Float radius], [param:Float length], [param:Integer capSegments], [param:Integer radialSegments])
+			[name]([param:Float radius], [param:Float height], [param:Integer capSegments], [param:Integer radialSegments], [param:Integer heightSegments])
 		</h3>
 		</h3>
 		<p>
 		<p>
 			radius — 胶囊半径。可选的; 默认值为1。<br />
 			radius — 胶囊半径。可选的; 默认值为1。<br />
-			length — 中间区域的长度。可选的; 默认值为1。<br />
+			height — 中间区域的高度。可选的; 默认值为1。<br />
 			capSegments — 构造盖子的曲线部分的个数。可选的; 默认值为4。<br />
 			capSegments — 构造盖子的曲线部分的个数。可选的; 默认值为4。<br />
 			radialSegments — 覆盖胶囊圆周的分离的面的个数。可选的; 默认值为8。<br />
 			radialSegments — 覆盖胶囊圆周的分离的面的个数。可选的; 默认值为8。<br />
 			heightSegments — 胶囊侧面沿其高度的段数,默认值为 1。<br />
 			heightSegments — 胶囊侧面沿其高度的段数,默认值为 1。<br />

+ 3 - 3
docs/scenes/geometry-browser.html

@@ -166,7 +166,7 @@
 
 
 					const data = {
 					const data = {
 						radius: 5,
 						radius: 5,
-						length: 5,
+						height: 5,
 						capSegments: 10,
 						capSegments: 10,
 						radialSegments: 20,
 						radialSegments: 20,
 						heightSegments: 1
 						heightSegments: 1
@@ -175,7 +175,7 @@
 					function generateGeometry() {
 					function generateGeometry() {
 
 
 						updateGroupGeometry( mesh,
 						updateGroupGeometry( mesh,
-							new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments, data.heightSegments ),
+							new CapsuleGeometry( data.radius, data.height, data.capSegments, data.radialSegments, data.heightSegments ),
 						);
 						);
 
 
 					}
 					}
@@ -183,7 +183,7 @@
 					const folder = gui.addFolder( 'THREE.CapsuleGeometry' );
 					const folder = gui.addFolder( 'THREE.CapsuleGeometry' );
 
 
 					folder.add( data, 'radius', 1, 30 ).onChange( generateGeometry );
 					folder.add( data, 'radius', 1, 30 ).onChange( generateGeometry );
-					folder.add( data, 'length', 1, 30 ).onChange( generateGeometry );
+					folder.add( data, 'height', 1, 30 ).onChange( generateGeometry );
 					folder.add( data, 'capSegments', 1, 32 ).step( 1 ).onChange( generateGeometry );
 					folder.add( data, 'capSegments', 1, 32 ).step( 1 ).onChange( generateGeometry );
 					folder.add( data, 'radialSegments', 1, 64 ).step( 1 ).onChange( generateGeometry );
 					folder.add( data, 'radialSegments', 1, 64 ).step( 1 ).onChange( generateGeometry );
 					folder.add( data, 'heightSegments', 1, 64 ).step( 1 ).onChange( generateGeometry );
 					folder.add( data, 'heightSegments', 1, 64 ).step( 1 ).onChange( generateGeometry );

+ 8 - 8
editor/js/Sidebar.Geometry.CapsuleGeometry.js

@@ -24,15 +24,15 @@ function GeometryParametersPanel( editor, object ) {
 
 
 	container.add( radiusRow );
 	container.add( radiusRow );
 
 
-	// length
+	// height
 
 
-	const lengthRow = new UIRow();
-	const length = new UINumber( parameters.length ).onChange( update );
+	const heightRow = new UIRow();
+	const height = new UINumber( parameters.height ).onChange( update );
 
 
-	lengthRow.add( new UIText( strings.getKey( 'sidebar/geometry/capsule_geometry/length' ) ).setClass( 'Label' ) );
-	lengthRow.add( length );
+	heightRow.add( new UIText( strings.getKey( 'sidebar/geometry/capsule_geometry/height' ) ).setClass( 'Label' ) );
+	heightRow.add( height );
 
 
-	container.add( lengthRow );
+	container.add( heightRow );
 
 
 	// capSegments
 	// capSegments
 
 
@@ -71,7 +71,7 @@ function GeometryParametersPanel( editor, object ) {
 		const parameters = object.geometry.parameters;
 		const parameters = object.geometry.parameters;
 
 
 		radius.setValue( parameters.radius );
 		radius.setValue( parameters.radius );
-		length.setValue( parameters.length );
+		height.setValue( parameters.height );
 		capSegments.setValue( parameters.capSegments );
 		capSegments.setValue( parameters.capSegments );
 		radialSegments.setValue( parameters.radialSegments );
 		radialSegments.setValue( parameters.radialSegments );
 		heightSegments.setValue( parameters.heightSegments );
 		heightSegments.setValue( parameters.heightSegments );
@@ -94,7 +94,7 @@ function GeometryParametersPanel( editor, object ) {
 
 
 		editor.execute( new SetGeometryCommand( editor, object, new THREE.CapsuleGeometry(
 		editor.execute( new SetGeometryCommand( editor, object, new THREE.CapsuleGeometry(
 			radius.getValue(),
 			radius.getValue(),
-			length.getValue(),
+			height.getValue(),
 			capSegments.getValue(),
 			capSegments.getValue(),
 			radialSegments.getValue(),
 			radialSegments.getValue(),
 			heightSegments.getValue()
 			heightSegments.getValue()

+ 6 - 6
editor/js/Strings.js

@@ -179,7 +179,7 @@ function Strings( config ) {
 			'sidebar/geometry/buffer_geometry/morphRelative': 'صفات نسبی (رلتیو)',
 			'sidebar/geometry/buffer_geometry/morphRelative': 'صفات نسبی (رلتیو)',
 
 
 			'sidebar/geometry/capsule_geometry/radius': 'شعاع',
 			'sidebar/geometry/capsule_geometry/radius': 'شعاع',
-			'sidebar/geometry/capsule_geometry/length': 'طول',
+			'sidebar/geometry/capsule_geometry/height': 'ارتفاع',
 			'sidebar/geometry/capsule_geometry/capseg': 'Cap Seg',
 			'sidebar/geometry/capsule_geometry/capseg': 'Cap Seg',
 			'sidebar/geometry/capsule_geometry/radialseg': 'Radial Seg',
 			'sidebar/geometry/capsule_geometry/radialseg': 'Radial Seg',
 			'sidebar/geometry/capsule_geometry/heightseg': 'Height Seg',
 			'sidebar/geometry/capsule_geometry/heightseg': 'Height Seg',
@@ -581,7 +581,7 @@ function Strings( config ) {
 			'sidebar/geometry/buffer_geometry/morphRelative': 'Morph Relative',
 			'sidebar/geometry/buffer_geometry/morphRelative': 'Morph Relative',
 
 
 			'sidebar/geometry/capsule_geometry/radius': 'Radius',
 			'sidebar/geometry/capsule_geometry/radius': 'Radius',
-			'sidebar/geometry/capsule_geometry/length': 'Length',
+			'sidebar/geometry/capsule_geometry/height': 'Height',
 			'sidebar/geometry/capsule_geometry/capseg': 'Cap Seg',
 			'sidebar/geometry/capsule_geometry/capseg': 'Cap Seg',
 			'sidebar/geometry/capsule_geometry/radialseg': 'Radial Seg',
 			'sidebar/geometry/capsule_geometry/radialseg': 'Radial Seg',
 			'sidebar/geometry/capsule_geometry/heightseg': 'Height Seg',
 			'sidebar/geometry/capsule_geometry/heightseg': 'Height Seg',
@@ -984,7 +984,7 @@ function Strings( config ) {
 			'sidebar/geometry/buffer_geometry/morphRelative': 'Morph Relative',
 			'sidebar/geometry/buffer_geometry/morphRelative': 'Morph Relative',
 
 
 			'sidebar/geometry/capsule_geometry/radius': 'Radius',
 			'sidebar/geometry/capsule_geometry/radius': 'Radius',
-			'sidebar/geometry/capsule_geometry/length': 'Length',
+			'sidebar/geometry/capsule_geometry/height': 'Hauteur',
 			'sidebar/geometry/capsule_geometry/capseg': 'Cap Seg',
 			'sidebar/geometry/capsule_geometry/capseg': 'Cap Seg',
 			'sidebar/geometry/capsule_geometry/radialseg': 'Radial Seg',
 			'sidebar/geometry/capsule_geometry/radialseg': 'Radial Seg',
 			'sidebar/geometry/capsule_geometry/heightseg': 'Height Seg',
 			'sidebar/geometry/capsule_geometry/heightseg': 'Height Seg',
@@ -1387,7 +1387,7 @@ function Strings( config ) {
 			'sidebar/geometry/buffer_geometry/morphRelative': '相对变形',
 			'sidebar/geometry/buffer_geometry/morphRelative': '相对变形',
 
 
 			'sidebar/geometry/capsule_geometry/radius': '半径',
 			'sidebar/geometry/capsule_geometry/radius': '半径',
-			'sidebar/geometry/capsule_geometry/length': '长度',
+			'sidebar/geometry/capsule_geometry/height': '高度',
 			'sidebar/geometry/capsule_geometry/capseg': '胶囊分段',
 			'sidebar/geometry/capsule_geometry/capseg': '胶囊分段',
 			'sidebar/geometry/capsule_geometry/radialseg': '半径分段',
 			'sidebar/geometry/capsule_geometry/radialseg': '半径分段',
 			'sidebar/geometry/capsule_geometry/heightseg': '高度分段',
 			'sidebar/geometry/capsule_geometry/heightseg': '高度分段',
@@ -1790,7 +1790,7 @@ function Strings( config ) {
 			'sidebar/geometry/buffer_geometry/morphRelative': '相対モーフ',
 			'sidebar/geometry/buffer_geometry/morphRelative': '相対モーフ',
 
 
 			'sidebar/geometry/capsule_geometry/radius': '半径',
 			'sidebar/geometry/capsule_geometry/radius': '半径',
-			'sidebar/geometry/capsule_geometry/length': '長さ',
+			'sidebar/geometry/capsule_geometry/height': '高さ',
 			'sidebar/geometry/capsule_geometry/capseg': 'キャップの分割数',
 			'sidebar/geometry/capsule_geometry/capseg': 'キャップの分割数',
 			'sidebar/geometry/capsule_geometry/radialseg': '円の分割数',
 			'sidebar/geometry/capsule_geometry/radialseg': '円の分割数',
 			'sidebar/geometry/capsule_geometry/heightseg': '高さの分割数',
 			'sidebar/geometry/capsule_geometry/heightseg': '高さの分割数',
@@ -2192,7 +2192,7 @@ function Strings( config ) {
 			'sidebar/geometry/buffer_geometry/morphRelative': '상대적 모프',
 			'sidebar/geometry/buffer_geometry/morphRelative': '상대적 모프',
 
 
 			'sidebar/geometry/capsule_geometry/radius': '반지름',
 			'sidebar/geometry/capsule_geometry/radius': '반지름',
-			'sidebar/geometry/capsule_geometry/length': '길이',
+			'sidebar/geometry/capsule_geometry/height': '높이',
 			'sidebar/geometry/capsule_geometry/capseg': '캡 분할 수',
 			'sidebar/geometry/capsule_geometry/capseg': '캡 분할 수',
 			'sidebar/geometry/capsule_geometry/radialseg': '방사 분할 수',
 			'sidebar/geometry/capsule_geometry/radialseg': '방사 분할 수',
 			'sidebar/geometry/capsule_geometry/heightseg': '높이 분할 수',
 			'sidebar/geometry/capsule_geometry/heightseg': '높이 분할 수',

+ 166 - 31
src/geometries/CapsuleGeometry.js

@@ -1,49 +1,33 @@
-import { Path } from '../extras/core/Path.js';
-import { LatheGeometry } from './LatheGeometry.js';
+import { BufferGeometry } from '../core/BufferGeometry.js';
+import { Float32BufferAttribute } from '../core/BufferAttribute.js';
+import { Vector3 } from '../math/Vector3.js';
 
 
 /**
 /**
- * A geometry class for a capsule with given radii and height. It is constructed using a lathe.
+ * A geometry class for representing a capsule.
  *
  *
  * ```js
  * ```js
- * const geometry = new THREE.CapsuleGeometry( 1, 1, 4, 8 );
+ * const geometry = new THREE.CapsuleGeometry( 1, 1, 4, 8, 1 );
  * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
  * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
  * const capsule = new THREE.Mesh( geometry, material );
  * const capsule = new THREE.Mesh( geometry, material );
  * scene.add( capsule );
  * scene.add( capsule );
  * ```
  * ```
  *
  *
- * @augments LatheGeometry
+ * @augments BufferGeometry
  */
  */
-class CapsuleGeometry extends LatheGeometry {
+class CapsuleGeometry extends BufferGeometry {
 
 
 	/**
 	/**
 	 * Constructs a new capsule geometry.
 	 * Constructs a new capsule geometry.
 	 *
 	 *
 	 * @param {number} [radius=1] - Radius of the capsule.
 	 * @param {number} [radius=1] - Radius of the capsule.
-	 * @param {number} [length=1] - Length of the middle section.
-	 * @param {number} [capSegments=4] - Number of curve segments used to build the caps.
-	 * @param {number} [radialSegments=8] - Number of segmented faces around the circumference of the capsule.
-	 * @param {number} [heightSegments=1] - Number of rows of faces along the height of the capsule.
+	 * @param {number} [height=1] - Height of the middle section.
+	 * @param {number} [capSegments=4] - Number of curve segments used to build each cap.
+	 * @param {number} [radialSegments=8] - Number of segmented faces around the circumference of the capsule. Must be an integer >= 3.
+	 * @param {number} [heightSegments=1] - Number of rows of faces along the height of the middle section. Must be an integer >= 1.
 	 */
 	 */
-	constructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8, heightSegments = 1 ) {
+	constructor( radius = 1, height = 1, capSegments = 4, radialSegments = 8, heightSegments = 1 ) {
 
 
-		const path = new Path();
-		path.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 );
-
-		if ( heightSegments > 1 ) {
-
-			for ( let i = 1; i < heightSegments; i ++ ) {
-
-				const y = - length / 2 + ( length * i / heightSegments );
-
-				path.lineTo( radius, y );
-
-			}
-
-		}
-
-		path.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 );
-
-		super( path.getPoints( capSegments ), radialSegments );
+		super();
 
 
 		this.type = 'CapsuleGeometry';
 		this.type = 'CapsuleGeometry';
 
 
@@ -56,12 +40,163 @@ class CapsuleGeometry extends LatheGeometry {
 		 */
 		 */
 		this.parameters = {
 		this.parameters = {
 			radius: radius,
 			radius: radius,
-			length: length,
+			height: height,
 			capSegments: capSegments,
 			capSegments: capSegments,
 			radialSegments: radialSegments,
 			radialSegments: radialSegments,
 			heightSegments: heightSegments,
 			heightSegments: heightSegments,
 		};
 		};
 
 
+		height = Math.max( 0, height );
+		capSegments = Math.max( 1, Math.floor( capSegments ) );
+		radialSegments = Math.max( 3, Math.floor( radialSegments ) );
+		heightSegments = Math.max( 1, Math.floor( heightSegments ) );
+
+		// buffers
+
+		const indices = [];
+		const vertices = [];
+		const normals = [];
+		const uvs = [];
+
+		// helper variables
+
+		const halfHeight = height / 2;
+		const capArcLength = ( Math.PI / 2 ) * radius;
+		const cylinderPartLength = height;
+		const totalArcLength = 2 * capArcLength + cylinderPartLength;
+
+		const numVerticalSegments = capSegments * 2 + heightSegments;
+		const verticesPerRow = radialSegments + 1;
+
+		const normal = new Vector3();
+		const vertex = new Vector3();
+
+		// generate vertices, normals, and uvs
+
+		for ( let iy = 0; iy <= numVerticalSegments; iy ++ ) {
+
+			let currentArcLength = 0;
+			let profileY = 0;
+			let profileRadius = 0;
+			let normalYComponent = 0;
+
+			if ( iy <= capSegments ) {
+
+				// bottom cap
+				const segmentProgress = iy / capSegments;
+				const angle = ( segmentProgress * Math.PI ) / 2;
+				profileY = - halfHeight - radius * Math.cos( angle );
+				profileRadius = radius * Math.sin( angle );
+				normalYComponent = - radius * Math.cos( angle );
+				currentArcLength = segmentProgress * capArcLength;
+
+			} else if ( iy <= capSegments + heightSegments ) {
+
+				// middle section
+				const segmentProgress = ( iy - capSegments ) / heightSegments;
+				profileY = - halfHeight + segmentProgress * height;
+				profileRadius = radius;
+				normalYComponent = 0;
+				currentArcLength = capArcLength + segmentProgress * cylinderPartLength;
+
+			} else {
+
+				// top cap
+				const segmentProgress =
+					( iy - capSegments - heightSegments ) / capSegments;
+				const angle = ( segmentProgress * Math.PI ) / 2;
+				profileY = halfHeight + radius * Math.sin( angle );
+				profileRadius = radius * Math.cos( angle );
+				normalYComponent = radius * Math.sin( angle );
+				currentArcLength =
+					capArcLength + cylinderPartLength + segmentProgress * capArcLength;
+
+			}
+
+			const v = Math.max( 0, Math.min( 1, currentArcLength / totalArcLength ) );
+
+
+			// special case for the poles
+
+			let uOffset = 0;
+
+			if ( iy === 0 ) {
+
+				uOffset = 0.5 / radialSegments;
+
+			} else if ( iy === numVerticalSegments ) {
+
+				uOffset = - 0.5 / radialSegments;
+
+			}
+
+			for ( let ix = 0; ix <= radialSegments; ix ++ ) {
+
+				const u = ix / radialSegments;
+				const theta = u * Math.PI * 2;
+
+				const sinTheta = Math.sin( theta );
+				const cosTheta = Math.cos( theta );
+
+				// vertex
+
+				vertex.x = - profileRadius * cosTheta;
+				vertex.y = profileY;
+				vertex.z = profileRadius * sinTheta;
+				vertices.push( vertex.x, vertex.y, vertex.z );
+
+				// normal
+
+				normal.set(
+					- profileRadius * cosTheta,
+					normalYComponent,
+					profileRadius * sinTheta
+				);
+				normal.normalize();
+				normals.push( normal.x, normal.y, normal.z );
+
+				// uv
+
+				uvs.push( u + uOffset, v );
+
+			}
+
+			if ( iy > 0 ) {
+
+				const prevIndexRow = ( iy - 1 ) * verticesPerRow;
+				for ( let ix = 0; ix < radialSegments; ix ++ ) {
+
+					const i1 = prevIndexRow + ix;
+					const i2 = prevIndexRow + ix + 1;
+					const i3 = iy * verticesPerRow + ix;
+					const i4 = iy * verticesPerRow + ix + 1;
+
+					indices.push( i1, i2, i3 );
+					indices.push( i2, i4, i3 );
+
+				}
+
+			}
+
+		}
+
+		// build geometry
+
+		this.setIndex( indices );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+
+	}
+
+	copy( source ) {
+
+		super.copy( source );
+
+		this.parameters = Object.assign( {}, source.parameters );
+
+		return this;
+
 	}
 	}
 
 
 	/**
 	/**
@@ -73,7 +208,7 @@ class CapsuleGeometry extends LatheGeometry {
 	 */
 	 */
 	static fromJSON( data ) {
 	static fromJSON( data ) {
 
 
-		return new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments, data.heightSegments );
+		return new CapsuleGeometry( data.radius, data.height, data.capSegments, data.radialSegments, data.heightSegments );
 
 
 	}
 	}
 
 

+ 8 - 8
test/unit/src/geometries/CapsuleGeometry.tests.js

@@ -2,7 +2,7 @@
 
 
 import { CapsuleGeometry } from '../../../../src/geometries/CapsuleGeometry.js';
 import { CapsuleGeometry } from '../../../../src/geometries/CapsuleGeometry.js';
 
 
-import { LatheGeometry } from '../../../../src/geometries/LatheGeometry.js';
+import { BufferGeometry } from '../../../../src/core/BufferGeometry.js';
 import { runStdGeometryTests } from '../../utils/qunit-utils.js';
 import { runStdGeometryTests } from '../../utils/qunit-utils.js';
 
 
 export default QUnit.module( 'Geometries', () => {
 export default QUnit.module( 'Geometries', () => {
@@ -14,7 +14,7 @@ export default QUnit.module( 'Geometries', () => {
 
 
 			const parameters = {
 			const parameters = {
 				radius: 2,
 				radius: 2,
-				length: 2,
+				height: 2,
 				capSegments: 20,
 				capSegments: 20,
 				radialSegments: 20,
 				radialSegments: 20,
 				heightSegments: 1
 				heightSegments: 1
@@ -23,10 +23,10 @@ export default QUnit.module( 'Geometries', () => {
 			geometries = [
 			geometries = [
 				new CapsuleGeometry(),
 				new CapsuleGeometry(),
 				new CapsuleGeometry( parameters.radius ),
 				new CapsuleGeometry( parameters.radius ),
-				new CapsuleGeometry( parameters.radius, parameters.length ),
-				new CapsuleGeometry( parameters.radius, parameters.length, parameters.capSegments ),
-				new CapsuleGeometry( parameters.radius, parameters.length, parameters.capSegments, parameters.radialSegments ),
-				new CapsuleGeometry( parameters.radius, parameters.length, parameters.capSegments, parameters.radialSegments, parameters.heightSegments )
+				new CapsuleGeometry( parameters.radius, parameters.height ),
+				new CapsuleGeometry( parameters.radius, parameters.height, parameters.capSegments ),
+				new CapsuleGeometry( parameters.radius, parameters.height, parameters.capSegments, parameters.radialSegments ),
+				new CapsuleGeometry( parameters.radius, parameters.height, parameters.capSegments, parameters.radialSegments, parameters.heightSegments )
 			];
 			];
 
 
 		} );
 		} );
@@ -36,8 +36,8 @@ export default QUnit.module( 'Geometries', () => {
 
 
 			const object = new CapsuleGeometry();
 			const object = new CapsuleGeometry();
 			assert.strictEqual(
 			assert.strictEqual(
-				object instanceof LatheGeometry, true,
-				'CapsuleGeometry extends from LatheGeometry'
+				object instanceof BufferGeometry, true,
+				'CapsuleGeometry extends from BufferGeometry'
 			);
 			);
 
 
 		} );
 		} );

粤ICP备19079148号