1
1
/*
2
- * Copyright (c) 2009-2021 jMonkeyEngine
2
+ * Copyright (c) 2009-2025 jMonkeyEngine
3
3
* All rights reserved.
4
4
*
5
5
* Redistribution and use in source and binary forms, with or without
36
36
import com .jme3 .scene .Mesh ;
37
37
import com .jme3 .scene .VertexBuffer .Type ;
38
38
import com .jme3 .util .BufferUtils ;
39
+
39
40
import java .util .ArrayList ;
40
41
import java .util .List ;
41
42
@@ -52,79 +53,131 @@ public EmitterMeshFaceShape() {
52
53
}
53
54
54
55
/**
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.
58
62
*/
59
63
public EmitterMeshFaceShape (List <Mesh > meshes ) {
60
64
super (meshes );
61
65
}
62
66
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
+ */
63
74
@ Override
64
75
public void setMeshes (List <Mesh > meshes ) {
65
76
this .vertices = new ArrayList <List <Vector3f >>(meshes .size ());
66
77
this .normals = new ArrayList <List <Vector3f >>(meshes .size ());
78
+
67
79
for (Mesh mesh : meshes ) {
68
80
Vector3f [] vertexTable = BufferUtils .getVector3Array (mesh .getFloatBuffer (Type .Position ));
69
81
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
+
72
85
for (int i = 0 ; i < mesh .getTriangleCount (); ++i ) {
73
86
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 ));
78
99
}
79
- this .vertices .add (vertices );
80
- this .normals .add (normals );
100
+ this .vertices .add (meshVertices );
101
+ this .normals .add (meshNormals );
81
102
}
82
103
}
83
104
84
105
/**
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.
86
109
*
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.
89
112
*/
90
113
@ Override
91
114
public void getRandomPoint (Vector3f store ) {
92
115
int meshIndex = FastMath .nextRandomInt (0 , vertices .size () - 1 );
116
+ List <Vector3f > currVertices = vertices .get (meshIndex );
117
+ int numVertices = currVertices .size ();
118
+
93
119
// 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 );
103
125
}
104
126
105
127
/**
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.
108
131
*
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.
113
136
*/
114
137
@ Override
115
138
public void getRandomPointAndNormal (Vector3f store , Vector3f normal ) {
116
139
int meshIndex = FastMath .nextRandomInt (0 , vertices .size () - 1 );
140
+ List <Vector3f > currVertices = vertices .get (meshIndex );
141
+ int numVertices = currVertices .size ();
142
+
117
143
// 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 );
119
145
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
128
150
normal .set (normals .get (meshIndex ).get (faceIndex ));
129
151
}
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
+
130
183
}
0 commit comments