public static Node createPatchField(Spatial spatial,
AssetManager assetManager, String texturePath,
float patchScaleVariation, float patchWidth, float patchHeight,
float inc, float fadeEnd, float fadeRange, float minIntensity,
int channelId, int clusters) {
Node spatNode = (Node) spatial;
Node grassLayer = new Node("grass_" + spatial.getName());
grassLayer.setModelBound(new BoundingBox());
Texture tex = assetManager.loadTexture(texturePath);
Material faceMat = new Material(assetManager,
"/com/l2client/materials/LightingGrass.j3md");
faceMat.getAdditionalRenderState().setBlendMode(
RenderState.BlendMode.Alpha);
faceMat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off);
faceMat.getAdditionalRenderState().setDepthWrite(true);
faceMat.getAdditionalRenderState().setDepthTest(true);
faceMat.setTransparent(true);
faceMat.setTextureParam("DiffuseMap", VarType.Texture2D, tex);
faceMat.setFloat("AlphaDiscardThreshold", 0.3f);
// faceMat.setTextureParam("AlphaMap", VarType.Texture2D,tex);
faceMat.setBoolean("UseAlpha", true);
if (fadeEnd > 0f) {
faceMat.setFloat("FadeEnd", fadeEnd);// 300f);
faceMat.setFloat("FadeRange", fadeRange); // 50f);
faceMat.setBoolean("FadeEnabled", true);
}
faceMat.setBoolean("Swaying", true);
faceMat.setVector3("SwayData", new Vector3f(1.0f, 0.5f, 300f));// frequency,
// variation,
// third?
faceMat.setVector2("Wind", new Vector2f(1f, 1f));
Geometry terrain = null;
if (spatial instanceof Geometry) {
terrain = (Geometry) spatial;
} else {
for (Spatial currentSpatial : spatNode.getChildren()) {
if (currentSpatial instanceof Geometry) {
terrain = (Geometry) currentSpatial;
break;
}
}
}
if (terrain == null || spatNode.getChildren().isEmpty()) {
Logger.getLogger(GrassLayerUtil.class.getName()).log(Level.SEVERE,
"Could not find terrain object.", new Exception());
System.exit(0);
}
// Generate grass uniformly with random offset.
float terrainWidth = 1f * 256; // get width length of terrain(assuming
// its a square)
BoundingVolume bounds = ((Spatial) terrain).getWorldBound();
if (BoundingVolume.Type.AABB.equals(bounds.getType())) {
BoundingBox bb = ((BoundingBox) bounds);
terrainWidth = Math.max(bb.getXExtent(), bb.getZExtent());
terrainWidth *= 2f;
} else if (BoundingVolume.Type.Sphere.equals(bounds.getType())) {
terrainWidth = ((BoundingSphere) bounds).getRadius();
terrainWidth *= 2f;
}
Vector3f centre = bounds.getCenter(); // get the centr location of the
// terrain
Vector2f grassPatchRandomOffset = new Vector2f().zero();
Vector3f candidateGrassPatchLocation = new Vector3f();
Random rand = new Random();
Ray ray = new Ray(Vector3f.ZERO, Vector3f.UNIT_Y.mult(-1f));
CollisionResults results = new CollisionResults();
float ax, az;
for (float x = centre.x - terrainWidth / 2 + inc; x < centre.x
+ terrainWidth / 2 - inc; x += inc) {
for (float z = centre.z - terrainWidth / 2 + inc; z < centre.z
+ terrainWidth / 2 - inc; z += inc) {
grassPatchRandomOffset.set(inc, inc);
grassPatchRandomOffset.multLocal(rand.nextFloat()); // make the
// off set
// length a
// random
// distance
// smaller
// than the
// increment
// size
grassPatchRandomOffset
.rotateAroundOrigin(
(float) (((int) (rand.nextFloat() * 359)) * (Math.PI / 180)),
true); // rotate the offset by a random angle
ax = x + grassPatchRandomOffset.x;
az = z + grassPatchRandomOffset.y;
ray.setOrigin(new Vector3f(ax, centre.y + terrainWidth, az));
terrain.collideWith(ray, results);
if (results.size() <= 0)
continue;
try {
if (results.size() > 0) {
candidateGrassPatchLocation.set(ax, results
.getCollision(0).getContactPoint().y, az);
results.clear();
if (isGrassLayer(candidateGrassPatchLocation, terrain,
minIntensity, terrainWidth, channelId)) {
// this will be in world coords, but we want it to
// be in local
candidateGrassPatchLocation.subtractLocal(terrain
.getWorldTranslation());
grassLayer.attachChild(createGrassPatch(
candidateGrassPatchLocation, faceMat,
patchScaleVariation, patchWidth,
patchHeight, rand.nextFloat()));
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
GeometryBatchFactory.optimize(grassLayer);
grassLayer.updateGeometricState();
// DistanceLodControl c = new DistanceLodControl();
// (grassLayer).getChild(0).addControl(c);
// c.setDistTolerance(250f);