diff --git a/jme3-examples/src/main/java/jme3test/audio/TestAudioDirectional.java b/jme3-examples/src/main/java/jme3test/audio/TestAudioDirectional.java new file mode 100644 index 0000000000..a996431655 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/audio/TestAudioDirectional.java @@ -0,0 +1,141 @@ +package jme3test.audio; + +import com.jme3.app.SimpleApplication; +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioNode; +import com.jme3.environment.util.BoundingSphereDebug; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.Trigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.Arrow; +import com.jme3.scene.debug.Grid; +import com.jme3.scene.shape.Line; + +/** + * @author capdevon + */ +public class TestAudioDirectional extends SimpleApplication implements ActionListener { + + public static void main(String[] args) { + TestAudioDirectional app = new TestAudioDirectional(); + app.start(); + } + + private AudioNode audioSource; + private final Vector3f tempDirection = new Vector3f(); + private boolean rotationEnabled = true; + + @Override + public void simpleInitApp() { + configureCamera(); + + audioSource = new AudioNode(assetManager, + "Sound/Environment/Ocean Waves.ogg", AudioData.DataType.Buffer); + audioSource.setLooping(true); + audioSource.setPositional(true); + audioSource.setMaxDistance(100); + audioSource.setRefDistance(5); + audioSource.setDirectional(true); +// audioSource.setOuterGain(0.2f); // Volume outside the cone is 20% of the inner volume (Not Supported by jME) + audioSource.setInnerAngle(30); // 30-degree cone (15 degrees on each side of the direction) + audioSource.setOuterAngle(90); // 90-degree cone (45 degrees on each side of the direction) + audioSource.play(); + + // just a green sphere to mark the spot + Geometry sphere = BoundingSphereDebug.createDebugSphere(assetManager); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Green); + sphere.setMaterial(mat); + sphere.setLocalScale(0.5f); + audioSource.attachChild(sphere); + + float angleIn = audioSource.getInnerAngle() * FastMath.DEG_TO_RAD; + float angleOut = audioSource.getOuterAngle() * FastMath.DEG_TO_RAD; + Vector3f forwardDir = audioSource.getWorldRotation().mult(Vector3f.UNIT_Z); + + audioSource.attachChild(createFOV(angleIn, 20f)); + audioSource.attachChild(createFOV(angleOut, 20f)); + audioSource.attachChild(makeShape("ZAxis", new Arrow(forwardDir.mult(5)), ColorRGBA.Blue)); + rootNode.attachChild(audioSource); + + Geometry grid = makeShape("DebugGrid", new Grid(21, 21, 2), ColorRGBA.Gray); + grid.center().move(0, 0, 0); + rootNode.attachChild(grid); + + registerInputMappings(); + } + + @Override + public void simpleUpdate(float tpf) { + if (rotationEnabled) { + // Example: Rotate the audio node + audioSource.rotate(0, tpf * 0.5f, 0); + audioSource.setDirection(audioSource.getWorldRotation().mult(Vector3f.UNIT_Z, tempDirection)); + } + } + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (!isPressed) return; + + if (name.equals("toggleDirectional")) { + boolean directional = !audioSource.isDirectional(); + audioSource.setDirectional(directional); + System.out.println("directional: " + directional); + + } else if (name.equals("toggleRotationEnabled")) { + rotationEnabled = !rotationEnabled; + System.out.println("rotationEnabled: " + rotationEnabled); + } + } + + private void registerInputMappings() { + addMapping("toggleDirectional", new KeyTrigger(KeyInput.KEY_SPACE)); + addMapping("toggleRotationEnabled", new KeyTrigger(KeyInput.KEY_P)); + } + + private void addMapping(String mappingName, Trigger... triggers) { + inputManager.addMapping(mappingName, triggers); + inputManager.addListener(this, mappingName); + } + + private void configureCamera() { + flyCam.setMoveSpeed(25f); + flyCam.setDragToRotate(true); + + cam.setLocation(new Vector3f(12, 5, 12)); + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + } + + private Geometry makeShape(String name, Mesh mesh, ColorRGBA color) { + Geometry geo = new Geometry(name, mesh); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", color); + geo.setMaterial(mat); + return geo; + } + + private Spatial createFOV(float angleRad, float extent) { + Vector3f origin = new Vector3f(); + Node node = new Node("Cone"); + Vector3f sx = dirFromAngle(angleRad/2).scaleAdd(extent, origin); + Vector3f dx = dirFromAngle(-angleRad/2).scaleAdd(extent, origin); + node.attachChild(makeShape("Line.SX", new Line(origin, sx), ColorRGBA.Red)); + node.attachChild(makeShape("Line.DX", new Line(origin, dx), ColorRGBA.Red)); + + return node; + } + + private Vector3f dirFromAngle(float angleRad) { + return new Vector3f(FastMath.sin(angleRad), 0, FastMath.cos(angleRad)); + } +}