improvements and optimizations
This commit is contained in:
@@ -41,6 +41,15 @@ namespace wi
|
||||
rgba |= (c - 'A' + 10) << shift;
|
||||
shift += 4u;
|
||||
break;
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
rgba |= (c - 'a' + 10) << shift;
|
||||
shift += 4u;
|
||||
break;
|
||||
case '#':
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -412,11 +412,15 @@ namespace wi::primitive
|
||||
}
|
||||
XMFLOAT4X4 Sphere::GetPlacementOrientation(const XMFLOAT3& position, const XMFLOAT3& normal) const
|
||||
{
|
||||
XMVECTOR N = XMLoadFloat3(&normal);
|
||||
XMVECTOR N = XMVector3Normalize(XMLoadFloat3(&normal));
|
||||
XMVECTOR P = XMLoadFloat3(&position);
|
||||
XMVECTOR E = XMLoadFloat3(¢er) - P;
|
||||
XMVECTOR T = XMVector3Normalize(XMVector3Cross(N, P - E));
|
||||
XMVECTOR B = XMVector3Normalize(XMVector3Cross(T, N));
|
||||
N = XMVectorSetW(N, 0);
|
||||
T = XMVectorSetW(T, 0);
|
||||
B = XMVectorSetW(B, 0);
|
||||
P = XMVectorSetW(P, 1);
|
||||
XMMATRIX M = { T, N, B, P };
|
||||
XMFLOAT4X4 orientation;
|
||||
XMStoreFloat4x4(&orientation, M);
|
||||
@@ -574,12 +578,16 @@ namespace wi::primitive
|
||||
const XMVECTOR Base = XMLoadFloat3(&base);
|
||||
const XMVECTOR Tip = XMLoadFloat3(&tip);
|
||||
const XMVECTOR Axis = XMVector3Normalize(Tip - Base);
|
||||
XMVECTOR N = XMLoadFloat3(&normal);
|
||||
XMVECTOR N = XMVector3Normalize(XMLoadFloat3(&normal));
|
||||
XMVECTOR P = XMLoadFloat3(&position);
|
||||
XMVECTOR E = Axis;
|
||||
XMVECTOR T = XMVector3Normalize(XMVector3Cross(N, P - E));
|
||||
XMVECTOR Binorm = XMVector3Normalize(XMVector3Cross(T, N));
|
||||
XMMATRIX M = { T, N, Binorm, P };
|
||||
XMVECTOR B = XMVector3Normalize(XMVector3Cross(T, N));
|
||||
N = XMVectorSetW(N, 0);
|
||||
T = XMVectorSetW(T, 0);
|
||||
B = XMVectorSetW(B, 0);
|
||||
P = XMVectorSetW(P, 1);
|
||||
XMMATRIX M = { T, N, B, P };
|
||||
XMFLOAT4X4 orientation;
|
||||
XMStoreFloat4x4(&orientation, M);
|
||||
return orientation;
|
||||
@@ -800,11 +808,15 @@ namespace wi::primitive
|
||||
}
|
||||
XMFLOAT4X4 Ray::GetPlacementOrientation(const XMFLOAT3& position, const XMFLOAT3& normal) const
|
||||
{
|
||||
XMVECTOR N = XMLoadFloat3(&normal);
|
||||
XMVECTOR N = XMVector3Normalize(XMLoadFloat3(&normal));
|
||||
XMVECTOR P = XMLoadFloat3(&position);
|
||||
XMVECTOR E = XMLoadFloat3(&origin);
|
||||
XMVECTOR T = XMVector3Normalize(XMVector3Cross(N, P - E));
|
||||
XMVECTOR B = XMVector3Normalize(XMVector3Cross(T, N));
|
||||
N = XMVectorSetW(N, 0);
|
||||
T = XMVectorSetW(T, 0);
|
||||
B = XMVectorSetW(B, 0);
|
||||
P = XMVectorSetW(P, 1);
|
||||
XMMATRIX M = { T, N, B, P };
|
||||
XMFLOAT4X4 orientation;
|
||||
XMStoreFloat4x4(&orientation, M);
|
||||
|
||||
+24
-14
@@ -11,16 +11,16 @@ namespace wi::random
|
||||
{
|
||||
uint64_t state = 0;
|
||||
|
||||
inline RNG(uint64_t seed = 0) : state(seed) {}
|
||||
constexpr RNG(uint64_t seed = 0) : state(seed) {}
|
||||
|
||||
// seeds the random number generator, seed should be non-zero number
|
||||
inline void seed(uint64_t seed)
|
||||
constexpr void seed(uint64_t seed)
|
||||
{
|
||||
state = seed;
|
||||
}
|
||||
|
||||
// gives an uint in range [0, UINT64_MAX]
|
||||
inline uint64_t next_uint()
|
||||
constexpr uint64_t next_uint()
|
||||
{
|
||||
state ^= state >> 12;
|
||||
state ^= state << 25;
|
||||
@@ -28,14 +28,14 @@ namespace wi::random
|
||||
return state * 0x2545F4914F6CDD1DULL;
|
||||
}
|
||||
// gives an uint64 in range [min, max]
|
||||
inline uint64_t next_uint(uint64_t min, uint64_t max)
|
||||
constexpr uint64_t next_uint(uint64_t min, uint64_t max)
|
||||
{
|
||||
if (min == max)
|
||||
return min;
|
||||
return min + (next_uint() % (std::min(std::numeric_limits<uint64_t>::max() - uint64_t(1), std::max(uint64_t(1), max - min)) + uint64_t(1)));
|
||||
}
|
||||
// gives an uint32 in range [min, max]
|
||||
inline uint32_t next_uint(uint32_t min, uint32_t max)
|
||||
constexpr uint32_t next_uint(uint32_t min, uint32_t max)
|
||||
{
|
||||
if (min == max)
|
||||
return min;
|
||||
@@ -43,20 +43,25 @@ namespace wi::random
|
||||
}
|
||||
|
||||
// gives an int64 in range [-INT64_MAX, INT64_MAX]
|
||||
inline int64_t next_int()
|
||||
constexpr int64_t next_int()
|
||||
{
|
||||
uint64_t u = next_uint();
|
||||
return *(int64_t*)&u;
|
||||
union
|
||||
{
|
||||
uint64_t u;
|
||||
int64_t i;
|
||||
} value = {};
|
||||
value.u = next_uint();
|
||||
return value.i;
|
||||
}
|
||||
// gives an int64 in range [min, max]
|
||||
inline int64_t next_int(int64_t min, int64_t max)
|
||||
constexpr int64_t next_int(int64_t min, int64_t max)
|
||||
{
|
||||
if (min == max)
|
||||
return min;
|
||||
return min + int64_t(next_uint() % (std::min(std::numeric_limits<int64_t>::max() - int64_t(1), std::max(int64_t(1), max - min)) + int64_t(1))); // we roll next_uint here to avoid negative value messing with range mapping
|
||||
}
|
||||
// gives an int32 in range [min, max]
|
||||
inline int32_t next_int(int32_t min, int32_t max)
|
||||
constexpr int32_t next_int(int32_t min, int32_t max)
|
||||
{
|
||||
if (min == max)
|
||||
return min;
|
||||
@@ -64,13 +69,18 @@ namespace wi::random
|
||||
}
|
||||
|
||||
// gives a float in range [0, 1]
|
||||
inline float next_float()
|
||||
constexpr float next_float()
|
||||
{
|
||||
uint32_t u = 0x3f800000 | (uint32_t(next_uint()) >> 9);
|
||||
return *((float*)&u) - 1.0f;
|
||||
union
|
||||
{
|
||||
uint32_t u;
|
||||
float f;
|
||||
} value = {};
|
||||
value.u = 0x3f800000 | (uint32_t(next_uint()) >> 9);
|
||||
return value.f - 1.0f;
|
||||
}
|
||||
// gives a float in range [min, max]
|
||||
inline float next_float(float min, float max)
|
||||
constexpr float next_float(float min, float max)
|
||||
{
|
||||
return min + (max - min) * next_float();
|
||||
}
|
||||
|
||||
@@ -1164,6 +1164,16 @@ namespace wi
|
||||
);
|
||||
}
|
||||
|
||||
if (scene->weather.IsRealisticSky())
|
||||
{
|
||||
wi::renderer::ComputeSkyAtmosphereSkyViewLut(cmd);
|
||||
|
||||
if (scene->weather.IsRealisticSkyAerialPerspective())
|
||||
{
|
||||
wi::renderer::ComputeSkyAtmosphereCameraVolumeLut(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
if (scene->weather.IsVolumetricClouds() && !scene->weather.IsVolumetricCloudsReceiveShadow())
|
||||
{
|
||||
// When volumetric cloud DOESN'T receive shadow it can be done async to shadow maps!
|
||||
@@ -1470,52 +1480,6 @@ namespace wi
|
||||
});
|
||||
}
|
||||
|
||||
// Main camera weather compute effects depending on shadow maps, envmaps, etc, but don't depend on async surface pass:
|
||||
if (scene->weather.IsRealisticSky() || scene->weather.IsVolumetricClouds())
|
||||
{
|
||||
cmd = device->BeginCommandList();
|
||||
wi::jobsystem::Execute(ctx, [this, cmd](wi::jobsystem::JobArgs args) {
|
||||
|
||||
wi::renderer::BindCameraCB(
|
||||
*camera,
|
||||
camera_previous,
|
||||
camera_reflection,
|
||||
cmd
|
||||
);
|
||||
|
||||
if (scene->weather.IsRealisticSky())
|
||||
{
|
||||
wi::renderer::ComputeSkyAtmosphereSkyViewLut(cmd);
|
||||
|
||||
if (scene->weather.IsRealisticSkyAerialPerspective())
|
||||
{
|
||||
wi::renderer::ComputeSkyAtmosphereCameraVolumeLut(cmd);
|
||||
}
|
||||
}
|
||||
if (scene->weather.IsRealisticSky() && scene->weather.IsRealisticSkyAerialPerspective())
|
||||
{
|
||||
wi::renderer::Postprocess_AerialPerspective(
|
||||
aerialperspectiveResources,
|
||||
cmd
|
||||
);
|
||||
}
|
||||
if (scene->weather.IsVolumetricClouds() && scene->weather.IsVolumetricCloudsReceiveShadow())
|
||||
{
|
||||
// When volumetric cloud receives shadow it must be done AFTER shadow maps!
|
||||
wi::renderer::Postprocess_VolumetricClouds(
|
||||
volumetriccloudResources,
|
||||
cmd,
|
||||
*camera,
|
||||
camera_previous,
|
||||
camera_reflection,
|
||||
wi::renderer::GetTemporalAAEnabled() || getFSR2Enabled(),
|
||||
scene->weather.volumetricCloudsWeatherMapFirst.IsValid() ? &scene->weather.volumetricCloudsWeatherMapFirst.GetTexture() : nullptr,
|
||||
scene->weather.volumetricCloudsWeatherMapSecond.IsValid() ? &scene->weather.volumetricCloudsWeatherMapSecond.GetTexture() : nullptr
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Main camera opaque color pass:
|
||||
cmd = device->BeginCommandList();
|
||||
device->WaitCommandList(cmd, cmd_maincamera_compute_effects);
|
||||
@@ -1531,6 +1495,28 @@ namespace wi
|
||||
cmd
|
||||
);
|
||||
|
||||
if (scene->weather.IsRealisticSky() && scene->weather.IsRealisticSkyAerialPerspective())
|
||||
{
|
||||
wi::renderer::Postprocess_AerialPerspective(
|
||||
aerialperspectiveResources,
|
||||
cmd
|
||||
);
|
||||
}
|
||||
if (scene->weather.IsVolumetricClouds() && scene->weather.IsVolumetricCloudsReceiveShadow())
|
||||
{
|
||||
// When volumetric cloud receives shadow it must be done AFTER shadow maps!
|
||||
wi::renderer::Postprocess_VolumetricClouds(
|
||||
volumetriccloudResources,
|
||||
cmd,
|
||||
*camera,
|
||||
camera_previous,
|
||||
camera_reflection,
|
||||
wi::renderer::GetTemporalAAEnabled() || getFSR2Enabled(),
|
||||
scene->weather.volumetricCloudsWeatherMapFirst.IsValid() ? &scene->weather.volumetricCloudsWeatherMapFirst.GetTexture() : nullptr,
|
||||
scene->weather.volumetricCloudsWeatherMapSecond.IsValid() ? &scene->weather.volumetricCloudsWeatherMapSecond.GetTexture() : nullptr
|
||||
);
|
||||
}
|
||||
|
||||
if (getRaytracedReflectionEnabled())
|
||||
{
|
||||
wi::renderer::Postprocess_RTReflection(
|
||||
|
||||
@@ -5795,6 +5795,7 @@ namespace wi::scene
|
||||
spline.spline_node_transforms.resize(spline.spline_node_entities.size());
|
||||
|
||||
// BEFORE mesh update: LOCAL space transform (because mesh will be also transformed by ObjectComponent instance)
|
||||
spline.precomputed_total_distance = 0;
|
||||
for (size_t i = 0; i < spline.spline_node_entities.size(); ++i)
|
||||
{
|
||||
Entity node_entity = spline.spline_node_entities[i];
|
||||
@@ -5808,6 +5809,7 @@ namespace wi::scene
|
||||
// Force update in local space:
|
||||
spline.spline_node_transforms[i].SetDirty();
|
||||
spline.spline_node_transforms[i].UpdateTransform();
|
||||
spline.spline_node_transforms[i].ApplyTransform();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5822,6 +5824,7 @@ namespace wi::scene
|
||||
MeshComponent* mesh = meshes.GetComponent(entity);
|
||||
if (mesh != nullptr)
|
||||
{
|
||||
spline.PrecomputeSplineNodeDistances(); // local space
|
||||
spline.prev_mesh_generation_subdivision = spline.mesh_generation_subdivision;
|
||||
spline.prev_mesh_generation_vertical_subdivision = spline.mesh_generation_vertical_subdivision;
|
||||
spline.prev_mesh_generation_nodes = (int)spline.spline_node_entities.size();
|
||||
@@ -6007,6 +6010,7 @@ namespace wi::scene
|
||||
}
|
||||
|
||||
// AFTER mesh generation, parented update:
|
||||
spline.precomputed_total_distance = 0;
|
||||
for (size_t i = 0; i < spline.spline_node_entities.size(); ++i)
|
||||
{
|
||||
Entity node_entity = spline.spline_node_entities[i];
|
||||
@@ -6014,9 +6018,12 @@ namespace wi::scene
|
||||
if (node_transform != nullptr)
|
||||
{
|
||||
XMStoreFloat4x4(&spline.spline_node_transforms[i].world, ComputeEntityMatrixRecursive(node_entity));
|
||||
spline.spline_node_transforms[i].ApplyTransform();
|
||||
}
|
||||
}
|
||||
|
||||
spline.PrecomputeSplineNodeDistances(); // world space
|
||||
|
||||
// Compute AABB:
|
||||
if (dirty || (spline.dirty_terrain && spline.terrain_modifier_amount > 0))
|
||||
{
|
||||
|
||||
@@ -102,6 +102,14 @@ namespace wi::scene
|
||||
XMFLOAT3 v = wi::math::GetRight(world);
|
||||
return XMLoadFloat3(&v);
|
||||
}
|
||||
void TransformComponent::GetPositionRotationScale(XMFLOAT3& position, XMFLOAT4& rotation, XMFLOAT3& scale) const
|
||||
{
|
||||
XMVECTOR S, R, T;
|
||||
XMMatrixDecompose(&S, &R, &T, XMLoadFloat4x4(&world));
|
||||
XMStoreFloat3(&position, T);
|
||||
XMStoreFloat4(&rotation, R);
|
||||
XMStoreFloat3(&scale, S);
|
||||
}
|
||||
void TransformComponent::UpdateTransform()
|
||||
{
|
||||
if (IsDirty())
|
||||
@@ -2861,6 +2869,13 @@ namespace wi::scene
|
||||
|
||||
XMMATRIX SplineComponent::EvaluateSplineAt(float t) const
|
||||
{
|
||||
// Notes:
|
||||
// - This function uses the spline_node_transforms which are precomputed before using this by the scene's RunSplineUpdateSystem()
|
||||
// - it uses _local members of the transforms, but they can be either wlocal or world space, depending on when we use it and what was stored in them at that point
|
||||
// for example mesh updates will use local spaces, but terrain updates will use world spaces
|
||||
// - precomputed_node_distances must be updated before this, it is done by RunSplineUpdateSystem()
|
||||
// this is made to avoid computing distances every time we call this which might be a lot
|
||||
|
||||
if (spline_node_transforms.empty())
|
||||
return {};
|
||||
if (spline_node_transforms.size() == 1)
|
||||
@@ -2868,14 +2883,14 @@ namespace wi::scene
|
||||
|
||||
if (spline_node_transforms.size() == 2)
|
||||
{
|
||||
XMVECTOR P0 = spline_node_transforms[0].GetPositionV();
|
||||
XMVECTOR P1 = spline_node_transforms[1].GetPositionV();
|
||||
XMVECTOR P0 = XMLoadFloat3(&spline_node_transforms[0].translation_local);
|
||||
XMVECTOR P1 = XMLoadFloat3(&spline_node_transforms[1].translation_local);
|
||||
|
||||
XMVECTOR W0 = XMVectorReplicate(spline_node_transforms[0].GetScale().x);
|
||||
XMVECTOR W1 = XMVectorReplicate(spline_node_transforms[1].GetScale().x);
|
||||
XMVECTOR W0 = XMVectorReplicate(spline_node_transforms[0].scale_local.x);
|
||||
XMVECTOR W1 = XMVectorReplicate(spline_node_transforms[1].scale_local.x);
|
||||
|
||||
XMVECTOR Q0 = XMQuaternionNormalize(spline_node_transforms[0].GetRotationV());
|
||||
XMVECTOR Q1 = XMQuaternionNormalize(spline_node_transforms[1].GetRotationV());
|
||||
XMVECTOR Q0 = XMQuaternionNormalize(XMLoadFloat4(&spline_node_transforms[0].rotation_local));
|
||||
XMVECTOR Q1 = XMQuaternionNormalize(XMLoadFloat4(&spline_node_transforms[1].rotation_local));
|
||||
|
||||
XMVECTOR P = XMVectorLerp(P0, P1, t);
|
||||
XMVECTOR Q = XMQuaternionNormalize(XMQuaternionSlerp(Q0, Q1, t));
|
||||
@@ -2905,26 +2920,19 @@ namespace wi::scene
|
||||
beforelast++;
|
||||
}
|
||||
|
||||
float total_distance = 0;
|
||||
for (int i = 0; i < beforelast; ++i)
|
||||
{
|
||||
const TransformComponent& transform0 = spline_node_transforms[(i + first) % cnt];
|
||||
const TransformComponent& transform1 = spline_node_transforms[(i + second) % cnt];
|
||||
total_distance += wi::math::Distance(transform0.GetPosition(), transform1.GetPosition());
|
||||
}
|
||||
float tdist = t * total_distance;
|
||||
float tdist = t * precomputed_total_distance;
|
||||
int t0 = 0; // prev
|
||||
int t1 = 0; // current
|
||||
int t2 = 1; // next
|
||||
int t3 = 1; // after next
|
||||
float tmid = 0;
|
||||
total_distance = 0;
|
||||
|
||||
// This is similar to a keyframe search:
|
||||
float total_distance = 0;
|
||||
for (int i = 0; i < beforelast; ++i)
|
||||
{
|
||||
const TransformComponent& transform0 = spline_node_transforms[(i + first) % cnt];
|
||||
const TransformComponent& transform1 = spline_node_transforms[(i + second) % cnt];
|
||||
float dist_prev = total_distance;
|
||||
total_distance += wi::math::Distance(transform0.GetPosition(), transform1.GetPosition());
|
||||
total_distance += precomputed_node_distances[i];
|
||||
if (total_distance >= tdist)
|
||||
{
|
||||
if (IsLooped())
|
||||
@@ -2946,10 +2954,10 @@ namespace wi::scene
|
||||
}
|
||||
}
|
||||
|
||||
XMVECTOR P0 = spline_node_transforms[t0].GetPositionV();
|
||||
XMVECTOR P1 = spline_node_transforms[t1].GetPositionV();
|
||||
XMVECTOR P2 = spline_node_transforms[t2].GetPositionV();
|
||||
XMVECTOR P3 = spline_node_transforms[t3].GetPositionV();
|
||||
XMVECTOR P0 = XMLoadFloat3(&spline_node_transforms[t0].translation_local);
|
||||
XMVECTOR P1 = XMLoadFloat3(&spline_node_transforms[t1].translation_local);
|
||||
XMVECTOR P2 = XMLoadFloat3(&spline_node_transforms[t2].translation_local);
|
||||
XMVECTOR P3 = XMLoadFloat3(&spline_node_transforms[t3].translation_local);
|
||||
|
||||
if (t1 == t0)
|
||||
{
|
||||
@@ -2962,15 +2970,15 @@ namespace wi::scene
|
||||
P3 += P2 - P1;
|
||||
}
|
||||
|
||||
XMVECTOR W0 = XMVectorReplicate(spline_node_transforms[t0].GetScale().x);
|
||||
XMVECTOR W1 = XMVectorReplicate(spline_node_transforms[t1].GetScale().x);
|
||||
XMVECTOR W2 = XMVectorReplicate(spline_node_transforms[t2].GetScale().x);
|
||||
XMVECTOR W3 = XMVectorReplicate(spline_node_transforms[t3].GetScale().x);
|
||||
XMVECTOR W0 = XMVectorReplicate(spline_node_transforms[t0].scale_local.x);
|
||||
XMVECTOR W1 = XMVectorReplicate(spline_node_transforms[t1].scale_local.x);
|
||||
XMVECTOR W2 = XMVectorReplicate(spline_node_transforms[t2].scale_local.x);
|
||||
XMVECTOR W3 = XMVectorReplicate(spline_node_transforms[t3].scale_local.x);
|
||||
|
||||
XMVECTOR Q0 = XMQuaternionNormalize(spline_node_transforms[t0].GetRotationV());
|
||||
XMVECTOR Q1 = XMQuaternionNormalize(spline_node_transforms[t1].GetRotationV());
|
||||
XMVECTOR Q2 = XMQuaternionNormalize(spline_node_transforms[t2].GetRotationV());
|
||||
XMVECTOR Q3 = XMQuaternionNormalize(spline_node_transforms[t3].GetRotationV());
|
||||
XMVECTOR Q0 = XMQuaternionNormalize(XMLoadFloat4(&spline_node_transforms[t0].rotation_local));
|
||||
XMVECTOR Q1 = XMQuaternionNormalize(XMLoadFloat4(&spline_node_transforms[t1].rotation_local));
|
||||
XMVECTOR Q2 = XMQuaternionNormalize(XMLoadFloat4(&spline_node_transforms[t2].rotation_local));
|
||||
XMVECTOR Q3 = XMQuaternionNormalize(XMLoadFloat4(&spline_node_transforms[t3].rotation_local));
|
||||
|
||||
XMVECTOR P = wi::math::CatmullRomCentripetal(P0, P1, P2, P3, tmid);
|
||||
XMVECTOR P_prev = wi::math::CatmullRomCentripetal(P0, P1, P2, P3, saturate(tmid - 0.01f));
|
||||
@@ -2997,7 +3005,7 @@ namespace wi::scene
|
||||
if (spline_node_transforms.empty())
|
||||
return XMVectorZero();
|
||||
if (spline_node_transforms.size() == 1)
|
||||
return spline_node_transforms[0].GetPositionV();
|
||||
return XMLoadFloat3(&spline_node_transforms[0].translation_local);
|
||||
|
||||
steps *= (int)spline_node_transforms.size();
|
||||
float mindist = FLT_MAX;
|
||||
@@ -3081,4 +3089,30 @@ namespace wi::scene
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
void SplineComponent::PrecomputeSplineNodeDistances()
|
||||
{
|
||||
if (spline_node_transforms.empty())
|
||||
return;
|
||||
precomputed_node_distances.resize(spline_node_transforms.size());
|
||||
int cnt = (int)spline_node_transforms.size();
|
||||
int first = 0;
|
||||
int second = 1;
|
||||
int beforelast = cnt - 1;
|
||||
if (IsLooped())
|
||||
{
|
||||
first = cnt - 1;
|
||||
second = first + 1;
|
||||
beforelast++;
|
||||
}
|
||||
|
||||
precomputed_total_distance = 0;
|
||||
for (int i = 0; i < beforelast; ++i)
|
||||
{
|
||||
const XMFLOAT3& pos0 = spline_node_transforms[(i + first) % cnt].translation_local;
|
||||
const XMFLOAT3& pos1 = spline_node_transforms[(i + second) % cnt].translation_local;
|
||||
const float distance = wi::math::Distance(pos0, pos1);
|
||||
precomputed_total_distance += distance;
|
||||
precomputed_node_distances[i] = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ namespace wi::scene
|
||||
XMVECTOR GetForwardV() const;
|
||||
XMVECTOR GetUpV() const;
|
||||
XMVECTOR GetRightV() const;
|
||||
void GetPositionRotationScale(XMFLOAT3& position, XMFLOAT4& rotation, XMFLOAT3& scale) const;
|
||||
// Computes the local space matrix from scale, rotation, translation and returns it
|
||||
XMMATRIX GetLocalMatrix() const;
|
||||
// Returns the stored world matrix that was computed the last time UpdateTransform() was called
|
||||
@@ -2558,6 +2559,8 @@ namespace wi::scene
|
||||
|
||||
// Non-serialized attributes:
|
||||
wi::vector<TransformComponent> spline_node_transforms;
|
||||
wi::vector<float> precomputed_node_distances;
|
||||
float precomputed_total_distance = 0;
|
||||
float prev_width = 1;
|
||||
float prev_rotation = 0;
|
||||
int prev_mesh_generation_subdivision = 0;
|
||||
@@ -2579,8 +2582,12 @@ namespace wi::scene
|
||||
// Trace a point on the spline's plane:
|
||||
XMVECTOR TraceSplinePlane(const XMVECTOR& ORIGIN, const XMVECTOR& DIRECTION, int steps = 10) const;
|
||||
|
||||
// Compute the boounding box of the spline iteratively
|
||||
wi::primitive::AABB ComputeAABB(int steps = 10) const;
|
||||
|
||||
// Precompute the spline node distances that will be used at spline evaluation calls
|
||||
void PrecomputeSplineNodeDistances();
|
||||
|
||||
// By default the spline is drawn as camera facing, this can be used to set it to be drawn aligned to segment rotations:
|
||||
bool IsDrawAligned() const { return _flags & DRAW_ALIGNED; }
|
||||
void SetDrawAligned(bool value = true) { if (value) { _flags |= DRAW_ALIGNED; } else { _flags &= ~DRAW_ALIGNED; } }
|
||||
|
||||
+27
-27
@@ -963,8 +963,9 @@ namespace wi::terrain
|
||||
constexpr int chunk_width_padded = chunk_width + 1;
|
||||
constexpr uint32_t vertexCount_padded = chunk_width_padded * chunk_width_padded;
|
||||
float heights_padded[chunk_width_padded][chunk_width_padded];
|
||||
const XMVECTOR UP = XMVectorSet(0, 1, 0, 0);
|
||||
wi::jobsystem::Dispatch(ctx, vertexCount_padded, chunk_width_padded * 4, [&](wi::jobsystem::JobArgs args) {
|
||||
uint32_t index = args.jobIndex;
|
||||
const uint32_t index = args.jobIndex;
|
||||
const XMUINT2 coord = XMUINT2(index % chunk_width_padded, index / chunk_width_padded);
|
||||
const float x = (float(coord.x) - chunk_half_width) * chunk_scale;
|
||||
const float z = (float(coord.y) - chunk_half_width) * chunk_scale;
|
||||
@@ -976,22 +977,19 @@ namespace wi::terrain
|
||||
modifier->Apply(world_pos, height);
|
||||
}
|
||||
height = lerp(bottomLevel, topLevel, height);
|
||||
XMVECTOR corner = XMVectorSet(world_pos.x, height, world_pos.y, 0);
|
||||
|
||||
// Apply splines:
|
||||
// Apply splines to height only:
|
||||
const XMVECTOR P = XMVectorSet(world_pos.x, -100000, world_pos.y, 0);
|
||||
for (size_t j = 0; j < generator->splines.size(); ++j)
|
||||
{
|
||||
const SplineComponent& spline = generator->splines[j];
|
||||
if (spline.terrain_modifier_amount <= 0 || !spline.aabb.intersects(corner))
|
||||
if (!spline.aabb.intersects(P))
|
||||
continue;
|
||||
XMVECTOR P = XMVectorSetY(corner, -1000);
|
||||
XMVECTOR S = spline.TraceSplinePlane(P, XMVectorSet(0, 1, 0, 0), 4);
|
||||
XMVECTOR S = spline.TraceSplinePlane(P, UP, 4);
|
||||
S = spline.ClosestPointOnSpline(S, 4);
|
||||
float splineheight = XMVectorGetY(S);
|
||||
P = XMVectorSetY(P, splineheight);
|
||||
float splinedist = wi::math::Distance(P, S);
|
||||
const float splineheight = XMVectorGetY(S);
|
||||
const float splinedist = wi::math::Distance(XMVectorSetY(P, splineheight), S);
|
||||
height = lerp(splineheight, height, smoothstep(0.0f, 1.0f, saturate(splinedist * sqr(spline.terrain_modifier_amount))));
|
||||
corner = XMVectorSetY(corner, height);
|
||||
}
|
||||
|
||||
heights_padded[coord.x][coord.y] = height;
|
||||
@@ -1084,8 +1082,6 @@ namespace wi::terrain
|
||||
chunk_data.grass.CreateFromMesh(mesh);
|
||||
}
|
||||
|
||||
wi::jobsystem::Wait(ctx); // wait until mesh.CreateRenderData() async task finishes
|
||||
|
||||
// Create the textures for virtual texture update:
|
||||
CreateChunkRegionTexture(chunk_data);
|
||||
|
||||
@@ -1101,6 +1097,8 @@ namespace wi::terrain
|
||||
wi::physics::CreateRigidBodyShape(newrigidbody, transform.scale_local, &mesh);
|
||||
}
|
||||
|
||||
wi::jobsystem::Wait(ctx); // wait until mesh.CreateRenderData() async task finishes
|
||||
|
||||
generated_something = true;
|
||||
}
|
||||
|
||||
@@ -1147,22 +1145,22 @@ namespace wi::terrain
|
||||
generator->scene.Component_Attach(chunk_data.props_entity, chunk_data.entity, true);
|
||||
chunk_data.prop_density_current = prop_density;
|
||||
|
||||
wi::random::RNG rng((uint32_t)chunk.compute_hash() ^ seed);
|
||||
wi::random::RNG rng(chunk.compute_hash());
|
||||
|
||||
for (const auto& prop : props)
|
||||
{
|
||||
if (prop.data.empty())
|
||||
continue;
|
||||
int gen_count = (int)rng.next_uint(
|
||||
const int gen_count = (int)rng.next_uint(
|
||||
uint32_t(prop.min_count_per_chunk * chunk_data.prop_density_current),
|
||||
std::max(1u, uint32_t(prop.max_count_per_chunk * chunk_data.prop_density_current))
|
||||
);
|
||||
for (int i = 0; i < gen_count; ++i)
|
||||
{
|
||||
uint32_t tri = rng.next_uint(0, chunk_indices().lods[0].indexCount / 3); // random triangle on the chunk mesh
|
||||
uint32_t ind0 = chunk_indices().indices[tri * 3 + 0];
|
||||
uint32_t ind1 = chunk_indices().indices[tri * 3 + 1];
|
||||
uint32_t ind2 = chunk_indices().indices[tri * 3 + 2];
|
||||
const uint32_t tri = rng.next_uint(0, chunk_indices().lods[0].indexCount / 3); // random triangle on the chunk mesh
|
||||
const uint32_t ind0 = chunk_indices().indices[tri * 3 + 0];
|
||||
const uint32_t ind1 = chunk_indices().indices[tri * 3 + 1];
|
||||
const uint32_t ind2 = chunk_indices().indices[tri * 3 + 2];
|
||||
const XMFLOAT3& pos0 = chunk_data.mesh_vertex_positions[ind0];
|
||||
const XMFLOAT3& pos1 = chunk_data.mesh_vertex_positions[ind1];
|
||||
const XMFLOAT3& pos2 = chunk_data.mesh_vertex_positions[ind2];
|
||||
@@ -1180,15 +1178,17 @@ namespace wi::terrain
|
||||
f = 1 - f;
|
||||
g = 1 - g;
|
||||
}
|
||||
XMFLOAT3 vertex_pos;
|
||||
vertex_pos.x = pos0.x + f * (pos1.x - pos0.x) + g * (pos2.x - pos0.x);
|
||||
vertex_pos.y = pos0.y + f * (pos1.y - pos0.y) + g * (pos2.y - pos0.y);
|
||||
vertex_pos.z = pos0.z + f * (pos1.z - pos0.z) + g * (pos2.z - pos0.z);
|
||||
XMFLOAT4 region;
|
||||
region.x = region0.x + f * (region1.x - region0.x) + g * (region2.x - region0.x);
|
||||
region.y = region0.y + f * (region1.y - region0.y) + g * (region2.y - region0.y);
|
||||
region.z = region0.z + f * (region1.z - region0.z) + g * (region2.z - region0.z);
|
||||
region.w = region0.w + f * (region1.w - region0.w) + g * (region2.w - region0.w);
|
||||
const XMFLOAT3 vertex_pos = XMFLOAT3(
|
||||
pos0.x + f * (pos1.x - pos0.x) + g * (pos2.x - pos0.x),
|
||||
pos0.y + f * (pos1.y - pos0.y) + g * (pos2.y - pos0.y),
|
||||
pos0.z + f * (pos1.z - pos0.z) + g * (pos2.z - pos0.z)
|
||||
);
|
||||
const XMFLOAT4 region = XMFLOAT4(
|
||||
region0.x + f * (region1.x - region0.x) + g * (region2.x - region0.x),
|
||||
region0.y + f * (region1.y - region0.y) + g * (region2.y - region0.y),
|
||||
region0.z + f * (region1.z - region0.z) + g * (region2.z - region0.z),
|
||||
region0.w + f * (region1.w - region0.w) + g * (region2.w - region0.w)
|
||||
);
|
||||
|
||||
const float noise = std::pow(perlin_noise.compute((vertex_pos.x + chunk_data.position.x) * prop.noise_frequency, vertex_pos.y * prop.noise_frequency, (vertex_pos.z + chunk_data.position.z) * prop.noise_frequency) * 0.5f + 0.5f, prop.noise_power);
|
||||
const float chance = std::pow(((float*)®ion)[prop.region], prop.region_power) * noise;
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace wi::version
|
||||
// minor features, major updates, breaking compatibility changes
|
||||
const int minor = 71;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 741;
|
||||
const int revision = 742;
|
||||
|
||||
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user