Speckle v2 integration
This commit is contained in:
Родитель
e3ef0e8a1e
Коммит
52a2a153ca
|
@ -37,3 +37,4 @@ SpeckleUnrealProject/Plugins/SpeckleUnreal/Binaries/
|
|||
SpeckleUnrealProject/Plugins/SpeckleUnreal/Intermediate/
|
||||
SpeckleUnrealProject/Saved/
|
||||
SpeckleUnrealProject/.vs/
|
||||
.idea/
|
||||
|
|
43
README.md
43
README.md
|
@ -1,29 +1,13 @@
|
|||
# SpeckleUnreal
|
||||
# speckle-unreal
|
||||
|
||||
[![Version](https://img.shields.io/badge/Version-v0.1.0-orange)](https://github.com/mobiusnode/SpeckleUnreal) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](http://makeapullrequest.com)
|
||||
[![Version](https://img.shields.io/badge/Version-v0.1.0-orange)](https://github.com/specklesystems/speckle-unreal) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](http://makeapullrequest.com)
|
||||
|
||||
Our Team is developing a Speckle plugin and interoperability transport schema for UE4. Our goal is to enable Revit/Dynamo and Rhino/Grasshopper to send + receive geometry to UE4 for visualization. Our current priority is to establish and release a data sender (TO UE4). We’re also working on receiver methods, however our initial focus is on Rhino/Grasshopper to UE4 translation and the attachment of UE4-specific metadata to the core JSON ‘blobs’ in transport.
|
||||
Plugin for Unreal Engine 4 to import objects from Speckle v2.
|
||||
|
||||
In this repository you will find the source code, assets and project settings of the SpeckleUnreal plugin for Unreal Engine app development (Unreal Engine 4.25.1 or newer recommended).
|
||||
|
||||
# Useful Links
|
||||
Use the following links to access resources related to bug reporting, issues, feature requests, and general questions regarding SpeckleUnreal. Future releases may not contain these links & note.
|
||||
|
||||
## Speckle Unreal Server
|
||||
https://speckle.mobiusnode.io
|
||||
|
||||
## Discourse Forums (Bugs, Issues, etc.)
|
||||
https://discourse.mobiusnode.io
|
||||
|
||||
## SpeckleUnreal Slack Workspace
|
||||
https://speckle-works-unreal.slack.com
|
||||
|
||||
## YouTub Demo & Tutorial - Getting Started
|
||||
https://bit.ly/3ehHQE6
|
||||
|
||||
## NOTICE
|
||||
|
||||
* Tested on Windows and MacOS and Linux.
|
||||
* Tested on Windows, Unreal Engine v4.26 and Visual Studio Community 2019
|
||||
* Only displays meshes. Breps are converted using their display values.
|
||||
* Does not use the Speckle Kit workflow as conversions all happen in C++.
|
||||
|
||||
|
@ -37,20 +21,5 @@ https://bit.ly/3ehHQE6
|
|||
|
||||
We will eventually look to distributing the plugin officially on the Unreal Engine Marketplace but for now you'll need to install the plugin manually like this.
|
||||
|
||||
---
|
||||
|
||||
## Roadmap
|
||||
|
||||
> Roadmap is subject to change. Last reviewed 10th of July 2020.
|
||||
|
||||
| Version | Defining Feature |
|
||||
| ------- | -------------------------------------------------------------------------------- |
|
||||
| ~0.1~ | ~First prototype release as Unreal Engine plugin~ |
|
||||
| 0.2 | New component workflow and custom materials assigned via inspector~ |
|
||||
| 0.3 | Spawn geometry in transform heirarchy based on layer data |
|
||||
| 0.4 | User login API, get Stream API and no dependency on a local install of Speckle |
|
||||
| 0.5 | Rendering Rule API |
|
||||
| 0.6 | Support Lines, Points, Numbers and Text|
|
||||
| 0.7 | Local caching of Speckle streams |
|
||||
| 0.8 | Implement Sender API |
|
||||
| 1.0 | Production ready (out of preview) |
|
||||
## Credits
|
||||
Based off the original Unreal integration for Speckle v1 by Mark and Jak which can be found here: [https://github.com/mobiusnode/SpeckleUnreal](https://github.com/mobiusnode/SpeckleUnreal).
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
|
Двоичный файл не отображается.
Двоичные данные
SpeckleUnrealProject/Plugins/SpeckleUnreal/Content/SpeckleGlassMaterial.uasset
Normal file
Двоичные данные
SpeckleUnrealProject/Plugins/SpeckleUnreal/Content/SpeckleGlassMaterial.uasset
Normal file
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичные данные
SpeckleUnrealProject/Plugins/SpeckleUnreal/Resources/Icon128.png
Двоичные данные
SpeckleUnrealProject/Plugins/SpeckleUnreal/Resources/Icon128.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 5.7 KiB После Ширина: | Высота: | Размер: 1.8 KiB |
|
@ -3,10 +3,17 @@
|
|||
// Sets default values
|
||||
ASpeckleUnrealManager::ASpeckleUnrealManager()
|
||||
{
|
||||
static ConstructorHelpers::FObjectFinder<UMaterial> SpeckleMaterial(TEXT("Material'/SpeckleUnreal/SpeckleMaterial.SpeckleMaterial'"));
|
||||
static ConstructorHelpers::FObjectFinder<UMaterial> SpeckleGlassMaterial(TEXT("Material'/SpeckleUnreal/SpeckleGlassMaterial.SpeckleGlassMaterial'"));
|
||||
|
||||
//When the object is constructed, Get the HTTP module
|
||||
Http = &FHttpModule::Get();
|
||||
// default conversion is millimeters to centimeters because streams tend to be in ml and unreal is in cm by defaults
|
||||
ScaleFactor = 0.1;
|
||||
World = GetWorld();
|
||||
|
||||
DefaultMeshOpaqueMaterial = SpeckleMaterial.Object;
|
||||
DefaultMeshTransparentMaterial = SpeckleGlassMaterial.Object;
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
|
@ -15,242 +22,308 @@ void ASpeckleUnrealManager::BeginPlay()
|
|||
Super::BeginPlay();
|
||||
|
||||
World = GetWorld();
|
||||
GetStream();
|
||||
if (ImportAtRuntime)
|
||||
ImportSpeckleObject();
|
||||
}
|
||||
|
||||
void ASpeckleUnrealManager::SetUpGetRequest(TSharedRef<IHttpRequest> Request)
|
||||
/*Import the Speckle object*/
|
||||
void ASpeckleUnrealManager::ImportSpeckleObject()
|
||||
{
|
||||
FString url = ServerUrl + "/objects/" + StreamID + "/" + ObjectID;
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, "[Speckle] Downloading: " + url);
|
||||
|
||||
FHttpRequestRef Request = Http->CreateRequest();
|
||||
|
||||
Request->SetVerb("GET");
|
||||
Request->SetHeader("Content-Type", TEXT("application/json"));
|
||||
Request->SetHeader("Authorization", AuthToken);
|
||||
}
|
||||
|
||||
/*Http call*/
|
||||
void ASpeckleUnrealManager::GetStream()
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, "Downloading: " + StreamID);
|
||||
|
||||
TSharedRef<IHttpRequest> Request = Http->CreateRequest();
|
||||
|
||||
SetUpGetRequest(Request);
|
||||
|
||||
Request->OnProcessRequestComplete().BindUObject(this, &ASpeckleUnrealManager::OnStreamResponseReceived);
|
||||
|
||||
//This is the url on which to process the request
|
||||
Request->SetURL(ServerUrl + "streams/" + StreamID);
|
||||
Request->SetHeader("Accept", TEXT("text/plain"));
|
||||
Request->SetHeader("Authorization", "Bearer " + AuthToken);
|
||||
|
||||
Request->OnProcessRequestComplete().BindUObject(this, &ASpeckleUnrealManager::OnStreamTextResponseReceived);
|
||||
Request->SetURL(url);
|
||||
Request->ProcessRequest();
|
||||
}
|
||||
|
||||
/*Assigned function on successfull http call*/
|
||||
void ASpeckleUnrealManager::OnStreamResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
|
||||
void ASpeckleUnrealManager::OnStreamTextResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
|
||||
{
|
||||
if (!bWasSuccessful)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Stream Request failed");
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Stream Request failed: " + Response->GetContentAsString());
|
||||
return;
|
||||
}
|
||||
auto responseCode = Response->GetResponseCode();
|
||||
if (responseCode != 200)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, FString::Printf(TEXT("Error response. Response code %d"), responseCode));
|
||||
return;
|
||||
}
|
||||
|
||||
//Create a pointer to hold the json serialized data
|
||||
TSharedPtr<FJsonObject> ResponseJsonObject;
|
||||
FString response = Response->GetContentAsString();
|
||||
|
||||
//Create a reader pointer to read the json data
|
||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
|
||||
// ParseIntoArray is very inneficient for large strings.
|
||||
// https://docs.unrealengine.com/en-US/API/Runtime/Core/Containers/FString/ParseIntoArrayLines/index.html
|
||||
// https://answers.unrealengine.com/questions/81697/reading-text-file-line-by-line.html
|
||||
// Can be fixed by setting the size of the array
|
||||
int lineCount = 0;
|
||||
for (const TCHAR* ptr = *response; *ptr; ptr++)
|
||||
if (*ptr == '\n')
|
||||
lineCount++;
|
||||
TArray<FString> lines;
|
||||
lines.Reserve(lineCount);
|
||||
response.ParseIntoArray(lines, TEXT("\n"), true);
|
||||
|
||||
//Deserialize the json data given Reader and the actual object to deserialize
|
||||
if (FJsonSerializer::Deserialize(Reader, ResponseJsonObject))
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, FString::Printf(TEXT("[Speckle] Parsing %d downloaded objects..."), lineCount));
|
||||
|
||||
for (auto& line : lines)
|
||||
{
|
||||
//Get the value of the json object by field name
|
||||
FString ResponseMessage = ResponseJsonObject->GetStringField("message");
|
||||
TSharedPtr<FJsonObject> Stream = ResponseJsonObject->GetObjectField("resource");
|
||||
FString StreamName = Stream->GetStringField("name");
|
||||
FString StreamDescription = Stream->GetStringField("description");
|
||||
FString objectId, objectJson;
|
||||
if (!line.Split("\t", &objectId, &objectJson))
|
||||
continue;
|
||||
TSharedPtr<FJsonObject> jsonObject;
|
||||
TSharedRef<TJsonReader<>> jsonReader = TJsonReaderFactory<>::Create(objectJson);
|
||||
if (!FJsonSerializer::Deserialize(jsonReader, jsonObject))
|
||||
continue;
|
||||
|
||||
FString Units = ResponseJsonObject->GetObjectField("baseProperties")->GetStringField("units").ToLower();
|
||||
|
||||
// unreal engine units are in cm by default but the conversion is editable by users so
|
||||
// this needs to be accounted for later.
|
||||
if (Units == "meters" || Units == "metres")
|
||||
ScaleFactor = 100;
|
||||
|
||||
if (Units == "centimeters" || Units == "centimetres")
|
||||
ScaleFactor = 1;
|
||||
|
||||
if (Units == "millimeters" || Units == "millimetres")
|
||||
ScaleFactor = 0.1;
|
||||
|
||||
if (Units == "yards")
|
||||
ScaleFactor = 91.4402757;
|
||||
|
||||
if (Units == "feet")
|
||||
ScaleFactor = 30.4799990;
|
||||
|
||||
if (Units == "inches")
|
||||
ScaleFactor = 2.5399986;
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> LayersInStream = Stream->GetArrayField("layers");
|
||||
SpeckleUnrealLayers = TArray<USpeckleUnrealLayer*>();
|
||||
|
||||
for (size_t i = 0; i < LayersInStream.Num(); i++)
|
||||
{
|
||||
TSharedPtr<FJsonObject> LayerObject = LayersInStream[i]->AsObject();
|
||||
|
||||
FString LayerName = LayerObject->GetStringField("name");
|
||||
int32 StartIndex = LayerObject->GetIntegerField("startIndex");
|
||||
int32 ObjectCount = LayerObject->GetIntegerField("objectCount");
|
||||
|
||||
//USpeckleUnrealLayer NewLayer = USpeckleUnrealLayer(LayerName, StartIndex, ObjectCount);
|
||||
USpeckleUnrealLayer* NewLayer = NewObject<USpeckleUnrealLayer> (this);
|
||||
NewLayer->Init(LayerName, StartIndex, ObjectCount);
|
||||
SpeckleUnrealLayers.Add(NewLayer);
|
||||
}
|
||||
|
||||
//Output it to the engine
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, "Units: " + FString::SanitizeFloat(ScaleFactor));
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Green, "Status: " + ResponseMessage);
|
||||
GEngine->AddOnScreenDebugMessage(2, 5.0f, FColor::Green, "Name: " + StreamName);
|
||||
GEngine->AddOnScreenDebugMessage(3, 5.0f, FColor::Green, "Description: " + StreamDescription);
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectPlaceholderArray = Stream->GetArrayField("objects");
|
||||
|
||||
GetStreamObjects(ObjectPlaceholderArray.Num());
|
||||
SpeckleObjects.Add(objectId, jsonObject);
|
||||
}
|
||||
else
|
||||
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, FString::Printf(TEXT("[Speckle] Converting %d objects..."), lineCount));
|
||||
|
||||
ImportObjectFromCache(SpeckleObjects[ObjectID]);
|
||||
|
||||
for (auto& m : CreatedSpeckleMeshes)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Couldn't deserialize Json from stream response");
|
||||
GEngine->AddOnScreenDebugMessage(2, 10.0f, FColor::Red, Response->GetContentAsString());
|
||||
if (InProgressSpeckleMeshes.Contains(m.Key) && InProgressSpeckleMeshes[m.Key] == m.Value)
|
||||
continue;
|
||||
if (m.Value->Scene) // actors removed by the user in the editor have the Scene set to nullptr
|
||||
m.Value->Destroy();
|
||||
}
|
||||
|
||||
CreatedSpeckleMeshes = InProgressSpeckleMeshes;
|
||||
InProgressSpeckleMeshes.Empty();
|
||||
|
||||
GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Green, FString::Printf(TEXT("[Speckle] Objects imported successfully. Created %d Actors"), CreatedSpeckleMeshes.Num()));
|
||||
|
||||
}
|
||||
|
||||
void ASpeckleUnrealManager::GetStreamObjects(int32 objectCount)
|
||||
ASpeckleUnrealMesh* ASpeckleUnrealManager::GetExistingMesh(const FString &objectId)
|
||||
{
|
||||
int32 RequestLimit = 1;
|
||||
CurrentObjectIndex = 0;
|
||||
LayerIndex = 0;
|
||||
if (InProgressSpeckleMeshes.Contains(objectId))
|
||||
return InProgressSpeckleMeshes[objectId];
|
||||
|
||||
for (size_t i = 0; i < objectCount; i += RequestLimit)
|
||||
{
|
||||
TSharedRef<IHttpRequest> Request = Http->CreateRequest();
|
||||
|
||||
SetUpGetRequest(Request);
|
||||
|
||||
Request->OnProcessRequestComplete().BindUObject(this, &ASpeckleUnrealManager::OnStreamObjectResponseReceived);
|
||||
|
||||
//This is the url on which to process the request
|
||||
Request->SetURL(ServerUrl + "streams/" + StreamID + "/objects?limit=" + FString::FromInt(RequestLimit) + "&offset=" + FString::FromInt(i));
|
||||
|
||||
Request->ProcessRequest();
|
||||
}
|
||||
if(!CreatedSpeckleMeshes.Contains(objectId))
|
||||
return nullptr;
|
||||
ASpeckleUnrealMesh* meshActor = CreatedSpeckleMeshes[objectId];
|
||||
// Check if actor has been deleted by the user
|
||||
if (!meshActor || !meshActor->Scene)
|
||||
return nullptr;
|
||||
return meshActor;
|
||||
}
|
||||
|
||||
void ASpeckleUnrealManager::OnStreamObjectResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
|
||||
void ASpeckleUnrealManager::ImportObjectFromCache(const TSharedPtr<FJsonObject> speckleObj)
|
||||
{
|
||||
if (!bWasSuccessful)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Object Request failed");
|
||||
if (!speckleObj->HasField("speckle_type"))
|
||||
return;
|
||||
if (speckleObj->GetStringField("speckle_type") == "reference" && speckleObj->HasField("referencedId")) {
|
||||
TSharedPtr<FJsonObject> referencedObj;
|
||||
if (SpeckleObjects.Contains(speckleObj->GetStringField("referencedId")))
|
||||
ImportObjectFromCache(SpeckleObjects[speckleObj->GetStringField("referencedId")]);
|
||||
return;
|
||||
}
|
||||
if (!speckleObj->HasField("id"))
|
||||
return;
|
||||
FString objectId = speckleObj->GetStringField("id");
|
||||
FString speckleType = speckleObj->GetStringField("speckle_type");
|
||||
|
||||
// UE_LOG(LogTemp, Warning, TEXT("Importing object %s (type %s)"), *objectId, *speckleType);
|
||||
|
||||
if (speckleObj->GetStringField("speckle_type") == "Objects.Geometry.Mesh") {
|
||||
ASpeckleUnrealMesh* mesh = GetExistingMesh(objectId);
|
||||
if (!mesh)
|
||||
mesh = CreateMesh(speckleObj);
|
||||
InProgressSpeckleMeshes.Add(objectId, mesh);
|
||||
return;
|
||||
}
|
||||
|
||||
//Create a pointer to hold the json serialized data
|
||||
TSharedPtr<FJsonObject> ResponseJsonObject;
|
||||
|
||||
//Create a reader pointer to read the json data
|
||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
|
||||
|
||||
//Deserialize the json data given Reader and the actual object to deserialize
|
||||
if (FJsonSerializer::Deserialize(Reader, ResponseJsonObject))
|
||||
if (speckleObj->HasField("@displayMesh"))
|
||||
{
|
||||
UMaterialInterface* explicitMaterial = nullptr;
|
||||
if (speckleObj->HasField("renderMaterial"))
|
||||
explicitMaterial = CreateMaterial(speckleObj->GetObjectField("renderMaterial"));
|
||||
|
||||
int32 Offset = FCString::Atoi (*Request->GetURLParameter("offset"));
|
||||
//Get the value of the json object by field name
|
||||
TArray<TSharedPtr<FJsonValue>> StreamObjects = ResponseJsonObject->GetArrayField("resources");
|
||||
// Check if the @displayMesh is an object or an array
|
||||
const TSharedPtr<FJsonObject> *meshObjPtr;
|
||||
const TArray<TSharedPtr<FJsonValue>> *meshArrayPtr;
|
||||
|
||||
for (size_t i = 0; i < SpeckleUnrealLayers.Num(); i++)
|
||||
if (speckleObj->TryGetObjectField("@displayMesh", meshObjPtr))
|
||||
{
|
||||
if (Offset >= SpeckleUnrealLayers[i]->StartIndex)
|
||||
{
|
||||
if (Offset < (SpeckleUnrealLayers[i]->StartIndex + SpeckleUnrealLayers[i]->ObjectCount))
|
||||
LayerIndex = i;
|
||||
}
|
||||
TSharedPtr<FJsonObject> meshObj = SpeckleObjects[(*meshObjPtr)->GetStringField("referencedId")];
|
||||
|
||||
ASpeckleUnrealMesh* mesh = GetExistingMesh(objectId);
|
||||
if (!mesh)
|
||||
mesh = CreateMesh(meshObj, explicitMaterial);
|
||||
InProgressSpeckleMeshes.Add(objectId, mesh);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < StreamObjects.Num(); i++)
|
||||
else if (speckleObj->TryGetArrayField("@displayMesh", meshArrayPtr))
|
||||
{
|
||||
TSharedPtr<FJsonObject> StreamObject = StreamObjects[i].Get()->AsObject();
|
||||
|
||||
TSharedPtr<FJsonObject> ObjectToConvert = StreamObject;
|
||||
|
||||
FString objectType = ObjectToConvert->GetStringField("type");
|
||||
|
||||
if (objectType.ToLower().Contains("brep"))
|
||||
for (auto& meshObjValue : *meshArrayPtr)
|
||||
{
|
||||
ObjectToConvert = StreamObject->GetObjectField("displayValue");
|
||||
|
||||
objectType = ObjectToConvert->GetStringField("type");
|
||||
}
|
||||
|
||||
if (objectType.ToLower().Contains("mesh"))
|
||||
{
|
||||
AActor* ActorInstance = World->SpawnActor(MeshActor);
|
||||
ASpeckleUnrealMesh* MeshInstance = (ASpeckleUnrealMesh*)ActorInstance;
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectVertices = ObjectToConvert->GetArrayField("vertices");
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectFaces = ObjectToConvert->GetArrayField("faces");
|
||||
|
||||
TArray<FVector> ParsedVerticies;
|
||||
|
||||
for (size_t j = 0; j < ObjectVertices.Num(); j += 3)
|
||||
{
|
||||
ParsedVerticies.Add(FVector
|
||||
(
|
||||
(float)(ObjectVertices[j].Get()->AsNumber()) * -1,
|
||||
(float)(ObjectVertices[j + 1].Get()->AsNumber()),
|
||||
(float)(ObjectVertices[j + 2].Get()->AsNumber())
|
||||
) * ScaleFactor);
|
||||
}
|
||||
|
||||
//convert mesh faces into triangle array regardless of whether or not they are quads
|
||||
TArray<int32> ParsedTriangles;
|
||||
int32 j = 0;
|
||||
while (j < ObjectFaces.Num())
|
||||
{
|
||||
if (ObjectFaces[j].Get()->AsNumber() == 0)
|
||||
{
|
||||
//Triangles
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 2].Get()->AsNumber());
|
||||
j += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Quads to triangles
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 2].Get()->AsNumber());
|
||||
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 4].Get()->AsNumber());
|
||||
|
||||
j += 5;
|
||||
}
|
||||
}
|
||||
|
||||
if (RandomColorsPerLayer)
|
||||
MeshInstance->SetMesh(ParsedVerticies, ParsedTriangles, DefaultMeshMaterial, SpeckleUnrealLayers[LayerIndex]->LayerColor);
|
||||
else
|
||||
MeshInstance->SetMesh(ParsedVerticies, ParsedTriangles, DefaultMeshMaterial, FLinearColor::White);
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("%d"), Offset);
|
||||
UE_LOG(LogTemp, Warning, TEXT("%s"), *SpeckleUnrealLayers[LayerIndex]->LayerName);
|
||||
FString meshId = meshObjValue->AsObject()->GetStringField("referencedId");
|
||||
FString unrealMeshKey = objectId + meshId;
|
||||
|
||||
ASpeckleUnrealMesh* mesh = GetExistingMesh(unrealMeshKey);
|
||||
if (!mesh)
|
||||
mesh = CreateMesh(SpeckleObjects[meshId], explicitMaterial);
|
||||
InProgressSpeckleMeshes.Add(unrealMeshKey, mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// Go recursively into all object fields (except @displayMesh)
|
||||
for (auto& kv : speckleObj->Values)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(1, 5.0f, FColor::Red, "Couldn't deserialize Json from object response");
|
||||
GEngine->AddOnScreenDebugMessage(2, 10.0f, FColor::Red, Response->GetContentAsString());
|
||||
if (kv.Key == "@displayMesh")
|
||||
continue;
|
||||
|
||||
const TSharedPtr< FJsonObject > *subObjectPtr;
|
||||
if (kv.Value->TryGetObject(subObjectPtr))
|
||||
{
|
||||
ImportObjectFromCache(*subObjectPtr);
|
||||
continue;
|
||||
}
|
||||
|
||||
const TArray<TSharedPtr<FJsonValue>> *subArrayPtr;
|
||||
if (kv.Value->TryGetArray(subArrayPtr))
|
||||
{
|
||||
for (auto& arrayElement : *subArrayPtr)
|
||||
{
|
||||
const TSharedPtr<FJsonObject> *arraySubObjPtr;
|
||||
if (!arrayElement->TryGetObject(arraySubObjPtr))
|
||||
continue;
|
||||
ImportObjectFromCache(*arraySubObjPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UMaterialInterface* ASpeckleUnrealManager::CreateMaterial(TSharedPtr<FJsonObject> obj)
|
||||
{
|
||||
if (obj->GetStringField("speckle_type") == "reference")
|
||||
obj = SpeckleObjects[obj->GetStringField("referencedId")];
|
||||
|
||||
int opacity;
|
||||
if (obj->TryGetNumberField("opacity", opacity)) {
|
||||
if (opacity < 1) {
|
||||
return DefaultMeshTransparentMaterial;
|
||||
}
|
||||
}
|
||||
return DefaultMeshOpaqueMaterial;
|
||||
}
|
||||
|
||||
ASpeckleUnrealMesh* ASpeckleUnrealManager::CreateMesh(TSharedPtr<FJsonObject> obj, UMaterialInterface* explicitMaterial)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("Creating mesh for object %s"), *obj->GetStringField("id"));
|
||||
|
||||
FString Units = obj->GetStringField("units");
|
||||
// unreal engine units are in cm by default but the conversion is editable by users so
|
||||
// this needs to be accounted for later.
|
||||
ScaleFactor = 1;
|
||||
if (Units == "meters" || Units == "metres" || Units == "m")
|
||||
ScaleFactor = 100;
|
||||
|
||||
if (Units == "centimeters" || Units == "centimetres" || Units == "cm")
|
||||
ScaleFactor = 1;
|
||||
|
||||
if (Units == "millimeters" || Units == "millimetres" || Units == "mm")
|
||||
ScaleFactor = 0.1;
|
||||
|
||||
if (Units == "yards" || Units == "yd")
|
||||
ScaleFactor = 91.4402757;
|
||||
|
||||
if (Units == "feet" || Units == "ft")
|
||||
ScaleFactor = 30.4799990;
|
||||
|
||||
if (Units == "inches" || Units == "in")
|
||||
ScaleFactor = 2.5399986;
|
||||
|
||||
// The following line can be used to debug large objects
|
||||
// ScaleFactor = ScaleFactor * 0.1;
|
||||
|
||||
FString verticesId = obj->GetArrayField("vertices")[0]->AsObject()->GetStringField("referencedId");
|
||||
FString facesId = obj->GetArrayField("faces")[0]->AsObject()->GetStringField("referencedId");
|
||||
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectVertices = SpeckleObjects[verticesId]->GetArrayField("data");
|
||||
TArray<TSharedPtr<FJsonValue>> ObjectFaces = SpeckleObjects[facesId]->GetArrayField("data");
|
||||
|
||||
AActor* ActorInstance = World->SpawnActor(MeshActor);
|
||||
ASpeckleUnrealMesh* MeshInstance = (ASpeckleUnrealMesh*)ActorInstance;
|
||||
|
||||
#if WITH_EDITOR
|
||||
MeshInstance->SetFolderPath(FName(GetActorLabel() + FString(TEXT("_")) + StreamID));
|
||||
#endif
|
||||
|
||||
TArray<FVector> ParsedVerticies;
|
||||
|
||||
for (size_t j = 0; j < ObjectVertices.Num(); j += 3)
|
||||
{
|
||||
ParsedVerticies.Add(FVector
|
||||
(
|
||||
(float)(ObjectVertices[j].Get()->AsNumber()) * -1,
|
||||
(float)(ObjectVertices[j + 1].Get()->AsNumber()),
|
||||
(float)(ObjectVertices[j + 2].Get()->AsNumber())
|
||||
) * ScaleFactor);
|
||||
}
|
||||
|
||||
//convert mesh faces into triangle array regardless of whether or not they are quads
|
||||
TArray<int32> ParsedTriangles;
|
||||
int32 j = 0;
|
||||
while (j < ObjectFaces.Num())
|
||||
{
|
||||
if (ObjectFaces[j].Get()->AsNumber() == 0)
|
||||
{
|
||||
//Triangles
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 2].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
j += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Quads to triangles
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 2].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
|
||||
ParsedTriangles.Add(ObjectFaces[j + 1].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 3].Get()->AsNumber());
|
||||
ParsedTriangles.Add(ObjectFaces[j + 4].Get()->AsNumber());
|
||||
|
||||
j += 5;
|
||||
}
|
||||
}
|
||||
|
||||
// Material priority (low to high): DefaultMeshOpaqueMaterial, renderMaterial set on parent, renderMaterial set on mesh
|
||||
if (!explicitMaterial)
|
||||
explicitMaterial = DefaultMeshOpaqueMaterial;
|
||||
if (obj->HasField("renderMaterial"))
|
||||
explicitMaterial = CreateMaterial(obj->GetObjectField("renderMaterial"));
|
||||
|
||||
MeshInstance->SetMesh(ParsedVerticies, ParsedTriangles, explicitMaterial, FLinearColor::White);
|
||||
|
||||
// UE_LOG(LogTemp, Warning, TEXT("Added %d vertices and %d triangles"), ParsedVerticies.Num(), ParsedTriangles.Num());
|
||||
|
||||
return MeshInstance;
|
||||
}
|
||||
|
||||
|
||||
void ASpeckleUnrealManager::DeleteObjects()
|
||||
{
|
||||
for (auto& m : CreatedSpeckleMeshes)
|
||||
{
|
||||
if (m.Value->Scene)
|
||||
m.Value->Destroy();
|
||||
}
|
||||
|
||||
CreatedSpeckleMeshes.Empty();
|
||||
InProgressSpeckleMeshes.Empty();
|
||||
}
|
|
@ -11,9 +11,10 @@ ASpeckleUnrealMesh::ASpeckleUnrealMesh()
|
|||
|
||||
ProceduralMesh = CreateDefaultSubobject<UProceduralMeshComponent>("Mesh");
|
||||
ProceduralMesh->SetupAttachment(RootComponent);
|
||||
|
||||
}
|
||||
|
||||
void ASpeckleUnrealMesh::SetMesh(TArray<FVector> Vertices, TArray<int32> Triangles, UMaterialInterface* Material, FLinearColor Color)
|
||||
void ASpeckleUnrealMesh::SetMesh(const TArray<FVector> &Vertices, const TArray<int32> &Triangles, UMaterialInterface* Material, FLinearColor Color)
|
||||
{
|
||||
ProceduralMesh->ClearAllMeshSections();
|
||||
|
||||
|
@ -45,7 +46,7 @@ void ASpeckleUnrealMesh::SetMesh(TArray<FVector> Vertices, TArray<int32> Triangl
|
|||
|
||||
UMaterialInstanceDynamic* DynMaterial = UMaterialInstanceDynamic::Create(Material, this);
|
||||
|
||||
DynMaterial->SetVectorParameterValue("BaseColor", Color);
|
||||
DynMaterial->SetVectorParameterValue("BaseColor", FLinearColor::White);
|
||||
|
||||
ProceduralMesh->SetMaterial(0, DynMaterial);
|
||||
}
|
||||
|
|
|
@ -26,12 +26,16 @@ public:
|
|||
FHttpModule* Http;
|
||||
|
||||
/* The actual HTTP call */
|
||||
UFUNCTION()
|
||||
void GetStream();
|
||||
UFUNCTION(CallInEditor, Category = "Speckle")
|
||||
void ImportSpeckleObject();
|
||||
|
||||
UFUNCTION(CallInEditor, Category = "Speckle")
|
||||
void DeleteObjects();
|
||||
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString ServerUrl {
|
||||
"https://hestia.speckle.works/api/"
|
||||
"https://speckle.xyz"
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
|
@ -39,24 +43,33 @@ public:
|
|||
""
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString ObjectID {
|
||||
""
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
FString AuthToken {
|
||||
""
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
TSubclassOf<ASpeckleUnrealMesh> MeshActor;
|
||||
TSubclassOf<ASpeckleUnrealMesh> MeshActor {
|
||||
ASpeckleUnrealMesh::StaticClass()
|
||||
};
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
UMaterialInterface* DefaultMeshMaterial;
|
||||
UMaterialInterface* DefaultMeshOpaqueMaterial;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
bool RandomColorsPerLayer;
|
||||
UMaterialInterface* DefaultMeshTransparentMaterial;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speckle")
|
||||
bool ImportAtRuntime;
|
||||
|
||||
TArray<USpeckleUnrealLayer*> SpeckleUnrealLayers;
|
||||
|
||||
/*Assign this function to call when the GET request processes sucessfully*/
|
||||
void OnStreamResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
|
||||
void OnStreamTextResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
|
||||
|
||||
// Sets default values for this actor's properties
|
||||
ASpeckleUnrealManager();
|
||||
|
@ -70,12 +83,16 @@ protected:
|
|||
|
||||
float ScaleFactor;
|
||||
|
||||
int32 LayerIndex;
|
||||
int32 CurrentObjectIndex;
|
||||
TMap<FString, TSharedPtr<FJsonObject>> SpeckleObjects;
|
||||
|
||||
void SetUpGetRequest(TSharedRef<IHttpRequest> Request);
|
||||
TMap<FString, ASpeckleUnrealMesh*> CreatedSpeckleMeshes;
|
||||
TMap<FString, ASpeckleUnrealMesh*> InProgressSpeckleMeshes;
|
||||
|
||||
void GetStreamObjects(int32 objectCount);
|
||||
ASpeckleUnrealMesh* GetExistingMesh(const FString &objectId);
|
||||
|
||||
void ImportObjectFromCache(const TSharedPtr<FJsonObject> speckleObject);
|
||||
|
||||
UMaterialInterface* CreateMaterial(TSharedPtr<FJsonObject>);
|
||||
ASpeckleUnrealMesh* CreateMesh(TSharedPtr<FJsonObject>, UMaterialInterface *explicitMaterial = nullptr);
|
||||
|
||||
void OnStreamObjectResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
|
||||
};
|
|
@ -22,7 +22,7 @@ public:
|
|||
// Sets default values for this actor's properties
|
||||
ASpeckleUnrealMesh();
|
||||
|
||||
virtual void SetMesh(TArray<FVector> Vertices, TArray<int32> Triangles, UMaterialInterface* Material, FLinearColor Color);
|
||||
virtual void SetMesh(const TArray<FVector> &Vertices, const TArray<int32> &Triangles, UMaterialInterface* Material, FLinearColor Color);
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"FriendlyName": "SpeckleUnreal",
|
||||
"Description": "Speckle is an open source data platform for Architecture, Engineering, and Construction. It has been open sourced under the MIT license, is customizable, and available in the cloud or via a self-hosted server. It allows users to exchange data between various AEC modelling and content creation platforms.",
|
||||
"Category": "AEC",
|
||||
"CreatedBy": "Mobius Node",
|
||||
"CreatedByURL": "https://www.mobiusnode.io/",
|
||||
"DocsURL": "https://github.com/mobiusnode/SpeckleUnreal",
|
||||
"CreatedBy": "Speckle",
|
||||
"CreatedByURL": "https://speckle.systems/",
|
||||
"DocsURL": "https://github.com/specklesystems/speckle-unreal",
|
||||
"MarketplaceURL": "",
|
||||
"SupportURL": "",
|
||||
"CanContainContent": true,
|
||||
|
|
|
@ -7,81 +7,63 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{94A6C6
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Games", "Games", "{8E2F6A87-1826-34F4-940C-CC23A48F9FE4}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UE4", "Intermediate\ProjectFiles\UE4.vcxproj", "{DE17FD13-E94F-4875-9509-F6023C8B5747}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UE4", "Intermediate\ProjectFiles\UE4.vcxproj", "{B30CC638-032E-480C-8503-6B5AB8230CA3}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpeckleUnrealProject", "Intermediate\ProjectFiles\SpeckleUnrealProject.vcxproj", "{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpeckleUnrealProject", "Intermediate\ProjectFiles\SpeckleUnrealProject.vcxproj", "{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Visualizers", "Visualizers", "{1CCEC849-CC72-4C59-8C36-2F7C38706D4C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\..\..\Epic Games\UE_4.25\Engine\Extras\VisualStudioDebugging\UE4.natvis = ..\..\..\Epic Games\UE_4.25\Engine\Extras\VisualStudioDebugging\UE4.natvis
|
||||
..\..\..\..\Program Files (x86)\Epic Games\UE_4.26\Engine\Extras\VisualStudioDebugging\UE4.natvis = ..\..\..\..\Program Files (x86)\Epic Games\UE_4.26\Engine\Extras\VisualStudioDebugging\UE4.natvis
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
DebugGame Editor|Android = DebugGame Editor|Android
|
||||
DebugGame Editor|Win32 = DebugGame Editor|Win32
|
||||
DebugGame Editor|Win64 = DebugGame Editor|Win64
|
||||
DebugGame|Android = DebugGame|Android
|
||||
DebugGame|Win32 = DebugGame|Win32
|
||||
DebugGame|Win64 = DebugGame|Win64
|
||||
Development Editor|Android = Development Editor|Android
|
||||
Development Editor|Win32 = Development Editor|Win32
|
||||
Development Editor|Win64 = Development Editor|Win64
|
||||
Development|Android = Development|Android
|
||||
Development|Win32 = Development|Win32
|
||||
Development|Win64 = Development|Win64
|
||||
Shipping|Android = Shipping|Android
|
||||
Shipping|Win32 = Shipping|Win32
|
||||
Shipping|Win64 = Shipping|Win64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame Editor|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame Editor|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.DebugGame|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development Editor|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development Editor|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Development|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Shipping|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Shipping|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747}.Shipping|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame Editor|Android.ActiveCfg = Invalid|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame Editor|Win32.ActiveCfg = Invalid|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame Editor|Win64.ActiveCfg = DebugGame_Editor|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame Editor|Win64.Build.0 = DebugGame_Editor|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Android.ActiveCfg = Android_DebugGame|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Android.Build.0 = Android_DebugGame|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Win32.ActiveCfg = DebugGame|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Win32.Build.0 = DebugGame|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Win64.ActiveCfg = DebugGame|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.DebugGame|Win64.Build.0 = DebugGame|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development Editor|Android.ActiveCfg = Invalid|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development Editor|Win32.ActiveCfg = Invalid|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development Editor|Win64.ActiveCfg = Development_Editor|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development Editor|Win64.Build.0 = Development_Editor|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Android.ActiveCfg = Android_Development|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Android.Build.0 = Android_Development|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Win32.ActiveCfg = Development|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Win32.Build.0 = Development|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Win64.ActiveCfg = Development|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Development|Win64.Build.0 = Development|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Android.ActiveCfg = Android_Shipping|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Android.Build.0 = Android_Shipping|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Win32.ActiveCfg = Shipping|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Win32.Build.0 = Shipping|Win32
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Win64.ActiveCfg = Shipping|x64
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9}.Shipping|Win64.Build.0 = Shipping|x64
|
||||
{B30CC638-032E-480C-8503-6B5AB8230CA3}.DebugGame Editor|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{B30CC638-032E-480C-8503-6B5AB8230CA3}.DebugGame Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{B30CC638-032E-480C-8503-6B5AB8230CA3}.DebugGame|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{B30CC638-032E-480C-8503-6B5AB8230CA3}.DebugGame|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{B30CC638-032E-480C-8503-6B5AB8230CA3}.Development Editor|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{B30CC638-032E-480C-8503-6B5AB8230CA3}.Development Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{B30CC638-032E-480C-8503-6B5AB8230CA3}.Development|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{B30CC638-032E-480C-8503-6B5AB8230CA3}.Development|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{B30CC638-032E-480C-8503-6B5AB8230CA3}.Shipping|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{B30CC638-032E-480C-8503-6B5AB8230CA3}.Shipping|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.DebugGame Editor|Win32.ActiveCfg = Invalid|Win32
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.DebugGame Editor|Win64.ActiveCfg = DebugGame_Editor|x64
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.DebugGame Editor|Win64.Build.0 = DebugGame_Editor|x64
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.DebugGame|Win32.ActiveCfg = DebugGame|Win32
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.DebugGame|Win32.Build.0 = DebugGame|Win32
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.DebugGame|Win64.ActiveCfg = DebugGame|x64
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.DebugGame|Win64.Build.0 = DebugGame|x64
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.Development Editor|Win32.ActiveCfg = Invalid|Win32
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.Development Editor|Win64.ActiveCfg = Development_Editor|x64
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.Development Editor|Win64.Build.0 = Development_Editor|x64
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.Development|Win32.ActiveCfg = Development|Win32
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.Development|Win32.Build.0 = Development|Win32
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.Development|Win64.ActiveCfg = Development|x64
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.Development|Win64.Build.0 = Development|x64
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.Shipping|Win32.ActiveCfg = Shipping|Win32
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.Shipping|Win32.Build.0 = Shipping|Win32
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.Shipping|Win64.ActiveCfg = Shipping|x64
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B}.Shipping|Win64.Build.0 = Shipping|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{DE17FD13-E94F-4875-9509-F6023C8B5747} = {94A6C6F3-99B3-346E-9557-ABF9D4064DBD}
|
||||
{A1185D9A-4D4D-4C9C-A9CD-D130F0A23FB9} = {8E2F6A87-1826-34F4-940C-CC23A48F9FE4}
|
||||
{B30CC638-032E-480C-8503-6B5AB8230CA3} = {94A6C6F3-99B3-346E-9557-ABF9D4064DBD}
|
||||
{1FCE0C58-EC21-48B6-82CD-DE8E94CC9C5B} = {8E2F6A87-1826-34F4-940C-CC23A48F9FE4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"FileVersion": 3,
|
||||
"EngineAssociation": "4.25",
|
||||
"EngineAssociation": "4.26",
|
||||
"Category": "",
|
||||
"Description": "",
|
||||
"Modules": [
|
||||
|
|
Загрузка…
Ссылка в новой задаче