diff --git a/samples/resources/mapFactory/data/basic.frag b/samples/resources/mapFactory/data/basic.frag new file mode 100644 index 0000000..13d2aa8 --- /dev/null +++ b/samples/resources/mapFactory/data/basic.frag @@ -0,0 +1,17 @@ +#version 400 core + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +in vec2 io_textureCoords; + +uniform sampler2D in_textureBase; + +// output: +out vec4 out_Color; + +void main(void) { + out_Color = texture(in_textureBase, io_textureCoords); +} diff --git a/samples/resources/mapFactory/data/basic.vert b/samples/resources/mapFactory/data/basic.vert new file mode 100644 index 0000000..62bc6b6 --- /dev/null +++ b/samples/resources/mapFactory/data/basic.vert @@ -0,0 +1,21 @@ +#version 400 core + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +// Input: +layout (location = 0) in vec3 in_position; +layout (location = 1) in vec2 in_textureCoords; +uniform mat4 in_matrixTransformation; +uniform mat4 in_matrixProjection; +uniform mat4 in_matrixView; + +// output: +out vec2 io_textureCoords; + +void main(void) { + gl_Position = in_matrixProjection * in_matrixView * in_matrixTransformation * vec4(in_position, 1.0); + io_textureCoords = in_textureCoords; +} diff --git a/samples/resources/mapFactory/data/basicPalette.frag b/samples/resources/mapFactory/data/basicPalette.frag new file mode 100644 index 0000000..3cd9d62 --- /dev/null +++ b/samples/resources/mapFactory/data/basicPalette.frag @@ -0,0 +1,87 @@ +#version 400 core + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct Light { + vec3 color; + vec3 position; + vec3 attenuation; +}; + + +const int MAX_LIGHT_NUMBER = 8; + + +in vec2 io_textureCoords; +in vec3 io_surfaceNormal; +in vec3 io_toCameraVector; +in vec3 io_toLightVector[MAX_LIGHT_NUMBER]; +// FOW: Fog Of War result calculation +in float io_fowVisibility; + +// texture properties +uniform sampler2D in_textureBase; +// Material +//uniform Material in_material; +// 2 light for suns and other for locals ... +uniform Light in_lights[MAX_LIGHT_NUMBER]; +// global color of the sky ... needed to have a better color for the FOW +//uniform vec3 in_sky_color; +const vec3 in_sky_color = vec3(1.0,1.0,1.0); + +// output: +out vec4 out_Color; + +void main(void) { + // disable transparency elements in the texture ... + // Can be set at the start of the shader ... + /* + vec4 textureColour = texture(in_textureBase, io_textureCoords); + if (textureColour.a < 0.5) { + discard; + } + */ + //vec4 textureColour = vec4(1.0,1.0,1.0,1.0); + // keep material: + vec3 tex_ambientFactor = texture(in_textureBase, vec2(io_textureCoords.x, 4.5/8.0)).xyz; + //vec3 tex_diffuseFactor = texture(in_textureBase, vec2(io_textureCoords.x, 0.5/8.0)).xyz; + //vec4 textureColour = texture(in_textureBase, vec2(io_textureCoords.x, 0.5/8.0)); + vec4 textureColour = texture(in_textureBase, io_textureCoords); + vec3 tex_specularFactor = texture(in_textureBase, vec2(io_textureCoords.x, 2.5/8.0)).xyz; + float tex_shininess = texture(in_textureBase, vec2(io_textureCoords.x, 6.5/8.0)).x; + + vec3 unitNormal = normalize(io_surfaceNormal); + vec3 unitVectorToCamera = normalize(io_toCameraVector); + vec3 totalDiffuse = vec3(0.0); + vec3 totalSpecular = vec3(0.0); + for(int iii=0; iii maybe set an uniform for this + //totalDiffuse = max(totalDiffuse, 1.0); + //totalDiffuse = min(totalDiffuse, 0.4); + + //////out_Color = vec4(totalDiffuse,1.0) * textureColour + vec4(totalSpecular, 1.0); + out_Color = (vec4(totalDiffuse,1.0)*0.5+0.5) * textureColour; + /////out_Color = mix(vec4(in_sky_color,1.0), out_Color, io_fowVisibility); +} + + + + diff --git a/samples/resources/mapFactory/data/basicPalette.vert b/samples/resources/mapFactory/data/basicPalette.vert new file mode 100644 index 0000000..a707aa7 --- /dev/null +++ b/samples/resources/mapFactory/data/basicPalette.vert @@ -0,0 +1,59 @@ +#version 400 core + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +struct Light { + vec3 color; + vec3 position; + vec3 attenuation; +}; +const int MAX_LIGHT_NUMBER = 8; + +// Input: +layout (location = 0) in vec3 in_position; +layout (location = 1) in vec2 in_textureCoords; +layout (location = 2) in vec3 in_normal; +// 2 light for suns and other for locals ... +uniform Light in_lights[MAX_LIGHT_NUMBER]; + +uniform mat4 in_matrixTransformation; +uniform mat4 in_matrixProjection; +uniform mat4 in_matrixView; + +//uniform float in_numberOfRows; +//uniform vec2 in_offset; +const float in_numberOfRows = 1; +const vec2 in_offset = vec2(0.0,0.0); + +// Configuration of the FOV ==> TODO: Set it in parameter uniform ... +const float c_density = 0.007; +const float c_gradient = 1.5; + +// output: +out vec2 io_textureCoords; +out vec3 io_surfaceNormal; +out vec3 io_toCameraVector; +out vec3 io_toLightVector[MAX_LIGHT_NUMBER]; +// FOW: Fog Of War result calculation +out float io_fowVisibility; + +void main(void) { + vec4 worldPosition = in_matrixTransformation * vec4(in_position, 1.0); + vec4 positionRelativeToCam = in_matrixView * worldPosition; + gl_Position = in_matrixProjection * positionRelativeToCam; + io_textureCoords = (in_textureCoords/in_numberOfRows) + in_offset; + + io_surfaceNormal = (in_matrixTransformation * vec4(in_normal, 0.0)).xyz; + for(int iii=0;iii Init APPL (END)"); -} - -@Override -public void onKeyboard(final KeySpecial special, final KeyKeyboard type, final Character value, final KeyStatus state) { - this.env.onKeyboard(special, type, value, state); -} - -@Override -public void onPointer(final KeySpecial special, final KeyType type, final int pointerID, final Vector2f pos, final KeyStatus state) { - this.env.onPointer(special, type, pointerID, pos, state); -} -*/ + public void setCurrentTool(MapToolInterface currentTool) { + this.currentTool = currentTool; + } +} \ No newline at end of file diff --git a/samples/src/sample/atriasoft/ege/mapFactory/EgeScene.java b/samples/src/sample/atriasoft/ege/mapFactory/EgeScene.java index f06a840..018a280 100644 --- a/samples/src/sample/atriasoft/ege/mapFactory/EgeScene.java +++ b/samples/src/sample/atriasoft/ege/mapFactory/EgeScene.java @@ -3,16 +3,18 @@ package sample.atriasoft.ege.mapFactory; import org.atriasoft.ege.Entity; import org.atriasoft.ege.Environement; import org.atriasoft.ege.camera.Camera; +import org.atriasoft.ege.camera.ProjectionInterface; +import org.atriasoft.ege.camera.ProjectionPerspective; import org.atriasoft.ege.components.ComponentPosition; import org.atriasoft.ege.components.ComponentRenderColoredStaticMesh; import org.atriasoft.ege.components.ComponentStaticMesh; import org.atriasoft.ege.tools.MeshGenerator; import org.atriasoft.esignal.Connection; import org.atriasoft.etk.Uri; -import org.atriasoft.etk.math.Matrix4f; import org.atriasoft.etk.math.Transform3D; import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector3f; +import org.atriasoft.ewol.event.EventEntry; import org.atriasoft.ewol.event.EventInput; import org.atriasoft.ewol.event.EventTime; import org.atriasoft.ewol.widget.Widget; @@ -35,6 +37,11 @@ public class EgeScene extends Widget { self.markToRedraw(); } + // Widget display camera + public Camera mainView; + // Widget view mode + public ProjectionInterface projection; + // Environment model system. protected Environement env; /// Periodic call handle to remove it when needed @@ -51,10 +58,12 @@ public class EgeScene extends Widget { this.env = new Environement(); // default camera.... - final Camera mainView = new Camera(); - this.env.addCamera("default", mainView); - mainView.setPitch((float) Math.PI * -0.25f); - mainView.setPosition(new Vector3f(4, -5, 5)); + this.mainView = new Camera(); + this.env.addCamera("default", this.mainView); + this.mainView.setPitch((float) Math.PI * -0.25f); + this.mainView.setPosition(new Vector3f(4, -5, 5)); + + this.projection = new ProjectionPerspective(); } @@ -77,22 +86,26 @@ public class EgeScene extends Widget { Log.error("min size = " + this.minSize); } - private float getAspectRatio() { + protected float getAspectRatio() { return this.size.x() / this.size.y(); } + @Override + public void onChangeSize() { + super.onChangeSize(); + // update the projection matrix on the view size; + this.projection.updateMatrix(getSize()); + } + @Override protected void onDraw() { - //Log.info("==> appl Draw ..."); - final Vector2f size = getSize(); // Store openGl context. OpenGL.push(); // set projection matrix: - final Matrix4f tmpProjection = Matrix4f.createMatrixPerspective(3.14f * 0.5f, getAspectRatio(), 0.1f, 50000); - OpenGL.setMatrix(tmpProjection); + OpenGL.setMatrix(this.projection.getMatrix()); // set the basic openGL view port: (Draw in all the windows...) - OpenGL.setViewPort(new Vector2f(0, 0), size); + OpenGL.setViewPort(new Vector2f(0, 0), getSize()); // clear background //final Color bgColor = new Color(0.0f, 1.0f, 0.0f, 1.0f); @@ -102,6 +115,7 @@ public class EgeScene extends Widget { OpenGL.clear(OpenGL.ClearFlag.clearFlag_depthBuffer); OpenGL.enable(Flag.flag_depthTest); this.env.render(20, "default"); + onDrawScene(); OpenGL.disable(Flag.flag_depthTest); OpenGL.clear(OpenGL.ClearFlag.clearFlag_depthBuffer); @@ -109,11 +123,24 @@ public class EgeScene extends Widget { OpenGL.pop(); } + protected void onDrawScene() { + // nothing to do... + } + + @Override + public boolean onEventEntry(final EventEntry event) { + this.env.onKeyboard(event.specialKey(), event.type(), event.getChar(), event.status()); + return true; + } + @Override public boolean onEventInput(final EventInput event) { + keepFocus(); Vector2f relPos = relativePosition(event.pos()); - Log.warning("Event on Input ... " + event + " relPos = " + relPos); - return false; + //Log.warning("Event on Input ... " + event + " relPos = " + relPos); + this.env.onPointer(event.specialKey(), event.type(), event.inputId(), relPos, event.status()); + + return true; } @Override diff --git a/samples/src/sample/atriasoft/ege/mapFactory/Ground.java b/samples/src/sample/atriasoft/ege/mapFactory/Ground.java index a6d0584..2b700b2 100644 --- a/samples/src/sample/atriasoft/ege/mapFactory/Ground.java +++ b/samples/src/sample/atriasoft/ege/mapFactory/Ground.java @@ -1,9 +1,17 @@ package sample.atriasoft.ege.mapFactory; +import java.util.function.BiFunction; + +import org.atriasoft.etk.Color; +import org.atriasoft.etk.math.Transform3D; +import org.atriasoft.etk.math.Vector3f; import org.atriasoft.etk.math.Vector4f; +import org.atriasoft.gale.resource.ResourceColored3DObject; import org.atriasoft.loader3d.model.Material; import org.atriasoft.loader3d.resources.ResourceMeshHeightMap; +import toolbox.Maths; + public class Ground { int sizeX = 16; int sizeY = 16; @@ -30,11 +38,46 @@ public class Ground { } } + public void changeHeightOfElement(Vector3f position, float distance, BiFunction applyer) { + for (int yyy = 0; yyy < this.sizeY; yyy++) { + for (int xxx = 0; xxx < this.sizeX; xxx++) { + float offset = 0.0f; + if (xxx % 2 == 1) { + offset = 0.5f; + } + float dist2 = position.less(xxx, yyy + offset, 0).length2(); + if (dist2 < distance * distance) { + this.heightMap[yyy][xxx] = applyer.apply(this.heightMap[yyy][xxx], Maths.sqrt(dist2)); + } + } + } + updateMesh(); + } + public ResourceMeshHeightMap createMesh() { return this.mesh; } + public void drawDynamicElement(ResourceColored3DObject dynamicElement, Vector3f position, float distance) { + for (int yyy = 0; yyy < this.sizeY; yyy++) { + for (int xxx = 0; xxx < this.sizeX; xxx++) { + float dist2 = position.less(xxx, yyy, 0).length2(); + if (dist2 < distance * distance) { + float coneHeight = 0.6f; + float offset = 0.0f; + if (xxx % 2 == 1) { + offset = 0.5f; + } + Transform3D tmpTransform = new Transform3D(new Vector3f(xxx, yyy + offset, this.heightMap[yyy][xxx] + coneHeight * 0.5f)); + dynamicElement.drawCone(coneHeight * 0.5f, coneHeight, 10, 3, tmpTransform.getOpenGLMatrix(), Color.RED); + } + } + } + + } + public void updateMesh() { + this.mesh.clearData(); Material mat = new Material(); this.mesh.addMaterial(this.baseNamePalette, mat); mat.setAmbientFactor(new Vector4f(1, 0, 0, 1.0f)); diff --git a/samples/src/sample/atriasoft/ege/mapFactory/MainWindows.java b/samples/src/sample/atriasoft/ege/mapFactory/MainWindows.java index 4bba2ff..ba72a3a 100644 --- a/samples/src/sample/atriasoft/ege/mapFactory/MainWindows.java +++ b/samples/src/sample/atriasoft/ege/mapFactory/MainWindows.java @@ -6,6 +6,8 @@ import org.atriasoft.ewol.widget.Sizer; import org.atriasoft.ewol.widget.Sizer.DisplayMode; import org.atriasoft.ewol.widget.Windows; +import sample.atriasoft.ege.mapFactory.tools.ToolMapHeight; + public class MainWindows extends Windows { public static void eventButtonIncrease(final MainWindows self) { @@ -18,7 +20,20 @@ public class MainWindows extends Windows { } } + public static void eventButtonTool(final MainWindows self) { + //Vector2b state = self.testWidget.getPropertyFill(); + //self.testWidget.setPropertyFill(state.withY(!state.y())); + if (self.toolButton.getPropertyValue() == "Brush") { + self.toolButton.setPropertyValue("Heigher"); + self.scene.setCurrentTool(new ToolMapHeight()); + } else { + self.toolButton.setPropertyValue("Brush"); + self.scene.setCurrentTool(null); + } + } + Button heightButton; + Button toolButton; ApplScene scene; public MainWindows() { @@ -40,12 +55,23 @@ public class MainWindows extends Windows { sizerMenu.setPropertyFill(Vector2b.TRUE_TRUE); sizerHoryMain.subWidgetAdd(sizerMenu); + this.toolButton = new Button(); + this.toolButton.setPropertyValue("Heigher"); + this.toolButton.setPropertyExpand(Vector2b.TRUE_FALSE); + this.toolButton.setPropertyFill(Vector2b.TRUE_TRUE); + sizerMenu.subWidgetAdd(this.toolButton); + this.toolButton.signalClick.connectAuto(this, MainWindows::eventButtonTool); + this.heightButton = new Button(); this.heightButton.setPropertyValue("Increase"); this.heightButton.setPropertyExpand(Vector2b.TRUE_FALSE); this.heightButton.setPropertyFill(Vector2b.TRUE_TRUE); sizerMenu.subWidgetAdd(this.heightButton); this.heightButton.signalClick.connectAuto(this, MainWindows::eventButtonIncrease); + + // set default tools: + this.scene.setCurrentTool(new ToolMapHeight()); + } } \ No newline at end of file diff --git a/samples/src/sample/atriasoft/ege/mapFactory/MapFactoryMain.java b/samples/src/sample/atriasoft/ege/mapFactory/MapFactoryMain.java index 3fb7072..86e24dc 100644 --- a/samples/src/sample/atriasoft/ege/mapFactory/MapFactoryMain.java +++ b/samples/src/sample/atriasoft/ege/mapFactory/MapFactoryMain.java @@ -11,10 +11,10 @@ public class MapFactoryMain { Ewol.init(); Ege.init(); Uri.setGroup("DATA", "data/"); - Uri.setGroup("RES", "res"); - //Uri.addLibrary("loxelEngine", MainCollisionTest.class, "testDataLoxelEngine/"); + //Uri.setGroup("RES", "res"); + //Uri.addLibrary("loxelEngine", MapFactoryMain.class, "testDataLoxelEngine/"); //Uri.addLibrary("plop", Appl.class, "resources/mapFactory/"); - Uri.setApplication(Appl.class, "lowPoly");//, "resources/mapFactory/"); + Uri.setApplication(Appl.class, "mapFactory");//, "resources/mapFactory/"); Ewol.run(new Appl(), args); } diff --git a/samples/src/sample/atriasoft/ege/mapFactory/model/Map.java b/samples/src/sample/atriasoft/ege/mapFactory/model/Map.java new file mode 100644 index 0000000..91b17bc --- /dev/null +++ b/samples/src/sample/atriasoft/ege/mapFactory/model/Map.java @@ -0,0 +1,12 @@ +package sample.atriasoft.ege.mapFactory.model; + +import sample.atriasoft.ege.mapFactory.Ground; + +public class Map { + public Ground ground = new Ground(); + + public void updateMesh() { + this.ground.updateMesh(); + } + +} diff --git a/samples/src/sample/atriasoft/ege/mapFactory/tools/MapToolInterface.java b/samples/src/sample/atriasoft/ege/mapFactory/tools/MapToolInterface.java new file mode 100644 index 0000000..e350430 --- /dev/null +++ b/samples/src/sample/atriasoft/ege/mapFactory/tools/MapToolInterface.java @@ -0,0 +1,16 @@ +package sample.atriasoft.ege.mapFactory.tools; + +import org.atriasoft.ewol.event.EventEntry; +import org.atriasoft.ewol.event.EventInput; + +import sample.atriasoft.ege.mapFactory.EgeScene; +import sample.atriasoft.ege.mapFactory.model.Map; + +public interface MapToolInterface { + void onDraw(Map map); + + boolean onEventEntry(final EventEntry event, Map map, EgeScene widget); + + boolean onEventInput(final EventInput event, Map relPos, EgeScene widget); + +} \ No newline at end of file diff --git a/samples/src/sample/atriasoft/ege/mapFactory/tools/ToolMapHeight.java b/samples/src/sample/atriasoft/ege/mapFactory/tools/ToolMapHeight.java new file mode 100644 index 0000000..2d2fa06 --- /dev/null +++ b/samples/src/sample/atriasoft/ege/mapFactory/tools/ToolMapHeight.java @@ -0,0 +1,120 @@ +package sample.atriasoft.ege.mapFactory.tools; + +import org.atriasoft.ege.geometry.Ray; +import org.atriasoft.etk.Color; +import org.atriasoft.etk.math.Transform3D; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector3f; +import org.atriasoft.ewol.event.EventEntry; +import org.atriasoft.ewol.event.EventInput; +import org.atriasoft.gale.key.KeyStatus; +import org.atriasoft.gale.resource.ResourceColored3DObject; + +import sample.atriasoft.ege.mapFactory.EgeScene; +import sample.atriasoft.ege.mapFactory.Log; +import sample.atriasoft.ege.mapFactory.model.Map; +import toolbox.Maths; + +public class ToolMapHeight implements MapToolInterface { + Vector3f positionRay = null; + float widthBrush = 3.0f; + float maxBrush = 10.0f; + float minBrush = -10.0f; + ResourceColored3DObject dynamicElement; + + public ToolMapHeight() { + this.dynamicElement = ResourceColored3DObject.create(); + } + + @Override + public void onDraw(Map map) { + // TODO Auto-generated method stub + if (this.positionRay != null) { + map.ground.drawDynamicElement(this.dynamicElement, this.positionRay, this.widthBrush); + float size = this.maxBrush - this.minBrush; + Transform3D tmpTransform = new Transform3D(this.positionRay.add(new Vector3f(0.0f, 0.0f, this.minBrush + size * 0.5f))); + this.dynamicElement.drawCylinder(this.widthBrush, size, 10, 22, tmpTransform.getOpenGLMatrix(), Color.AZURE.withA(0.5f), false, true); + } + + } + + @Override + public boolean onEventEntry(EventEntry event, Map map, EgeScene widget) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean onEventInput(EventInput event, Map map, EgeScene widget) { + Vector2f relPos = widget.relativePosition(event.pos()); + // simple ray-cast on the ground + Ray mouseRay = widget.mainView.getRayFromScreen(widget.projection, widget.getSize(), relPos); + this.positionRay = mouseRay.intersectPlane(new Vector3f(0.0f, 0.0f, 1.0f), 0.0f); + /* + if (this.positionRay != null) { + this.posRay.setTransform(this.posRay.getTransform().withPosition(this.positionRay)); + } + */ + if (event.inputId() == 1 && (event.status() == KeyStatus.move || event.status() == KeyStatus.down)) { + if (this.positionRay != null) { + map.ground.changeHeightOfElement(this.positionRay, this.widthBrush, (value, distance) -> { + if (value > this.maxBrush) { + return value; + } + if (value < this.minBrush) { + return Maths.avg(-128.0f, value + 0.1f, this.maxBrush); + } + return Maths.avg(this.minBrush, value + 0.1f, this.maxBrush); + }); + } + return true; + } + if (event.inputId() == 3 && (event.status() == KeyStatus.move || event.status() == KeyStatus.down)) { + if (this.positionRay != null) { + map.ground.changeHeightOfElement(this.positionRay, this.widthBrush, (value, distance) -> { + if (value < this.minBrush) { + return value; + } + if (value > this.maxBrush) { + return Maths.avg(this.minBrush, value - 0.1f, 128.0f); + } + return Maths.avg(this.minBrush, value - 0.1f, this.maxBrush); + }); + } + return true; + } + // max brush + if (event.inputId() == 4 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getAltLeft() && event.specialKey().getCtrlLeft())) { + this.maxBrush = Maths.avg(this.minBrush + 0.1f, this.maxBrush + 0.1f, 128.0f); + Log.warning(" values: " + this.minBrush + " / " + this.maxBrush); + return true; + } + if (event.inputId() == 5 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getAltLeft() && event.specialKey().getCtrlLeft())) { + this.maxBrush = Maths.avg(this.minBrush + 0.1f, this.maxBrush - 0.1f, 128.0f); + Log.warning(" values: " + this.minBrush + " / " + this.maxBrush); + return true; + } + // min brush + if (event.inputId() == 4 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getAltLeft())) { + this.minBrush = Maths.avg(-128.0f, this.minBrush + 0.1f, this.maxBrush - 0.1f); + Log.warning(" values: " + this.minBrush + " / " + this.maxBrush); + return true; + } + if (event.inputId() == 5 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getAltLeft())) { + this.minBrush = Maths.avg(-128.0f, this.minBrush - 0.1f, this.maxBrush - 0.1f); + Log.warning(" values: " + this.minBrush + " / " + this.maxBrush); + return true; + } + // width brush + if (event.inputId() == 4 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getCtrlLeft())) { + this.widthBrush = Maths.avg(0.1f, this.widthBrush + 0.1f, 30.0f); + return true; + } + if (event.inputId() == 5 && event.status() == KeyStatus.down && (event.specialKey() != null && event.specialKey().getCtrlLeft())) { + this.widthBrush = Maths.avg(0.1f, this.widthBrush - 0.1f, 30.0f); + return true; + } + return false; + } + +} diff --git a/src/org/atriasoft/ege/ControlCameraSimple.java b/src/org/atriasoft/ege/ControlCameraSimple.java index 5b6aee0..d69f57e 100644 --- a/src/org/atriasoft/ege/ControlCameraSimple.java +++ b/src/org/atriasoft/ege/ControlCameraSimple.java @@ -12,9 +12,6 @@ import org.atriasoft.gale.key.KeyStatus; public class ControlCameraSimple implements ControlInterface { private final Camera camera; - private float distanceFromCenter = 20; - private float angleZ = 0; - private float pitch = 0; private Vector2f lastMousePosition = null; private boolean moveUp = false; private boolean moveLeft = false; @@ -44,10 +41,10 @@ public class ControlCameraSimple implements ControlInterface { if (event.type() == KeyKeyboard.LEFT) { this.moveLeft = getState(event.status(), this.moveLeft); } - if (!event.specialKey().getCtrl() && event.type() == KeyKeyboard.RIGHT) { + if (event.type() == KeyKeyboard.RIGHT) { this.moveRight = getState(event.status(), this.moveRight); } - if (!event.specialKey().getCtrl() && event.type() == KeyKeyboard.DOWN) { + if (event.type() == KeyKeyboard.DOWN) { this.moveDown = getState(event.status(), this.moveDown); } this.ctrlIsSet = event.specialKey().getCtrl(); @@ -56,17 +53,20 @@ public class ControlCameraSimple implements ControlInterface { @Override public boolean onEventInput(final EventInput event, final Vector2f relativePosition) { - Log.info("" + event); // TODO Auto-generated method stub if (event.inputId() == 4) { + Vector3f delta = this.camera.getConvertionMatrix().transpose().multiply(new Vector3f(0,0,-1)); if (event.status() == KeyStatus.down) { - this.distanceFromCenter -= 1; + this.camera.setPosition(this.camera.getPosition().add(delta.multiply(1.0f))); } - } else if (event.inputId() == 5) { + } + if (event.inputId() == 5) { + Vector3f delta = this.camera.getConvertionMatrix().transpose().multiply(new Vector3f(0,0,-1)); if (event.status() == KeyStatus.down) { - this.distanceFromCenter += 1; + this.camera.setPosition(this.camera.getPosition().add(delta.multiply(-1.0f))); } - } else if (event.inputId() == 2) { + } + if (event.inputId() == 2) { if (event.status() == KeyStatus.down) { this.lastMousePosition = event.pos(); } else if (event.status() == KeyStatus.move) { @@ -83,7 +83,6 @@ public class ControlCameraSimple implements ControlInterface { this.camera.setPitch((float) -Math.PI); } this.camera.setRoll(this.camera.getRoll() + (float) Math.toRadians(delta.x())); - Log.info("Change camera: " + this.camera.getYaw() + " " + this.camera.getPitch()); if (this.camera.getRoll() > Math.PI) { this.camera.setRoll(this.camera.getRoll() - (float) Math.PI * 2.0f); } @@ -97,24 +96,26 @@ public class ControlCameraSimple implements ControlInterface { @Override public void periodicCall(final EventTime event) { + float roll = this.camera.getRoll(); if (this.moveLeft != this.moveRight) { + Vector3f orientation = new Vector3f(-(float)Math.cos(roll), (float)Math.sin(roll), 0); if (this.moveRight) { - this.camera.setPosition(this.camera.getPosition().add(new Vector3f(0.1f, 0, 0))); + this.camera.setPosition(this.camera.getPosition().add(orientation.multiply(-0.1f))); } else { - this.camera.setPosition(this.camera.getPosition().add(new Vector3f(-0.1f, 0, 0))); + this.camera.setPosition(this.camera.getPosition().add(orientation.multiply(0.1f))); } } if (!this.ctrlIsSet) { if (this.moveUp != this.moveDown) { + Vector3f orientation = new Vector3f((float)Math.sin(roll), (float)Math.cos(roll), 0); if (this.moveUp) { - this.camera.setPosition(this.camera.getPosition().add(new Vector3f(0, 0.1f, 0))); + this.camera.setPosition(this.camera.getPosition().add(orientation.multiply(0.1f))); } else { - this.camera.setPosition(this.camera.getPosition().add(new Vector3f(0, -0.1f, 0))); + this.camera.setPosition(this.camera.getPosition().add(orientation.multiply(-0.1f))); } } } else if (this.moveUp != this.moveDown) { if (this.moveUp) { - this.camera.setPosition(this.camera.getPosition().add(new Vector3f(0, 0, 0.1f))); } else { this.camera.setPosition(this.camera.getPosition().add(new Vector3f(0, 0, -0.1f))); diff --git a/src/org/atriasoft/ege/Environement.java b/src/org/atriasoft/ege/Environement.java index 3db8db7..6ab6927 100644 --- a/src/org/atriasoft/ege/Environement.java +++ b/src/org/atriasoft/ege/Environement.java @@ -71,7 +71,6 @@ public class Environement { addEngine(new EngineAI(this)); addEngine(new EngineDynamicMeshs(this)); addEngine(new EngineRender(this)); - //addEngine(new EnginePhysics(this)); addEngine(new EnginePhysics(this)); addEngine(new EngineParticle(this)); addEngine(new EngineLight(this)); diff --git a/src/org/atriasoft/ege/camera/Camera.java b/src/org/atriasoft/ege/camera/Camera.java index 502a348..67a6dbc 100644 --- a/src/org/atriasoft/ege/camera/Camera.java +++ b/src/org/atriasoft/ege/camera/Camera.java @@ -1,14 +1,15 @@ package org.atriasoft.ege.camera; +import org.atriasoft.ege.camera.ProjectionInterface.ValueLine; +import org.atriasoft.ege.geometry.Ray; import org.atriasoft.etk.math.Matrix4f; +import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector3f; - -//import entities.Player; -//import renderEngine.DisplayManager; +import org.atriasoft.etk.math.Vector4f; public class Camera { private float pitch = 0; - private Vector3f position = new Vector3f(0, 0, 2); + private Vector3f position = new Vector3f(0, 0, 0); private float roll = 0; private float yaw = 0; @@ -22,12 +23,6 @@ public class Camera { matrix = matrix.rotate(new Vector3f(0, 1, 0), getYaw()); matrix = matrix.rotate(new Vector3f(0, 0, 1), getRoll()); matrix = matrix.translate(new Vector3f(-this.position.x(), -this.position.y(), -this.position.z())); - /* - matrix = matrix.rotate(new Vector3f(1, 0, 0), 0.0f); - matrix = matrix.rotate(new Vector3f(0, 1, 0), 0.0f); - matrix = matrix.rotate(new Vector3f(0, 0, 1), 0.75f); - matrix = matrix.translate(new Vector3f(0, 0, -7)); - */ return matrix; } @@ -62,5 +57,18 @@ public class Camera { public void setYaw(final float yaw) { this.yaw = yaw; } - + + public ValueLine reverseTransform(ValueLine basicValues) { + Matrix4f cameraMatrix = getConvertionMatrix().transpose(); + // invert Matrix: + Matrix4f cameraMatrixInverted = cameraMatrix.invert(); + + return new ValueLine(cameraMatrixInverted.multiply(basicValues.near()), // compute near + cameraMatrixInverted.multiply(basicValues.far())); // compute far + } + public Ray getRayFromScreen(ProjectionInterface projection, Vector2f diplaySize, Vector2f mousePosition) { + ValueLine elem = projection.reverseTransform(diplaySize, mousePosition); + ValueLine result = reverseTransform(elem); + return Ray.createFromPoint(result.near(), result.far()); + } } diff --git a/src/org/atriasoft/ege/camera/ProjectionInterface.java b/src/org/atriasoft/ege/camera/ProjectionInterface.java new file mode 100644 index 0000000..3f24100 --- /dev/null +++ b/src/org/atriasoft/ege/camera/ProjectionInterface.java @@ -0,0 +1,14 @@ +package org.atriasoft.ege.camera; + +import org.atriasoft.etk.math.Matrix4f; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector3f; + + +public interface ProjectionInterface { + public record ValueLine(Vector3f near, Vector3f far) {}; + Matrix4f getMatrix(); + Matrix4f updateMatrix(Vector2f diplaySize); + ValueLine reverseTransform(Vector2f diplaySize, Vector2f mousePosition); + +} diff --git a/src/org/atriasoft/ege/camera/ProjectionOrthogonal.java b/src/org/atriasoft/ege/camera/ProjectionOrthogonal.java new file mode 100644 index 0000000..3d82545 --- /dev/null +++ b/src/org/atriasoft/ege/camera/ProjectionOrthogonal.java @@ -0,0 +1,69 @@ +package org.atriasoft.ege.camera; + +import org.atriasoft.etk.math.Matrix4f; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector3f; +import org.atriasoft.etk.math.Vector4f; + +public class ProjectionOrthogonal implements ProjectionInterface { + + Matrix4f lastMatrix = Matrix4f.IDENTITY; + float angleViewRad = 3.14f * 0.5f; + float nearView = 0.1f; + float farView = 5000.0f; + + protected float getAspectRatio(Vector2f size) { + return size.x() / size.y(); + } + public void setAngleViewRad(float angle) { + this.angleViewRad = angle; + } + public float getAngleViewRad() { + return this.angleViewRad; + } + @Override + public Matrix4f getMatrix() { + return lastMatrix; + } + @Override + public Matrix4f updateMatrix(Vector2f diplaySize) { + lastMatrix = Matrix4f.createMatrixOrtho( + diplaySize.x() * -0.5f, diplaySize.x() * 0.5f, // width + diplaySize.y() * -0.5f, diplaySize.y() * 0.5f, // height + nearView, farView);; + return lastMatrix; + } + public float getNear() { + return nearView; + } + public void setNear(float nearView) { + this.nearView = nearView; + } + public float getFar() { + return farView; + } + public void setFar(float farView) { + this.farView = farView; + } + @Override + public ValueLine reverseTransform(Vector2f diplaySize, Vector2f mousePosition) { + float mouse_pos_x_clip = mousePosition.x() / diplaySize.x() * 2.0f - 1.0f; + float mouse_pos_y_clip = mousePosition.y() / diplaySize.y() * 2.0f - 1.0f; + Vector4f mouse_pos_near_clip = new Vector4f(mouse_pos_x_clip, mouse_pos_y_clip, -1.0f, 1.0f); + Vector4f mouse_pos_far_clip = new Vector4f(mouse_pos_x_clip, mouse_pos_y_clip, 1.0f, 1.0f); + + Matrix4f projectionMatrix = getMatrix().transpose(); + // invert Matrix: + Matrix4f projectionMatrixInverted = projectionMatrix.invert(); + + Vector4f mouse_pos_near_view = projectionMatrixInverted.multiply(mouse_pos_near_clip); + Vector4f mouse_pos_far_view = projectionMatrixInverted.multiply(mouse_pos_far_clip); + // only for perspective + //mouse_pos_near_view = mouse_pos_near_view.divide(mouse_pos_near_view.w()); + //mouse_pos_far_view = mouse_pos_far_view.divide(mouse_pos_far_view.w()); + + return new ValueLine(new Vector3f(mouse_pos_near_view.x(), mouse_pos_near_view.y(), mouse_pos_near_view.z()), + new Vector3f(mouse_pos_far_view.x(), mouse_pos_far_view.y(), mouse_pos_far_view.z())); + } + +} diff --git a/src/org/atriasoft/ege/camera/ProjectionPerspective.java b/src/org/atriasoft/ege/camera/ProjectionPerspective.java new file mode 100644 index 0000000..142e0a8 --- /dev/null +++ b/src/org/atriasoft/ege/camera/ProjectionPerspective.java @@ -0,0 +1,55 @@ +package org.atriasoft.ege.camera; + +import org.atriasoft.etk.math.Matrix4f; +import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.math.Vector3f; +import org.atriasoft.etk.math.Vector4f; + +public class ProjectionPerspective implements ProjectionInterface { + Matrix4f lastMatrix = Matrix4f.IDENTITY; + float angleViewRad = 3.14f * 0.5f; + float nearView = 0.1f; + float farView = 5000.0f; + + protected float getAspectRatio(Vector2f size) { + return size.x() / size.y(); + } + public void setAngleViewRad(float angle) { + this.angleViewRad = angle; + } + public float getAngleViewRad() { + return this.angleViewRad; + } + @Override + public Matrix4f getMatrix() { + return lastMatrix; + } + @Override + public Matrix4f updateMatrix(Vector2f diplaySize) { + lastMatrix = Matrix4f.createMatrixPerspective(getAngleViewRad(), getAspectRatio(diplaySize), nearView, farView);; + return lastMatrix; + } + @Override + public ValueLine reverseTransform(Vector2f diplaySize, Vector2f mousePosition) { + + float mouse_pos_x_clip = mousePosition.x() / diplaySize.x() * 2.0f - 1.0f; + float mouse_pos_y_clip = mousePosition.y() / diplaySize.y() * 2.0f - 1.0f; + Vector4f mouse_pos_near_clip = new Vector4f(mouse_pos_x_clip, mouse_pos_y_clip, -1.0f, 1.0f); + Vector4f mouse_pos_far_clip = new Vector4f(mouse_pos_x_clip, mouse_pos_y_clip, 1.0f, 1.0f); + + Matrix4f projectionMatrix = getMatrix().transpose(); + // invert Matrix: + Matrix4f projectionMatrixInverted = projectionMatrix.invert(); + + Vector4f mouse_pos_near_view = projectionMatrixInverted.multiply(mouse_pos_near_clip); + Vector4f mouse_pos_far_view = projectionMatrixInverted.multiply(mouse_pos_far_clip); + // only for perspective + mouse_pos_near_view = mouse_pos_near_view.divide(mouse_pos_near_view.w()); + mouse_pos_far_view = mouse_pos_far_view.divide(mouse_pos_far_view.w()); + + return new ValueLine(new Vector3f(mouse_pos_near_view.x(), mouse_pos_near_view.y(), mouse_pos_near_view.z()), + new Vector3f(mouse_pos_far_view.x(), mouse_pos_far_view.y(), mouse_pos_far_view.z())); + + } + +} diff --git a/src/org/atriasoft/ege/engines/EnginePhysics.java b/src/org/atriasoft/ege/engines/EnginePhysics.java index 1f29b7a..1ebcfac 100644 --- a/src/org/atriasoft/ege/engines/EnginePhysics.java +++ b/src/org/atriasoft/ege/engines/EnginePhysics.java @@ -97,7 +97,6 @@ public class EnginePhysics extends Engine { @Override public void renderDebug(long deltaMili, Camera camera) { - // TODO Auto-generated method stub DebugDisplay.onDraw(); DebugDisplay.clear(); } @@ -113,7 +112,7 @@ public class EnginePhysics extends Engine { applyForces(TIME_STEP); // update AABB after because in rotation force, the Bounding box change... updateAABB(TIME_STEP); - // update the colision tree between each object in the room + // update the collision tree between each object in the room updateCollisionsAABB(TIME_STEP); updateCollisionsNarrowPhase(TIME_STEP); generateResultCollisionsForces(TIME_STEP); diff --git a/src/org/atriasoft/ege/geometry/Ray.java b/src/org/atriasoft/ege/geometry/Ray.java index 7f02b18..9e82cf7 100644 --- a/src/org/atriasoft/ege/geometry/Ray.java +++ b/src/org/atriasoft/ege/geometry/Ray.java @@ -2,33 +2,176 @@ package org.atriasoft.ege.geometry; import org.atriasoft.etk.math.Vector3f; -public class Ray { +import toolbox.Maths; + +public record Ray(Vector3f origin, Vector3f direction) { public static Ray createFromPoint(final Vector3f origin, final Vector3f destination) { - Ray out = new Ray(origin, destination.less(origin)); - out.normalizeDirection(); - return out; + return new Ray(origin, destination.less(origin).safeNormalize()); } - public Vector3f origin; - - public Vector3f direction; - public Ray() { - this.origin = Vector3f.ZERO; - this.direction = new Vector3f(0.0f, 0.0f, 1.0f); + this(Vector3f.ZERO, new Vector3f(0.0f, 0.0f, 1.0f)); } public Ray(final Vector3f origin, final Vector3f direction) { this.origin = origin; this.direction = direction; } - - public void normalizeDirection() { - this.direction = this.direction.safeNormalize(); - } - + @Override public String toString() { return "Ray [origin=" + this.origin + ", direction=" + this.direction + "]"; } + + /** + * Get the position on the top or bottom plane describe in parameters. + * @param normalPlane Normal description of the plane. + * @param distancePlane distance to define the plane position. + * @return position on the plane intersection (null if not collide). + */ + public Vector3f intersectPlane(Vector3f normalPlane, float distancePlane) { + float denom = normalPlane.dot(this.direction); + // Prevent divide by zero: + if (Math.abs(denom) <= 1e-4f) { + return null; + } + float t = -(normalPlane.dot(this.origin) + distancePlane) / normalPlane.dot(this.direction); + + // Use pointy end of the ray. + // It is technically correct to compare t < 0, + // but that may be undesirable in a raytracer. + if (t <= 1e-4) { + return null; + } + return this.origin.add(this.direction.multiply(t)); + } + /** + * Get the position on the top plane describe in parameters. + * @param normalPlane Normal description of the plane. + * @param distancePlane distance to define the plane position. + * @return position on the plane intersection (null if not collide). + */ + public Vector3f intersectPlaneTop(Vector3f normalPlane, float distancePlane) { + float denom = normalPlane.dot(this.direction); + + if (-denom <= 1e-4f) { + return null; + } + + float t = -(normalPlane.dot(this.origin) + distancePlane) / normalPlane.dot(this.direction); + + // Use pointy end of the ray. + // It is technically correct to compare t < 0, + // but that may be undesirable in a raytracer. + if (t <= 1e-4) { + return null; + } + return this.origin.add(this.direction.multiply(t)); + } + + public boolean intersectSphere(Vector3f sphereCenter, float sphereSize) { + //solve for tc + Vector3f L = sphereCenter.less(this.origin); + float tc = L.dot(this.direction); + if ( tc < 0.0f ) { + return false; + } + float d2 = tc*tc - L.length2(); + float radius2 = sphereSize * sphereSize; + if ( d2 > radius2) { + return false; + } + return true; + } + public record ReturnIntersectSphere(Vector3f pos1, Vector3f pos2) {}; + + public ReturnIntersectSphere intersectSpherePos(Vector3f sphereCenter, float sphereSize) { + //solve for tc + Vector3f L = sphereCenter.less(this.origin); + float tc = L.dot(this.direction); + if ( tc < 0.0f ) { + return null; + } + float d2 = tc*tc - L.length2(); + + float radius2 = sphereSize * sphereSize; + if ( d2 > radius2) { + return null; + } + + //solve for t1c + float t1c = (float) Math.sqrt( radius2 - d2 ); + + //solve for intersection points + float t1 = tc - t1c; + float t2 = tc + t1c; + + return new ReturnIntersectSphere(this.origin.add(this.direction().multiply(t1)), + this.origin.add(this.direction().multiply(t2)) ); + } + + Vector3f intersectTriangle( + Vector3f orig, Vector3f dir, + Vector3f v0, Vector3f v1, Vector3f v2) { + float t = 0; // output distance. + // compute plane's normal + Vector3f v0v1 = v1.less(v0); + Vector3f v0v2 = v2.less(v0); + // no need to normalize + Vector3f N = v0v1.cross(v0v2); // N + float area2 = N.length(); + + // Step 1: finding P + + // check if ray and plane are parallel ? + float NdotRayDirection = N.dot(dir); + if (Math.abs(NdotRayDirection) < 0.0000001) // almost 0 + return null; // they are parallel so they don't intersect ! + + // compute d parameter using equation 2 + float d = -N.dot(v0); + + // compute t (equation 3) + t = -(N.dot(orig) + d) / NdotRayDirection; + + // check if the triangle is in behind the ray + if (t < 0) { + return null; // the triangle is behind + } + + // compute the intersection point using equation 1 + Vector3f P = orig.add(dir.multiply(t)); + + // Step 2: inside-outside test + Vector3f C; // vector perpendicular to triangle's plane + + // edge 0 + Vector3f edge0 = v1.less(v0); + Vector3f vp0 = P.less(v0); + C = edge0.cross(vp0); + if (N.dot(C) < 0) { + return null; // P is on the right side + } + + // edge 1 + Vector3f edge1 = v2.less(v1); + Vector3f vp1 = P.less(v1); + C = edge1.cross(vp1); + if (N.dot(C) < 0) { + return null; // P is on the right side + } + + // edge 2 + Vector3f edge2 = v0.less(v2); + Vector3f vp2 = P.less(v2); + C = edge2.cross(vp2); + if (N.dot(C) < 0) { + return null; // P is on the right side; + } + + return this.origin.add(this.direction().multiply(t)); // this ray hits the triangle + } + + + } diff --git a/src/org/atriasoft/phyligram/math/ToolCollisionSphereWithTriangle.java b/src/org/atriasoft/phyligram/math/ToolCollisionSphereWithTriangle.java index 49dba4f..d59f1ae 100644 --- a/src/org/atriasoft/phyligram/math/ToolCollisionSphereWithTriangle.java +++ b/src/org/atriasoft/phyligram/math/ToolCollisionSphereWithTriangle.java @@ -7,20 +7,10 @@ import org.atriasoft.phyligram.ColisionPoint; import org.atriasoft.phyligram.PhysicSphere; import org.atriasoft.phyligram.PhysicTriangle; +import toolbox.Maths; + // https://realtimecollisiondetection.net/blog/?p=103 public class ToolCollisionSphereWithTriangle { - public static float clamp(float val, float min, float max) { - return Math.max(min, Math.min(max, val)); - } - - public static Vector3f getClosestPointOnFiniteLine(Vector3f point, Vector3f lineStart, Vector3f lineEnd) { - Vector3f lineDirection = lineEnd.less(lineStart); - float lineLength = lineDirection.length(); - lineDirection = lineDirection.normalize(); - float position = point.less(lineStart).dot(lineDirection); - float ProjectionLength = clamp(position, 0, lineLength); - return lineStart.add(lineDirection.multiply(ProjectionLength)); - } public static ColisionPoint getCollisionPoint(PhysicSphere sphere1, PhysicTriangle shapeReference) { Plane plane = new Plane(shapeReference.getTriangleGlobalPos()); @@ -66,13 +56,13 @@ public class ToolCollisionSphereWithTriangle { System.out.println("Not in center"); // now we need to check if we have a collision with the border. - Vector3f nearestPointP1 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p1, shapeReference.getTriangleGlobalPos().p2); + Vector3f nearestPointP1 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p1, shapeReference.getTriangleGlobalPos().p2); float distanceP1Square = Vector3f.length2(nearestPointP1, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP1Square=" + distanceP1Square); - Vector3f nearestPointP2 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p2, shapeReference.getTriangleGlobalPos().p3); + Vector3f nearestPointP2 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p2, shapeReference.getTriangleGlobalPos().p3); float distanceP2Square = Vector3f.length2(nearestPointP2, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP2Square=" + distanceP2Square); - Vector3f nearestPointP3 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p3, shapeReference.getTriangleGlobalPos().p1); + Vector3f nearestPointP3 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p3, shapeReference.getTriangleGlobalPos().p1); float distanceP3Square = Vector3f.length2(nearestPointP3, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP3Square=" + distanceP3Square); float distanceFinal; @@ -133,19 +123,19 @@ public class ToolCollisionSphereWithTriangle { System.out.println("Not in center"); // now we need to check if we have a collision with the border. - Vector3f nearestPointP1 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p1, shapeReference.getTriangleGlobalPos().p2); + Vector3f nearestPointP1 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p1, shapeReference.getTriangleGlobalPos().p2); float distanceP1Square = Vector3f.length2(nearestPointP1, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP1Square=" + distanceP1Square); if (distanceP1Square < distance2) { return true; } - Vector3f nearestPointP2 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p2, shapeReference.getTriangleGlobalPos().p3); + Vector3f nearestPointP2 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p2, shapeReference.getTriangleGlobalPos().p3); float distanceP2Square = Vector3f.length2(nearestPointP2, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP2Square=" + distanceP2Square); if (distanceP2Square < distance2) { return true; } - Vector3f nearestPointP3 = getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p3, shapeReference.getTriangleGlobalPos().p1); + Vector3f nearestPointP3 = Maths.getClosestPointOnFiniteLine(sphere1.narrowPhaseGlobalPos, shapeReference.getTriangleGlobalPos().p3, shapeReference.getTriangleGlobalPos().p1); float distanceP3Square = Vector3f.length2(nearestPointP3, sphere1.narrowPhaseGlobalPos); System.out.println("distanceP3Square=" + distanceP3Square); if (distanceP3Square < distance2) { diff --git a/src/toolbox/Maths.java b/src/toolbox/Maths.java index 574bf7e..8fbd7d4 100644 --- a/src/toolbox/Maths.java +++ b/src/toolbox/Maths.java @@ -49,5 +49,33 @@ public class Maths { matrix = matrix.rotate(new Vector3f(0, 1, 0), camera.getYaw()); return matrix; } + + public static float clamp(float val, float min, float max) { + return Math.max(min, Math.min(max, val)); + } + public static float avg(float min, float val, float max) { + return Math.max(min, Math.min(max, val)); + } + + public static Vector3f getClosestPointOnFiniteLine(Vector3f point, Vector3f lineStart, Vector3f lineEnd) { + Vector3f lineDirection = lineEnd.less(lineStart); + float lineLength = lineDirection.length(); + lineDirection = lineDirection.normalize(); + float position = point.less(lineStart).dot(lineDirection); + float ProjectionLength = clamp(position, 0, lineLength); + return lineStart.add(lineDirection.multiply(ProjectionLength)); + } + + public static Vector3f getClosestPointOnInfiniteLine(Vector3f point, Vector3f lineStart, Vector3f lineEnd) { + Vector3f lineDirection = lineEnd.less(lineStart); + lineDirection = lineDirection.normalize(); + float position = point.less(lineStart).dot(lineDirection); + return lineStart.add(lineDirection.multiply(position)); + } + + public static float sqrt(float dist2) { + // TODO Auto-generated method stub + return (float)Math.sqrt(dist2); + } }