1 [
EntityEditorProps(
category:
"GameLib/Scripted/Generator", description:
"PrefabGeneratorEntity", dynamicBox:
true, visible:
false)]
13 protected ref array<ResourceName> m_PrefabNames;
21 [
Attribute(
category:
"Prefabs", defvalue:
"5",
desc:
"Distance between spawned assets along the spline/polyline")]
24 [
Attribute(
category:
"Prefabs", defvalue:
"1",
desc:
"If checked prefabs are aligned with the shape")]
40 [
Attribute(
category:
"Offset",
desc:
"How much offset variability we want in meters when using offset from the center")]
62 [
Attribute(
category:
"Perlin",
desc:
"Spawns prefabs if perlin value is above this threshold",
"-1 1")]
65 [
Attribute(
desc:
"Prefab spawn type uses Perlin distribution. Prefabs in the prefab array are stacked up from lower to higher indicies on the Y axis")]
71 [
Attribute(
category:
"Perlin", defvalue:
"40",
desc:
"Perlin frequency, higher values mean smoother transitions")]
91 protected ref array<ref SCR_PrefabGeneratorAssetPoint> m_aPoints = {};
93 protected static ref array<ref Shape> s_aDebugShapes = {};
96 protected override bool _WB_OnKeyChanged(BaseContainer src,
string key, BaseContainerList ownerContainers, IEntity parent)
98 super._WB_OnKeyChanged(src, key, ownerContainers, parent);
103 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
104 if (!worldEditorAPI || worldEditorAPI.UndoOrRedoIsRestoring())
107 IEntitySource entSrc = src.ToEntitySource();
109 IEntitySource thisSrc = worldEditorAPI.EntityToSource(
this);
110 IEntitySource parentSrc = thisSrc.GetParent();
111 BaseContainerTools.WriteToInstance(
this, thisSrc);
113 OnShapeChanged(parentSrc, ShapeEntity.Cast(parent), {}, {});
118 protected vector
GetPos(BaseContainerList points,
int i)
120 BaseContainer point = points.Get(i);
122 point.Get(
"Position", pos);
127 protected override void OnShapeInitInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity)
129 super.OnShapeInitInternal(shapeEntitySrc, shapeEntity);
132 shapeEntity = ShapeEntity.Cast(_WB_GetEditorAPI().SourceToEntity(shapeEntitySrc));
134 OnShapeChanged(shapeEntitySrc, shapeEntity, {}, {});
139 protected void OffsetPointsMeta(notnull array<ref SCR_PrefabGeneratorPointMeta> metas,
float offset)
141 array<ref SCR_PrefabGeneratorPointMeta> metasTemp = {};
147 tmpMeta.m_vPos = meta.m_vPos;
148 tmpMeta.m_bGenerate = meta.m_bGenerate;
149 metasTemp.Insert(tmpMeta);
154 GetWorldTransform(matWorld);
156 vector forwardPrev =
"1 1 1";
157 for (
int i, count = metas.Count(); i < count; i++)
162 forwardNext = metas.Get(i + 1).m_vPos - metas.Get(i).m_vPos;
164 forwardNext = -forwardPrev;
167 forwardPrev = -forwardNext;
169 forwardNext.Normalize();
170 forwardPrev.Normalize();
172 float dotProductPrevNext = vector.Dot(forwardPrev, forwardNext);
173 bool almostLine = dotProductPrevNext < -0.95;
174 vector diagonal = forwardNext + forwardPrev;
176 vector normalRight = -forwardPrev *
"0 1 0";
177 normalRight.Normalize();
178 float dotProductNormNext = vector.Dot(normalRight, forwardNext);
179 bool isLeft = dotProductNormNext > 0;
181 vector nextModified = dotProductPrevNext * forwardNext;
182 float dist = vector.Distance(nextModified, forwardPrev);
185 diff = offset / dist;
190 diagonal = diagonal * -1;
194 vector vec = forwardNext - forwardPrev;
195 vector right = vec *
"0 1 0";
197 diagonal = right * offset;
200 metas.Get(i).m_vPos = metasTemp.Get(i).m_vPos + diagonal;
201 forwardPrev = -forwardNext;
206 diagonal = metas[i].m_vPos.Multiply4(matWorld);
207 s_aDebugShapes.Insert(Shape.Create(ShapeType.LINE, ARGB(255, 255, 255, 255), ShapeFlags.NOZBUFFER, diagonal, diagonal + forwardNext));
208 s_aDebugShapes.Insert(Shape.Create(ShapeType.LINE, ARGB(255, 0, 255, 0), ShapeFlags.NOZBUFFER, diagonal, diagonal + forwardPrev));
209 s_aDebugShapes.Insert(Shape.Create(ShapeType.LINE, ARGB(255, 255, 0, 0), ShapeFlags.NOZBUFFER, metasTemp[i].m_vPos.Multiply4(matWorld), diagonal));
216 protected float SamplePerlin(
float time,
float frequency = 20,
float seed = 1,
float amplitude = 1,
float phaseOffset = 0)
218 if (frequency == 0 || amplitude == 0)
221 return Math.PerlinNoise(time / frequency, seed * 100, seed * 1000) * amplitude;
226 protected void GenerateAssetPoints(array<ref SCR_PrefabGeneratorPointMeta> metas)
233 float distanceWalked = 0;
239 vector lastPos =
"0 0 0";
240 bool firstPoint =
true;
243 for (
int i = 0, countMinusOne = metas.Count() - 1; i < countMinusOne; i++)
245 vector posThis = metas[i].m_vPos;
248 vector forward = metas[i + 1].m_vPos - posThis;
249 float dist = forward.Length();
253 draw = metas.Get(i).m_bGenerate;
256 while (space >= stepDistance)
258 float leftOver = space - dist;
270 moveDist = dist - (space - stepDistance);
280 if (leftOver> stepDistance)
284 moveDist = stepDistance - leftOver;
287 space -= moveDist + leftOver;
288 distanceWalked += stepDistance;
292 newPos = lastPos + forward.Normalized() * moveDist;
295 genPoint.m_vPos = newPos;
296 genPoint.m_vForward = forward;
297 genPoint.m_fPerlinWeight = valuePerlin;
302 invValue = Math.Clamp(invValue, 0, 1);
303 stepDistance = Math.Lerp(
m_fDistance, 1, invValue);
306 bool throwAway =
false;
316 genPoint.m_bDraw = draw && !throwAway;
317 m_aPoints.Insert(genPoint);
323 protected void GenerateMetaListLine(notnull BaseContainerList points, notnull out array<ref SCR_PrefabGeneratorPointMeta> pointsMeta)
325 BaseContainerList dataArr;
328 typename pointDataTypename;
329 for (
int i = 0, count = points.Count(); i < count; i++)
331 data = points.Get(i);
332 dataArr =
data.GetObjectArray(
"Data");
333 bool generate =
true;
335 data.Get(
"Position", pos);
339 for (
int j = 0, dataCount = dataArr.Count(); j < dataCount; j++)
341 data = dataArr.Get(j);
342 pointDataTypename =
data.GetClassName().ToType();
345 if (
data.Get(
"m_bGenerate", generate))
352 meta.m_bGenerate = generate;
354 pointsMeta.Insert(meta);
359 protected void GenerateMetaListSpline(array<ref SCR_PrefabGeneratorPointMeta> pointsMetaLine, array<vector> tesselatedPoints, array<ref SCR_PrefabGeneratorPointMeta> pointsMetaSpline)
361 if (!tesselatedPoints)
364 bool generate =
true;
366 foreach (vector tesselatedPoint : tesselatedPoints)
370 if (tesselatedPoint == meta.m_vPos)
372 generate = meta.m_bGenerate;
378 tmpMeta.m_bGenerate = generate;
379 tmpMeta.m_vPos = tesselatedPoint;
380 pointsMetaSpline.Insert(tmpMeta);
385 protected override void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array<vector> mins, array<vector> maxes)
387 s_aDebugShapes.Clear();
393 BaseContainerList points = shapeEntitySrc.GetObjectArray(
"Points");
396 array<ref SCR_PrefabGeneratorPointMeta> pointsMetaLine = {};
397 GenerateMetaListLine(points, pointsMetaLine);
399 int pointCount = points.Count();
404 shapeEntitySrc.Get(
"IsClosed", isShapeClosed);
406 if (pointCount > 2 && isShapeClosed)
407 pointsMetaLine.Insert(pointsMetaLine[0]);
412 typename shapeTypename = shapeEntitySrc.GetClassName().ToType();
415 GenerateAssetPoints(pointsMetaLine);
417 DrawCurveDebug(pointsMetaLine);
421 array<vector> pointsCurve = {};
422 shapeEntity.GenerateTesselatedShape(pointsCurve);
424 array<ref SCR_PrefabGeneratorPointMeta> pointsMetaSpline = {};
426 GenerateMetaListSpline(pointsMetaLine, pointsCurve, pointsMetaSpline);
428 if (pointCount > 2 && isShapeClosed)
429 pointsMetaSpline.Insert(pointsMetaSpline[0]);
434 GenerateAssetPoints(pointsMetaSpline);
437 DrawCurveDebug(pointsMetaSpline);
442 DrawCurveDebug(pointsMetaLine);
446 genPoint.m_vPos = pointsMetaLine[0].m_vPos;
449 genPoint.m_bDraw = pointsMetaLine.Get(0).m_bGenerate;
451 if (isShapeClosed && pointCount > 2)
452 genPoint.m_vForward = pointsMetaLine[1].m_vPos - pointsMetaLine[pointCount - 1].m_vPos.Normalized();
453 else if (pointCount > 1)
454 genPoint.m_vForward = (pointsMetaLine[1].m_vPos - pointsMetaLine[0].m_vPos).Normalized();
456 m_aPoints.Insert(genPoint);
459 for (
int i = 1, count = pointsMetaLine.Count(); i < count; i++)
462 genPoint.m_vPos = pointsMetaLine[i % pointCount].m_vPos;
464 genPoint.m_bDraw = pointsMetaLine.Get(i).m_bGenerate;
466 if (i < count - 1 || isShapeClosed)
467 genPoint.m_vForward = (pointsMetaLine[(i + 1) % pointCount].m_vPos - pointsMetaLine[i - 1].m_vPos).Normalized();
468 else if (i == count - 1)
469 genPoint.m_vForward = (pointsMetaLine[i % pointCount].m_vPos - pointsMetaLine[i - 1].m_vPos).Normalized();
471 m_aPoints.Insert(genPoint);
485 protected void Generate()
487 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
488 if (!worldEditorAPI || worldEditorAPI.UndoOrRedoIsRestoring())
491 bool hasOneFilledPrefab;
492 foreach (ResourceName prefabName : m_PrefabNames)
494 if (!prefabName.IsEmpty())
496 hasOneFilledPrefab =
true;
501 if (!hasOneFilledPrefab)
504 IEntitySource entSrc = worldEditorAPI.EntityToSource(
this);
506 for (
int i = entSrc.GetNumChildren() - 1; i >= 0; --i)
508 worldEditorAPI.DeleteEntity(entSrc.GetChild(i));
511 bool isGeneratorVisible = worldEditorAPI.IsEntityVisible(entSrc);
513 GetWorldTransform(worldMat);
514 BaseContainerList editorData;
518 if (!localPoint.m_bDraw)
521 vector worldPos = localPoint.m_vPos.Multiply4(worldMat);
525 Math3D.DirectionAndUpMatrix(localPoint.m_vForward, vector.Up, mat);
526 vector right = mat[0];
527 vector angles = Math3D.MatrixToAngles(mat);
532 if (offsetRandom < 0)
533 offsetRandom -=
m_fGap * 0.5;
535 offsetRandom +=
m_fGap * 0.5;
537 worldPos = worldPos + offsetRandom * right;
543 angles[0] = angles[0] - 90;
546 angles[0] = angles[0] + 180;
548 rot = { angles[1], angles[0], angles[2] };
565 string asset = m_PrefabNames[
index];
567 IEntitySource src = worldEditorAPI.CreateEntityExt(asset,
"", 0,
null, worldPos, rot, TraceFlags.WORLD);
571 editorData = src.GetObjectArray(
"editorData");
573 if (editorData && editorData.Count() > 0)
579 editorData.Get(0).Get(
"randomScale", val);
581 string scale = (Math.Lerp(val[0], val[1], invValue)).ToString();
582 worldEditorAPI.SetVariableValue(src,
null,
"scale", scale);
589 src.Get(
"coords", entPos);
591 string coords = entPos[0].ToString() +
" " + entPos[1].ToString() +
" " + entPos[2].ToString();
592 worldEditorAPI.SetVariableValue(src,
null,
"coords", coords);
595 worldEditorAPI.SetEntityVisible(src, isGeneratorVisible,
false);
596 worldEditorAPI.ParentEntity(entSrc, src,
true);
602 protected void DrawCurveDebug(array<ref SCR_PrefabGeneratorPointMeta> metas)
604 const int DEBUG_CURVE_LINE_SIZE = 8192;
605 const float DEBUG_Y_MULTIPLIER = 5;
606 static vector m_PerlinDebugLine[DEBUG_CURVE_LINE_SIZE];
607 static vector m_ZeroDebugLine[DEBUG_CURVE_LINE_SIZE];
608 static vector m_EdgeDebugLine[DEBUG_CURVE_LINE_SIZE];
609 static vector m_ThresholdDebugLine[DEBUG_CURVE_LINE_SIZE];
611 float stepDistance = 0.1;
612 float distanceWalked = 0;
613 vector lastPos =
"0 0 0";
617 array<vector> line = {};
621 GetWorldTransform(matWrld);
624 for (
int countMinusOne = metas.Count() - 1; i < countMinusOne; i++)
626 vector posThis = metas[i].m_vPos;
628 vector forward = metas[i + 1].m_vPos - posThis;
629 float dist = forward.Length();
632 m_ZeroDebugLine[i] = posThis.Multiply4(matWrld);
634 if (i == countMinusOne - 1)
635 m_ZeroDebugLine[i + 1] = metas[i + 1].m_vPos.Multiply4(matWrld);
637 while (space >= stepDistance)
639 float leftOver = space - dist;
643 moveDist = stepDistance - leftOver;
645 space -= moveDist + leftOver;
646 distanceWalked += stepDistance;
648 vector perlinPointPos;
650 stepPos = lastPos + forward.Normalized() * moveDist;
654 vector up = {0, 1, 0};
655 Math3D.DirectionAndUpMatrix(forward, up, mat);
656 vector right = mat[0];
661 perlinPointPos = stepPos + right * valuePerlin * DEBUG_Y_MULTIPLIER;
663 if (itemsNum < DEBUG_CURVE_LINE_SIZE)
665 m_PerlinDebugLine[itemsNum] = perlinPointPos.Multiply4(matWrld);
666 m_EdgeDebugLine[itemsNum] = (stepPos + right * DEBUG_Y_MULTIPLIER).Multiply4(matWrld);
667 m_ThresholdDebugLine[itemsNum] = (stepPos + right * DEBUG_Y_MULTIPLIER *
m_fPerlinThreshold).Multiply4(matWrld);
673 s_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 255, 255, 0), ShapeFlags.NOZBUFFER, m_PerlinDebugLine, itemsNum));
674 s_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 0, 255, 0), ShapeFlags.NOZBUFFER, m_ZeroDebugLine, i+ 1));
675 s_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 255, 0, 0), ShapeFlags.NOZBUFFER, m_EdgeDebugLine, itemsNum));
676 s_aDebugShapes.Insert(Shape.CreateLines(ARGB(255, 0, 0, 255), ShapeFlags.NOZBUFFER, m_ThresholdDebugLine, itemsNum));
682 protected void PerlinDebug()
684 string filePath =
"d:\\test.dds";
685 array<int>
data = {};
687 const int WIDTH = 1024;
690 for (
int y = 0; y <
HEIGHT; y++)
692 for (
int x = 0; x <
WIDTH; x++)
699 int pixel = ARGB(255, perlinVal * 255, perlinVal * 255, perlinVal * 255);