Merge branch 'master' into PBRisComing
This commit is contained in:
commit
be58be75ef
21
.travis.yml
21
.travis.yml
@ -14,11 +14,28 @@ branches:
|
|||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
slack:
|
slack:
|
||||||
secure: "PWEk4+VL986c3gAjWp12nqyifvxCjBqKoESG9d7zWh1uiTLadTHhZJRMdsye36FCpz/c/Jt7zCRO/5y7FaubQptnRrkrRfjp5f99MJRzQVXnUAM+y385qVkXKRKd/PLpM7XPm4AvjvxHCyvzX2wamRvul/TekaXKB9Ti5FCN87s="
|
|
||||||
on_success: change
|
on_success: change
|
||||||
on_failure: always
|
on_failure: always
|
||||||
|
rooms:
|
||||||
|
secure: "PWEk4+VL986c3gAjWp12nqyifvxCjBqKoESG9d7zWh1uiTLadTHhZJRMdsye36FCpz/c/Jt7zCRO/5y7FaubQptnRrkrRfjp5f99MJRzQVXnUAM+y385qVkXKRKd/PLpM7XPm4AvjvxHCyvzX2wamRvul/TekaXKB9Ti5FCN87s="
|
||||||
|
|
||||||
before_install:
|
install:
|
||||||
|
- ./gradlew assemble
|
||||||
|
|
||||||
|
script:
|
||||||
|
- ./gradlew check
|
||||||
|
- ./gradlew createZipDistribution
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
provider: releases
|
||||||
|
api_key:
|
||||||
|
secure: "KbFiMt0a8FxUKvCJUYwikLYaqqGMn1p6k4OsXnGqwptQZEUIayabNLHeaD2kTNT3e6AY1ETwQLff/lB2LttmIo4g5NWW63g1K3A/HwgnhJwETengiProZ/Udl+ugPeDL/+ar43HUhFq4knBnzFKnEcHAThTPVqH/RMDvZf1UUYI="
|
||||||
|
file: build/distributions/jME3.1.0_snapshot-github_2015-06-20.zip
|
||||||
|
skip_cleanup: true
|
||||||
|
on:
|
||||||
|
tags: true
|
||||||
|
|
||||||
|
# before_install:
|
||||||
# required libs for android build tools
|
# required libs for android build tools
|
||||||
# sudo apt-get update
|
# sudo apt-get update
|
||||||
# sudo apt-get install -qq p7zip-full
|
# sudo apt-get install -qq p7zip-full
|
||||||
|
@ -6,4 +6,7 @@ dependencies {
|
|||||||
compile project(':jme3-core')
|
compile project(':jme3-core')
|
||||||
compile project(':jme3-desktop')
|
compile project(':jme3-desktop')
|
||||||
compile project(':jme3-effects')
|
compile project(':jme3-effects')
|
||||||
|
compile ('org.ejml:core:0.27')
|
||||||
|
compile ('org.ejml:dense64:0.27')
|
||||||
|
compile ('org.ejml:simple:0.27')
|
||||||
}
|
}
|
@ -64,7 +64,7 @@ public abstract class Constraint {
|
|||||||
Pointer pData = (Pointer) constraintStructure.getFieldValue("data");
|
Pointer pData = (Pointer) constraintStructure.getFieldValue("data");
|
||||||
if (pData.isNotNull()) {
|
if (pData.isNotNull()) {
|
||||||
Structure data = pData.fetchData().get(0);
|
Structure data = pData.fetchData().get(0);
|
||||||
constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(data, ownerOMA, blenderContext);
|
constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(data, name, ownerOMA, blenderContext);
|
||||||
Pointer pTar = (Pointer) data.getFieldValue("tar");
|
Pointer pTar = (Pointer) data.getFieldValue("tar");
|
||||||
if (pTar != null && pTar.isNotNull()) {
|
if (pTar != null && pTar.isNotNull()) {
|
||||||
targetOMA = pTar.getOldMemoryAddress();
|
targetOMA = pTar.getOldMemoryAddress();
|
||||||
@ -77,7 +77,7 @@ public abstract class Constraint {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Null constraint has no data, so create it here
|
// Null constraint has no data, so create it here
|
||||||
constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(null, null, blenderContext);
|
constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(null, name, null, blenderContext);
|
||||||
}
|
}
|
||||||
ownerSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("ownspace")).byteValue());
|
ownerSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("ownspace")).byteValue());
|
||||||
ipo = influenceIpo;
|
ipo = influenceIpo;
|
||||||
|
@ -7,6 +7,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.Stack;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.jme3.animation.AnimChannel;
|
import com.jme3.animation.AnimChannel;
|
||||||
@ -209,7 +210,6 @@ public class SimulationNode {
|
|||||||
TempVars vars = TempVars.get();
|
TempVars vars = TempVars.get();
|
||||||
AnimChannel animChannel = animControl.createChannel();
|
AnimChannel animChannel = animControl.createChannel();
|
||||||
|
|
||||||
// List<Bone> bonesWithConstraints = this.collectBonesWithConstraints(skeleton);
|
|
||||||
for (Animation animation : animations) {
|
for (Animation animation : animations) {
|
||||||
float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation);
|
float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation);
|
||||||
int maxFrame = (int) animationTimeBoundaries[0];
|
int maxFrame = (int) animationTimeBoundaries[0];
|
||||||
@ -233,7 +233,7 @@ public class SimulationNode {
|
|||||||
for (Bone rootBone : skeleton.getRoots()) {
|
for (Bone rootBone : skeleton.getRoots()) {
|
||||||
// ignore the 0-indexed bone
|
// ignore the 0-indexed bone
|
||||||
if (skeleton.getBoneIndex(rootBone) > 0) {
|
if (skeleton.getBoneIndex(rootBone) > 0) {
|
||||||
this.applyConstraints(rootBone, alteredOmas, applied, frame);
|
this.applyConstraints(rootBone, alteredOmas, applied, frame, new Stack<Bone>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,18 +294,21 @@ public class SimulationNode {
|
|||||||
* the set of OMAS of the altered bones (is populated if necessary)
|
* the set of OMAS of the altered bones (is populated if necessary)
|
||||||
* @param frame
|
* @param frame
|
||||||
* the current frame of the animation
|
* the current frame of the animation
|
||||||
|
* @param bonesStack
|
||||||
|
* the stack of bones used to avoid infinite loops while applying constraints
|
||||||
*/
|
*/
|
||||||
private void applyConstraints(Bone bone, Set<Long> alteredOmas, Set<Long> applied, int frame) {
|
private void applyConstraints(Bone bone, Set<Long> alteredOmas, Set<Long> applied, int frame, Stack<Bone> bonesStack) {
|
||||||
|
if (!bonesStack.contains(bone)) {
|
||||||
|
bonesStack.push(bone);
|
||||||
BoneContext boneContext = blenderContext.getBoneContext(bone);
|
BoneContext boneContext = blenderContext.getBoneContext(bone);
|
||||||
if(!applied.contains(boneContext.getBoneOma())) {
|
if (!applied.contains(boneContext.getBoneOma())) {
|
||||||
List<Constraint> constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext);
|
List<Constraint> constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext);
|
||||||
if (constraints != null && constraints.size() > 0) {
|
if (constraints != null && constraints.size() > 0) {
|
||||||
// TODO: BEWARE OF INFINITE LOOPS !!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
for (Constraint constraint : constraints) {
|
for (Constraint constraint : constraints) {
|
||||||
if (constraint.getTargetOMA() != null && constraint.getTargetOMA() > 0L) {
|
if (constraint.getTargetOMA() != null && constraint.getTargetOMA() > 0L) {
|
||||||
// first apply constraints of the target bone
|
// first apply constraints of the target bone
|
||||||
BoneContext targetBone = blenderContext.getBoneContext(constraint.getTargetOMA());
|
BoneContext targetBone = blenderContext.getBoneContext(constraint.getTargetOMA());
|
||||||
this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame);
|
this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame, bonesStack);
|
||||||
}
|
}
|
||||||
constraint.apply(frame);
|
constraint.apply(frame);
|
||||||
if (constraint.getAlteredOmas() != null) {
|
if (constraint.getAlteredOmas() != null) {
|
||||||
@ -320,9 +323,11 @@ public class SimulationNode {
|
|||||||
List<Bone> children = bone.getChildren();
|
List<Bone> children = bone.getChildren();
|
||||||
if (children != null && children.size() > 0) {
|
if (children != null && children.size() > 0) {
|
||||||
for (Bone child : bone.getChildren()) {
|
for (Bone child : bone.getChildren()) {
|
||||||
this.applyConstraints(child, alteredOmas, applied, frame);
|
this.applyConstraints(child, alteredOmas, applied, frame, bonesStack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bonesStack.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +30,8 @@ public abstract class ConstraintDefinition {
|
|||||||
protected Set<Long> alteredOmas;
|
protected Set<Long> alteredOmas;
|
||||||
/** The variable that determines if the constraint will alter the track in any way. */
|
/** The variable that determines if the constraint will alter the track in any way. */
|
||||||
protected boolean trackToBeChanged = true;
|
protected boolean trackToBeChanged = true;
|
||||||
|
/** The name of the constraint. */
|
||||||
|
protected String constraintName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a constraint definition based on the constraint definition
|
* Loads a constraint definition based on the constraint definition
|
||||||
@ -54,6 +56,10 @@ public abstract class ConstraintDefinition {
|
|||||||
this.ownerOMA = ownerOMA;
|
this.ownerOMA = ownerOMA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setConstraintName(String constraintName) {
|
||||||
|
this.constraintName = constraintName;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return determines if the definition of the constraint will change the bone in any way; in most cases
|
* @return determines if the definition of the constraint will change the bone in any way; in most cases
|
||||||
* it is possible to tell that even before the constraint baking simulation is started, so we can discard such bones from constraint
|
* it is possible to tell that even before the constraint baking simulation is started, so we can discard such bones from constraint
|
||||||
|
@ -92,7 +92,7 @@ public class ConstraintDefinitionFactory {
|
|||||||
* this exception is thrown when the blender file is somehow
|
* this exception is thrown when the blender file is somehow
|
||||||
* corrupted
|
* corrupted
|
||||||
*/
|
*/
|
||||||
public static ConstraintDefinition createConstraintDefinition(Structure constraintStructure, Long ownerOMA, BlenderContext blenderContext) throws BlenderFileException {
|
public static ConstraintDefinition createConstraintDefinition(Structure constraintStructure, String constraintName, Long ownerOMA, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
if (constraintStructure == null) {
|
if (constraintStructure == null) {
|
||||||
return new ConstraintDefinitionNull(null, ownerOMA, blenderContext);
|
return new ConstraintDefinitionNull(null, ownerOMA, blenderContext);
|
||||||
}
|
}
|
||||||
@ -100,7 +100,9 @@ public class ConstraintDefinitionFactory {
|
|||||||
Class<? extends ConstraintDefinition> constraintDefinitionClass = CONSTRAINT_CLASSES.get(constraintClassName);
|
Class<? extends ConstraintDefinition> constraintDefinitionClass = CONSTRAINT_CLASSES.get(constraintClassName);
|
||||||
if (constraintDefinitionClass != null) {
|
if (constraintDefinitionClass != null) {
|
||||||
try {
|
try {
|
||||||
return (ConstraintDefinition) constraintDefinitionClass.getDeclaredConstructors()[0].newInstance(constraintStructure, ownerOMA, blenderContext);
|
ConstraintDefinition def = (ConstraintDefinition) constraintDefinitionClass.getDeclaredConstructors()[0].newInstance(constraintStructure, ownerOMA, blenderContext);
|
||||||
|
def.setConstraintName(constraintName);
|
||||||
|
return def;
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new BlenderFileException(e.getLocalizedMessage(), e);
|
throw new BlenderFileException(e.getLocalizedMessage(), e);
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
@ -113,9 +115,9 @@ public class ConstraintDefinitionFactory {
|
|||||||
throw new BlenderFileException(e.getLocalizedMessage(), e);
|
throw new BlenderFileException(e.getLocalizedMessage(), e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String constraintName = UNSUPPORTED_CONSTRAINTS.get(constraintClassName);
|
String unsupportedConstraintClassName = UNSUPPORTED_CONSTRAINTS.get(constraintClassName);
|
||||||
if (constraintName != null) {
|
if (unsupportedConstraintClassName != null) {
|
||||||
return new UnsupportedConstraintDefinition(constraintName);
|
return new UnsupportedConstraintDefinition(unsupportedConstraintClassName);
|
||||||
} else {
|
} else {
|
||||||
throw new BlenderFileException("Unknown constraint type: " + constraintClassName);
|
throw new BlenderFileException("Unknown constraint type: " + constraintClassName);
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,44 @@
|
|||||||
package com.jme3.scene.plugins.blender.constraints.definitions;
|
package com.jme3.scene.plugins.blender.constraints.definitions;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.ejml.simple.SimpleMatrix;
|
||||||
|
|
||||||
import com.jme3.animation.Bone;
|
import com.jme3.animation.Bone;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.math.Vector3f;
|
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.animations.BoneContext;
|
import com.jme3.scene.plugins.blender.animations.BoneContext;
|
||||||
|
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
|
||||||
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space;
|
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
import com.jme3.scene.plugins.blender.math.DQuaternion;
|
import com.jme3.scene.plugins.blender.math.DQuaternion;
|
||||||
import com.jme3.scene.plugins.blender.math.DTransform;
|
import com.jme3.scene.plugins.blender.math.DTransform;
|
||||||
|
import com.jme3.scene.plugins.blender.math.Matrix;
|
||||||
import com.jme3.scene.plugins.blender.math.Vector3d;
|
import com.jme3.scene.plugins.blender.math.Vector3d;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Inverse Kinematics constraint.
|
* A definiotion of a Inverse Kinematics constraint. This implementation uses Jacobian pseudoinverse algorithm.
|
||||||
*
|
*
|
||||||
* @author Wesley Shillingford (wezrule)
|
|
||||||
* @author Marcin Roguski (Kaelthas)
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
public class ConstraintDefinitionIK extends ConstraintDefinition {
|
public class ConstraintDefinitionIK extends ConstraintDefinition {
|
||||||
private static final float MIN_DISTANCE = 0.0001f;
|
private static final float MIN_DISTANCE = 0.001f;
|
||||||
|
private static final float MIN_ANGLE_CHANGE = 0.001f;
|
||||||
private static final int FLAG_USE_TAIL = 0x01;
|
private static final int FLAG_USE_TAIL = 0x01;
|
||||||
private static final int FLAG_POSITION = 0x20;
|
private static final int FLAG_POSITION = 0x20;
|
||||||
|
|
||||||
|
private BonesChain bones;
|
||||||
/** The number of affected bones. Zero means that all parent bones of the current bone should take part in baking. */
|
/** The number of affected bones. Zero means that all parent bones of the current bone should take part in baking. */
|
||||||
private int bonesAffected;
|
private int bonesAffected;
|
||||||
/** The total length of the bone chain. Useful for optimisation of computations speed in some cases. */
|
|
||||||
private double chainLength;
|
|
||||||
/** Indicates if the tail of the bone should be used or not. */
|
/** Indicates if the tail of the bone should be used or not. */
|
||||||
private boolean useTail;
|
private boolean useTail;
|
||||||
/** The amount of iterations of the algorithm. */
|
/** The amount of iterations of the algorithm. */
|
||||||
private int iterations;
|
private int iterations;
|
||||||
|
/** The count of bones' chain. */
|
||||||
|
private int bonesCount = -1;
|
||||||
|
|
||||||
public ConstraintDefinitionIK(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) {
|
public ConstraintDefinitionIK(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) {
|
||||||
super(constraintData, ownerOMA, blenderContext);
|
super(constraintData, ownerOMA, blenderContext);
|
||||||
@ -51,122 +55,104 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Below are the variables that only need to be allocated once for IK constraint instance.
|
||||||
|
*/
|
||||||
|
/** Temporal quaternion. */
|
||||||
|
private DQuaternion tempDQuaternion = new DQuaternion();
|
||||||
|
/** Temporal matrix column. */
|
||||||
|
private Vector3d col = new Vector3d();
|
||||||
|
/** Effector's position change. */
|
||||||
|
private Matrix deltaP = new Matrix(3, 1);
|
||||||
|
/** The current target position. */
|
||||||
|
private Vector3d target = new Vector3d();
|
||||||
|
/** Rotation vectors for each joint (allocated when we know the size of a bones' chain. */
|
||||||
|
private Vector3d[] rotationVectors;
|
||||||
|
/** The Jacobian matrix. Allocated when the bones' chain size is known. */
|
||||||
|
private Matrix J;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
|
||||||
if (influence == 0 || !trackToBeChanged || targetTransform == null) {
|
if (influence == 0 || !trackToBeChanged || targetTransform == null || bonesCount == 0) {
|
||||||
return;// no need to do anything
|
return;// no need to do anything
|
||||||
}
|
}
|
||||||
DQuaternion q = new DQuaternion();
|
|
||||||
Vector3d t = new Vector3d(targetTransform.getTranslation());
|
if (bones == null) {
|
||||||
List<BoneContext> bones = this.loadBones();
|
bones = new BonesChain((Bone) this.getOwner(), useTail, bonesAffected, alteredOmas, blenderContext);
|
||||||
|
}
|
||||||
if (bones.size() == 0) {
|
if (bones.size() == 0) {
|
||||||
|
bonesCount = 0;
|
||||||
return;// no need to do anything
|
return;// no need to do anything
|
||||||
}
|
}
|
||||||
double distanceFromTarget = Double.MAX_VALUE;
|
double distanceFromTarget = Double.MAX_VALUE;
|
||||||
|
target.set(targetTransform.getTranslation().x, targetTransform.getTranslation().y, targetTransform.getTranslation().z);
|
||||||
|
|
||||||
int iterations = this.iterations;
|
if (bonesCount < 0) {
|
||||||
if (bones.size() == 1) {
|
bonesCount = bones.size();
|
||||||
iterations = 1;// if only one bone is in the chain then only one iteration that will properly rotate it will be needed
|
rotationVectors = new Vector3d[bonesCount];
|
||||||
} else {
|
for (int i = 0; i < bonesCount; ++i) {
|
||||||
// if the target cannot be rached by the bones' chain then the chain will become straight and point towards the target
|
rotationVectors[i] = new Vector3d();
|
||||||
// in this case only one iteration will be needed, computed from the root to top bone
|
|
||||||
BoneContext rootBone = bones.get(bones.size() - 1);
|
|
||||||
Transform rootBoneTransform = constraintHelper.getTransform(rootBone.getArmatureObjectOMA(), rootBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD);
|
|
||||||
if (t.distance(new Vector3d(rootBoneTransform.getTranslation())) >= chainLength) {
|
|
||||||
Collections.reverse(bones);
|
|
||||||
|
|
||||||
for (BoneContext boneContext : bones) {
|
|
||||||
Bone bone = boneContext.getBone();
|
|
||||||
DTransform boneTransform = new DTransform(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD));
|
|
||||||
|
|
||||||
Vector3d e = boneTransform.getTranslation().add(boneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(boneContext.getLength()));// effector
|
|
||||||
Vector3d j = boneTransform.getTranslation(); // current join position
|
|
||||||
|
|
||||||
Vector3d currentDir = e.subtractLocal(j).normalizeLocal();
|
|
||||||
Vector3d target = t.subtract(j).normalizeLocal();
|
|
||||||
double angle = currentDir.angleBetween(target);
|
|
||||||
if (angle != 0) {
|
|
||||||
Vector3d cross = currentDir.crossLocal(target).normalizeLocal();
|
|
||||||
q.fromAngleAxis(angle, cross);
|
|
||||||
|
|
||||||
if(bone.equals(this.getOwner())) {
|
|
||||||
if (boneContext.isLockX()) {
|
|
||||||
q.set(0, q.getY(), q.getZ(), q.getW());
|
|
||||||
}
|
|
||||||
if (boneContext.isLockY()) {
|
|
||||||
q.set(q.getX(), 0, q.getZ(), q.getW());
|
|
||||||
}
|
|
||||||
if (boneContext.isLockZ()) {
|
|
||||||
q.set(q.getX(), q.getY(), 0, q.getW());
|
|
||||||
}
|
}
|
||||||
|
J = new Matrix(3, bonesCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
boneTransform.getRotation().set(q.multLocal(boneTransform.getRotation()));
|
|
||||||
constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneTransform.toTransform());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iterations = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Transform> bestSolution = new ArrayList<Transform>(bones.size());
|
|
||||||
double bestSolutionDistance = Double.MAX_VALUE;
|
|
||||||
BoneContext topBone = bones.get(0);
|
BoneContext topBone = bones.get(0);
|
||||||
for (int i = 0; i < iterations && distanceFromTarget > MIN_DISTANCE; ++i) {
|
for (int i = 0; i < iterations; ++i) {
|
||||||
for (BoneContext boneContext : bones) {
|
DTransform topBoneTransform = bones.getWorldTransform(topBone);
|
||||||
Bone bone = boneContext.getBone();
|
Vector3d e = topBoneTransform.getTranslation().add(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector
|
||||||
DTransform topBoneTransform = new DTransform(constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD));
|
distanceFromTarget = e.distance(target);
|
||||||
DTransform boneWorldTransform = new DTransform(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD));
|
if (distanceFromTarget <= MIN_DISTANCE) {
|
||||||
|
|
||||||
Vector3d e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector
|
|
||||||
Vector3d j = boneWorldTransform.getTranslation(); // current join position
|
|
||||||
|
|
||||||
Vector3d currentDir = e.subtractLocal(j).normalizeLocal();
|
|
||||||
Vector3d target = t.subtract(j).normalizeLocal();
|
|
||||||
double angle = currentDir.angleBetween(target);
|
|
||||||
if (angle != 0) {
|
|
||||||
Vector3d cross = currentDir.crossLocal(target).normalizeLocal();
|
|
||||||
q.fromAngleAxis(angle, cross);
|
|
||||||
|
|
||||||
if(bone.equals(this.getOwner())) {
|
|
||||||
if (boneContext.isLockX()) {
|
|
||||||
q.set(0, q.getY(), q.getZ(), q.getW());
|
|
||||||
}
|
|
||||||
if (boneContext.isLockY()) {
|
|
||||||
q.set(q.getX(), 0, q.getZ(), q.getW());
|
|
||||||
}
|
|
||||||
if (boneContext.isLockZ()) {
|
|
||||||
q.set(q.getX(), q.getY(), 0, q.getW());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boneWorldTransform.getRotation().set(q.multLocal(boneWorldTransform.getRotation()));
|
|
||||||
constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneWorldTransform.toTransform());
|
|
||||||
} else {
|
|
||||||
iterations = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
DTransform topBoneTransform = new DTransform(constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD));
|
deltaP.setColumn(0, 0, target.x - e.x, target.y - e.y, target.z - e.z);
|
||||||
Vector3d e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector
|
int column = 0;
|
||||||
distanceFromTarget = e.distance(t);
|
for (BoneContext boneContext : bones) {
|
||||||
|
DTransform boneWorldTransform = bones.getWorldTransform(boneContext);
|
||||||
if(distanceFromTarget < bestSolutionDistance) {
|
Vector3d j = boneWorldTransform.getTranslation(); // current join position
|
||||||
bestSolutionDistance = distanceFromTarget;
|
Vector3d vectorFromJointToEffector = e.subtract(j);
|
||||||
bestSolution.clear();
|
vectorFromJointToEffector.cross(target.subtract(j), rotationVectors[column]).normalizeLocal();
|
||||||
for(BoneContext boneContext : bones) {
|
rotationVectors[column].cross(vectorFromJointToEffector, col);
|
||||||
bestSolution.add(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD));
|
J.setColumn(col, column++);
|
||||||
}
|
}
|
||||||
|
Matrix J_1 = J.pseudoinverse();
|
||||||
|
|
||||||
|
SimpleMatrix deltaThetas = J_1.mult(deltaP);
|
||||||
|
if (deltaThetas.elementMaxAbs() < MIN_ANGLE_CHANGE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < deltaThetas.numRows(); ++j) {
|
||||||
|
double angle = deltaThetas.get(j, 0);
|
||||||
|
Vector3d rotationVector = rotationVectors[j];
|
||||||
|
|
||||||
|
tempDQuaternion.fromAngleAxis(angle, rotationVector);
|
||||||
|
BoneContext boneContext = bones.get(j);
|
||||||
|
Bone bone = boneContext.getBone();
|
||||||
|
if (bone.equals(this.getOwner())) {
|
||||||
|
if (boneContext.isLockX()) {
|
||||||
|
tempDQuaternion.set(0, tempDQuaternion.getY(), tempDQuaternion.getZ(), tempDQuaternion.getW());
|
||||||
|
}
|
||||||
|
if (boneContext.isLockY()) {
|
||||||
|
tempDQuaternion.set(tempDQuaternion.getX(), 0, tempDQuaternion.getZ(), tempDQuaternion.getW());
|
||||||
|
}
|
||||||
|
if (boneContext.isLockZ()) {
|
||||||
|
tempDQuaternion.set(tempDQuaternion.getX(), tempDQuaternion.getY(), 0, tempDQuaternion.getW());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// applying best solution
|
DTransform boneTransform = bones.getWorldTransform(boneContext);
|
||||||
for(int i=0;i<bestSolution.size();++i) {
|
boneTransform.getRotation().set(tempDQuaternion.mult(boneTransform.getRotation()));
|
||||||
|
bones.setWorldTransform(boneContext, boneTransform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// applying the results
|
||||||
|
for (int i = bonesCount - 1; i >= 0; --i) {
|
||||||
BoneContext boneContext = bones.get(i);
|
BoneContext boneContext = bones.get(i);
|
||||||
constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD, bestSolution.get(i));
|
DTransform transform = bones.getWorldTransform(boneContext);
|
||||||
|
constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD, transform.toTransform());
|
||||||
}
|
}
|
||||||
|
bones = null;// need to reload them again
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -174,56 +160,68 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
|
|||||||
return "Inverse kinematics";
|
return "Inverse kinematics";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the bone contexts of all bones that will be used in this constraint computations
|
|
||||||
*/
|
|
||||||
private List<BoneContext> loadBones() {
|
|
||||||
List<BoneContext> bones = new ArrayList<BoneContext>();
|
|
||||||
Bone bone = (Bone) this.getOwner();
|
|
||||||
if (bone == null) {
|
|
||||||
return bones;
|
|
||||||
}
|
|
||||||
if (!useTail) {
|
|
||||||
bone = bone.getParent();
|
|
||||||
}
|
|
||||||
chainLength = 0;
|
|
||||||
while (bone != null) {
|
|
||||||
BoneContext boneContext = blenderContext.getBoneContext(bone);
|
|
||||||
chainLength += boneContext.getLength();
|
|
||||||
bones.add(boneContext);
|
|
||||||
alteredOmas.add(boneContext.getBoneOma());
|
|
||||||
if (bonesAffected != 0 && bones.size() >= bonesAffected) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// need to add spaces between bones to the chain length
|
|
||||||
Transform boneWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD);
|
|
||||||
Vector3f boneWorldTranslation = boneWorldTransform.getTranslation();
|
|
||||||
|
|
||||||
bone = bone.getParent();
|
|
||||||
|
|
||||||
if (bone != null) {
|
|
||||||
boneContext = blenderContext.getBoneContext(bone);
|
|
||||||
Transform parentWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD);
|
|
||||||
Vector3f parentWorldTranslation = parentWorldTransform.getTranslation();
|
|
||||||
chainLength += boneWorldTranslation.distance(parentWorldTranslation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bones;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTrackToBeChanged() {
|
|
||||||
if (trackToBeChanged) {
|
|
||||||
// need to check the bone structure too (when constructor was called not all of the bones might have been loaded yet)
|
|
||||||
// that is why it is also checked here
|
|
||||||
List<BoneContext> bones = this.loadBones();
|
|
||||||
trackToBeChanged = bones.size() > 0;
|
|
||||||
}
|
|
||||||
return trackToBeChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTargetRequired() {
|
public boolean isTargetRequired() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loaded bones' chain. This class allows to operate on transform matrices that use double precision in computations.
|
||||||
|
* Only the final result is being transformed to single precision numbers.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
private static class BonesChain extends ArrayList<BoneContext> {
|
||||||
|
private static final long serialVersionUID = -1850524345643600718L;
|
||||||
|
|
||||||
|
private List<Matrix> bonesMatrices = new ArrayList<Matrix>();
|
||||||
|
|
||||||
|
public BonesChain(Bone bone, boolean useTail, int bonesAffected, Collection<Long> alteredOmas, BlenderContext blenderContext) {
|
||||||
|
if (bone != null) {
|
||||||
|
ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
|
||||||
|
if (!useTail) {
|
||||||
|
bone = bone.getParent();
|
||||||
|
}
|
||||||
|
while (bone != null && (bonesAffected <= 0 || this.size() < bonesAffected)) {
|
||||||
|
BoneContext boneContext = blenderContext.getBoneContext(bone);
|
||||||
|
this.add(boneContext);
|
||||||
|
alteredOmas.add(boneContext.getBoneOma());
|
||||||
|
|
||||||
|
Space space = this.size() < bonesAffected ? Space.CONSTRAINT_SPACE_LOCAL : Space.CONSTRAINT_SPACE_WORLD;
|
||||||
|
Transform transform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), space);
|
||||||
|
bonesMatrices.add(new DTransform(transform).toMatrix());
|
||||||
|
|
||||||
|
bone = bone.getParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DTransform getWorldTransform(BoneContext bone) {
|
||||||
|
int index = this.indexOf(bone);
|
||||||
|
return this.getWorldMatrix(index).toTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWorldTransform(BoneContext bone, DTransform transform) {
|
||||||
|
int index = this.indexOf(bone);
|
||||||
|
Matrix boneMatrix = transform.toMatrix();
|
||||||
|
|
||||||
|
if (index < this.size() - 1) {
|
||||||
|
// computing the current bone local transform
|
||||||
|
Matrix parentWorldMatrix = this.getWorldMatrix(index + 1);
|
||||||
|
SimpleMatrix m = parentWorldMatrix.invert().mult(boneMatrix);
|
||||||
|
boneMatrix = new Matrix(m);
|
||||||
|
}
|
||||||
|
bonesMatrices.set(index, boneMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix getWorldMatrix(int index) {
|
||||||
|
if (index == this.size() - 1) {
|
||||||
|
return new Matrix(bonesMatrices.get(this.size() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleMatrix result = this.getWorldMatrix(index + 1);
|
||||||
|
result = result.mult(bonesMatrices.get(index));
|
||||||
|
return new Matrix(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,6 +164,134 @@ public final class DQuaternion implements Savable, Cloneable, java.io.Serializab
|
|||||||
w = 1;
|
w = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>norm</code> returns the norm of this quaternion. This is the dot
|
||||||
|
* product of this quaternion with itself.
|
||||||
|
*
|
||||||
|
* @return the norm of the quaternion.
|
||||||
|
*/
|
||||||
|
public double norm() {
|
||||||
|
return w * w + x * x + y * y + z * z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DQuaternion fromRotationMatrix(double m00, double m01, double m02,
|
||||||
|
double m10, double m11, double m12, double m20, double m21, double m22) {
|
||||||
|
// first normalize the forward (F), up (U) and side (S) vectors of the rotation matrix
|
||||||
|
// so that the scale does not affect the rotation
|
||||||
|
double lengthSquared = m00 * m00 + m10 * m10 + m20 * m20;
|
||||||
|
if (lengthSquared != 1f && lengthSquared != 0f) {
|
||||||
|
lengthSquared = 1.0 / Math.sqrt(lengthSquared);
|
||||||
|
m00 *= lengthSquared;
|
||||||
|
m10 *= lengthSquared;
|
||||||
|
m20 *= lengthSquared;
|
||||||
|
}
|
||||||
|
lengthSquared = m01 * m01 + m11 * m11 + m21 * m21;
|
||||||
|
if (lengthSquared != 1 && lengthSquared != 0f) {
|
||||||
|
lengthSquared = 1.0 / Math.sqrt(lengthSquared);
|
||||||
|
m01 *= lengthSquared;
|
||||||
|
m11 *= lengthSquared;
|
||||||
|
m21 *= lengthSquared;
|
||||||
|
}
|
||||||
|
lengthSquared = m02 * m02 + m12 * m12 + m22 * m22;
|
||||||
|
if (lengthSquared != 1f && lengthSquared != 0f) {
|
||||||
|
lengthSquared = 1.0 / Math.sqrt(lengthSquared);
|
||||||
|
m02 *= lengthSquared;
|
||||||
|
m12 *= lengthSquared;
|
||||||
|
m22 *= lengthSquared;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the Graphics Gems code, from
|
||||||
|
// ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z
|
||||||
|
// *NOT* the "Matrix and Quaternions FAQ", which has errors!
|
||||||
|
|
||||||
|
// the trace is the sum of the diagonal elements; see
|
||||||
|
// http://mathworld.wolfram.com/MatrixTrace.html
|
||||||
|
double t = m00 + m11 + m22;
|
||||||
|
|
||||||
|
// we protect the division by s by ensuring that s>=1
|
||||||
|
if (t >= 0) { // |w| >= .5
|
||||||
|
double s = Math.sqrt(t + 1); // |s|>=1 ...
|
||||||
|
w = 0.5f * s;
|
||||||
|
s = 0.5f / s; // so this division isn't bad
|
||||||
|
x = (m21 - m12) * s;
|
||||||
|
y = (m02 - m20) * s;
|
||||||
|
z = (m10 - m01) * s;
|
||||||
|
} else if (m00 > m11 && m00 > m22) {
|
||||||
|
double s = Math.sqrt(1.0 + m00 - m11 - m22); // |s|>=1
|
||||||
|
x = s * 0.5f; // |x| >= .5
|
||||||
|
s = 0.5f / s;
|
||||||
|
y = (m10 + m01) * s;
|
||||||
|
z = (m02 + m20) * s;
|
||||||
|
w = (m21 - m12) * s;
|
||||||
|
} else if (m11 > m22) {
|
||||||
|
double s = Math.sqrt(1.0 + m11 - m00 - m22); // |s|>=1
|
||||||
|
y = s * 0.5f; // |y| >= .5
|
||||||
|
s = 0.5f / s;
|
||||||
|
x = (m10 + m01) * s;
|
||||||
|
z = (m21 + m12) * s;
|
||||||
|
w = (m02 - m20) * s;
|
||||||
|
} else {
|
||||||
|
double s = Math.sqrt(1.0 + m22 - m00 - m11); // |s|>=1
|
||||||
|
z = s * 0.5f; // |z| >= .5
|
||||||
|
s = 0.5f / s;
|
||||||
|
x = (m02 + m20) * s;
|
||||||
|
y = (m21 + m12) * s;
|
||||||
|
w = (m10 - m01) * s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>toRotationMatrix</code> converts this quaternion to a rotational
|
||||||
|
* matrix. The result is stored in result. 4th row and 4th column values are
|
||||||
|
* untouched. Note: the result is created from a normalized version of this quat.
|
||||||
|
*
|
||||||
|
* @param result
|
||||||
|
* The Matrix4f to store the result in.
|
||||||
|
* @return the rotation matrix representation of this quaternion.
|
||||||
|
*/
|
||||||
|
public Matrix toRotationMatrix(Matrix result) {
|
||||||
|
Vector3d originalScale = new Vector3d();
|
||||||
|
|
||||||
|
result.toScaleVector(originalScale);
|
||||||
|
result.setScale(1, 1, 1);
|
||||||
|
double norm = this.norm();
|
||||||
|
// we explicitly test norm against one here, saving a division
|
||||||
|
// at the cost of a test and branch. Is it worth it?
|
||||||
|
double s = norm == 1f ? 2f : norm > 0f ? 2f / norm : 0;
|
||||||
|
|
||||||
|
// compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs
|
||||||
|
// will be used 2-4 times each.
|
||||||
|
double xs = x * s;
|
||||||
|
double ys = y * s;
|
||||||
|
double zs = z * s;
|
||||||
|
double xx = x * xs;
|
||||||
|
double xy = x * ys;
|
||||||
|
double xz = x * zs;
|
||||||
|
double xw = w * xs;
|
||||||
|
double yy = y * ys;
|
||||||
|
double yz = y * zs;
|
||||||
|
double yw = w * ys;
|
||||||
|
double zz = z * zs;
|
||||||
|
double zw = w * zs;
|
||||||
|
|
||||||
|
// using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here
|
||||||
|
result.set(0, 0, 1 - (yy + zz));
|
||||||
|
result.set(0, 1, xy - zw);
|
||||||
|
result.set(0, 2, xz + yw);
|
||||||
|
result.set(1, 0, xy + zw);
|
||||||
|
result.set(1, 1, 1 - (xx + zz));
|
||||||
|
result.set(1, 2, yz - xw);
|
||||||
|
result.set(2, 0, xz - yw);
|
||||||
|
result.set(2, 1, yz + xw);
|
||||||
|
result.set(2, 2, 1 - (xx + yy));
|
||||||
|
|
||||||
|
result.setScale(originalScale);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>fromAngleAxis</code> sets this quaternion to the values specified
|
* <code>fromAngleAxis</code> sets this quaternion to the values specified
|
||||||
* by an angle and an axis of rotation. This method creates an object, so
|
* by an angle and an axis of rotation. This method creates an object, so
|
||||||
|
@ -31,11 +31,15 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.math;
|
package com.jme3.scene.plugins.blender.math;
|
||||||
|
|
||||||
import com.jme3.export.*;
|
|
||||||
import com.jme3.math.Transform;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.jme3.export.InputCapsule;
|
||||||
|
import com.jme3.export.JmeExporter;
|
||||||
|
import com.jme3.export.JmeImporter;
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.export.Savable;
|
||||||
|
import com.jme3.math.Transform;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Started Date: Jul 16, 2004<br>
|
* Started Date: Jul 16, 2004<br>
|
||||||
* <br>
|
* <br>
|
||||||
@ -57,6 +61,12 @@ public final class DTransform implements Savable, Cloneable, java.io.Serializabl
|
|||||||
private Vector3d translation;
|
private Vector3d translation;
|
||||||
private Vector3d scale;
|
private Vector3d scale;
|
||||||
|
|
||||||
|
public DTransform() {
|
||||||
|
translation = new Vector3d();
|
||||||
|
rotation = new DQuaternion();
|
||||||
|
scale = new Vector3d();
|
||||||
|
}
|
||||||
|
|
||||||
public DTransform(Transform transform) {
|
public DTransform(Transform transform) {
|
||||||
translation = new Vector3d(transform.getTranslation());
|
translation = new Vector3d(transform.getTranslation());
|
||||||
rotation = new DQuaternion(transform.getRotation());
|
rotation = new DQuaternion(transform.getRotation());
|
||||||
@ -67,6 +77,14 @@ public final class DTransform implements Savable, Cloneable, java.io.Serializabl
|
|||||||
return new Transform(translation.toVector3f(), rotation.toQuaternion(), scale.toVector3f());
|
return new Transform(translation.toVector3f(), rotation.toQuaternion(), scale.toVector3f());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Matrix toMatrix() {
|
||||||
|
Matrix m = Matrix.identity(4);
|
||||||
|
m.setTranslation(translation);
|
||||||
|
m.setRotationQuaternion(rotation);
|
||||||
|
m.setScale(scale);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets this translation to the given value.
|
* Sets this translation to the given value.
|
||||||
* @param trans
|
* @param trans
|
||||||
|
@ -0,0 +1,214 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.math;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
|
||||||
|
import org.ejml.ops.CommonOps;
|
||||||
|
import org.ejml.simple.SimpleMatrix;
|
||||||
|
import org.ejml.simple.SimpleSVD;
|
||||||
|
|
||||||
|
import com.jme3.math.FastMath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates a 4x4 matrix
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Matrix extends SimpleMatrix {
|
||||||
|
private static final long serialVersionUID = 2396600537315902559L;
|
||||||
|
|
||||||
|
public Matrix(int rows, int cols) {
|
||||||
|
super(rows, cols);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy constructor
|
||||||
|
*/
|
||||||
|
public Matrix(SimpleMatrix m) {
|
||||||
|
super(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix(double[][] data) {
|
||||||
|
super(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matrix identity(int size) {
|
||||||
|
Matrix result = new Matrix(size, size);
|
||||||
|
CommonOps.setIdentity(result.mat);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix pseudoinverse() {
|
||||||
|
return this.pseudoinverse(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Matrix pseudoinverse(double lambda) {
|
||||||
|
SimpleSVD<SimpleMatrix> simpleSVD = this.svd();
|
||||||
|
|
||||||
|
SimpleMatrix U = simpleSVD.getU();
|
||||||
|
SimpleMatrix S = simpleSVD.getW();
|
||||||
|
SimpleMatrix V = simpleSVD.getV();
|
||||||
|
|
||||||
|
int N = Math.min(this.numRows(),this.numCols());
|
||||||
|
double maxSingular = 0;
|
||||||
|
for( int i = 0; i < N; ++i ) {
|
||||||
|
if( S.get(i, i) > maxSingular ) {
|
||||||
|
maxSingular = S.get(i, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double tolerance = FastMath.DBL_EPSILON * Math.max(this.numRows(),this.numCols()) * maxSingular;
|
||||||
|
for(int i=0;i<Math.min(S.numRows(), S.numCols());++i) {
|
||||||
|
double a = S.get(i, i);
|
||||||
|
if(a <= tolerance) {
|
||||||
|
a = 0;
|
||||||
|
} else {
|
||||||
|
a = a/(a * a + lambda * lambda);
|
||||||
|
}
|
||||||
|
S.set(i, i, a);
|
||||||
|
}
|
||||||
|
return new Matrix(V.mult(S.transpose()).mult(U.transpose()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColumn(Vector3d col, int column) {
|
||||||
|
this.setColumn(column, 0, col.x, col.y, col.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just for some debug informations in order to compare the results with the scilab computation program.
|
||||||
|
* @param name the name of the matrix
|
||||||
|
* @param m the matrix to print out
|
||||||
|
* @return the String format of the matrix to easily input it to Scilab
|
||||||
|
*/
|
||||||
|
public String toScilabString(String name, SimpleMatrix m) {
|
||||||
|
String result = name + " = [";
|
||||||
|
|
||||||
|
for(int i=0;i<m.numRows();++i) {
|
||||||
|
for(int j=0;j<m.numCols();++j) {
|
||||||
|
result += m.get(i, j) + " ";
|
||||||
|
}
|
||||||
|
result += ";";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a String representation of the matrix
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
DecimalFormat df = new DecimalFormat("#.0000");
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
for (int r = 0; r < this.numRows(); ++r) {
|
||||||
|
buf.append("\n| ");
|
||||||
|
for (int c = 0; c < this.numCols(); ++c) {
|
||||||
|
buf.append(df.format(this.get(r, c))).append(' ');
|
||||||
|
}
|
||||||
|
buf.append('|');
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTranslation(Vector3d translation) {
|
||||||
|
this.setColumn(translation, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scale.
|
||||||
|
*
|
||||||
|
* @param scale
|
||||||
|
* the scale vector to set
|
||||||
|
*/
|
||||||
|
public void setScale(Vector3d scale) {
|
||||||
|
this.setScale(scale.x, scale.y, scale.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scale.
|
||||||
|
*
|
||||||
|
* @param x
|
||||||
|
* the X scale
|
||||||
|
* @param y
|
||||||
|
* the Y scale
|
||||||
|
* @param z
|
||||||
|
* the Z scale
|
||||||
|
*/
|
||||||
|
public void setScale(double x, double y, double z) {
|
||||||
|
Vector3d vect1 = new Vector3d(this.get(0, 0), this.get(1, 0), this.get(2, 0));
|
||||||
|
vect1.normalizeLocal().multLocal(x);
|
||||||
|
this.set(0, 0, vect1.x);
|
||||||
|
this.set(1, 0, vect1.y);
|
||||||
|
this.set(2, 0, vect1.z);
|
||||||
|
|
||||||
|
vect1.set(this.get(0, 1), this.get(1, 1), this.get(2, 1));
|
||||||
|
vect1.normalizeLocal().multLocal(y);
|
||||||
|
this.set(0, 1, vect1.x);
|
||||||
|
this.set(1, 1, vect1.y);
|
||||||
|
this.set(2, 1, vect1.z);
|
||||||
|
|
||||||
|
vect1.set(this.get(0, 2), this.get(1, 2), this.get(2, 2));
|
||||||
|
vect1.normalizeLocal().multLocal(z);
|
||||||
|
this.set(0, 2, vect1.x);
|
||||||
|
this.set(1, 2, vect1.y);
|
||||||
|
this.set(2, 2, vect1.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>setRotationQuaternion</code> builds a rotation from a
|
||||||
|
* <code>Quaternion</code>.
|
||||||
|
*
|
||||||
|
* @param quat
|
||||||
|
* the quaternion to build the rotation from.
|
||||||
|
* @throws NullPointerException
|
||||||
|
* if quat is null.
|
||||||
|
*/
|
||||||
|
public void setRotationQuaternion(DQuaternion quat) {
|
||||||
|
quat.toRotationMatrix(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DTransform toTransform() {
|
||||||
|
DTransform result = new DTransform();
|
||||||
|
result.setTranslation(this.toTranslationVector());
|
||||||
|
result.setRotation(this.toRotationQuat());
|
||||||
|
result.setScale(this.toScaleVector());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3d toTranslationVector() {
|
||||||
|
return new Vector3d(this.get(0, 3), this.get(1, 3), this.get(2, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DQuaternion toRotationQuat() {
|
||||||
|
DQuaternion quat = new DQuaternion();
|
||||||
|
quat.fromRotationMatrix(this.get(0, 0), this.get(0, 1), this.get(0, 2), this.get(1, 0), this.get(1, 1), this.get(1, 2), this.get(2, 0), this.get(2, 1), this.get(2, 2));
|
||||||
|
return quat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retreives the scale vector from the matrix and stores it into a given
|
||||||
|
* vector.
|
||||||
|
*
|
||||||
|
* @param the
|
||||||
|
* vector where the scale will be stored
|
||||||
|
*/
|
||||||
|
public Vector3d toScaleVector() {
|
||||||
|
Vector3d result = new Vector3d();
|
||||||
|
this.toScaleVector(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retreives the scale vector from the matrix and stores it into a given
|
||||||
|
* vector.
|
||||||
|
*
|
||||||
|
* @param the
|
||||||
|
* vector where the scale will be stored
|
||||||
|
*/
|
||||||
|
public void toScaleVector(Vector3d vector) {
|
||||||
|
double scaleX = Math.sqrt(this.get(0, 0) * this.get(0, 0) + this.get(1, 0) * this.get(1, 0) + this.get(2, 0) * this.get(2, 0));
|
||||||
|
double scaleY = Math.sqrt(this.get(0, 1) * this.get(0, 1) + this.get(1, 1) * this.get(1, 1) + this.get(2, 1) * this.get(2, 1));
|
||||||
|
double scaleZ = Math.sqrt(this.get(0, 2) * this.get(0, 2) + this.get(1, 2) * this.get(1, 2) + this.get(2, 2) * this.get(2, 2));
|
||||||
|
vector.set(scaleX, scaleY, scaleZ);
|
||||||
|
}
|
||||||
|
}
|
@ -75,4 +75,6 @@ public enum Limits {
|
|||||||
ColorTextureSamples,
|
ColorTextureSamples,
|
||||||
|
|
||||||
DepthTextureSamples,
|
DepthTextureSamples,
|
||||||
|
|
||||||
|
VertexUniformVectors,
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,7 @@ public interface GL {
|
|||||||
public static final int GL_FRONT_AND_BACK = 0x408;
|
public static final int GL_FRONT_AND_BACK = 0x408;
|
||||||
public static final int GL_GEQUAL = 0x206;
|
public static final int GL_GEQUAL = 0x206;
|
||||||
public static final int GL_GREATER = 0x204;
|
public static final int GL_GREATER = 0x204;
|
||||||
|
public static final int GL_GREEN = 0x1904;
|
||||||
public static final int GL_INCR = 0x1E02;
|
public static final int GL_INCR = 0x1E02;
|
||||||
public static final int GL_INCR_WRAP = 0x8507;
|
public static final int GL_INCR_WRAP = 0x8507;
|
||||||
public static final int GL_INFO_LOG_LENGTH = 0x8B84;
|
public static final int GL_INFO_LOG_LENGTH = 0x8B84;
|
||||||
@ -99,6 +100,8 @@ public interface GL {
|
|||||||
public static final int GL_MAX_TEXTURE_SIZE = 0xD33;
|
public static final int GL_MAX_TEXTURE_SIZE = 0xD33;
|
||||||
public static final int GL_MAX_VERTEX_ATTRIBS = 0x8869;
|
public static final int GL_MAX_VERTEX_ATTRIBS = 0x8869;
|
||||||
public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C;
|
public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C;
|
||||||
|
public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A;
|
||||||
|
public static final int GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB;
|
||||||
public static final int GL_MIRRORED_REPEAT = 0x8370;
|
public static final int GL_MIRRORED_REPEAT = 0x8370;
|
||||||
public static final int GL_NEAREST = 0x2600;
|
public static final int GL_NEAREST = 0x2600;
|
||||||
public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702;
|
public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702;
|
||||||
@ -114,6 +117,7 @@ public interface GL {
|
|||||||
public static final int GL_OUT_OF_MEMORY = 0x505;
|
public static final int GL_OUT_OF_MEMORY = 0x505;
|
||||||
public static final int GL_POINTS = 0x0;
|
public static final int GL_POINTS = 0x0;
|
||||||
public static final int GL_POLYGON_OFFSET_FILL = 0x8037;
|
public static final int GL_POLYGON_OFFSET_FILL = 0x8037;
|
||||||
|
public static final int GL_RED = 0x1903;
|
||||||
public static final int GL_RENDERER = 0x1F01;
|
public static final int GL_RENDERER = 0x1F01;
|
||||||
public static final int GL_REPEAT = 0x2901;
|
public static final int GL_REPEAT = 0x2901;
|
||||||
public static final int GL_REPLACE = 0x1E01;
|
public static final int GL_REPLACE = 0x1E01;
|
||||||
|
@ -34,7 +34,7 @@ package com.jme3.renderer.opengl;
|
|||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GL functions only available on vanilla desktop OpenGL 3.0.
|
* GL functions only available on vanilla desktop OpenGL 3.0+.
|
||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
*/
|
*/
|
||||||
@ -43,6 +43,17 @@ public interface GL3 extends GL2 {
|
|||||||
public static final int GL_DEPTH_STENCIL_ATTACHMENT = 0x821A;
|
public static final int GL_DEPTH_STENCIL_ATTACHMENT = 0x821A;
|
||||||
public static final int GL_GEOMETRY_SHADER = 0x8DD9;
|
public static final int GL_GEOMETRY_SHADER = 0x8DD9;
|
||||||
public static final int GL_NUM_EXTENSIONS = 0x821D;
|
public static final int GL_NUM_EXTENSIONS = 0x821D;
|
||||||
|
public static final int GL_R8 = 0x8229;
|
||||||
|
public static final int GL_R16F = 0x822D;
|
||||||
|
public static final int GL_R32F = 0x822E;
|
||||||
|
public static final int GL_RG16F = 0x822F;
|
||||||
|
public static final int GL_RG32F = 0x8230;
|
||||||
|
public static final int GL_RG = 0x8227;
|
||||||
|
public static final int GL_RG8 = 0x822B;
|
||||||
|
public static final int GL_TEXTURE_SWIZZLE_A = 0x8E45;
|
||||||
|
public static final int GL_TEXTURE_SWIZZLE_B = 0x8E44;
|
||||||
|
public static final int GL_TEXTURE_SWIZZLE_G = 0x8E43;
|
||||||
|
public static final int GL_TEXTURE_SWIZZLE_R = 0x8E42;
|
||||||
|
|
||||||
public void glBindFragDataLocation(int param1, int param2, String param3); /// GL3+
|
public void glBindFragDataLocation(int param1, int param2, String param3); /// GL3+
|
||||||
public void glBindVertexArray(int param1); /// GL3+
|
public void glBindVertexArray(int param1); /// GL3+
|
||||||
|
@ -34,7 +34,7 @@ package com.jme3.renderer.opengl;
|
|||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GL functions only available on vanilla desktop OpenGL 3.0.
|
* GL functions only available on vanilla desktop OpenGL 4.0.
|
||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
*/
|
*/
|
||||||
|
@ -42,6 +42,7 @@ public final class GLImageFormat {
|
|||||||
public final int format;
|
public final int format;
|
||||||
public final int dataType;
|
public final int dataType;
|
||||||
public final boolean compressed;
|
public final boolean compressed;
|
||||||
|
public final boolean swizzleRequired;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for formats.
|
* Constructor for formats.
|
||||||
@ -55,6 +56,7 @@ public final class GLImageFormat {
|
|||||||
this.format = format;
|
this.format = format;
|
||||||
this.dataType = dataType;
|
this.dataType = dataType;
|
||||||
this.compressed = false;
|
this.compressed = false;
|
||||||
|
this.swizzleRequired = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,11 +65,30 @@ public final class GLImageFormat {
|
|||||||
* @param internalFormat OpenGL internal format
|
* @param internalFormat OpenGL internal format
|
||||||
* @param format OpenGL format
|
* @param format OpenGL format
|
||||||
* @param dataType OpenGL datatype
|
* @param dataType OpenGL datatype
|
||||||
|
* @param compressed Format is compressed
|
||||||
*/
|
*/
|
||||||
public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed) {
|
public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed) {
|
||||||
this.internalFormat = internalFormat;
|
this.internalFormat = internalFormat;
|
||||||
this.format = format;
|
this.format = format;
|
||||||
this.dataType = dataType;
|
this.dataType = dataType;
|
||||||
this.compressed = compressed;
|
this.compressed = compressed;
|
||||||
|
this.swizzleRequired = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for formats.
|
||||||
|
*
|
||||||
|
* @param internalFormat OpenGL internal format
|
||||||
|
* @param format OpenGL format
|
||||||
|
* @param dataType OpenGL datatype
|
||||||
|
* @param compressed Format is compressed
|
||||||
|
* @param swizzleRequired Need to use texture swizzle to upload texture
|
||||||
|
*/
|
||||||
|
public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed, boolean swizzleRequired) {
|
||||||
|
this.internalFormat = internalFormat;
|
||||||
|
this.format = format;
|
||||||
|
this.dataType = dataType;
|
||||||
|
this.compressed = compressed;
|
||||||
|
this.swizzleRequired = swizzleRequired;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,13 @@ public final class GLImageFormats {
|
|||||||
formatToGL[0][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType);
|
formatToGL[0][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void formatSwiz(GLImageFormat[][] formatToGL, Image.Format format,
|
||||||
|
int glInternalFormat,
|
||||||
|
int glFormat,
|
||||||
|
int glDataType){
|
||||||
|
formatToGL[0][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
private static void formatSrgb(GLImageFormat[][] formatToGL, Image.Format format,
|
private static void formatSrgb(GLImageFormat[][] formatToGL, Image.Format format,
|
||||||
int glInternalFormat,
|
int glInternalFormat,
|
||||||
int glFormat,
|
int glFormat,
|
||||||
@ -60,6 +67,14 @@ public final class GLImageFormats {
|
|||||||
formatToGL[1][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType);
|
formatToGL[1][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void formatSrgbSwiz(GLImageFormat[][] formatToGL, Image.Format format,
|
||||||
|
int glInternalFormat,
|
||||||
|
int glFormat,
|
||||||
|
int glDataType)
|
||||||
|
{
|
||||||
|
formatToGL[1][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
private static void formatComp(GLImageFormat[][] formatToGL, Image.Format format,
|
private static void formatComp(GLImageFormat[][] formatToGL, Image.Format format,
|
||||||
int glCompressedFormat,
|
int glCompressedFormat,
|
||||||
int glFormat,
|
int glFormat,
|
||||||
@ -88,6 +103,19 @@ public final class GLImageFormats {
|
|||||||
public static GLImageFormat[][] getFormatsForCaps(EnumSet<Caps> caps) {
|
public static GLImageFormat[][] getFormatsForCaps(EnumSet<Caps> caps) {
|
||||||
GLImageFormat[][] formatToGL = new GLImageFormat[2][Image.Format.values().length];
|
GLImageFormat[][] formatToGL = new GLImageFormat[2][Image.Format.values().length];
|
||||||
|
|
||||||
|
// Core Profile Formats (supported by both OpenGL Core 3.3 and OpenGL ES 3.0+)
|
||||||
|
if (caps.contains(Caps.CoreProfile)) {
|
||||||
|
formatSwiz(formatToGL, Format.Alpha8, GL3.GL_R8, GL.GL_RED, GL.GL_UNSIGNED_BYTE);
|
||||||
|
formatSwiz(formatToGL, Format.Luminance8, GL3.GL_R8, GL.GL_RED, GL.GL_UNSIGNED_BYTE);
|
||||||
|
formatSwiz(formatToGL, Format.Luminance8Alpha8, GL3.GL_RG8, GL3.GL_RG, GL.GL_UNSIGNED_BYTE);
|
||||||
|
formatSwiz(formatToGL, Format.Luminance16F, GL3.GL_R16F, GL.GL_RED, GLExt.GL_HALF_FLOAT_ARB);
|
||||||
|
formatSwiz(formatToGL, Format.Luminance32F, GL3.GL_R32F, GL.GL_RED, GL.GL_FLOAT);
|
||||||
|
formatSwiz(formatToGL, Format.Luminance16FAlpha16F, GL3.GL_RG16F, GL3.GL_RG, GLExt.GL_HALF_FLOAT_ARB);
|
||||||
|
|
||||||
|
formatSrgbSwiz(formatToGL, Format.Luminance8, GLExt.GL_SRGB8_EXT, GL.GL_RED, GL.GL_UNSIGNED_BYTE);
|
||||||
|
formatSrgbSwiz(formatToGL, Format.Luminance8Alpha8, GLExt.GL_SRGB8_ALPHA8_EXT, GL3.GL_RG, GL.GL_UNSIGNED_BYTE);
|
||||||
|
}
|
||||||
|
|
||||||
if (caps.contains(Caps.OpenGL20)) {
|
if (caps.contains(Caps.OpenGL20)) {
|
||||||
if (!caps.contains(Caps.CoreProfile)) {
|
if (!caps.contains(Caps.CoreProfile)) {
|
||||||
format(formatToGL, Format.Alpha8, GL2.GL_ALPHA8, GL.GL_ALPHA, GL.GL_UNSIGNED_BYTE);
|
format(formatToGL, Format.Alpha8, GL2.GL_ALPHA8, GL.GL_ALPHA, GL.GL_UNSIGNED_BYTE);
|
||||||
|
@ -106,7 +106,7 @@ public class GLRenderer implements Renderer {
|
|||||||
this.gl4 = gl instanceof GL4 ? (GL4)gl : null;
|
this.gl4 = gl instanceof GL4 ? (GL4)gl : null;
|
||||||
this.glfbo = glfbo;
|
this.glfbo = glfbo;
|
||||||
this.glext = glext;
|
this.glext = glext;
|
||||||
this.texUtil = new TextureUtil(gl, gl2, glext, context);
|
this.texUtil = new TextureUtil(gl, gl2, glext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -257,7 +257,11 @@ public class GLRenderer implements Renderer {
|
|||||||
// gl.glGetInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16);
|
// gl.glGetInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16);
|
||||||
// fragUniforms = intBuf16.get(0);
|
// fragUniforms = intBuf16.get(0);
|
||||||
// logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms);
|
// logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms);
|
||||||
|
if (caps.contains(Caps.OpenGLES20)) {
|
||||||
|
limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_VECTORS));
|
||||||
|
} else {
|
||||||
|
limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4);
|
||||||
|
}
|
||||||
limits.put(Limits.VertexAttributes, getInteger(GL.GL_MAX_VERTEX_ATTRIBS));
|
limits.put(Limits.VertexAttributes, getInteger(GL.GL_MAX_VERTEX_ATTRIBS));
|
||||||
limits.put(Limits.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE));
|
limits.put(Limits.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE));
|
||||||
limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE));
|
limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE));
|
||||||
|
@ -54,14 +54,12 @@ final class TextureUtil {
|
|||||||
private final GL gl;
|
private final GL gl;
|
||||||
private final GL2 gl2;
|
private final GL2 gl2;
|
||||||
private final GLExt glext;
|
private final GLExt glext;
|
||||||
private final RenderContext context;
|
|
||||||
private GLImageFormat[][] formats;
|
private GLImageFormat[][] formats;
|
||||||
|
|
||||||
public TextureUtil(GL gl, GL2 gl2, GLExt glext, RenderContext context) {
|
public TextureUtil(GL gl, GL2 gl2, GLExt glext) {
|
||||||
this.gl = gl;
|
this.gl = gl;
|
||||||
this.gl2 = gl2;
|
this.gl2 = gl2;
|
||||||
this.glext = glext;
|
this.glext = glext;
|
||||||
this.context = context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(EnumSet<Caps> caps) {
|
public void initialize(EnumSet<Caps> caps) {
|
||||||
@ -103,6 +101,33 @@ final class TextureUtil {
|
|||||||
return glFmt;
|
return glFmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupTextureSwizzle(int target, Format format) {
|
||||||
|
// Needed for OpenGL 3.3 to support luminance / alpha formats
|
||||||
|
switch (format) {
|
||||||
|
case Alpha8:
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_R, GL.GL_ZERO);
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_G, GL.GL_ZERO);
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_B, GL.GL_ZERO);
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_A, GL.GL_RED);
|
||||||
|
break;
|
||||||
|
case Luminance8:
|
||||||
|
case Luminance16F:
|
||||||
|
case Luminance32F:
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_R, GL.GL_RED);
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_G, GL.GL_RED);
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_B, GL.GL_RED);
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_A, GL.GL_ONE);
|
||||||
|
break;
|
||||||
|
case Luminance8Alpha8:
|
||||||
|
case Luminance16FAlpha16F:
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_R, GL.GL_RED);
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_G, GL.GL_RED);
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_B, GL.GL_RED);
|
||||||
|
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_A, GL.GL_GREEN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void uploadTextureLevel(GLImageFormat format, int target, int level, int slice, int sliceCount, int width, int height, int depth, int samples, ByteBuffer data) {
|
private void uploadTextureLevel(GLImageFormat format, int target, int level, int slice, int sliceCount, int width, int height, int depth, int samples, ByteBuffer data) {
|
||||||
if (format.compressed && data != null) {
|
if (format.compressed && data != null) {
|
||||||
if (target == GL2.GL_TEXTURE_3D) {
|
if (target == GL2.GL_TEXTURE_3D) {
|
||||||
@ -243,6 +268,11 @@ final class TextureUtil {
|
|||||||
|
|
||||||
int samples = image.getMultiSamples();
|
int samples = image.getMultiSamples();
|
||||||
|
|
||||||
|
// For OGL3 core: setup texture swizzle.
|
||||||
|
if (oglFormat.swizzleRequired) {
|
||||||
|
setupTextureSwizzle(target, jmeFormat);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < mipSizes.length; i++) {
|
for (int i = 0; i < mipSizes.length; i++) {
|
||||||
int mipWidth = Math.max(1, width >> i);
|
int mipWidth = Math.max(1, width >> i);
|
||||||
int mipHeight = Math.max(1, height >> i);
|
int mipHeight = Math.max(1, height >> i);
|
||||||
|
@ -37,6 +37,7 @@ varying vec3 SpecularSum;
|
|||||||
#endif
|
#endif
|
||||||
#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)
|
#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)
|
||||||
uniform float m_ParallaxHeight;
|
uniform float m_ParallaxHeight;
|
||||||
|
varying vec3 vViewDirPrlx;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LIGHTMAP
|
#ifdef LIGHTMAP
|
||||||
@ -78,18 +79,18 @@ void main(){
|
|||||||
#ifdef STEEP_PARALLAX
|
#ifdef STEEP_PARALLAX
|
||||||
#ifdef NORMALMAP_PARALLAX
|
#ifdef NORMALMAP_PARALLAX
|
||||||
//parallax map is stored in the alpha channel of the normal map
|
//parallax map is stored in the alpha channel of the normal map
|
||||||
newTexCoord = steepParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight);
|
newTexCoord = steepParallaxOffset(m_NormalMap, vViewDirPrlx, texCoord, m_ParallaxHeight);
|
||||||
#else
|
#else
|
||||||
//parallax map is a texture
|
//parallax map is a texture
|
||||||
newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight);
|
newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDirPrlx, texCoord, m_ParallaxHeight);
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#ifdef NORMALMAP_PARALLAX
|
#ifdef NORMALMAP_PARALLAX
|
||||||
//parallax map is stored in the alpha channel of the normal map
|
//parallax map is stored in the alpha channel of the normal map
|
||||||
newTexCoord = classicParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight);
|
newTexCoord = classicParallaxOffset(m_NormalMap, vViewDirPrlx, texCoord, m_ParallaxHeight);
|
||||||
#else
|
#else
|
||||||
//parallax map is a texture
|
//parallax map is a texture
|
||||||
newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight);
|
newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDirPrlx, texCoord, m_ParallaxHeight);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
|
@ -48,6 +48,10 @@ varying vec3 lightVec;
|
|||||||
uniform vec4 g_LightDirection;
|
uniform vec4 g_LightDirection;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)
|
||||||
|
varying vec3 vViewDirPrlx;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_REFLECTION
|
#ifdef USE_REFLECTION
|
||||||
uniform vec3 g_CameraPosition;
|
uniform vec3 g_CameraPosition;
|
||||||
|
|
||||||
@ -107,17 +111,25 @@ void main(){
|
|||||||
wvLightPos.w = g_LightPosition.w;
|
wvLightPos.w = g_LightPosition.w;
|
||||||
vec4 lightColor = g_LightColor;
|
vec4 lightColor = g_LightColor;
|
||||||
|
|
||||||
#if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
|
#if (defined(NORMALMAP) || defined(PARALLAXMAP)) && !defined(VERTEX_LIGHTING)
|
||||||
vec3 wvTangent = normalize(TransformNormal(modelSpaceTan));
|
vec3 wvTangent = normalize(TransformNormal(modelSpaceTan));
|
||||||
vec3 wvBinormal = cross(wvNormal, wvTangent);
|
vec3 wvBinormal = cross(wvNormal, wvTangent);
|
||||||
mat3 tbnMat = mat3(wvTangent, wvBinormal * inTangent.w,wvNormal);
|
mat3 tbnMat = mat3(wvTangent, wvBinormal * inTangent.w,wvNormal);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
|
||||||
vViewDir = -wvPosition * tbnMat;
|
vViewDir = -wvPosition * tbnMat;
|
||||||
|
#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP)))
|
||||||
|
vViewDirPrlx = vViewDir;
|
||||||
|
#endif
|
||||||
lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec);
|
lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec);
|
||||||
vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz;
|
vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz;
|
||||||
#elif !defined(VERTEX_LIGHTING)
|
#elif !defined(VERTEX_LIGHTING)
|
||||||
vNormal = wvNormal;
|
vNormal = wvNormal;
|
||||||
vViewDir = viewDir;
|
vViewDir = viewDir;
|
||||||
|
#if defined(PARALLAXMAP)
|
||||||
|
vViewDirPrlx = -wvPosition * tbnMat;
|
||||||
|
#endif
|
||||||
lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec);
|
lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ ShaderNodeDefinitions{
|
|||||||
ShaderNodeDefinition TextureFetch {
|
ShaderNodeDefinition TextureFetch {
|
||||||
Type: Fragment
|
Type: Fragment
|
||||||
Shader GLSL100: Common/MatDefs/ShaderNodes/Basic/texture.frag
|
Shader GLSL100: Common/MatDefs/ShaderNodes/Basic/texture.frag
|
||||||
|
Shader GLSL150: Common/MatDefs/ShaderNodes/Basic/texture15.frag
|
||||||
Documentation{
|
Documentation{
|
||||||
Fetches a color value in the given texture acording to given texture coordinates
|
Fetches a color value in the given texture acording to given texture coordinates
|
||||||
@input texture the texture to read
|
@input texture the texture to read
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
void main(){
|
||||||
|
outColor = texture(texture,texCoord);
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
#if _VERSION_ >= 150
|
||||||
|
out vec4 outFragColor;
|
||||||
|
# define texture1D texture
|
||||||
|
# define texture2D texture
|
||||||
|
# define texture3D texture
|
||||||
|
# define texture2DLod texture
|
||||||
|
# if defined VERTEX_SHADER
|
||||||
|
# define varying out
|
||||||
|
# define attribute in
|
||||||
|
# elif defined FRAGMENT_SHADER
|
||||||
|
# define varying in
|
||||||
|
# define gl_FragColor outFragColor
|
||||||
|
# endif
|
||||||
|
#endif
|
@ -82,6 +82,7 @@ public class ZipLocator implements AssetLocator {
|
|||||||
|
|
||||||
public AssetInfo locate(AssetManager manager, AssetKey key) {
|
public AssetInfo locate(AssetManager manager, AssetKey key) {
|
||||||
String name = key.getName();
|
String name = key.getName();
|
||||||
|
if(name.startsWith("/"))name=name.substring(1);
|
||||||
ZipEntry entry = zipfile.getEntry(name);
|
ZipEntry entry = zipfile.getEntry(name);
|
||||||
if (entry == null)
|
if (entry == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
* Copyright (c) 2009-2015 jMonkeyEngine
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -39,20 +39,17 @@ import com.jme3.input.controls.KeyTrigger;
|
|||||||
import com.jme3.light.DirectionalLight;
|
import com.jme3.light.DirectionalLight;
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
import com.jme3.math.*;
|
import com.jme3.math.*;
|
||||||
import com.jme3.post.FilterPostProcessor;
|
|
||||||
import com.jme3.post.filters.FXAAFilter;
|
|
||||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.shape.Quad;
|
import com.jme3.scene.shape.Quad;
|
||||||
import com.jme3.texture.Texture.WrapMode;
|
|
||||||
import com.jme3.util.SkyFactory;
|
import com.jme3.util.SkyFactory;
|
||||||
import com.jme3.util.TangentBinormalGenerator;
|
import com.jme3.util.TangentBinormalGenerator;
|
||||||
|
|
||||||
public class TestParallax extends SimpleApplication {
|
public class TestParallax extends SimpleApplication {
|
||||||
|
|
||||||
private Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal();
|
private final Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal();
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
TestParallax app = new TestParallax();
|
TestParallax app = new TestParallax();
|
||||||
@ -60,7 +57,7 @@ public class TestParallax extends SimpleApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setupSkyBox() {
|
public void setupSkyBox() {
|
||||||
rootNode.attachChild(SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", false));
|
rootNode.attachChild(SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", SkyFactory.EnvMapType.CubeMap));
|
||||||
}
|
}
|
||||||
DirectionalLight dl;
|
DirectionalLight dl;
|
||||||
|
|
||||||
@ -75,12 +72,7 @@ public class TestParallax extends SimpleApplication {
|
|||||||
|
|
||||||
public void setupFloor() {
|
public void setupFloor() {
|
||||||
mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall2.j3m");
|
mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall2.j3m");
|
||||||
mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat);
|
//mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m");
|
||||||
mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat);
|
|
||||||
|
|
||||||
// Node floorGeom = (Node) assetManager.loadAsset("Models/WaterTest/WaterTest.mesh.xml");
|
|
||||||
//Geometry g = ((Geometry) floorGeom.getChild(0));
|
|
||||||
//g.getMesh().scaleTextureCoordinates(new Vector2f(10, 10));
|
|
||||||
|
|
||||||
Node floorGeom = new Node("floorGeom");
|
Node floorGeom = new Node("floorGeom");
|
||||||
Quad q = new Quad(100, 100);
|
Quad q = new Quad(100, 100);
|
||||||
@ -100,9 +92,9 @@ public class TestParallax extends SimpleApplication {
|
|||||||
|
|
||||||
public void setupSignpost() {
|
public void setupSignpost() {
|
||||||
Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml");
|
Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml");
|
||||||
Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
|
Material matSp = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
|
||||||
TangentBinormalGenerator.generate(signpost);
|
TangentBinormalGenerator.generate(signpost);
|
||||||
signpost.setMaterial(mat);
|
signpost.setMaterial(matSp);
|
||||||
signpost.rotate(0, FastMath.HALF_PI, 0);
|
signpost.rotate(0, FastMath.HALF_PI, 0);
|
||||||
signpost.setLocalTranslation(12, 23.5f, 30);
|
signpost.setLocalTranslation(12, 23.5f, 30);
|
||||||
signpost.setLocalScale(4);
|
signpost.setLocalScale(4);
|
||||||
@ -116,7 +108,6 @@ public class TestParallax extends SimpleApplication {
|
|||||||
cam.setRotation(new Quaternion(0.05173137f, 0.92363626f, -0.13454558f, 0.35513034f));
|
cam.setRotation(new Quaternion(0.05173137f, 0.92363626f, -0.13454558f, 0.35513034f));
|
||||||
flyCam.setMoveSpeed(30);
|
flyCam.setMoveSpeed(30);
|
||||||
|
|
||||||
|
|
||||||
setupLighting();
|
setupLighting();
|
||||||
setupSkyBox();
|
setupSkyBox();
|
||||||
setupFloor();
|
setupFloor();
|
||||||
@ -124,13 +115,14 @@ public class TestParallax extends SimpleApplication {
|
|||||||
|
|
||||||
inputManager.addListener(new AnalogListener() {
|
inputManager.addListener(new AnalogListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onAnalog(String name, float value, float tpf) {
|
public void onAnalog(String name, float value, float tpf) {
|
||||||
if ("heightUP".equals(name)) {
|
if ("heightUP".equals(name)) {
|
||||||
parallaxHeigh += 0.0001;
|
parallaxHeigh += 0.01;
|
||||||
mat.setFloat("ParallaxHeight", parallaxHeigh);
|
mat.setFloat("ParallaxHeight", parallaxHeigh);
|
||||||
}
|
}
|
||||||
if ("heightDown".equals(name)) {
|
if ("heightDown".equals(name)) {
|
||||||
parallaxHeigh -= 0.0001;
|
parallaxHeigh -= 0.01;
|
||||||
parallaxHeigh = Math.max(parallaxHeigh, 0);
|
parallaxHeigh = Math.max(parallaxHeigh, 0);
|
||||||
mat.setFloat("ParallaxHeight", parallaxHeigh);
|
mat.setFloat("ParallaxHeight", parallaxHeigh);
|
||||||
}
|
}
|
||||||
@ -142,6 +134,7 @@ public class TestParallax extends SimpleApplication {
|
|||||||
|
|
||||||
inputManager.addListener(new ActionListener() {
|
inputManager.addListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onAction(String name, boolean isPressed, float tpf) {
|
public void onAction(String name, boolean isPressed, float tpf) {
|
||||||
if (isPressed && "toggleSteep".equals(name)) {
|
if (isPressed && "toggleSteep".equals(name)) {
|
||||||
steep = !steep;
|
steep = !steep;
|
||||||
|
@ -87,7 +87,8 @@ public class GZIPSerializer extends Serializer {
|
|||||||
ByteArrayOutputStream byteArrayOutput = new ByteArrayOutputStream();
|
ByteArrayOutputStream byteArrayOutput = new ByteArrayOutputStream();
|
||||||
GZIPOutputStream gzipOutput = new GZIPOutputStream(byteArrayOutput);
|
GZIPOutputStream gzipOutput = new GZIPOutputStream(byteArrayOutput);
|
||||||
|
|
||||||
gzipOutput.write(tempBuffer.array());
|
tempBuffer.flip();
|
||||||
|
gzipOutput.write(tempBuffer.array(), 0, tempBuffer.limit());
|
||||||
gzipOutput.flush();
|
gzipOutput.flush();
|
||||||
gzipOutput.finish();
|
gzipOutput.finish();
|
||||||
gzipOutput.close();
|
gzipOutput.close();
|
||||||
|
@ -98,7 +98,8 @@ public class ZIPSerializer extends Serializer {
|
|||||||
ZipEntry zipEntry = new ZipEntry("zip");
|
ZipEntry zipEntry = new ZipEntry("zip");
|
||||||
|
|
||||||
zipOutput.putNextEntry(zipEntry);
|
zipOutput.putNextEntry(zipEntry);
|
||||||
zipOutput.write(tempBuffer.array());
|
tempBuffer.flip();
|
||||||
|
zipOutput.write(tempBuffer.array(), 0, tempBuffer.limit());
|
||||||
zipOutput.flush();
|
zipOutput.flush();
|
||||||
zipOutput.closeEntry();
|
zipOutput.closeEntry();
|
||||||
zipOutput.close();
|
zipOutput.close();
|
||||||
|
@ -38,6 +38,8 @@ import com.jme3.export.JmeImporter;
|
|||||||
import com.jme3.export.OutputCapsule;
|
import com.jme3.export.OutputCapsule;
|
||||||
import de.lessvoid.nifty.Nifty;
|
import de.lessvoid.nifty.Nifty;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -45,6 +47,8 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
public class GuiEvent extends AbstractCinematicEvent {
|
public class GuiEvent extends AbstractCinematicEvent {
|
||||||
|
|
||||||
|
static final Logger log = Logger.getLogger(GuiEvent.class.getName());
|
||||||
|
|
||||||
protected String screen;
|
protected String screen;
|
||||||
protected Nifty nifty;
|
protected Nifty nifty;
|
||||||
|
|
||||||
@ -76,7 +80,7 @@ public class GuiEvent extends AbstractCinematicEvent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlay() {
|
public void onPlay() {
|
||||||
System.out.println("screen should be " + screen);
|
log.log(Level.FINEST, "screen should be {0}", screen);
|
||||||
nifty.gotoScreen(screen);
|
nifty.gotoScreen(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
Material Pong Rock : Common/MatDefs/Light/Lighting.j3md {
|
Material Pong Rock : Common/MatDefs/Light/Lighting.j3md {
|
||||||
MaterialParameters {
|
MaterialParameters {
|
||||||
Shininess: 2.0
|
Shininess: 2.0
|
||||||
DiffuseMap : Textures/Terrain/BrickWall/BrickWall.jpg
|
DiffuseMap : Repeat Textures/Terrain/BrickWall/BrickWall.jpg
|
||||||
NormalMap : Textures/Terrain/BrickWall/BrickWall_normal.jpg
|
ParallaxMap : Repeat Textures/Terrain/BrickWall/BrickWall_height.jpg
|
||||||
ParallaxMap : Textures/Terrain/BrickWall/BrickWall_height.jpg
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
Material Pong Rock : Common/MatDefs/Light/Lighting.j3md {
|
Material Pong Rock : Common/MatDefs/Light/Lighting.j3md {
|
||||||
MaterialParameters {
|
MaterialParameters {
|
||||||
Shininess: 2.0
|
Shininess: 2.0
|
||||||
DiffuseMap : Textures/Terrain/BrickWall/BrickWall.jpg
|
DiffuseMap : Repeat Textures/Terrain/BrickWall/BrickWall.jpg
|
||||||
NormalMap : Textures/Terrain/BrickWall/BrickWall_normal_parallax.dds
|
NormalMap : Repeat Textures/Terrain/BrickWall/BrickWall_normal_parallax.dds
|
||||||
PackedNormalParallax: true
|
PackedNormalParallax: true
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user