use of com.jme3.scene.Spatial in project jmonkeyengine by jMonkeyEngine.
the class TextureAtlas method makeAtlasBatch.
/**
* Creates one geometry out of the given root spatial and merges all single
* textures into one texture of the given size.
* @param spat The root spatial of the scene to batch
* @param mgr An assetmanager that can be used to create the material.
* @param atlasSize A size for the atlas texture, it has to be large enough to hold all single textures.
* @return A new geometry that uses the generated texture atlas and merges all meshes of the root spatial, null if the atlas cannot be created because not all textures fit.
*/
public static Geometry makeAtlasBatch(Spatial spat, AssetManager mgr, int atlasSize) {
List<Geometry> geometries = new ArrayList<Geometry>();
GeometryBatchFactory.gatherGeoms(spat, geometries);
TextureAtlas atlas = createAtlas(spat, atlasSize);
if (atlas == null) {
return null;
}
Geometry geom = new Geometry();
Mesh mesh = new Mesh();
GeometryBatchFactory.mergeGeometries(geometries, mesh);
applyAtlasCoords(geometries, mesh, atlas);
mesh.updateCounts();
mesh.updateBound();
geom.setMesh(mesh);
Material mat = new Material(mgr, "Common/MatDefs/Light/Lighting.j3md");
Texture diffuseMap = atlas.getAtlasTexture("DiffuseMap");
Texture normalMap = atlas.getAtlasTexture("NormalMap");
Texture specularMap = atlas.getAtlasTexture("SpecularMap");
if (diffuseMap != null) {
mat.setTexture("DiffuseMap", diffuseMap);
}
if (normalMap != null) {
mat.setTexture("NormalMap", normalMap);
}
if (specularMap != null) {
mat.setTexture("SpecularMap", specularMap);
}
mat.setFloat("Shininess", 16.0f);
geom.setMaterial(mat);
return geom;
}
use of com.jme3.scene.Spatial in project jmonkeyengine by jMonkeyEngine.
the class TextureAtlas method createAtlas.
/**
* Create a texture atlas for the given root node, containing DiffuseMap, NormalMap and SpecularMap.
* @param root The rootNode to create the atlas for.
* @param atlasSize The size of the atlas (width and height).
* @return Null if the atlas cannot be created because not all textures fit.
*/
public static TextureAtlas createAtlas(Spatial root, int atlasSize) {
List<Geometry> geometries = new ArrayList<Geometry>();
GeometryBatchFactory.gatherGeoms(root, geometries);
TextureAtlas atlas = new TextureAtlas(atlasSize, atlasSize);
for (Geometry geometry : geometries) {
if (!atlas.addGeometry(geometry)) {
logger.log(Level.WARNING, "Texture atlas size too small, cannot add all textures");
return null;
}
}
return atlas;
}
use of com.jme3.scene.Spatial in project jmonkeyengine by jMonkeyEngine.
the class FbxLoader method constructAnimations.
private void constructAnimations() {
// In FBX, animation are not attached to any root.
// They are implicitly global.
// So, we need to use hueristics to find which node(s)
// an animation is associated with, so we can create the AnimControl
// in the appropriate location in the scene.
Map<FbxToJmeTrack, FbxToJmeTrack> pairs = new HashMap<FbxToJmeTrack, FbxToJmeTrack>();
for (FbxAnimStack stack : animStacks) {
for (FbxAnimLayer layer : stack.getLayers()) {
for (FbxAnimCurveNode curveNode : layer.getAnimationCurveNodes()) {
for (Map.Entry<FbxNode, String> nodePropertyEntry : curveNode.getInfluencedNodeProperties().entrySet()) {
FbxToJmeTrack lookupPair = new FbxToJmeTrack();
lookupPair.animStack = stack;
lookupPair.animLayer = layer;
lookupPair.node = nodePropertyEntry.getKey();
// Find if this pair is already stored
FbxToJmeTrack storedPair = pairs.get(lookupPair);
if (storedPair == null) {
// If not, store it.
storedPair = lookupPair;
pairs.put(storedPair, storedPair);
}
String property = nodePropertyEntry.getValue();
storedPair.animCurves.put(property, curveNode);
}
}
}
}
// At this point we can construct the animation for all pairs ...
for (FbxToJmeTrack pair : pairs.values()) {
String animName = pair.animStack.getName();
float duration = pair.animStack.getDuration();
System.out.println("ANIMATION: " + animName + ", duration = " + duration);
System.out.println("NODE: " + pair.node.getName());
duration = pair.getDuration();
if (pair.node instanceof FbxLimbNode) {
// Find the spatial that has the skeleton for this limb.
FbxLimbNode limbNode = (FbxLimbNode) pair.node;
Bone bone = limbNode.getJmeBone();
Spatial jmeSpatial = limbNode.getSkeletonHolder().getJmeObject();
Skeleton skeleton = limbNode.getSkeletonHolder().getJmeSkeleton();
// Get the animation control (create if missing).
AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
if (animControl.getSkeleton() != skeleton) {
throw new UnsupportedOperationException();
}
// Get the animation (create if missing).
Animation anim = animControl.getAnim(animName);
if (anim == null) {
anim = new Animation(animName, duration);
animControl.addAnim(anim);
}
// Find the bone index from the spatial's skeleton.
int boneIndex = skeleton.getBoneIndex(bone);
// Generate the bone track.
BoneTrack bt = pair.toJmeBoneTrack(boneIndex, bone.getBindInverseTransform());
// Add the bone track to the animation.
anim.addTrack(bt);
} else {
// Create the spatial animation
Animation anim = new Animation(animName, duration);
anim.setTracks(new Track[] { pair.toJmeSpatialTrack() });
// Get the animation control (create if missing).
Spatial jmeSpatial = pair.node.getJmeObject();
AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
if (animControl == null) {
animControl = new AnimControl(null);
jmeSpatial.addControl(animControl);
}
// Add the spatial animation
animControl.addAnim(anim);
}
}
}
use of com.jme3.scene.Spatial in project jmonkeyengine by jMonkeyEngine.
the class ObjectHelper method isParent.
/**
* Checks if the first given OMA points to a parent of the second one.
* The parent need not to be the direct one. This method should be called when we are sure
* that both of the features are alred loaded because it does not check it.
* The OMA's should point to a spatials, otherwise the function will throw ClassCastException.
* @param supposedParentOMA
* the OMA of the node that we suppose might be a parent of the second one
* @param spatialOMA
* the OMA of the scene's node
* @return <b>true</b> if the first given OMA points to a parent of the second one and <b>false</b> otherwise
*/
public boolean isParent(Long supposedParentOMA, Long spatialOMA) {
Spatial supposedParent = (Spatial) blenderContext.getLoadedFeature(supposedParentOMA, LoadedDataType.FEATURE);
Spatial spatial = (Spatial) blenderContext.getLoadedFeature(spatialOMA, LoadedDataType.FEATURE);
Spatial parent = spatial.getParent();
while (parent != null) {
if (parent.equals(supposedParent)) {
return true;
}
parent = parent.getParent();
}
return false;
}
use of com.jme3.scene.Spatial in project jmonkeyengine by jMonkeyEngine.
the class CombinedTexture method generateSkyTexture.
/**
* Generates a texture that will be used by the sky spatial.
* The result texture has 6 layers. Every image in each layer has equal size and its shape is a square.
* The size of each image is the maximum size (width or height) of the textures given.
* The default sky generated texture size is used (this value is set in the BlenderKey) if no picture textures
* are present or their sizes is lower than the generated texture size.
* The textures of lower sizes are properly scaled.
* All the textures are mixed into one and put as layers in the result texture.
*
* @param horizontalColor
* the horizon color
* @param zenithColor
* the zenith color
* @param blenderContext
* the blender context
* @return texture for the sky
*/
public TextureCubeMap generateSkyTexture(ColorRGBA horizontalColor, ColorRGBA zenithColor, BlenderContext blenderContext) {
LOGGER.log(Level.FINE, "Preparing sky texture from {0} applied textures.", textureDatas.size());
LOGGER.fine("Computing the texture size.");
int size = -1;
for (TextureData textureData : textureDatas) {
if (textureData.texture instanceof Texture2D) {
size = Math.max(textureData.texture.getImage().getWidth(), size);
size = Math.max(textureData.texture.getImage().getHeight(), size);
}
}
if (size < 0) {
size = blenderContext.getBlenderKey().getSkyGeneratedTextureSize();
}
LOGGER.log(Level.FINE, "The sky texture size will be: {0}x{0}.", size);
TextureCubeMap result = null;
for (TextureData textureData : textureDatas) {
TextureCubeMap texture = null;
if (textureData.texture instanceof GeneratedTexture) {
texture = ((GeneratedTexture) textureData.texture).generateSkyTexture(size, horizontalColor, zenithColor, blenderContext);
} else {
// first create a grayscale version of the image
Image image = textureData.texture.getImage();
if (image.getWidth() != image.getHeight() || image.getWidth() != size) {
image = ImageUtils.resizeTo(image, size, size);
}
Image grayscaleImage = ImageUtils.convertToGrayscaleTexture(image);
// add the sky colors to the image
PixelInputOutput sourcePixelIO = PixelIOFactory.getPixelIO(grayscaleImage.getFormat());
PixelInputOutput targetPixelIO = PixelIOFactory.getPixelIO(image.getFormat());
TexturePixel texturePixel = new TexturePixel();
for (int x = 0; x < image.getWidth(); ++x) {
for (int y = 0; y < image.getHeight(); ++y) {
sourcePixelIO.read(grayscaleImage, 0, texturePixel, x, y);
// no matter which factor we use here, in grayscale they are all equal
texturePixel.intensity = texturePixel.red;
ImageUtils.color(texturePixel, horizontalColor, zenithColor);
targetPixelIO.write(image, 0, texturePixel, x, y);
}
}
// create the cubemap texture from the coloured image
ByteBuffer sourceData = image.getData(0);
ArrayList<ByteBuffer> data = new ArrayList<ByteBuffer>(6);
for (int i = 0; i < 6; ++i) {
data.add(BufferUtils.clone(sourceData));
}
texture = new TextureCubeMap(new Image(image.getFormat(), image.getWidth(), image.getHeight(), 6, data, ColorSpace.Linear));
}
if (result == null) {
result = texture;
} else {
ImageUtils.mix(result.getImage(), texture.getImage());
}
}
return result;
}
Aggregations