2 * Copyright (c) 2003-2009 jMonkeyEngine
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 package com.jme.scene.shape;
35 import java.io.IOException;
37 import com.jme.math.FastMath;
38 import com.jme.math.Vector3f;
39 import com.jme.scene.TexCoords;
40 import com.jme.scene.TriMesh;
41 import com.jme.util.export.InputCapsule;
42 import com.jme.util.export.JMEExporter;
43 import com.jme.util.export.JMEImporter;
44 import com.jme.util.export.OutputCapsule;
45 import com.jme.util.geom.BufferUtils;
48 * <code>Sphere</code> represents a 3D object with all points equidistance
49 * from a center point.
51 * @author Joshua Slack
52 * @version $Revision$, $Date$
54 public class Sphere extends TriMesh {
56 private static final long serialVersionUID = 1L;
58 public static final int TEX_ORIGINAL = 0;
60 // Spherical projection mode, donated by Ogli from the jME forums.
61 public static final int TEX_PROJECTED = 1;
63 protected int zSamples;
65 protected int radialSamples;
67 /** the distance from the center point each point falls on */
69 /** the center of the sphere */
70 public Vector3f center;
72 private static Vector3f tempVa = new Vector3f();
74 private static Vector3f tempVb = new Vector3f();
76 private static Vector3f tempVc = new Vector3f();
78 // TODO: replace with a boolean property
79 protected int textureMode = TEX_ORIGINAL;
85 * Constructs a sphere. By default the Sphere has not geometry data or
89 * The name of the sphere.
91 public Sphere(String name) {
96 * Constructs a sphere with center at the origin. For details, see the other
102 * The samples along the Z.
103 * @param radialSamples
104 * The samples along the radial.
106 * Radius of the sphere.
107 * @see #Sphere(java.lang.String, com.jme.math.Vector3f, int, int, float)
109 public Sphere(String name, int zSamples, int radialSamples, float radius) {
110 this(name, new Vector3f(0, 0, 0), zSamples, radialSamples, radius);
114 * Constructs a sphere. All geometry data buffers are updated automatically.
115 * Both zSamples and radialSamples increase the quality of the generated
119 * Name of the sphere.
121 * Center of the sphere.
123 * The number of samples along the Z.
124 * @param radialSamples
125 * The number of samples along the radial.
127 * The radius of the sphere.
129 public Sphere(String name, Vector3f center, int zSamples,
130 int radialSamples, float radius) {
132 updateGeometry(center, zSamples, radialSamples, radius);
136 * Returns the center of this sphere.
138 * @return The sphere's center.
140 public Vector3f getCenter() {
144 public int getRadialSamples() {
145 return radialSamples;
148 public float getRadius() {
153 * @return Returns the textureMode.
155 public int getTextureMode() {
159 public int getZSamples() {
163 public void read(JMEImporter e) throws IOException {
165 InputCapsule capsule = e.getCapsule(this);
166 zSamples = capsule.readInt("zSamples", 0);
167 radialSamples = capsule.readInt("radialSamples", 0);
168 radius = capsule.readFloat("radius", 0);
169 center = (Vector3f) capsule
170 .readSavable("center", Vector3f.ZERO.clone());
171 textureMode = capsule.readInt("textureMode", TEX_ORIGINAL);
175 * @deprecated Use {@link #updateGeometry(Vector3f,int,int,float)} instead
177 public void setCenter(Vector3f aCenter) {
182 * @deprecated Use {@link #updateGeometry(Vector3f,int,int,float)} instead
184 public void setData(Vector3f center, int zSamples, int radialSamples, float radius) {
185 updateGeometry(center, zSamples, radialSamples, radius);
189 * builds the vertices based on the radius, center and radial and zSamples.
191 private void setGeometryData() {
193 setVertexCount((zSamples - 2) * (radialSamples + 1) + 2);
194 setVertexBuffer(BufferUtils.createVector3Buffer(getVertexBuffer(),
197 // allocate normals if requested
198 setNormalBuffer(BufferUtils.createVector3Buffer(getNormalBuffer(),
201 // allocate texture coordinates
202 setTextureCoords(new TexCoords(BufferUtils.createVector2Buffer(getVertexCount())));
205 float fInvRS = 1.0f / radialSamples;
206 float fZFactor = 2.0f / (zSamples - 1);
208 // Generate points on the unit circle to be used in computing the mesh
209 // points on a sphere slice.
210 float[] afSin = new float[(radialSamples + 1)];
211 float[] afCos = new float[(radialSamples + 1)];
212 for (int iR = 0; iR < radialSamples; iR++) {
213 float fAngle = FastMath.TWO_PI * fInvRS * iR;
214 afCos[iR] = FastMath.cos(fAngle);
215 afSin[iR] = FastMath.sin(fAngle);
217 afSin[radialSamples] = afSin[0];
218 afCos[radialSamples] = afCos[0];
220 // generate the sphere itself
222 for (int iZ = 1; iZ < (zSamples - 1); iZ++) {
223 float fZFraction = -1.0f + fZFactor * iZ; // in (-1,1)
224 float fZ = radius * fZFraction;
226 // compute center of slice
227 Vector3f kSliceCenter = tempVb.set(center);
228 kSliceCenter.z += fZ;
230 // compute radius of slice
231 float fSliceRadius = FastMath.sqrt(FastMath.abs(radius * radius
234 // compute slice vertices with duplication at end point
237 for (int iR = 0; iR < radialSamples; iR++) {
238 float fRadialFraction = iR * fInvRS; // in [0,1)
239 Vector3f kRadial = tempVc.set(afCos[iR], afSin[iR], 0);
240 kRadial.mult(fSliceRadius, tempVa);
241 getVertexBuffer().put(kSliceCenter.x + tempVa.x).put(
242 kSliceCenter.y + tempVa.y).put(
243 kSliceCenter.z + tempVa.z);
245 BufferUtils.populateFromBuffer(tempVa, getVertexBuffer(), i);
246 kNormal = tempVa.subtractLocal(center);
247 kNormal.normalizeLocal();
248 if (true) // later we may allow interior texture vs. exterior
249 getNormalBuffer().put(kNormal.x).put(kNormal.y).put(
252 getNormalBuffer().put(-kNormal.x).put(-kNormal.y).put(
255 if (textureMode == TEX_ORIGINAL)
256 getTextureCoords().get(0).coords.put(fRadialFraction).put(
257 0.5f * (fZFraction + 1.0f));
258 else if (textureMode == TEX_PROJECTED)
259 getTextureCoords().get(0).coords.put(fRadialFraction).put(
261 * (FastMath.HALF_PI + FastMath
267 BufferUtils.copyInternalVector3(getVertexBuffer(), iSave, i);
268 BufferUtils.copyInternalVector3(getNormalBuffer(), iSave, i);
270 if (textureMode == TEX_ORIGINAL)
271 getTextureCoords().get(0).coords.put(1.0f).put(
272 0.5f * (fZFraction + 1.0f));
273 else if (textureMode == TEX_PROJECTED)
274 getTextureCoords().get(0).coords.put(1.0f)
277 * (FastMath.HALF_PI + FastMath
284 getVertexBuffer().position(i * 3);
285 getVertexBuffer().put(center.x).put(center.y).put(center.z - radius);
287 getNormalBuffer().position(i * 3);
289 getNormalBuffer().put(0).put(0).put(-1); // allow for inner
290 // texture orientation
293 getNormalBuffer().put(0).put(0).put(1);
295 getTextureCoords().get(0).coords.position(i * 2);
296 getTextureCoords().get(0).coords.put(0.5f).put(0.0f);
301 getVertexBuffer().put(center.x).put(center.y).put(center.z + radius);
304 getNormalBuffer().put(0).put(0).put(1);
306 getNormalBuffer().put(0).put(0).put(-1);
308 getTextureCoords().get(0).coords.put(0.5f).put(1.0f);
312 * sets the indices for rendering the sphere.
314 private void setIndexData() {
315 // allocate connectivity
316 setTriangleQuantity(2 * (zSamples - 2) * radialSamples);
317 setIndexBuffer(BufferUtils.createIntBuffer(3 * getTriangleCount()));
319 // generate connectivity
321 for (int iZ = 0, iZStart = 0; iZ < (zSamples - 3); iZ++) {
324 iZStart += (radialSamples + 1);
327 for (int i = 0; i < radialSamples; i++, index += 6) {
329 getIndexBuffer().put(i0++);
330 getIndexBuffer().put(i1);
331 getIndexBuffer().put(i2);
332 getIndexBuffer().put(i1++);
333 getIndexBuffer().put(i3++);
334 getIndexBuffer().put(i2++);
335 } else // inside view
337 getIndexBuffer().put(i0++);
338 getIndexBuffer().put(i2);
339 getIndexBuffer().put(i1);
340 getIndexBuffer().put(i1++);
341 getIndexBuffer().put(i2++);
342 getIndexBuffer().put(i3++);
347 // south pole triangles
348 for (int i = 0; i < radialSamples; i++, index += 3) {
350 getIndexBuffer().put(i);
351 getIndexBuffer().put(getVertexCount() - 2);
352 getIndexBuffer().put(i + 1);
353 } else { // inside view
354 getIndexBuffer().put(i);
355 getIndexBuffer().put(i + 1);
356 getIndexBuffer().put(getVertexCount() - 2);
360 // north pole triangles
361 int iOffset = (zSamples - 3) * (radialSamples + 1);
362 for (int i = 0; i < radialSamples; i++, index += 3) {
364 getIndexBuffer().put(i + iOffset);
365 getIndexBuffer().put(i + 1 + iOffset);
366 getIndexBuffer().put(getVertexCount() - 1);
367 } else { // inside view
368 getIndexBuffer().put(i + iOffset);
369 getIndexBuffer().put(getVertexCount() - 1);
370 getIndexBuffer().put(i + 1 + iOffset);
377 * The textureMode to set.
379 public void setTextureMode(int textureMode) {
380 this.textureMode = textureMode;
385 * Changes the information of the sphere into the given values.
387 * @param center the center of the sphere.
388 * @param zSamples the number of zSamples of the sphere.
389 * @param radialSamples the number of radial samples of the sphere.
390 * @param radius the radius of the sphere.
392 public void updateGeometry(Vector3f center, int zSamples, int radialSamples, float radius) {
393 this.center = center != null ? center : new Vector3f();
394 this.zSamples = zSamples;
395 this.radialSamples = radialSamples;
396 this.radius = radius;
401 public void write(JMEExporter e) throws IOException {
403 OutputCapsule capsule = e.getCapsule(this);
404 capsule.write(zSamples, "zSamples", 0);
405 capsule.write(radialSamples, "radialSamples", 0);
406 capsule.write(radius, "radius", 0);
407 capsule.write(center, "center", Vector3f.ZERO);
408 capsule.write(textureMode, "textureMode", TEX_ORIGINAL);