de.javagl.jgltf.model.BoundingBoxComputer Maven / Gradle / Ivy
/*
* www.javagl.de - JglTF
*
* Copyright 2015-2016 Marco Hutter - http://www.javagl.de
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package de.javagl.jgltf.model;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
/**
* A (package-private!) utility class to compute bounding volumes
*/
class BoundingBoxComputer
{
/**
* The logger used in this class
*/
private static final Logger logger =
Logger.getLogger(BoundingBoxComputer.class.getName());
/**
* The {@link GltfModel}
*/
private final GltfModel gltfModel;
/**
* Create a new bounding box computer for the given {@link GltfModel}
*
* @param gltfModel The {@link GltfModel}
*/
BoundingBoxComputer(GltfModel gltfModel)
{
this.gltfModel = gltfModel;
}
/**
* Compute the bounding box of the {@link GltfModel}
*
* @return The bounding box
*/
BoundingBox compute()
{
BoundingBox boundingBox = new BoundingBox();
List sceneModels = gltfModel.getSceneModels();
for (SceneModel sceneModel : sceneModels)
{
float rootTransform[] = MathUtils.createIdentity4x4();
computeSceneBoundingBox(sceneModel, rootTransform, boundingBox);
}
return boundingBox;
}
/**
* Recursively compute the bounding box of the {@link MeshPrimitiveModel}
* objects of all {@link MeshModel} objects in the given {@link SceneModel}
* (including the respective global node transforms).
* If the given result is null
, then a new bounding box
* will be created and returned.
*
* @param sceneModel The {@link SceneModel}
* @param transform The root transform, as a column major 4x4 matrix
* @param boundingBox The optional bounding box that will store the result
* @return The result
*/
private BoundingBox computeSceneBoundingBox(
SceneModel sceneModel, float transform[], BoundingBox boundingBox)
{
BoundingBox localResult = boundingBox;
if (localResult == null)
{
localResult = new BoundingBox();
}
List nodeModels = sceneModel.getNodeModels();
for (NodeModel nodeModel : nodeModels)
{
computeNodeBoundingBox(nodeModel, transform, localResult);
}
return localResult;
}
/**
* Recursively compute the bounding box of the {@link MeshPrimitiveModel}
* objects of all {@link MeshModel} objects in the given {@link NodeModel}
* and its children (including the respective global node transforms).
* If the given result is null
, then a new bounding box
* will be created and returned.
*
* @param nodeModel The {@link NodeModel}
* @param parentTransform The transform, as a column major 4x4 matrix
* @param boundingBox The optional bounding box that will store the result
* @return The result
*/
private BoundingBox computeNodeBoundingBox(
NodeModel nodeModel, float parentTransform[], BoundingBox boundingBox)
{
BoundingBox result = boundingBox;
if (result == null)
{
result = new BoundingBox();
}
float[] localTransform = nodeModel.computeLocalTransform(null);
float[] transform = new float[16];
MathUtils.mul4x4(parentTransform, localTransform, transform);
List meshModels = nodeModel.getMeshModels();
for (MeshModel meshModel : meshModels)
{
BoundingBox meshBoundingBox =
computeMeshBoundingBox(
meshModel, transform, result);
result.combine(meshBoundingBox);
}
List children = nodeModel.getChildren();
for (NodeModel child : children)
{
computeNodeBoundingBox(child, transform, result);
}
return result;
}
/**
* Compute the bounding box of the given {@link MeshModel}, under
* the given transform.
* If the given result is null
, then a new bounding box
* will be created and returned.
*
* @param meshModel The {@link MeshModel}
* @param transform The optional transform. If this is null
,
* then the identity matrix will be assumed.
* @param boundingBox The optional bounding box that will store the result
* @return The result
*/
private BoundingBox computeMeshBoundingBox(
MeshModel meshModel, float transform[], BoundingBox boundingBox)
{
BoundingBox result = boundingBox;
if (result == null)
{
result = new BoundingBox();
}
List primitives =
meshModel.getMeshPrimitiveModels();
for (MeshPrimitiveModel meshPrimitiveModel : primitives)
{
BoundingBox meshPrimitiveBoundingBox =
computeBoundingBox(meshPrimitiveModel, transform);
if (meshPrimitiveBoundingBox != null)
{
result.combine(meshPrimitiveBoundingBox);
}
}
return result;
}
/**
* Compute the bounding box of the given {@link MeshPrimitiveModel}, under
* the given transform.
*
* @param meshPrimitiveModel The {@link MeshPrimitiveModel}
* @param transform The optional transform. If this is null
,
* then the identity matrix will be assumed.
* @return The {@link BoundingBox}, or null
if the given
* {@link MeshPrimitiveModel} does not refer to an {@link AccessorModel}
* with its "POSITION"
attribute. If if refers to
* an {@link AccessorModel} that does not contain 3D float elements,
* then a warning will be printed and null
will be
* returned.
*/
private BoundingBox computeBoundingBox(
MeshPrimitiveModel meshPrimitiveModel, float transform[])
{
Map attributes =
meshPrimitiveModel.getAttributes();
String positionsAttributeName = "POSITION";
AccessorModel accessorModel = attributes.get(positionsAttributeName);
if (accessorModel == null)
{
return null;
}
ElementType accessorType = accessorModel.getElementType();
int numComponents = accessorType.getNumComponents();
if (numComponents < 3)
{
logger.warning("Mesh primitive " + positionsAttributeName +
" attribute refers to an accessor with type " + accessorType +
" - expected \"VEC3\" or \"VEC4\"");
return null;
}
Class> componentDataType = accessorModel.getComponentDataType();
if (!componentDataType.equals(float.class))
{
logger.warning("Mesh primitive " + positionsAttributeName +
" attribute refers to an accessor with component type " +
GltfConstants.stringFor(accessorModel.getComponentType()) +
" - expected GL_FLOAT");
}
AccessorData accessorData = accessorModel.getAccessorData();
AccessorFloatData accessorFloatData = (AccessorFloatData)accessorData;
float point[] = new float[3];
float transformedPoint[];
if (transform != null)
{
transformedPoint = new float[3];
}
else
{
transformedPoint = point;
}
BoundingBox boundingBox = new BoundingBox();
for (int e = 0; e < accessorData.getNumElements(); e++)
{
for (int c = 0; c < 3; c++)
{
point[c] = accessorFloatData.get(e, c);
}
if (transform != null)
{
MathUtils.transformPoint3D(transform, point, transformedPoint);
}
boundingBox.combine(
transformedPoint[0],
transformedPoint[1],
transformedPoint[2]);
}
return boundingBox;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy