[DEV] proto of map editor for future gane ==> state we need to externalize it

This commit is contained in:
Edouard DUPIN 2022-03-20 11:18:36 +01:00
parent 8d2e6305da
commit f0c86f20de
26 changed files with 971 additions and 166 deletions

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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<MAX_LIGHT_NUMBER; iii++) {
float distance = length(io_toLightVector[iii]);
float attenuationFactor = in_lights[iii].attenuation.x + (in_lights[iii].attenuation.y * distance) + (in_lights[iii].attenuation.z * distance * distance);
vec3 unitLightVector = normalize(io_toLightVector[iii]);
float nDot1 = dot(unitNormal, unitLightVector);
float brightness = max(nDot1, 0.0);
vec3 lightDirection = -unitLightVector;
vec3 reflectedLightDirection = reflect(lightDirection, unitNormal);
float specularFactor = dot(reflectedLightDirection, unitVectorToCamera);
specularFactor = max(specularFactor, 0.0);
float damperFactor = pow(specularFactor, tex_shininess);
vec3 diffuse = (brightness * in_lights[iii].color) / attenuationFactor;
vec3 finalSpecular = (damperFactor * tex_specularFactor.x * in_lights[iii].color) / attenuationFactor; // TODO: Remove the x ....
totalDiffuse = totalDiffuse + diffuse;
totalSpecular = totalSpecular + finalSpecular;
}
// the 0.2 represent the ambiant lightning ==> 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);
}

View File

@ -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<MAX_LIGHT_NUMBER;iii++) {
io_toLightVector[iii] = in_lights[iii].position - worldPosition.xyz;
}
io_toCameraVector = (inverse(in_matrixView) * vec4(0.0,0.0,0.0,1.0)).xyz - worldPosition.xyz;
float distance = length(positionRelativeToCam.xyz);
io_fowVisibility = exp(-pow((distance*c_density),c_gradient));
io_fowVisibility = clamp(io_fowVisibility, 0.0, 1.0);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,46 @@
# Blender v2.82 (sub 7) OBJ File: 'cube.blend'
# www.blender.org
mtllib cube.mtl
o Cube
v 0.5 0.5 -0.5
v 0.5 -0.5 -0.5
v 0.5 0.5 0.5
v 0.5 -0.5 0.5
v -0.5 0.5 -0.5
v -0.5 -0.5 -0.5
v -0.5 0.5 0.5
v -0.5 -0.5 0.5
vt 0.875000 0.500000
vt 0.625000 0.750000
vt 0.625000 0.500000
vt 0.375000 1.000000
vt 0.375000 0.750000
vt 0.625000 0.000000
vt 0.375000 0.250000
vt 0.375000 0.000000
vt 0.375000 0.500000
vt 0.125000 0.750000
vt 0.125000 0.500000
vt 0.625000 0.250000
vt 0.875000 0.750000
vt 0.625000 1.000000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
usemtl Material
s off
f 5/1/1 3/2/1 1/3/1
f 3/2/2 8/4/2 4/5/2
f 7/6/3 6/7/3 8/8/3
f 2/9/4 8/10/4 6/11/4
f 1/3/5 4/5/5 2/9/5
f 5/12/6 2/9/6 6/7/6
f 5/1/1 7/13/1 3/2/1
f 3/2/2 7/14/2 8/4/2
f 7/6/3 5/12/3 6/7/3
f 2/9/4 4/5/4 8/10/4
f 1/3/5 3/2/5 4/5/5
f 5/12/6 1/3/6 2/9/6

View File

@ -0,0 +1,41 @@
{
"default": {
"Ns":225.000000,
"Ka":"1.000000 1.000000 1.000000",
"Kd":"0.346704 0.558341 0.090842",
"Ks":"0.500000 0.500000 0.500000",
"Ke":"0.000000 0.000000 0.000000",
"vNi":1.000000,
"d":1.000000,
"illum":2
},
"palette": {
"leaf_1":{
"Kd":"0.346704 0.558341 0.090842"
},
"leaf_2":{
"Kd":"0.278894 0.278894 0.023153"
},
"leaf_3":{
"Kd":"0.800000 0.800000 0.800000"
},
"trunk_1":{
"Kd":"0.25 0.13 0.07"
},
"trunk_2":{
"Kd":"0.057805 0.039546 0.013702"
},
"grass_1":{
"Kd":"0.057805 1.0 0.013702"
},
"grass_2":{
"Kd":"1.0 0.0 0.013702"
},
"grass_3":{
"Kd":"1.0 1.0 0.013702"
},
"grass_4":{
"Kd":"0.0 0.0 1.0"
}
}
}

View File

@ -11,5 +11,7 @@ open module sample.atriasoft.ege {
exports sample.atriasoft.ege.s1_texturedCube;
requires org.atriasoft.ege;
requires org.atriasoft.ewol; // for map factory
requires org.atriasoft.ewol;
requires org.atriasoft.etk;
requires org.atriasoft.gale; // for map factory
}

View File

@ -1,5 +1,7 @@
package sample.atriasoft.ege.mapFactory;
import org.atriasoft.ege.ControlCameraSimple;
import org.atriasoft.ege.ControlInterface;
import org.atriasoft.ege.Entity;
import org.atriasoft.ege.components.ComponentMesh;
import org.atriasoft.ege.components.ComponentPosition;
@ -9,16 +11,23 @@ import org.atriasoft.ege.engines.EngineLight;
import org.atriasoft.etk.Uri;
import org.atriasoft.etk.math.Transform3D;
import org.atriasoft.etk.math.Vector3f;
import org.atriasoft.ewol.event.EventEntry;
import org.atriasoft.ewol.event.EventInput;
import sample.atriasoft.ege.mapFactory.model.Map;
import sample.atriasoft.ege.mapFactory.tools.MapToolInterface;
public class ApplScene extends EgeScene {
Ground ground = new Ground();
//Ground ground = new Ground();
Map map = new Map();
private ControlInterface simpleControl;
private MapToolInterface currentTool = null;
/**
* Constructor
*/
public ApplScene() {
addGenericGird();
// test entity
Entity groundEntity = new Entity(this.env);
ComponentPosition objectPosition = new ComponentPosition(new Transform3D(new Vector3f(0, 0, 0)));
@ -26,98 +35,71 @@ public class ApplScene extends EgeScene {
//this.materialCube = new Material();
//basicTree.addComponent(new ComponentMaterial(this.materialCube));
//groundEntity.addComponent(new ComponentMesh(new Uri("DATA", "tree1.emf", "plop")));
groundEntity.addComponent(new ComponentMesh(this.ground.createMesh()));
groundEntity.addComponent(new ComponentMesh(this.map.ground.createMesh()));
groundEntity.addComponent(new ComponentTexturePalette(new Uri("DATA", "palette_1.json")));
//basicTree.addComponent(new ComponentRenderTexturedStaticMesh(new Uri("DATA", "basic.vert", "loxelEngine"), new Uri("DATA", "basic.frag", "loxelEngine")));
groundEntity
.addComponent(new ComponentRenderMeshPalette(new Uri("DATA", "basicPalette.vert"), new Uri("DATA", "basicPalette.frag"), (EngineLight) this.env.getEngine(EngineLight.ENGINE_NAME)));
this.env.addEntity(groundEntity);
this.ground.updateMesh();
}
}
/*
private float angleLight = 0;
private Quaternion basicRotation = Quaternion.IDENTITY;
private Quaternion basicRotation2 = Quaternion.IDENTITY;
private ComponentPosition lightPosition;
private Material materialCube;
private ComponentPosition objectPosition;
private ControlCameraSimple simpleControl;
public LowPolyApplication() {}
@Override
public void onCreate(final GaleContext context) {
// simple sun to have a global light ...
final Entity sun = new Entity(this.env);
sun.addComponent(new ComponentPosition(new Transform3D(new Vector3f(1000, 1000, 1000))));
sun.addComponent(new ComponentLightSun(new Light(new Color(1.0f, 1.0f, 1.0f), new Vector3f(0, 0, 0), new Vector3f(1.0f, 0, 0))));
this.env.addEntity(sun);
// add a cube to show where in the light ...
final Entity localLight = new Entity(this.env);
this.lightPosition = new ComponentPosition(new Transform3D(new Vector3f(-10, -10, 1)));
localLight.addComponent(this.lightPosition);
localLight.addComponent(new ComponentStaticMesh(new Uri("DATA", "cube-one.obj")));
localLight.addComponent(new ComponentTexture(new Uri("DATA", "grass.png")));
localLight.addComponent(new ComponentLight(new Light(new Color(0.0f, 0.0f, 2.0f), new Vector3f(0, 0, 0), new Vector3f(0.8f, 0.01f, 0.002f))));
localLight.addComponent(new ComponentRenderTexturedStaticMesh(new Uri("DATA", "basic.vert", "loxelEngine"), new Uri("DATA", "basic.frag", "loxelEngine")));
this.env.addEntity(localLight);
// Simple Gird
final Entity gird = new Entity(this.env);
gird.addComponent(new ComponentPosition(new Transform3D(new Vector3f(0, 0, 0))));
gird.addComponent(new ComponentStaticMesh(MeshGenerator.createGrid(5)));
gird.addComponent(new ComponentRenderColoredStaticMesh(new Uri("DATA", "wireColor.vert", "ege"), new Uri("DATA", "wireColor.frag", "ege")));
this.env.addEntity(gird);
// test entity
Entity basicTree = new Entity(this.env);
this.objectPosition = new ComponentPosition(new Transform3D(new Vector3f(0, 0, 0)));
basicTree.addComponent(this.objectPosition);
//this.materialCube = new Material();
//basicTree.addComponent(new ComponentMaterial(this.materialCube));
basicTree.addComponent(new ComponentMesh(new Uri("DATA", "tree1.emf")));
basicTree.addComponent(new ComponentTexturePalette(new Uri("DATA", "palette_1.json")));
//basicTree.addComponent(new ComponentRenderTexturedStaticMesh(new Uri("DATA", "basic.vert", "loxelEngine"), new Uri("DATA", "basic.frag", "loxelEngine")));
basicTree.addComponent(new ComponentRenderMeshPalette(new Uri("DATA", "basicPalette.vert"), new Uri("DATA", "basicPalette.frag"),
(EngineLight) this.env.getEngine(EngineLight.ENGINE_NAME)));
this.env.addEntity(basicTree);
basicTree = new Entity(this.env);
this.objectPosition = new ComponentPosition(new Transform3D(new Vector3f(3, 2, 0)));
basicTree.addComponent(this.objectPosition);
//this.materialCube = new Material();
//basicTree.addComponent(new ComponentMaterial(this.materialCube));
basicTree.addComponent(new ComponentMesh(new Uri("DATA", "tree2.emf")));
basicTree.addComponent(new ComponentTexturePalette(new Uri("DATA", "palette_1.json")));
//basicTree.addComponent(new ComponentRenderTexturedStaticMesh(new Uri("DATA", "basic.vert", "loxelEngine"), new Uri("DATA", "basic.frag", "loxelEngine")));
basicTree.addComponent(new ComponentRenderMeshPalette(new Uri("DATA", "basicPalette.vert"), new Uri("DATA", "basicPalette.frag"),
(EngineLight) this.env.getEngine(EngineLight.ENGINE_NAME)));
this.env.addEntity(basicTree);
this.simpleControl = new ControlCameraSimple(mainView);
this.map.updateMesh();
this.simpleControl = new ControlCameraSimple(this.mainView);
this.env.addControlInterface(this.simpleControl);
// start the engine.
this.env.setPropertyStatus(GameStatus.gameStart);
// add a cube to test collision ...
// final Entity localBox = new Entity(this.env);
// localBox.addComponent(new ComponentStaticMesh(new Uri("DATA", "cube-one.obj")));
// localBox.addComponent(new ComponentTexture(new Uri("DATA", "clay.png")));
// //localBox.addComponent(new ComponentLight(new Light(new Color(0.0f, 1.0f, 0.0f), new Vector3f(0, 0, 0), new Vector3f(0.8f, 0.03f, 0.002f))));
// localBox.addComponent(new ComponentRenderTexturedStaticMesh(new Uri("DATA", "basic.vert"), new Uri("DATA", "basic.frag")));
// this.posRay = new ComponentPosition(new Transform3D(new Vector3f(0, 4, 2.5f)));
//
// localBox.addComponent(this.posRay);
// //final ComponentPhysics physics2 = new ComponentPhysics(this.env);
// //final PhysicBox box2 = new PhysicBox();
// //box2.setSize(new Vector3f(2.0f, 2.0f, 2.0f));
// //box2.setOrigin(new Vector3f(0, 0, 0));
// //box2.setMass(1);
// //physics2.addShape(box2);
// //localBox.addComponent(physics2);
// this.env.addEntity(localBox);
this.basicRotation = Quaternion.fromEulerAngles(new Vector3f(0.005f, 0.005f, 0.01f));
this.basicRotation2 = Quaternion.fromEulerAngles(new Vector3f(0.003f, 0.01f, 0.001f));
// ready to let Gale & Ege manage the display
Log.info("==> Init APPL (END)");
}
public MapToolInterface getCurrentTool() {
return this.currentTool;
}
@Override
public void onKeyboard(final KeySpecial special, final KeyKeyboard type, final Character value, final KeyStatus state) {
this.env.onKeyboard(special, type, value, state);
protected void onDrawScene() {
if (this.currentTool != null) {
this.currentTool.onDraw(this.map);
}
}
@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 boolean onEventEntry(final EventEntry event) {
if (this.currentTool != null) {
if (this.currentTool.onEventEntry(event, this.map, this)) {
return true;
}
}
return super.onEventEntry(event);
}
@Override
public boolean onEventInput(final EventInput event) {
if (this.currentTool != null) {
if (this.currentTool.onEventInput(event, this.map, this)) {
return true;
}
}
return super.onEventInput(event);
}
public void setCurrentTool(MapToolInterface currentTool) {
this.currentTool = currentTool;
}
}
*/

View File

@ -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

View File

@ -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<Float, Float, Float> 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));

View File

@ -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());
}
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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)));

View File

@ -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));

View File

@ -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;
}
@ -63,4 +58,17 @@ public class Camera {
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());
}
}

View File

@ -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);
}

View File

@ -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()));
}
}

View File

@ -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()));
}
}

View File

@ -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);

View File

@ -2,20 +2,15 @@ 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) {
@ -23,12 +18,160 @@ public class Ray {
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
}
}

View File

@ -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) {

View File

@ -50,4 +50,32 @@ public class Maths {
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);
}
}