third person character update
This commit is contained in:
@@ -719,6 +719,8 @@ Sphere defined by center Vector and radius. Can be intersected with other primit
|
||||
- Intersects(Ray ray) : bool result
|
||||
- GetCenter() : Vector result
|
||||
- GetRadius() : float result
|
||||
- SetCenter(Vector value)
|
||||
- SetRadius(float value)
|
||||
|
||||
### Input
|
||||
Query input devices
|
||||
|
||||
@@ -249,6 +249,8 @@ namespace wiIntersect_BindLua
|
||||
lunamethod(Sphere_BindLua, Intersects),
|
||||
lunamethod(Sphere_BindLua, GetCenter),
|
||||
lunamethod(Sphere_BindLua, GetRadius),
|
||||
lunamethod(Sphere_BindLua, SetCenter),
|
||||
lunamethod(Sphere_BindLua, SetRadius),
|
||||
{ NULL, NULL }
|
||||
};
|
||||
Luna<Sphere_BindLua>::PropertyType Sphere_BindLua::properties[] = {
|
||||
@@ -324,5 +326,39 @@ namespace wiIntersect_BindLua
|
||||
wiLua::SSetFloat(L, sphere.radius);
|
||||
return 1;
|
||||
}
|
||||
int Sphere_BindLua::SetCenter(lua_State* L)
|
||||
{
|
||||
int argc = wiLua::SGetArgCount(L);
|
||||
if (argc > 0)
|
||||
{
|
||||
Vector_BindLua* cV = Luna<Vector_BindLua>::lightcheck(L, 1);
|
||||
if (cV)
|
||||
{
|
||||
XMStoreFloat3(&sphere.center, cV->vector);
|
||||
}
|
||||
else
|
||||
{
|
||||
wiLua::SError(L, "SetCenter(Vector value) requires first argument to be of Vector type!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wiLua::SError(L, "SetCenter(Vector value) not enough arguments!");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int Sphere_BindLua::SetRadius(lua_State* L)
|
||||
{
|
||||
int argc = wiLua::SGetArgCount(L);
|
||||
if (argc > 0)
|
||||
{
|
||||
sphere.radius = wiLua::SGetFloat(L, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
wiLua::SError(L, "SetRadius(float value) not enough arguments!");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -62,5 +62,7 @@ namespace wiIntersect_BindLua
|
||||
int Intersects(lua_State* L);
|
||||
int GetCenter(lua_State* L);
|
||||
int GetRadius(lua_State* L);
|
||||
int SetCenter(lua_State* L);
|
||||
int SetRadius(lua_State* L);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2729,4 +2729,182 @@ namespace wiScene
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#include <DirectXCollision.h>
|
||||
SceneIntersectSphereResult SceneIntersectSphere(const SPHERE& sphere, uint32_t renderTypeMask, uint32_t layerMask, const Scene& scene)
|
||||
{
|
||||
SceneIntersectSphereResult result;
|
||||
XMVECTOR vCenter = XMLoadFloat3(&sphere.center);
|
||||
XMVECTOR vRadius = XMVectorReplicatePtr(&sphere.radius);
|
||||
XMVECTOR RadiusSq = XMVectorMultiply(vRadius, vRadius);
|
||||
|
||||
if (scene.objects.GetCount() > 0)
|
||||
{
|
||||
|
||||
for (size_t i = 0; i < scene.aabb_objects.GetCount(); ++i)
|
||||
{
|
||||
const AABB& aabb = scene.aabb_objects[i];
|
||||
if (!sphere.intersects(aabb))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const ObjectComponent& object = scene.objects[i];
|
||||
if (object.meshID == INVALID_ENTITY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!(renderTypeMask & object.GetRenderTypes()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Entity entity = scene.aabb_objects.GetEntity(i);
|
||||
const LayerComponent* layer = scene.layers.GetComponent(entity);
|
||||
if (layer != nullptr && !(layer->GetLayerMask() & layerMask))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const MeshComponent& mesh = *scene.meshes.GetComponent(object.meshID);
|
||||
const SoftBodyPhysicsComponent* softbody = scene.softbodies.GetComponent(object.meshID);
|
||||
const bool softbody_active = softbody != nullptr && !softbody->vertex_positions_simulation.empty();
|
||||
|
||||
const XMMATRIX objectMat = object.transform_index >= 0 ? XMLoadFloat4x4(&scene.transforms[object.transform_index].world) : XMMatrixIdentity();
|
||||
|
||||
const ArmatureComponent* armature = mesh.IsSkinned() ? scene.armatures.GetComponent(mesh.armatureID) : nullptr;
|
||||
|
||||
int subsetCounter = 0;
|
||||
for (auto& subset : mesh.subsets)
|
||||
{
|
||||
for (size_t i = 0; i < subset.indexCount; i += 3)
|
||||
{
|
||||
const uint32_t i0 = mesh.indices[subset.indexOffset + i + 0];
|
||||
const uint32_t i1 = mesh.indices[subset.indexOffset + i + 1];
|
||||
const uint32_t i2 = mesh.indices[subset.indexOffset + i + 2];
|
||||
|
||||
XMVECTOR p0;
|
||||
XMVECTOR p1;
|
||||
XMVECTOR p2;
|
||||
|
||||
if (softbody_active)
|
||||
{
|
||||
p0 = softbody->vertex_positions_simulation[i0].LoadPOS();
|
||||
p1 = softbody->vertex_positions_simulation[i1].LoadPOS();
|
||||
p2 = softbody->vertex_positions_simulation[i2].LoadPOS();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (armature == nullptr)
|
||||
{
|
||||
p0 = XMLoadFloat3(&mesh.vertex_positions[i0]);
|
||||
p1 = XMLoadFloat3(&mesh.vertex_positions[i1]);
|
||||
p2 = XMLoadFloat3(&mesh.vertex_positions[i2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
p0 = SkinVertex(mesh, *armature, i0);
|
||||
p1 = SkinVertex(mesh, *armature, i1);
|
||||
p2 = SkinVertex(mesh, *armature, i2);
|
||||
}
|
||||
}
|
||||
|
||||
p0 = XMVector3Transform(p0, objectMat);
|
||||
p1 = XMVector3Transform(p1, objectMat);
|
||||
p2 = XMVector3Transform(p2, objectMat);
|
||||
|
||||
// Compute the plane of the triangle (has to be normalized).
|
||||
XMVECTOR N = XMVector3Normalize(XMVector3Cross(XMVectorSubtract(p1, p0), XMVectorSubtract(p2, p0)));
|
||||
|
||||
// Assert that the triangle is not degenerate.
|
||||
assert(!XMVector3Equal(N, XMVectorZero()));
|
||||
|
||||
// Find the nearest feature on the triangle to the sphere.
|
||||
XMVECTOR Dist = XMVector3Dot(XMVectorSubtract(vCenter, p0), N);
|
||||
|
||||
if (XMVectorGetX(Dist) > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the center of the sphere is farther from the plane of the triangle than
|
||||
// the radius of the sphere, then there cannot be an intersection.
|
||||
XMVECTOR NoIntersection = XMVectorLess(Dist, XMVectorNegate(vRadius));
|
||||
NoIntersection = XMVectorOrInt(NoIntersection, XMVectorGreater(Dist, vRadius));
|
||||
|
||||
// Project the center of the sphere onto the plane of the triangle.
|
||||
XMVECTOR Point = XMVectorNegativeMultiplySubtract(N, Dist, vCenter);
|
||||
XMVECTOR planeIntersection = Point;
|
||||
|
||||
// Is it inside all the edges? If so we intersect because the distance
|
||||
// to the plane is less than the radius.
|
||||
XMVECTOR Intersection = DirectX::Internal::PointOnPlaneInsideTriangle(Point, p0, p1, p2);
|
||||
|
||||
bool inside = XMVector4EqualInt(XMVectorAndCInt(Intersection, NoIntersection), XMVectorTrueInt());
|
||||
XMVECTOR bestPoint = Point;
|
||||
float bestDist = inside ? 0 : FLT_MAX;
|
||||
|
||||
// Find the nearest point on each edge.
|
||||
|
||||
// Edge 0,1
|
||||
Point = DirectX::Internal::PointOnLineSegmentNearestPoint(p0, p1, vCenter);
|
||||
|
||||
// If the distance to the center of the sphere to the point is less than
|
||||
// the radius of the sphere then it must intersect.
|
||||
Intersection = XMVectorOrInt(Intersection, XMVectorLessOrEqual(XMVector3LengthSq(XMVectorSubtract(vCenter, Point)), RadiusSq));
|
||||
|
||||
float d = abs(XMVectorGetX(XMVector3LinePointDistance(p0, p1, planeIntersection)));
|
||||
if (d < bestDist)
|
||||
{
|
||||
bestDist = d;
|
||||
bestPoint = Point;
|
||||
}
|
||||
|
||||
// Edge 1,2
|
||||
Point = DirectX::Internal::PointOnLineSegmentNearestPoint(p1, p2, vCenter);
|
||||
|
||||
// If the distance to the center of the sphere to the point is less than
|
||||
// the radius of the sphere then it must intersect.
|
||||
Intersection = XMVectorOrInt(Intersection, XMVectorLessOrEqual(XMVector3LengthSq(XMVectorSubtract(vCenter, Point)), RadiusSq));
|
||||
|
||||
d = abs(XMVectorGetX(XMVector3LinePointDistance(p1, p2, planeIntersection)));
|
||||
if (d < bestDist)
|
||||
{
|
||||
bestDist = d;
|
||||
bestPoint = Point;
|
||||
}
|
||||
|
||||
// Edge 2,0
|
||||
Point = DirectX::Internal::PointOnLineSegmentNearestPoint(p2, p0, vCenter);
|
||||
|
||||
// If the distance to the center of the sphere to the point is less than
|
||||
// the radius of the sphere then it must intersect.
|
||||
Intersection = XMVectorOrInt(Intersection, XMVectorLessOrEqual(XMVector3LengthSq(XMVectorSubtract(vCenter, Point)), RadiusSq));
|
||||
|
||||
d = abs(XMVectorGetX(XMVector3LinePointDistance(p2, p0, planeIntersection)));
|
||||
if (d < bestDist)
|
||||
{
|
||||
bestDist = d;
|
||||
bestPoint = Point;
|
||||
}
|
||||
|
||||
bool intersects = XMVector4EqualInt(XMVectorAndCInt(Intersection, NoIntersection), XMVectorTrueInt());
|
||||
|
||||
if (intersects && bestDist < result.distance_to_polygon)
|
||||
{
|
||||
result.entity = entity;
|
||||
result.depth = sphere.radius - XMVectorGetX(XMVector3Length(vCenter - bestPoint));
|
||||
XMStoreFloat3(&result.position, bestPoint);
|
||||
XMStoreFloat3(&result.normal, XMVector3Normalize(vCenter - bestPoint));
|
||||
}
|
||||
}
|
||||
subsetCounter++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1353,5 +1353,16 @@ namespace wiScene
|
||||
// layerMask : filter based on layer
|
||||
// scene : the scene that will be traced against the ray
|
||||
PickResult Pick(const RAY& ray, uint32_t renderTypeMask = RENDERTYPE_OPAQUE, uint32_t layerMask = ~0, const Scene& scene = GetScene());
|
||||
|
||||
struct SceneIntersectSphereResult
|
||||
{
|
||||
wiECS::Entity entity = wiECS::INVALID_ENTITY;
|
||||
XMFLOAT3 position = XMFLOAT3(0, 0, 0);
|
||||
XMFLOAT3 normal = XMFLOAT3(0, 0, 0);
|
||||
float depth = 0;
|
||||
float distance_to_polygon = FLT_MAX;
|
||||
};
|
||||
SceneIntersectSphereResult SceneIntersectSphere(const SPHERE& sphere, uint32_t renderTypeMask = RENDERTYPE_OPAQUE, uint32_t layerMask = ~0, const Scene& scene = GetScene());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -139,6 +139,56 @@ int Pick(lua_State* L)
|
||||
|
||||
return 0;
|
||||
}
|
||||
int SceneIntersectSphere(lua_State* L)
|
||||
{
|
||||
int argc = wiLua::SGetArgCount(L);
|
||||
if (argc > 0)
|
||||
{
|
||||
Sphere_BindLua* sphere = Luna<Sphere_BindLua>::lightcheck(L, 1);
|
||||
if (sphere != nullptr)
|
||||
{
|
||||
uint32_t renderTypeMask = RENDERTYPE_OPAQUE;
|
||||
uint32_t layerMask = 0xFFFFFFFF;
|
||||
Scene* scene = &wiScene::GetScene();
|
||||
if (argc > 1)
|
||||
{
|
||||
renderTypeMask = (uint32_t)wiLua::SGetInt(L, 2);
|
||||
if (argc > 2)
|
||||
{
|
||||
int mask = wiLua::SGetInt(L, 3);
|
||||
layerMask = *reinterpret_cast<uint32_t*>(&mask);
|
||||
|
||||
if (argc > 3)
|
||||
{
|
||||
Scene_BindLua* custom_scene = Luna<Scene_BindLua>::lightcheck(L, 4);
|
||||
if (custom_scene)
|
||||
{
|
||||
scene = custom_scene->scene;
|
||||
}
|
||||
else
|
||||
{
|
||||
wiLua::SError(L, "SceneIntersectSphere(Sphere sphere, opt PICKTYPE pickType, opt uint layerMask, opt Scene scene) last argument is not of type Scene!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
auto& pick = wiScene::SceneIntersectSphere(sphere->sphere, renderTypeMask, layerMask, *scene);
|
||||
wiLua::SSetInt(L, (int)pick.entity);
|
||||
Luna<Vector_BindLua>::push(L, new Vector_BindLua(XMLoadFloat3(&pick.position)));
|
||||
Luna<Vector_BindLua>::push(L, new Vector_BindLua(XMLoadFloat3(&pick.normal)));
|
||||
wiLua::SSetFloat(L, pick.depth);
|
||||
return 4;
|
||||
}
|
||||
|
||||
wiLua::SError(L, "SceneIntersectSphere(Sphere sphere, opt PICKTYPE pickType, opt uint layerMask, opt Scene scene) first argument must be of Ray type!");
|
||||
}
|
||||
else
|
||||
{
|
||||
wiLua::SError(L, "SceneIntersectSphere(Sphere sphere, opt PICKTYPE pickType, opt uint layerMask, opt Scene scene) not enough arguments!");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Bind()
|
||||
{
|
||||
@@ -168,6 +218,7 @@ void Bind()
|
||||
wiLua::GetGlobal()->RegisterFunc("GetScene", GetScene);
|
||||
wiLua::GetGlobal()->RegisterFunc("LoadModel", LoadModel);
|
||||
wiLua::GetGlobal()->RegisterFunc("Pick", Pick);
|
||||
wiLua::GetGlobal()->RegisterFunc("SceneIntersectSphere", SceneIntersectSphere);
|
||||
|
||||
Luna<Scene_BindLua>::Register(L);
|
||||
Luna<NameComponent_BindLua>::Register(L);
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace wiVersion
|
||||
// minor features, major updates
|
||||
const int minor = 39;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 71;
|
||||
const int revision = 72;
|
||||
|
||||
|
||||
long GetVersion()
|
||||
|
||||
Binary file not shown.
@@ -32,9 +32,6 @@ Character = {
|
||||
face = Vector(0,0,1), -- forward direction
|
||||
force = Vector(),
|
||||
velocity = Vector(),
|
||||
ray = Ray(Vector(),Vector()),
|
||||
o = INVALID_ENTITY, -- collision prop with scene (entity)
|
||||
p,n = Vector(), -- collision props with scene (position,normal)
|
||||
savedPointerPos = Vector(),
|
||||
moveSpeed = 90,
|
||||
layerMask = 0x2, -- The character will be tagged to use this layer, so scene Picking can filter out the character
|
||||
@@ -87,9 +84,12 @@ Character = {
|
||||
model_transform.ClearTransform()
|
||||
dir = vector.Transform(dir:Normalize(), target_transform.GetMatrix())
|
||||
dir.SetY(0)
|
||||
dir = dir.Normalize()
|
||||
local dot = vector.Dot(self.face, dir)
|
||||
if(dot < 0) then
|
||||
self.face = vector.TransformNormal(self.face, matrix.RotationY(3.1415 * 0.01))
|
||||
end
|
||||
self.face = vector.Lerp(self.face, dir, 0.2);
|
||||
self.face = self.face.Normalize()
|
||||
self.face.Normalize()
|
||||
model_transform.MatrixTransform(matrix.LookTo(Vector(),self.face):Inverse())
|
||||
model_transform.Scale(self.scale)
|
||||
model_transform.Rotate(self.rotation)
|
||||
@@ -97,7 +97,9 @@ Character = {
|
||||
model_transform.UpdateTransform()
|
||||
scene.Component_Detach(self.target)
|
||||
scene.Component_Attach(self.target, self.model)
|
||||
self.force = vector.Add(self.force, self.face:Multiply(Vector(f,f,f)))
|
||||
if(dot > 0) then
|
||||
self.force = vector.Add(self.force, self.face:Multiply(Vector(f,f,f)))
|
||||
end
|
||||
self.state = self.states.WALK
|
||||
end,
|
||||
|
||||
@@ -163,13 +165,6 @@ Character = {
|
||||
local model_transform = scene.Component_GetTransform(self.model)
|
||||
local target_transform = scene.Component_GetTransform(self.target)
|
||||
|
||||
-- gravity:
|
||||
self.force = vector.Add(self.force, Vector(0,-9.8 * 20,0))
|
||||
|
||||
-- apply force:
|
||||
self.velocity = vector.Add(self.velocity, vector.Multiply(self.force, 0.016))
|
||||
self.force = Vector(0,0,0,0)
|
||||
|
||||
-- state and animation update
|
||||
if(self.state == self.states.STAND) then
|
||||
scene.Component_GetAnimation(self.walk_anim).Stop()
|
||||
@@ -198,50 +193,53 @@ Character = {
|
||||
end
|
||||
self.state_prev = self.state
|
||||
|
||||
-- front block shoots multiple rays in front to try to find obstruction
|
||||
local rotations = {0, 3.1415*0.3, -3.1415*0.3}
|
||||
for i,rot in ipairs(rotations) do
|
||||
local origin = vector.Add(model_transform.GetPosition(), Vector(0,1,0)) -- this ray starts a little above character ground position
|
||||
local dir = vector.Transform(self.face, matrix.RotationY(rot))
|
||||
local ray2 = Ray(origin,dir)
|
||||
local o2,p2,n2 = Pick(ray2, PICK_OPAQUE, ~self.layerMask)
|
||||
local dist = vector.Subtract(origin,p2):Length()
|
||||
if(o2 ~= INVALID_ENTITY and dist < 1) then
|
||||
-- run along wall instead of going through it
|
||||
-- gravity:
|
||||
self.force = vector.Add(self.force, Vector(0,-9.8 * 10,0))
|
||||
|
||||
-- apply force:
|
||||
self.velocity = vector.Add(self.velocity, vector.Multiply(self.force, 0.016))
|
||||
self.force = Vector(0,0,0,0)
|
||||
|
||||
-- Sphere collider for character:
|
||||
local sphere = Sphere(vector.Add(model_transform.GetPosition(), Vector(0,1.1)), 1)
|
||||
local pp = sphere.GetCenter()
|
||||
local intersection = false
|
||||
local ccd = 0
|
||||
local ccd_max = 5
|
||||
while(ccd < ccd_max) do
|
||||
ccd = ccd + 1
|
||||
local step = vector.Multiply(self.velocity, 1.0 / ccd_max * 0.016)
|
||||
|
||||
local prevpos = sphere.GetCenter()
|
||||
sphere.SetCenter(vector.Add(prevpos, step))
|
||||
local o2, p2, n2, depth = SceneIntersectSphere(sphere, PICK_OPAQUE, ~self.layerMask)
|
||||
if(o2 ~= INVALID_ENTITY) then
|
||||
DrawPoint(p2,0.5,Vector(1,1,0,1))
|
||||
DrawLine(p2, vector.Add(p2, n2), Vector(1,1,0,1))
|
||||
|
||||
-- Slide on surface:
|
||||
local velocityLen = self.velocity.Length()
|
||||
local velocityNormalized = self.velocity.Normalize()
|
||||
local undesiredMotion = n2:Multiply(vector.Dot(velocityNormalized, n2))
|
||||
local desiredMotion = vector.Subtract(velocityNormalized, undesiredMotion)
|
||||
self.velocity = vector.Multiply(desiredMotion, velocityLen)
|
||||
end
|
||||
end
|
||||
|
||||
-- check what is below the character
|
||||
self.ray = Ray(target_transform.GetPosition(),Vector(0,-1,0))
|
||||
local pPrev = self.p
|
||||
self.o,self.p,self.n = Pick(self.ray, PICK_OPAQUE, ~self.layerMask)
|
||||
if(self.o == INVALID_ENTITY) then
|
||||
self.p=pPrev -- if nothing, go back to previous position
|
||||
end
|
||||
|
||||
-- apply velocity:
|
||||
model_transform.Translate(vector.Multiply(self.velocity, 0.016))
|
||||
model_transform.UpdateTransform()
|
||||
|
||||
-- check if we are below or on the ground:
|
||||
local posY = model_transform.GetPosition().GetY()
|
||||
if(posY <= self.p.GetY() and self.velocity.GetY()<=0) then
|
||||
self.state = self.states.STAND
|
||||
if(self.o == INVALID_ENTITY) then
|
||||
model_transform.Translate(vector.Subtract(self.p,model_transform.GetPosition())) -- snap back to last succesfully traced position
|
||||
else
|
||||
model_transform.Translate(Vector(0,self.p.GetY()-posY,0)) -- snap to ground
|
||||
intersection = true
|
||||
sphere.SetCenter(prevpos)
|
||||
end
|
||||
self.velocity.SetY(0) -- don't fall below ground
|
||||
self.velocity = vector.Multiply(self.velocity, 0.8) -- slow down on ground
|
||||
else
|
||||
self.velocity = vector.Multiply(self.velocity, 0.94) -- slow down in air
|
||||
end
|
||||
--DrawPoint(sphere.GetCenter(), 0.5, Vector(0,1,0,1))
|
||||
|
||||
if intersection then
|
||||
self.velocity = vector.Multiply(self.velocity, 0.8) -- ground friction
|
||||
else
|
||||
self.velocity = vector.Multiply(self.velocity, 0.94) -- air friction
|
||||
end
|
||||
if(vector.Length(self.velocity) < 0.001) then
|
||||
self.state = self.states.STAND
|
||||
end
|
||||
model_transform.Translate(vector.Subtract(sphere.GetCenter(), pp))
|
||||
model_transform.UpdateTransform()
|
||||
|
||||
-- try to put water ripple if character head is directly above water
|
||||
local head_transform = scene.Component_GetTransform(self.head)
|
||||
@@ -441,7 +439,7 @@ runProcess(function()
|
||||
--face
|
||||
DrawLine(target_transform.GetPosition(),target_transform.GetPosition():Add(player.face:Normalize()),Vector(0,1,0,1))
|
||||
--intersection
|
||||
DrawAxis(player.p,0.5)
|
||||
--DrawAxis(player.p,0.5)
|
||||
|
||||
-- camera target box and axis
|
||||
DrawBox(target_transform.GetMatrix())
|
||||
|
||||
Reference in New Issue
Block a user