11/*
2- * Copyright (c) 2009-2021 jMonkeyEngine
2+ * Copyright (c) 2009-2025 jMonkeyEngine
33 * All rights reserved.
44 *
55 * Redistribution and use in source and binary forms, with or without
3636import com .jme3 .scene .Mesh ;
3737import com .jme3 .scene .VertexBuffer .Type ;
3838import com .jme3 .util .BufferUtils ;
39+
3940import java .util .ArrayList ;
4041import java .util .List ;
4142
@@ -52,79 +53,131 @@ public EmitterMeshFaceShape() {
5253 }
5354
5455 /**
55- * Constructor. It stores a copy of vertex list of all meshes.
56- * @param meshes
57- * a list of meshes that will form the emitter's shape
56+ * Constructor. Initializes the emitter shape with a list of meshes.
57+ * The vertices and normals for all triangles of these meshes are
58+ * extracted and stored internally.
59+ *
60+ * @param meshes a list of {@link Mesh} objects that will define the
61+ * shape from which particles are emitted.
5862 */
5963 public EmitterMeshFaceShape (List <Mesh > meshes ) {
6064 super (meshes );
6165 }
6266
67+ /**
68+ * Sets the meshes for this emitter shape. This method extracts all
69+ * triangle vertices and computes their normals, storing them internally
70+ * for subsequent particle emission.
71+ *
72+ * @param meshes a list of {@link Mesh} objects to set as the emitter's shape.
73+ */
6374 @ Override
6475 public void setMeshes (List <Mesh > meshes ) {
6576 this .vertices = new ArrayList <List <Vector3f >>(meshes .size ());
6677 this .normals = new ArrayList <List <Vector3f >>(meshes .size ());
78+
6779 for (Mesh mesh : meshes ) {
6880 Vector3f [] vertexTable = BufferUtils .getVector3Array (mesh .getFloatBuffer (Type .Position ));
6981 int [] indices = new int [3 ];
70- List <Vector3f > vertices = new ArrayList <>(mesh .getTriangleCount () * 3 );
71- List <Vector3f > normals = new ArrayList <>(mesh .getTriangleCount ());
82+ List <Vector3f > meshVertices = new ArrayList <>(mesh .getTriangleCount () * 3 );
83+ List <Vector3f > meshNormals = new ArrayList <>(mesh .getTriangleCount ());
84+
7285 for (int i = 0 ; i < mesh .getTriangleCount (); ++i ) {
7386 mesh .getTriangle (i , indices );
74- vertices .add (vertexTable [indices [0 ]]);
75- vertices .add (vertexTable [indices [1 ]]);
76- vertices .add (vertexTable [indices [2 ]]);
77- normals .add (FastMath .computeNormal (vertexTable [indices [0 ]], vertexTable [indices [1 ]], vertexTable [indices [2 ]]));
87+
88+ Vector3f v1 = vertexTable [indices [0 ]];
89+ Vector3f v2 = vertexTable [indices [1 ]];
90+ Vector3f v3 = vertexTable [indices [2 ]];
91+
92+ // Add all three vertices of the triangle
93+ meshVertices .add (v1 );
94+ meshVertices .add (v2 );
95+ meshVertices .add (v3 );
96+
97+ // Compute and add the normal for the current triangle face
98+ meshNormals .add (FastMath .computeNormal (v1 , v2 , v3 ));
7899 }
79- this .vertices .add (vertices );
80- this .normals .add (normals );
100+ this .vertices .add (meshVertices );
101+ this .normals .add (meshNormals );
81102 }
82103 }
83104
84105 /**
85- * Randomly selects a point on a random face.
106+ * Randomly selects a point on a random face of one of the stored meshes.
107+ * The point is generated using barycentric coordinates to ensure uniform
108+ * distribution within the selected triangle.
86109 *
87- * @param store
88- * storage for the coordinates of the selected point
110+ * @param store a {@link Vector3f} object where the coordinates of the
111+ * selected point will be stored.
89112 */
90113 @ Override
91114 public void getRandomPoint (Vector3f store ) {
92115 int meshIndex = FastMath .nextRandomInt (0 , vertices .size () - 1 );
116+ List <Vector3f > currVertices = vertices .get (meshIndex );
117+ int numVertices = currVertices .size ();
118+
93119 // the index of the first vertex of a face (must be dividable by 3)
94- int vertIndex = FastMath .nextRandomInt (0 , vertices .get (meshIndex ).size () / 3 - 1 ) * 3 ;
95- // put the point somewhere between the first and the second vertex of a face
96- float moveFactor = FastMath .nextRandomFloat ();
97- store .set (Vector3f .ZERO );
98- store .addLocal (vertices .get (meshIndex ).get (vertIndex ));
99- store .addLocal ((vertices .get (meshIndex ).get (vertIndex + 1 ).x - vertices .get (meshIndex ).get (vertIndex ).x ) * moveFactor , (vertices .get (meshIndex ).get (vertIndex + 1 ).y - vertices .get (meshIndex ).get (vertIndex ).y ) * moveFactor , (vertices .get (meshIndex ).get (vertIndex + 1 ).z - vertices .get (meshIndex ).get (vertIndex ).z ) * moveFactor );
100- // move the result towards the last face vertex
101- moveFactor = FastMath .nextRandomFloat ();
102- store .addLocal ((vertices .get (meshIndex ).get (vertIndex + 2 ).x - store .x ) * moveFactor , (vertices .get (meshIndex ).get (vertIndex + 2 ).y - store .y ) * moveFactor , (vertices .get (meshIndex ).get (vertIndex + 2 ).z - store .z ) * moveFactor );
120+ int faceIndex = FastMath .nextRandomInt (0 , numVertices / 3 - 1 );
121+ int vertIndex = faceIndex * 3 ;
122+
123+ // Generate the random point on the triangle
124+ generateRandomPointOnTriangle (currVertices , vertIndex , store );
103125 }
104126
105127 /**
106- * Randomly selects a point on a random face.
107- * The {@code normal} argument is set to the normal of the selected face.
128+ * Randomly selects a point on a random face of one of the stored meshes,
129+ * and also sets the normal of that selected face.
130+ * The point is generated using barycentric coordinates for uniform distribution.
108131 *
109- * @param store
110- * storage for the coordinates of the selected point
111- * @param normal
112- * storage for the normal of the selected face
132+ * @param store a {@link Vector3f} object where the coordinates of the
133+ * selected point will be stored.
134+ * @param normal a {@link Vector3f} object where the normal of the
135+ * selected face will be stored.
113136 */
114137 @ Override
115138 public void getRandomPointAndNormal (Vector3f store , Vector3f normal ) {
116139 int meshIndex = FastMath .nextRandomInt (0 , vertices .size () - 1 );
140+ List <Vector3f > currVertices = vertices .get (meshIndex );
141+ int numVertices = currVertices .size ();
142+
117143 // the index of the first vertex of a face (must be dividable by 3)
118- int faceIndex = FastMath .nextRandomInt (0 , vertices . get ( meshIndex ). size () / 3 - 1 );
144+ int faceIndex = FastMath .nextRandomInt (0 , numVertices / 3 - 1 );
119145 int vertIndex = faceIndex * 3 ;
120- // put the point somewhere between the first and the second vertex of a face
121- float moveFactor = FastMath .nextRandomFloat ();
122- store .set (Vector3f .ZERO );
123- store .addLocal (vertices .get (meshIndex ).get (vertIndex ));
124- store .addLocal ((vertices .get (meshIndex ).get (vertIndex + 1 ).x - vertices .get (meshIndex ).get (vertIndex ).x ) * moveFactor , (vertices .get (meshIndex ).get (vertIndex + 1 ).y - vertices .get (meshIndex ).get (vertIndex ).y ) * moveFactor , (vertices .get (meshIndex ).get (vertIndex + 1 ).z - vertices .get (meshIndex ).get (vertIndex ).z ) * moveFactor );
125- // move the result towards the last face vertex
126- moveFactor = FastMath .nextRandomFloat ();
127- store .addLocal ((vertices .get (meshIndex ).get (vertIndex + 2 ).x - store .x ) * moveFactor , (vertices .get (meshIndex ).get (vertIndex + 2 ).y - store .y ) * moveFactor , (vertices .get (meshIndex ).get (vertIndex + 2 ).z - store .z ) * moveFactor );
146+
147+ // Generate the random point on the triangle
148+ generateRandomPointOnTriangle (currVertices , vertIndex , store );
149+ // Set the normal from the pre-computed normals list for the selected face
128150 normal .set (normals .get (meshIndex ).get (faceIndex ));
129151 }
152+
153+ /**
154+ * Internal method to generate a random point within a specific triangle
155+ * using barycentric coordinates.
156+ *
157+ * @param currVertices The list of vertices for the current mesh.
158+ * @param vertIndex The starting index of the triangle's first vertex
159+ * within the {@code currVertices} list.
160+ * @param store A {@link Vector3f} object where the calculated point will be stored.
161+ */
162+ private void generateRandomPointOnTriangle (List <Vector3f > currVertices , int vertIndex , Vector3f store ) {
163+
164+ Vector3f v1 = currVertices .get (vertIndex );
165+ Vector3f v2 = currVertices .get (vertIndex + 1 );
166+ Vector3f v3 = currVertices .get (vertIndex + 2 );
167+
168+ // Generate random barycentric coordinates
169+ float u = FastMath .nextRandomFloat ();
170+ float v = FastMath .nextRandomFloat ();
171+
172+ if ((u + v ) > 1 ) {
173+ u = 1 - u ;
174+ v = 1 - v ;
175+ }
176+
177+ // P = v1 + u * (v2 - v1) + v * (v3 - v1)
178+ store .x = v1 .x + u * (v2 .x - v1 .x ) + v * (v3 .x - v1 .x );
179+ store .y = v1 .y + u * (v2 .y - v1 .y ) + v * (v3 .y - v1 .y );
180+ store .z = v1 .z + u * (v2 .z - v1 .z ) + v * (v3 .z - v1 .z );
181+ }
182+
130183}
0 commit comments