diff --git a/examples/jsm/loaders/collada/ColladaComposer.js b/examples/jsm/loaders/collada/ColladaComposer.js
index 414f9827f62905..dd3ecdd64b1309 100644
--- a/examples/jsm/loaders/collada/ColladaComposer.js
+++ b/examples/jsm/loaders/collada/ColladaComposer.js
@@ -32,10 +32,12 @@ import {
Skeleton,
SkinnedMesh,
SpotLight,
+ Triangle,
Vector2,
Vector3,
VectorKeyframeTrack,
- SRGBColorSpace
+ SRGBColorSpace,
+ ShapeUtils
} from 'three';
import { getElementsByTagName, parseFloats } from './ColladaParser.js';
@@ -1626,6 +1628,7 @@ class ColladaComposer {
count = primitive.count * 3;
break;
+ case 'polygons':
case 'polylist':
for ( let g = 0; g < primitive.count; g ++ ) {
@@ -1674,7 +1677,7 @@ class ColladaComposer {
const input = inputs[ name ];
- switch ( name ) {
+ switch ( name ) {
case 'VERTEX':
for ( const key in vertices ) {
@@ -1856,13 +1859,103 @@ class ColladaComposer {
} else if ( count > 4 ) {
- for ( let k = 1, kl = ( count - 2 ); k <= kl; k ++ ) {
+ const vertices = [];
- const a = index + stride * 0;
- const b = index + stride * k;
- const c = index + stride * ( k + 1 );
+ // prepare vertices which represent the polygon's contour
- pushVector( a ); pushVector( b ); pushVector( c );
+ for ( let k = 0; k < count; k ++ ) {
+
+ const a = index + stride * k;
+ const positionIndex = indices[ a ] * sourceStride;
+
+ const x = sourceArray[ positionIndex ];
+ const y = sourceArray[ positionIndex + 1 ];
+ const z = sourceArray[ positionIndex + 2 ];
+
+ vertices.push( new Vector3( x, y, z ) );
+
+ }
+
+ // determine surface normal
+
+ const normal = new Vector3();
+ const _triangle = new Triangle();
+
+ _triangle.a = vertices[ 0 ];
+ _triangle.b = vertices[ 1 ];
+ _triangle.c = vertices[ 2 ];
+ _triangle.getNormal( normal );
+
+ // project to 2D and triangulate
+
+ const vertices2D = [];
+
+ if ( Math.abs( normal.x ) > Math.abs( normal.y ) && Math.abs( normal.x ) > Math.abs( normal.z ) ) {
+
+ for ( let k = 0; k < count; k ++ ) {
+
+ vertices2D.push( new Vector2( vertices[ k ].y, vertices[ k ].z ) );
+
+ }
+
+ } else if ( Math.abs( normal.y ) > Math.abs( normal.z ) ) {
+
+ for ( let k = 0; k < count; k ++ ) {
+
+ vertices2D.push( new Vector2( vertices[ k ].x, vertices[ k ].z ) );
+
+ }
+
+ } else {
+
+ for ( let k = 0; k < count; k ++ ) {
+
+ vertices2D.push( new Vector2( vertices[ k ].x, vertices[ k ].y ) );
+
+ }
+
+ }
+
+ const isClockWise = ShapeUtils.isClockWise( vertices2D );
+
+ if ( isClockWise === true ) {
+
+ vertices2D.reverse();
+
+ }
+
+ const faces = ShapeUtils.triangulateShape( vertices2D, [] );
+
+ // build indices
+
+ for ( let k = 0; k < faces.length; k ++ ) {
+
+ const face = faces[ k ];
+
+ let i0, i1, i2;
+
+ if ( isClockWise === false ) {
+
+ i0 = face[ 0 ];
+ i1 = face[ 1 ];
+ i2 = face[ 2 ];
+
+
+ } else {
+
+ i0 = count - 1 - face[ 0 ];
+ i1 = count - 1 - face[ 2 ];
+ i2 = count - 1 - face[ 1 ];
+
+ }
+
+ const a = index + stride * i0;
+ const b = index + stride * i1;
+ const c = index + stride * i2;
+
+ pushVector( a );
+ pushVector( b );
+ pushVector( c );
}
@@ -2627,6 +2720,7 @@ class ColladaComposer {
break;
case 'triangles':
+ case 'polygons':
case 'polylist':
if ( skinning ) {
diff --git a/examples/jsm/loaders/collada/ColladaParser.js b/examples/jsm/loaders/collada/ColladaParser.js
index b23aacc26d7e09..90d8adf112fb44 100644
--- a/examples/jsm/loaders/collada/ColladaParser.js
+++ b/examples/jsm/loaders/collada/ColladaParser.js
@@ -1231,9 +1231,6 @@ class ColladaParser {
break;
case 'polygons':
- console.warn( 'THREE.ColladaLoader: Unsupported primitive type: ', child.nodeName );
- break;
-
case 'lines':
case 'linestrips':
case 'polylist':
@@ -1353,6 +1350,12 @@ class ColladaParser {
}
+ if ( primitive.type === 'polygons' ) {
+
+ primitive.vcount = [ primitive.p.length / primitive.stride ];
+
+ }
+
return primitive;
}
diff --git a/examples/models/collada/test/polygons.dae b/examples/models/collada/test/polygons.dae
new file mode 100644
index 00000000000000..1f3c4e8b962dee
--- /dev/null
+++ b/examples/models/collada/test/polygons.dae
@@ -0,0 +1,47 @@
+
+
+
+ 2026-03-09T12:00:00Z
+ 2026-03-09T12:00:00Z
+
+ Y_UP
+
+
+
+
+
+
+ -1.0 0.0 1.0
+ 1.0 0.0 1.0
+ 1.0 0.0 -1.0
+ -1.0 0.0 -1.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0 1 2 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/models/collada/test/polygons_concave.dae b/examples/models/collada/test/polygons_concave.dae
new file mode 100644
index 00000000000000..45641b020fa95c
--- /dev/null
+++ b/examples/models/collada/test/polygons_concave.dae
@@ -0,0 +1,49 @@
+
+
+
+ 2026-03-09T12:30:00Z
+ 2026-03-09T12:30:00Z
+
+ Y_UP
+
+
+
+
+
+
+ 0.0 0.0 -1.0
+ -1.0 0.0 -1.0
+ -1.0 0.0 1.0
+ 2.0 0.0 1.0
+ 2.0 0.0 0.0
+ 0.0 0.0 0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0 1 2 3 4 5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file