/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright EntityRef license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #include #include #include #include using namespace ScriptCanvasTests; template AZStd::vector TestMathFunction(std::initializer_list inputNamesList, std::initializer_list inputList, std::initializer_list outputNamesList, std::initializer_list outputList) { using namespace ScriptCanvas; using namespace Nodes; AZStd::vector inputNames(inputNamesList); AZStd::vector input(inputList); AZStd::vector outputNames(outputNamesList); AZStd::vector output(outputList); AZ_Assert(inputNames.size() == input.size(), "Size mismatch"); AZ_Assert(outputNames.size() == output.size(), "Size mismatch"); AZ::Entity graphEntity("Graph"); graphEntity.Init(); SystemRequestBus::Broadcast(&SystemRequests::CreateGraphOnEntity, &graphEntity); auto graph = graphEntity.FindComponent(); EXPECT_NE(nullptr, graph); const AZ::EntityId& graphEntityId = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); AZ::EntityId functionID; CreateTestNode(graphUniqueId, functionID); EXPECT_TRUE(Connect(*graph, startID, "Out", functionID, "In")); AZStd::vector inputNodes; AZStd::vector inputNodeIDs; AZStd::vector outputNodes; AZStd::vector outputNodeIDs; for (int i = 0; i < input.size(); ++i) { AZ::EntityId inputNodeID; auto node = CreateDataNodeByType(graphUniqueId, input[i].GetType(), inputNodeID); inputNodeIDs.push_back(inputNodeID); inputNodes.push_back(node); node->SetInput_UNIT_TEST(PureData::k_setThis, input[i]); } for (int i = 0; i < output.size(); ++i) { AZ::EntityId outputNodeID; auto node = CreateDataNodeByType(graphUniqueId, output[i].GetType(), outputNodeID); outputNodeIDs.push_back(outputNodeID); outputNodes.push_back(node); } for (int i = 0; i < inputNames.size(); ++i) { EXPECT_TRUE(Connect(*graph, inputNodeIDs[i], "Get", functionID, inputNames[i].data())); } for (int i = 0; i < output.size(); ++i) { EXPECT_TRUE(Connect(*graph, functionID, outputNames[i].data(), outputNodeIDs[i], PureData::k_setThis)); } graph->GetEntity()->Activate(); EXPECT_FALSE(graph->IsInErrorState()); for (int i = 0; i < output.size(); ++i) { output[i] = *outputNodes[i]->GetInput_UNIT_TEST(PureData::k_setThis); } graph->GetEntity()->Deactivate(); delete graph; return output; } TEST_F(ScriptCanvasTestFixture, MathCustom) { using namespace ScriptCanvas; UnitTestEventsHandler unitTestHandler; unitTestHandler.BusConnect(); Graph* graph = nullptr; SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); graph->GetEntity()->Init(); const AZ::EntityId graphEntityId = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); AZ::Vector3 allOne(1, 1, 1); AZ::EntityId justCompile; CreateTestNode(graphUniqueId, justCompile); CreateTestNode(graphUniqueId, justCompile); CreateTestNode(graphUniqueId, justCompile); CreateTestNode(graphUniqueId, justCompile); CreateTestNode(graphUniqueId, justCompile); CreateTestNode(graphUniqueId, justCompile); CreateTestNode(graphUniqueId, justCompile); CreateTestNode(graphUniqueId, justCompile); CreateTestNode(graphUniqueId, justCompile); CreateTestNode(graphUniqueId, justCompile); AZ::EntityId addVectorId; Node* addVector = CreateDataNode(graphUniqueId, allOne, addVectorId); AZ::EntityId subtractVectorId; Node* subtractVector = CreateDataNode(graphUniqueId, allOne, subtractVectorId); AZ::EntityId normalizeVectorId; Node* normalizeVector = CreateDataNode(graphUniqueId, allOne, normalizeVectorId); AZ::EntityId addId; CreateTestNode(graphUniqueId, addId); AZ::EntityId subtractId; CreateTestNode(graphUniqueId, subtractId); AZ::EntityId normalizeId; CreateTestNode(graphUniqueId, normalizeId); EXPECT_TRUE(Connect(*graph, addVectorId, "Get", addId, "Vector3: A")); EXPECT_TRUE(Connect(*graph, addVectorId, "Get", addId, "Vector3: B")); EXPECT_TRUE(Connect(*graph, addVectorId, "Set", addId, "Result: Vector3")); EXPECT_TRUE(Connect(*graph, subtractVectorId, "Get", subtractId, "Vector3: A")); EXPECT_TRUE(Connect(*graph, subtractVectorId, "Get", subtractId, "Vector3: B")); EXPECT_TRUE(Connect(*graph, subtractVectorId, "Set", subtractId, "Result: Vector3")); EXPECT_TRUE(Connect(*graph, normalizeVectorId, "Get", normalizeId, "Vector3: Source")); EXPECT_TRUE(Connect(*graph, normalizeVectorId, "Set", normalizeId, "Result: Vector3")); EXPECT_TRUE(Connect(*graph, startID, "Out", addId, "In")); EXPECT_TRUE(Connect(*graph, addId, "Out", subtractId, "In")); EXPECT_TRUE(Connect(*graph, subtractId, "Out", normalizeId, "In")); graph->GetEntity()->Activate(); EXPECT_FALSE(graph->IsInErrorState()); EXPECT_EQ(*addVector->GetInput_UNIT_TEST("Set"), AZ::Vector3(2, 2, 2)); EXPECT_EQ(*subtractVector->GetInput_UNIT_TEST("Set"), AZ::Vector3::CreateZero()); EXPECT_TRUE(normalizeVector->GetInput_UNIT_TEST("Set")->IsNormalized()); graph->GetEntity()->Deactivate(); delete graph->GetEntity(); } TEST_F(ScriptCanvasTestFixture, MathMixed1) { using namespace ScriptCanvas; using namespace ScriptCanvas::Nodes; UnitTestEventsHandler unitTestHandler; unitTestHandler.BusConnect(); Graph* graph = nullptr; SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); graph->GetEntity()->Init(); const AZ::EntityId& graphEntityId = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); const AZ::Vector3 allOne4(1, 1, 1); const AZ::Vector3 allTwo4(2, 2, 2); const AZ::Vector3 allFour4(4, 4, 4); const AZ::Vector3 allOne3(allOne4); const AZ::Vector3 allTwo3(allTwo4); const AZ::Vector3 allFour3(allFour4); AZ::EntityId vectorAId, vectorBId, vectorCId, vectorDId; Node* vectorANode = CreateDataNode(graphUniqueId, allOne4, vectorAId); Node* vectorBNode = CreateDataNode(graphUniqueId, allOne4, vectorBId); Node* vectorCNode = CreateDataNode(graphUniqueId, allOne4, vectorCId); Node* vectorDNode = CreateDataNode(graphUniqueId, allOne4, vectorDId); AZ::EntityId vector3AId, vector3BId, vector3CId, vector3DId; Core::BehaviorContextObjectNode* vector3ANode = CreateTestNode(graphUniqueId, vector3AId); vector3ANode->InitializeObject(azrtti_typeid()); *vector3ANode->ModInput_UNIT_TEST("Set") = allOne3; Core::BehaviorContextObjectNode* vector3BNode = CreateTestNode(graphUniqueId, vector3BId); vector3BNode->InitializeObject(azrtti_typeid()); *vector3BNode->ModInput_UNIT_TEST("Set") = allOne3; Core::BehaviorContextObjectNode* vector3CNode = CreateTestNode(graphUniqueId, vector3CId); vector3CNode->InitializeObject(azrtti_typeid()); *vector3CNode->ModInput_UNIT_TEST("Set") = allOne3; Core::BehaviorContextObjectNode* vector3DNode = CreateTestNode(graphUniqueId, vector3DId); vector3DNode->InitializeObject(azrtti_typeid()); *vector3DNode->ModInput_UNIT_TEST("Set") = allOne3; AZ::EntityId addId; CreateTestNode(graphUniqueId, addId); AZ::EntityId add3Id; CreateTestNode(graphUniqueId, add3Id); // data connections EXPECT_TRUE(Connect(*graph, vectorAId, "Get", addId, "Vector3: A")); EXPECT_TRUE(Connect(*graph, vector3AId, "Get", addId, "Vector3: B")); EXPECT_TRUE(Connect(*graph, addId, "Result: Vector3", vector3BId, "Set")); EXPECT_TRUE(Connect(*graph, addId, "Result: Vector3", vectorBId, "Set")); EXPECT_TRUE(Connect(*graph, vectorBId, "Get", vector3CId, "Set")); EXPECT_TRUE(Connect(*graph, vector3CId, "Get", vectorCId, "Set")); EXPECT_TRUE(Connect(*graph, vector3BId, "Get", add3Id, "Vector3: A")); EXPECT_TRUE(Connect(*graph, vector3CId, "Get", add3Id, "Vector3: B")); EXPECT_TRUE(Connect(*graph, add3Id, "Result: Vector3", vectorDId, "Set")); EXPECT_TRUE(Connect(*graph, add3Id, "Result: Vector3", vector3DId, "Set")); // execution connections EXPECT_TRUE(Connect(*graph, startID, "Out", addId, "In")); EXPECT_TRUE(Connect(*graph, addId, "Out", add3Id, "In")); EXPECT_EQ(*vectorANode->GetInput_UNIT_TEST("Set"), allOne4); EXPECT_EQ(*vectorBNode->GetInput_UNIT_TEST("Set"), allOne4); EXPECT_EQ(*vectorCNode->GetInput_UNIT_TEST("Set"), allOne4); EXPECT_EQ(*vectorDNode->GetInput_UNIT_TEST("Set"), allOne4); EXPECT_EQ(*vector3ANode->GetInput_UNIT_TEST("Set"), allOne3); EXPECT_EQ(*vector3BNode->GetInput_UNIT_TEST("Set"), allOne3); EXPECT_EQ(*vector3CNode->GetInput_UNIT_TEST("Set"), allOne3); EXPECT_EQ(*vector3DNode->GetInput_UNIT_TEST("Set"), allOne3); auto vector3Aptr = vector3ANode->GetInput_UNIT_TEST("Set"); auto vector3Bptr = vector3BNode->GetInput_UNIT_TEST("Set"); auto vector3Cptr = vector3CNode->GetInput_UNIT_TEST("Set"); auto vector3Dptr = vector3DNode->GetInput_UNIT_TEST("Set"); graph->GetEntity()->Activate(); EXPECT_FALSE(graph->IsInErrorState()); auto vectorA = *vectorANode->GetInput_UNIT_TEST("Set"); auto vectorB = *vectorBNode->GetInput_UNIT_TEST("Set"); auto vectorC = *vectorCNode->GetInput_UNIT_TEST("Set"); auto vectorD = *vectorDNode->GetInput_UNIT_TEST("Set"); auto vector3A = *vector3ANode->GetInput_UNIT_TEST("Set"); auto vector3B = *vector3BNode->GetInput_UNIT_TEST("Set"); auto vector3C = *vector3CNode->GetInput_UNIT_TEST("Set"); auto vector3D = *vector3DNode->GetInput_UNIT_TEST("Set"); EXPECT_EQ(vectorA, allOne4); EXPECT_EQ(vectorB, allTwo4); EXPECT_EQ(vectorC, allTwo4); EXPECT_EQ(vectorD, allFour4); EXPECT_EQ(vector3A, allOne3); EXPECT_EQ(vector3B, allTwo3); EXPECT_EQ(vector3C, allTwo3); EXPECT_EQ(vector3D, allFour3); graph->GetEntity()->Deactivate(); delete graph->GetEntity(); } TEST_F(ScriptCanvasTestFixture, MathMixed2) { using namespace ScriptCanvas; using namespace ScriptCanvas::Nodes; UnitTestEventsHandler unitTestHandler; unitTestHandler.BusConnect(); Graph* graph = nullptr; SystemRequestBus::BroadcastResult(graph, &SystemRequests::MakeGraph); EXPECT_TRUE(graph != nullptr); graph->GetEntity()->Init(); const AZ::EntityId& graphEntityId = graph->GetEntityId(); const ScriptCanvasId& graphUniqueId = graph->GetScriptCanvasId(); AZ::EntityId startID; CreateTestNode(graphUniqueId, startID); const AZ::Vector3 allOne4(1, 1, 1); const AZ::Vector3 allEight4(8, 8, 8); const AZ::Vector3 allOne3(allOne4); const AZ::Vector3 allEight3(allEight4); AZ::EntityId vectorIdA, vectorIdB, vectorIdC, vectorIdD; Node* vectorNodeA = CreateDataNode(graphUniqueId, allOne4, vectorIdA); Node* vectorNodeB = CreateDataNode(graphUniqueId, allOne4, vectorIdB); Node* vectorNodeC = CreateDataNode(graphUniqueId, allOne4, vectorIdC); Node* vectorNodeD = CreateDataNode(graphUniqueId, allOne4, vectorIdD); AZ::EntityId vector3IdA, vector3IdB, vector3IdC, vector3IdD; Core::BehaviorContextObjectNode* vector3NodeA = CreateTestNode(graphUniqueId, vector3IdA); vector3NodeA->InitializeObject(azrtti_typeid()); *vector3NodeA->ModInput_UNIT_TEST("Set") = allOne3; Core::BehaviorContextObjectNode* vector3NodeB = CreateTestNode(graphUniqueId, vector3IdB); vector3NodeB->InitializeObject(azrtti_typeid()); *vector3NodeB->ModInput_UNIT_TEST("Set") = allOne3; Core::BehaviorContextObjectNode* vector3NodeC = CreateTestNode(graphUniqueId, vector3IdC); vector3NodeC->InitializeObject(azrtti_typeid()); *vector3NodeC->ModInput_UNIT_TEST("Set") = allOne3; Core::BehaviorContextObjectNode* vector3NodeD = CreateTestNode(graphUniqueId, vector3IdD); vector3NodeD->InitializeObject(azrtti_typeid()); *vector3NodeD->ModInput_UNIT_TEST("Set") = allOne3; AZ::EntityId addIdA; CreateTestNode(graphUniqueId, addIdA); AZ::EntityId addIdB; CreateTestNode(graphUniqueId, addIdB); AZ::EntityId addIdC; CreateTestNode(graphUniqueId, addIdC); AZ::EntityId add3IdA; CreateTestNode(graphUniqueId, add3IdA); AZ::EntityId add3IdB; CreateTestNode(graphUniqueId, add3IdB); AZ::EntityId add3IdC; CreateTestNode(graphUniqueId, add3IdC); AZ::EntityId vectorNormalizeId; CreateTestNode(graphUniqueId, vectorNormalizeId); const AZ::Vector3 x10(10, 0, 0); AZ::EntityId vectorNormalizedInId, vectorNormalizedOutId, numberLengthId; Node* vectorNormalizedInNode = CreateDataNode(graphUniqueId, x10, vectorNormalizedInId); Node* vectorNormalizedOutNode = CreateDataNode(graphUniqueId, x10, vectorNormalizedOutId); // data connections EXPECT_TRUE(Connect(*graph, vectorIdA, "Get", addIdA, "Vector3: A")); EXPECT_TRUE(Connect(*graph, vectorIdA, "Get", add3IdA, "Vector3: A")); EXPECT_TRUE(Connect(*graph, addIdA, "Result: Vector3", addIdB, "Vector3: A")); EXPECT_TRUE(Connect(*graph, addIdA, "Result: Vector3", add3IdB, "Vector3: A")); EXPECT_TRUE(Connect(*graph, addIdB, "Result: Vector3", addIdC, "Vector3: A")); EXPECT_TRUE(Connect(*graph, addIdB, "Result: Vector3", add3IdC, "Vector3: A")); EXPECT_TRUE(Connect(*graph, addIdC, "Result: Vector3", vectorIdB, "Set")); EXPECT_TRUE(Connect(*graph, addIdC, "Result: Vector3", vector3IdB, "Set")); EXPECT_TRUE(Connect(*graph, vector3IdB, "Get", vectorIdC, "Set")); EXPECT_TRUE(Connect(*graph, vector3IdA, "Get", addIdA, "Vector3: B")); EXPECT_TRUE(Connect(*graph, vector3IdA, "Get", add3IdA, "Vector3: B")); EXPECT_TRUE(Connect(*graph, add3IdA, "Result: Vector3", addIdB, "Vector3: B")); EXPECT_TRUE(Connect(*graph, add3IdA, "Result: Vector3", add3IdB, "Vector3: B")); EXPECT_TRUE(Connect(*graph, add3IdB, "Result: Vector3", addIdC, "Vector3: B")); EXPECT_TRUE(Connect(*graph, add3IdB, "Result: Vector3", add3IdC, "Vector3: B")); EXPECT_TRUE(Connect(*graph, add3IdC, "Result: Vector3", vectorIdD, "Set")); EXPECT_TRUE(Connect(*graph, add3IdC, "Result: Vector3", vector3IdD, "Set")); EXPECT_TRUE(Connect(*graph, vectorIdD, "Get", vector3IdC, "Set")); EXPECT_TRUE(Connect(*graph, vectorNormalizedInId, "Get", vectorNormalizeId, "Vector3: Source")); EXPECT_TRUE(Connect(*graph, vectorNormalizeId, "Result: Vector3", vectorNormalizedOutId, "Set")); // execution connections EXPECT_TRUE(Connect(*graph, startID, "Out", addIdA, "In")); EXPECT_TRUE(Connect(*graph, addIdA, "Out", add3IdA, "In")); EXPECT_TRUE(Connect(*graph, add3IdA, "Out", addIdB, "In")); EXPECT_TRUE(Connect(*graph, addIdB, "Out", add3IdB, "In")); EXPECT_TRUE(Connect(*graph, add3IdB, "Out", addIdC, "In")); EXPECT_TRUE(Connect(*graph, addIdC, "Out", add3IdC, "In")); EXPECT_TRUE(Connect(*graph, add3IdC, "Out", vectorNormalizeId, "In")); EXPECT_EQ(*vectorNodeA->GetInput_UNIT_TEST("Set"), allOne4); EXPECT_EQ(*vectorNodeB->GetInput_UNIT_TEST("Set"), allOne4); EXPECT_EQ(*vectorNodeC->GetInput_UNIT_TEST("Set"), allOne4); EXPECT_EQ(*vectorNodeD->GetInput_UNIT_TEST("Set"), allOne4); EXPECT_EQ(*vectorNormalizedInNode->GetInput_UNIT_TEST("Set"), x10); EXPECT_EQ(*vectorNormalizedOutNode->GetInput_UNIT_TEST("Set"), x10); EXPECT_EQ(*vector3NodeA->GetInput_UNIT_TEST("Set"), allOne3); EXPECT_EQ(*vector3NodeB->GetInput_UNIT_TEST("Set"), allOne3); EXPECT_EQ(*vector3NodeC->GetInput_UNIT_TEST("Set"), allOne3); EXPECT_EQ(*vector3NodeD->GetInput_UNIT_TEST("Set"), allOne3); graph->GetEntity()->Activate(); EXPECT_FALSE(graph->IsInErrorState()); auto vectorA = *vectorNodeA->GetInput_UNIT_TEST("Set"); auto vectorB = *vectorNodeB->GetInput_UNIT_TEST("Set"); auto vectorC = *vectorNodeC->GetInput_UNIT_TEST("Set"); auto vectorD = *vectorNodeD->GetInput_UNIT_TEST("Set"); auto vector3A = *vector3NodeA->GetInput_UNIT_TEST("Set"); auto vector3Aptr = vector3NodeA->GetInput_UNIT_TEST("Set"); auto vector3B = *vector3NodeB->GetInput_UNIT_TEST("Set"); auto vector3C = *vector3NodeC->GetInput_UNIT_TEST("Set"); auto vector3D = *vector3NodeD->GetInput_UNIT_TEST("Set"); EXPECT_EQ(vectorA, allOne4); EXPECT_EQ(vectorB, allEight4); EXPECT_EQ(vectorC, allEight4); EXPECT_EQ(vectorD, allEight4); EXPECT_EQ(vector3A, allOne3); EXPECT_EQ(vector3B, allEight3); EXPECT_EQ(vector3C, allEight3); EXPECT_EQ(vector3D, allEight3); auto normalizedIn = *vectorNormalizedInNode->GetInput_UNIT_TEST("Set"); auto normalizedOut = *vectorNormalizedOutNode->GetInput_UNIT_TEST("Set"); EXPECT_EQ(x10, normalizedIn); EXPECT_EQ(AZ::Vector3(1, 0, 0), normalizedOut); delete graph->GetEntity(); } TEST_F(ScriptCanvasTestFixture, MathOperations) { using namespace ScriptCanvas; using namespace ScriptCanvas::Nodes::Math; BinaryOpTest(3, 4, 3 * 4); BinaryOpTest(3.5f, 2.0f, 3.5f*2.0f); BinaryOpTest(3, 4, 3 + 4); BinaryOpTest(3.f, 4.f, 3.0f + 4.0f); BinaryOpTest(3, 4, 3 - 4); BinaryOpTest(3.f, 4.f, 3.f - 4.f); BinaryOpTest(3, 4, 3 / 4); BinaryOpTest(3.f, 4.f, 3.f / 4.f); } TEST_F(ScriptCanvasTestFixture, ColorNodes) { using namespace ScriptCanvas; using namespace ScriptCanvas::ColorNodes; using namespace ScriptCanvas::Data; using namespace ScriptCanvas::Nodes; const ColorType a(Vector4Type(0.5f, 0.25f, 0.75f, 1.0f)); const ColorType b(Vector4Type(0.66f, 0.33f, 0.5f, 0.5f)); const NumberType number(0.314); { // Add auto result = a + b; auto output = TestMathFunction({ "Color: A", "Color: B" }, { Datum(a), Datum(b) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // DivideByColor auto result = a / b; auto output = TestMathFunction({ "Color: A", "Color: B" }, { Datum(a), Datum(b) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // DivideByNumber auto result = a / ToVectorFloat(number); auto output = TestMathFunction({ "Color: Source", "Number: Divisor" }, { Datum(a), Datum(number) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Dot auto result = a.Dot(b); auto output = TestMathFunction({ "Color: A", "Color: B" }, { Datum(a), Datum(b) }, { "Result: Number" }, { Datum(NumberType()) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // Dot3 auto result = a.Dot3(b); auto output = TestMathFunction({ "Color: A", "Color: B" }, { Datum(a), Datum(b) }, { "Result: Number" }, { Datum(NumberType()) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // FromValues auto result = ColorType(0.2f, 0.4f, 0.6f, 0.8f); auto output = TestMathFunction({ "Number: R", "Number: G", "Number: B", "Number: A" }, { Datum(0.2f), Datum(0.4f), Datum(0.6f), Datum(0.8f) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromVector3 auto source = Vector3Type(0.2f, 0.4f, 0.6f); auto result = ColorType::CreateFromVector3(source); auto output = TestMathFunction({ "Vector3: RGB" }, { Datum(source) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromVector3AndNumber auto vector3 = Vector3Type(0.1, 0.2, 0.3); auto number = 0.4f; auto result = ColorType::CreateFromVector3AndFloat(vector3, number); auto output = TestMathFunction({ "Vector3: RGB", "Number: A" }, { Datum(vector3), Datum(number) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // FromVector4 auto vector4 = Vector4Type(0.1, 0.2, 0.3, 0.4); auto result = ColorType(vector4); auto output = TestMathFunction({ "Vector4: RGBA" }, { Datum(vector4) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // GammaToLinear auto result = a.GammaToLinear(); auto output = TestMathFunction({ "Color: Source" }, { Datum(a) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // IsClose { auto result = a.IsClose(a); auto output = TestMathFunction({ "Color: A", "Color: B", "Number: Tolerance" }, { Datum(a), Datum(a), Datum(0.1f) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_TRUE(result); EXPECT_EQ(result, *output[0].GetAs()); } { auto result = b.IsClose(a); auto output = TestMathFunction({ "Color: A", "Color: B", "Number: Tolerance" }, { Datum(b), Datum(a), Datum(0.1f) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_FALSE(result); EXPECT_EQ(result, *output[0].GetAs()); } } { // IsZero { auto zero = ColorType::CreateZero(); auto result = zero.IsZero(); auto output = TestMathFunction({ "Color: Source", "Number: Tolerance" }, { Datum(zero), Datum(0.1f) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_TRUE(result); EXPECT_EQ(result, *output[0].GetAs()); } { auto result = a.IsZero(); auto output = TestMathFunction({ "Color: Source", "Number: Tolerance" }, { Datum(a), Datum(0.1f) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_FALSE(result); EXPECT_EQ(result, *output[0].GetAs()); } } { // LinearToGamma auto result = a.LinearToGamma(); auto output = TestMathFunction({ "Color: Source" }, { Datum(a) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByColor auto result = a * b; auto output = TestMathFunction({ "Color: A", "Color: B" }, { Datum(a), Datum(b) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByNumber auto result = a * ToVectorFloat(number); auto output = TestMathFunction({ "Color: Source", "Number: Multiplier" }, { Datum(a), Datum(number) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Negate auto result = -a; auto output = TestMathFunction({ "Color: Source" }, { Datum(a) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // One auto source = ColorType(); auto result = ColorType::CreateOne(); auto output = TestMathFunction({}, {}, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Subtract auto result = a - b; auto output = TestMathFunction({ "Color: A", "Color: B" }, { Datum(a), Datum(b) }, { "Result: Color" }, { Datum(ColorType()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } // Missing: // ModRNode // ModGNode // ModBNode // ModANode } TEST_F(ScriptCanvasTestFixture, CrcNodes) { using namespace ScriptCanvas; using namespace Nodes; using namespace ScriptCanvas::CrcNodes; { // FromString Data::StringType value = "Test"; auto result = Data::CRCType(value.data()); auto output = TestMathFunction({ "String: Value" }, { Datum(value) }, { "Result: CRC" }, { Datum(Data::CRCType()) }); EXPECT_EQ(result, *output[0].GetAs()); } #if ENABLE_EXTENDED_MATH_SUPPORT { // FromNumber AZ::u32 value = 0x784dd132; auto result = Data::CRCType(value); auto output = TestMathFunction({ "Number: Value" }, { Datum(static_cast(value)) }, { "Result: CRC" }, { Datum(Data::CRCType()) }); EXPECT_EQ(result, *output[0].GetAs()); } { // GetNumber auto source = Data::CRCType("Test"); auto result = source.operator AZ::u32(); auto output = TestMathFunction({ "CRC: Value", }, { Datum(source) }, { "Result: Number" }, { Datum(Data::NumberType()) }); EXPECT_EQ(result, *output[0].GetAs()); } #endif } TEST_F(ScriptCanvasTestFixture, AABBNodes) { using namespace ScriptCanvas; using namespace ScriptCanvas::Nodes; using namespace ScriptCanvas::AABBNodes; using namespace ScriptCanvas::Data; const Vector3Type outsideMax(222); const Vector3Type min3(-111, -111, -111); const Vector3Type max3(111, 111, 111); const Vector3Type minHalf3(min3 * 0.5f); const Vector3Type maxHalf3(max3 * 0.5f); auto IsClose = [](const AABBType& lhs, const AABBType& rhs)->bool { return lhs.GetMin().IsClose(rhs.GetMin()) && lhs.GetMax().IsClose(rhs.GetMax()); }; { // AddAabb auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: A", "AABB: B" }, { Datum(source), Datum(source) }, { "Result: AABB" }, { Datum(Data::AABBType()) }); source.AddAabb(source); EXPECT_TRUE(IsClose(source, *output[0].GetAs())); } { // AddPoint auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source", "Vector3: Point" }, { Datum(source), Datum(outsideMax) }, { "Result: AABB" }, { Datum(Data::AABBType()) }); source.AddPoint(outsideMax); EXPECT_TRUE(IsClose(source, *output[0].GetAs())); } { // ApplyTransform auto transform = TransformType::CreateFromColumns(Vector3Type(1, 2, 3), Vector3Type(1, 2, 3), Vector3Type(1, 2, 3), Vector3Type(4, 4, 4)); auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source", "Transform: Transform" }, { Datum(source), Datum(transform) }, { "Result: AABB" }, { Datum(Data::AABBType()) }); source.ApplyTransform(transform); EXPECT_TRUE(IsClose(source, *output[0].GetAs())); } { // Center auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(Vector3Type()) }); auto result = source.GetCenter(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Clamp auto source = AABBType::CreateFromMinMax(min3, max3); auto sourceHalf = AABBType::CreateFromMinMax(minHalf3, maxHalf3); auto output = TestMathFunction({ "AABB: Source", "AABB: Clamp" }, { Datum(source), Datum(sourceHalf) }, { "Result: AABB" }, { Datum(AABBType()) }); auto result = source.GetClamped(sourceHalf); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } { // ContainsAABB auto bigger = AABBType::CreateFromMinMax(min3, max3); auto smaller = AABBType::CreateFromMinMax(minHalf3, maxHalf3); auto output = TestMathFunction({ "AABB: Source", "AABB: Candidate" }, { Datum(bigger), Datum(smaller) }, { "Result: Boolean" }, { Datum(BooleanType()) }); auto result = bigger.Contains(smaller); EXPECT_EQ(result, *output[0].GetAs()); EXPECT_TRUE(result); } { // ContainsVector3Node auto source = AABBType::CreateFromMinMax(min3, max3); auto contained = Vector3Type::CreateZero(); auto NOTcontained = Vector3Type(-10000, -10000, -10000); { auto output = TestMathFunction({ "AABB: Source", "Vector3: Candidate" }, { Datum(source), Datum(contained) }, { "Result: Boolean" }, { Datum(false) }); auto result = source.Contains(contained); EXPECT_EQ(result, *output[0].GetAs()); EXPECT_TRUE(result); } { auto output = TestMathFunction({ "AABB: Source", "Vector3: Candidate" }, { Datum(source), Datum(NOTcontained) }, { "Result: Boolean" }, { Datum(true) }); auto result = source.Contains(NOTcontained); EXPECT_EQ(result, *output[0].GetAs()); EXPECT_FALSE(result); } } { // DepthNode auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(NumberType()) }); float result = source.GetDepth(); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // DistanceNode auto source = AABBType::CreateFromMinMax(min3, max3); auto point = Vector3Type(100, 3000, 15879); auto output = TestMathFunction({ "AABB: Source", "Vector3: Point" }, { Datum(source), Datum(point) }, { "Result: Number" }, { Datum(NumberType()) }); float result = source.GetDistance(point); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // ExpandNode auto source = AABBType::CreateFromMinMax(min3, max3); auto delta = Vector3Type(10, 20, 30); auto output = TestMathFunction({ "AABB: Source", "Vector3: Delta" }, { Datum(source), Datum(delta) }, { "Result: AABB" }, { Datum(AABBType()) }); source.Expand(delta); EXPECT_TRUE(IsClose(source, *output[0].GetAs())); } { // ExtentsNode auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(Vector3Type()) }); auto result = source.GetExtents(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromCenterHalfExtentsNode auto center = Vector3Type(1, 2, 3); auto extents = Vector3Type(9, 8, 7); auto output = TestMathFunction({ "Vector3: Center", "Vector3: HalfExtents" }, { Datum(center), Datum(extents) }, { "Result: AABB" }, { Datum(AABBType()) }); auto result = AABBType::CreateCenterHalfExtents(center, extents); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } { // FromCenterRadiusNode auto center = Vector3Type(1, 2, 3); auto radius = 33.0f; auto output = TestMathFunction({ "Vector3: Center", "Number: Radius" }, { Datum(center), Datum(radius) }, { "Result: AABB" }, { Datum(AABBType()) }); auto result = AABBType::CreateCenterRadius(center, radius); auto output0 = *output[0].GetAs(); EXPECT_TRUE(IsClose(result, output0)); } { // FromMinMaxNode auto result = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "Vector3: Min", "Vector3: Max" }, { Datum(min3), Datum(max3) }, { "Result: AABB" }, { Datum(AABBType()) }); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } { // FromOBBNode auto source = OBBType::CreateFromAabb(AABBType::CreateFromMinMax(min3, max3)); auto output = TestMathFunction({ "OBB: Source" }, { Datum(source) }, { "Result: AABB" }, { Datum(AABBType()) }); auto result = AABBType::CreateFromObb(source); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } { // FromPointNode auto source = Vector3Type(3, 2, 1); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: AABB" }, { Datum(AABBType()) }); auto result = AABBType::CreateFromPoint(source); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } { // IsFiniteNode auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: Boolean" }, { Datum(BooleanType()) }); auto result = source.IsFinite(); EXPECT_TRUE(result); EXPECT_EQ(result, *output[0].GetAs()); } { // IsValidNode { auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: Boolean" }, { Datum(BooleanType()) }); auto result = source.IsValid(); EXPECT_TRUE(result); EXPECT_EQ(result, *output[0].GetAs()); } { auto source = AABBType::CreateFromMinMax(min3, max3); source.SetMin(max3); source.SetMax(min3); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: Boolean" }, { Datum(BooleanType()) }); auto result = source.IsValid(); EXPECT_FALSE(result); EXPECT_EQ(result, *output[0].GetAs()); } } { // LengthNode auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(NumberType()) }); float result = source.GetHeight(); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // NullNode auto output = TestMathFunction({}, {}, { "Result: AABB" }, { Datum(AABBType()) }); auto result = AABBType::CreateNull(); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } { // OverlapsNode { auto a = AABBType::CreateFromMinMax(min3, max3); auto b = AABBType::CreateFromMinMax(min3 + Vector3Type(5, 5, 5), max3 + Vector3Type(5, 5, 5)); auto output = TestMathFunction({ "AABB: A", "AABB: B" }, { Datum(a), Datum(b) }, { "Result: Boolean" }, { Datum(false) }); auto result = a.Overlaps(b); EXPECT_TRUE(result); EXPECT_EQ(result, *output[0].GetAs()); } { auto a = AABBType::CreateFromMinMax(min3, max3); auto b = AABBType::CreateFromMinMax(min3 + Vector3Type(300, 300, 300), max3 + Vector3Type(300, 300, 300)); auto output = TestMathFunction({ "AABB: A", "AABB: B" }, { Datum(a), Datum(b) }, { "Result: Boolean" }, { Datum(false) }); auto result = a.Overlaps(b); EXPECT_FALSE(result); EXPECT_EQ(result, *output[0].GetAs()); } } { // SurfaceAreaNode auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(NumberType()) }); float result = source.GetSurfaceArea(); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // GetMaxNode auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(Vector3Type()) }); auto result = source.GetMax(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetMinNode auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(Vector3Type()) }); auto result = source.GetMin(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // ToSphereNode auto source = AABBType::CreateFromMinMax(min3 + Vector3Type(5, 5, 5), max3 + Vector3Type(5, 5, 5)); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Center: Vector3", "Radius: Number" }, { Datum(Vector3Type()), Datum(NumberType()) }); Vector3Type center; AZ::VectorFloat radiusVF; source.GetAsSphere(center, radiusVF); EXPECT_TRUE(center.IsClose(*output[0].GetAs())); float radius = radiusVF; SC_EXPECT_FLOAT_EQ(radius, aznumeric_caster(*output[1].GetAs())); } { // TranslateNode auto source = AABBType::CreateFromMinMax(min3, max3); auto translation = Vector3Type(25, 30, -40); auto output = TestMathFunction({ "AABB: Source", "Vector3: Translation" }, { Datum(source), Datum(translation) }, { "Result: AABB" }, { Datum(AABBType()) }); auto result = source.GetTranslated(translation); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } { // WidthNode auto source = AABBType::CreateFromMinMax(min3, max3); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(NumberType()) }); float result = source.GetWidth(); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } } TEST_F(ScriptCanvasTestFixture, Matrix3x3Nodes) { using namespace ScriptCanvas; using namespace Nodes; using namespace ScriptCanvas::Matrix3x3Nodes; { // Add auto a(Data::Matrix3x3Type::CreateFromRows(Data::Vector3Type::CreateOne(), Data::Vector3Type::CreateOne(), Data::Vector3Type::CreateOne())); auto b(Data::Matrix3x3Type::CreateFromRows(Data::Vector3Type::CreateOne(), Data::Vector3Type::CreateOne(), Data::Vector3Type::CreateOne())); auto c = a + b; auto output = TestMathFunction({ "Matrix3x3: A", "Matrix3x3: B" }, { Datum(a), Datum(b) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // DivideByNumber auto a(Data::Matrix3x3Type::CreateFromRows(Data::Vector3Type(3.0, 3.0, 3.0), Data::Vector3Type(3.0, 3.0, 3.0), Data::Vector3Type(3.0, 3.0, 3.0))); Data::NumberType b(3.0); auto result = a / Data::ToVectorFloat(b); auto output = TestMathFunction({ "Matrix3x3: Source", "Number: Divisor" }, { Datum(a), Datum(b) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromColumns auto col1 = Data::Vector3Type(1.0, 2.0, 3.0); auto col2 = Data::Vector3Type(4.0, 5.0, 6.0); auto col3 = Data::Vector3Type(7.0, 8.0, 9.0); auto result(Data::Matrix3x3Type::CreateFromColumns(col1, col2, col3)); auto output = TestMathFunction({ "Vector3: Column1", "Vector3: Column2", "Vector3: Column3" }, { Datum(col1), Datum(col2), Datum(col3) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromCrossProduct auto source = Data::Vector3Type(1.0, -1.0, 0.0); auto result(Data::Matrix3x3Type::CreateCrossProduct(source)); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromDiagonal auto source = Data::Vector3Type(1.0, 1.0, 1.0); auto result(Data::Matrix3x3Type::CreateDiagonal(source)); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromMatrix4x4 auto row1 = Data::Vector4Type(1.0, 2.0, 3.0, 10.0); auto row2 = Data::Vector4Type(4.0, 5.0, 6.0, 20.0); auto row3 = Data::Vector4Type(7.0, 8.0, 9.0, -30.0); auto row4 = Data::Vector4Type(-75.454, 2.5419, -102343435.72, 5587981.54); auto source = Data::Matrix4x4Type::CreateFromRows(row1, row2, row3, row4); auto result(Data::Matrix3x3Type::CreateFromMatrix4x4(source)); auto output = TestMathFunction({ "Matrix4x4: Source" }, { Datum(source) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromQuaternion auto rotation = Data::QuaternionType(1.0, 2.0, 3.0, 4.0); auto result(Data::Matrix3x3Type::CreateFromQuaternion(rotation)); auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(rotation) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromRotationXDegrees // FromRotationXRadians auto degrees = 45.0f; auto resultDegrees(Data::Matrix3x3Type::CreateRotationX(AZ::DegToRad(degrees))); auto outputDegrees = TestMathFunction({ "Number: Degrees" }, { Datum(degrees) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(resultDegrees.IsClose(*outputDegrees[0].GetAs())); } { // FromRotationYDegrees auto degrees = 30.0f; auto resultDegrees(Data::Matrix3x3Type::CreateRotationY(AZ::DegToRad(degrees))); auto outputDegrees = TestMathFunction({ "Number: Degrees" }, { Datum(degrees) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(resultDegrees.IsClose(*outputDegrees[0].GetAs())); } { // FromRotationZDegrees auto degrees = 60.0f; auto resultDegrees(Data::Matrix3x3Type::CreateRotationZ(AZ::DegToRad(degrees))); auto outputDegrees = TestMathFunction({ "Number: Degrees" }, { Datum(degrees) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(resultDegrees.IsClose(*outputDegrees[0].GetAs())); } { // FromRows auto row1 = Data::Vector3Type(1.0, 2.0, 3.0); auto row2 = Data::Vector3Type(4.0, 5.0, 6.0); auto row3 = Data::Vector3Type(7.0, 8.0, 9.0); auto result(Data::Matrix3x3Type::CreateFromRows(row1, row2, row3)); auto output = TestMathFunction({ "Vector3: Row1", "Vector3: Row2", "Vector3: Row3" }, { Datum(row1), Datum(row2), Datum(row3) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromScale auto scale = Data::Vector3Type(2.0, 2.0, 2.0); auto result(Data::Matrix3x3Type::CreateScale(scale)); auto output = TestMathFunction({ "Vector3: Scale" }, { Datum(scale) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromTransform auto transform = Data::TransformType::CreateFromRows( Data::Vector4Type(1.0, 0.0, 0.0, 0.0), Data::Vector4Type(0.0, 1.0, 0.0, 0.0), Data::Vector4Type(0.0, 0.0, 1.0, 0.0)); auto result(Data::Matrix3x3Type::CreateFromTransform(transform)); auto output = TestMathFunction({ "Transform: Transform" }, { Datum(transform) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Invert auto source = Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 2.0, 3.0), Data::Vector3Type(4.0, 1.0, 26.0), Data::Vector3Type(7.0, -8.0, 1.0)); auto result(source.GetInverseFull()); auto output = TestMathFunction({ "Matrix3x3: Source", }, { Datum(source) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // IsCloseNode auto a(Data::Matrix3x3Type::CreateFromRows(Data::Vector3Type::CreateOne(), Data::Vector3Type::CreateOne(), Data::Vector3Type::CreateOne())); auto b(Data::Matrix3x3Type::CreateFromRows(Data::Vector3Type(2, 2, 2), Data::Vector3Type(2, 2, 2), Data::Vector3Type(2, 2, 2))); auto c(Data::Matrix3x3Type::CreateFromRows(Data::Vector3Type(1.001, 1.001, 1.001), Data::Vector3Type(1.001, 1.001, 1.001), Data::Vector3Type(1.001, 1.001, 1.001))); bool resultFalse = a.IsClose(b); auto output = TestMathFunction({ "Matrix3x3: A", "Matrix3x3: B" }, { Datum(a), Datum(b) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); bool resultTrue = a.IsClose(b, Data::ToVectorFloat(2.1)); output = TestMathFunction({ "Matrix3x3: A", "Matrix3x3: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(2.1) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultTrue = a.IsClose(c); output = TestMathFunction({ "Matrix3x3: A", "Matrix3x3: B" }, { Datum(a), Datum(c) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultFalse = a.IsClose(b, Data::ToVectorFloat(0.9)); output = TestMathFunction({ "Matrix3x3: A", "Matrix3x3: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(0.9) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); } { // IsFinite auto source(Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 2.0, 3.0), Data::Vector3Type(4.0, std::numeric_limits::infinity(), 6.0), Data::Vector3Type(7.0, 8.0, 9.0))); auto result = source.IsFinite(); auto output = TestMathFunction({ "Matrix3x3: Source" }, { Datum(source) }, { "Result: Boolean", }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } { // IsOrthogonal auto source(Data::Matrix3x3Type::CreateDiagonal(Data::Vector3Type(2.0, 2.0, 2.0))); auto result = source.IsOrthogonal(); auto output = TestMathFunction({ "Matrix3x3: Source" }, { Datum(source) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); } { // MultiplyByNumber auto source(Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 2.0, 3.0), Data::Vector3Type(4.0, 5.0, 6.0), Data::Vector3Type(7.0, 8.0, 9.0))); Data::NumberType scalar(3.0); auto result = source * Data::ToVectorFloat(scalar); auto output = TestMathFunction({ "Matrix3x3: Source", "Number: Multiplier" }, { Datum(source), Datum(scalar) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByMatrix auto a(Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 2.0, 3.0), Data::Vector3Type(4.0, 5.0, 6.0), Data::Vector3Type(7.0, 8.0, 9.0))); auto b(Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(-1.0, -2.0, 13.0), Data::Vector3Type(14.0, 15.0, -6.0), Data::Vector3Type(17.0, -8.0, 19.0))); auto result = a * b; auto output = TestMathFunction({ "Matrix3x3: A", "Matrix3x3: B" }, { Datum(a), Datum(b) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByVector auto source(Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 2.0, 3.0), Data::Vector3Type(4.0, 5.0, 6.0), Data::Vector3Type(7.0, 8.0, 9.0))); Data::Vector3Type vector3(2.0); auto result = source * vector3; auto output = TestMathFunction({ "Matrix3x3: Source", "Vector3: Vector" }, { Datum(source), Datum(vector3) }, { "Result: Vector3" }, { Datum(Data::Vector3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Orthogonalize auto source(Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 2.0, 3.0), Data::Vector3Type(4.0, 5.0, 6.0), Data::Vector3Type(7.0, 8.0, 9.0))); auto result = source.GetOrthogonalized(); auto output = TestMathFunction({ "Matrix3x3: Source" }, { Datum(source) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Subtract auto a(Data::Matrix3x3Type::CreateFromRows(Data::Vector3Type(2.0, -8.5, -6.12), Data::Vector3Type(0.0, 0.0, 2.3), Data::Vector3Type(17.2, 4.533, 16.33492))); auto b(Data::Matrix3x3Type::CreateFromRows(Data::Vector3Type::CreateOne(), Data::Vector3Type::CreateOne(), Data::Vector3Type::CreateOne())); auto c = a - b; auto output = TestMathFunction({ "Matrix3x3: A", "Matrix3x3: B" }, { Datum(a), Datum(b) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // ToAdjugate auto source = Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 0.0, 0.0), Data::Vector3Type(0.0, 1.0, 0.0), Data::Vector3Type(0.0, 0.0, 1.0)); auto result(source.GetAdjugate()); auto output = TestMathFunction({ "Matrix3x3: Source" }, { Datum(source) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetColumnNode auto source = Data::Matrix3x3Type::CreateFromColumns( Data::Vector3Type(1.0, 2.0, 4.0), Data::Vector3Type(4.0, 5.0, 6.0), Data::Vector3Type(7.0, 8.0, 9.0)); auto result(source.GetColumn(1)); auto output = TestMathFunction({ "Matrix3x3: Source", "Number: Column" }, { Datum(source), Datum(1) }, { "Result: Vector3" }, { Datum(Data::Vector3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetColumns const Data::Vector3Type col1(1.0, 2.0, 3.0); const Data::Vector3Type col2(5.0, 16.5, 21.2); const Data::Vector3Type col3(-44.4, -72.1, 72.4); auto source = Data::Matrix3x3Type::CreateFromColumns(col1, col2, col3); auto output = TestMathFunction( { "Matrix3x3: Source" }, { Datum(source) }, { "Column1: Vector3", "Column2: Vector3", "Column3: Vector3" }, { Datum(Data::Vector3Type::CreateZero()), Datum(Data::Vector3Type::CreateZero()), Datum(Data::Vector3Type::CreateZero()) }); EXPECT_TRUE(col1.IsClose(*output[0].GetAs())); EXPECT_TRUE(col2.IsClose(*output[1].GetAs())); EXPECT_TRUE(col3.IsClose(*output[2].GetAs())); } { // ToDeterminant auto source = Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 0.0, 0.0), Data::Vector3Type(0.0, 1.0, 0.0), Data::Vector3Type(0.0, 0.0, 1.0)); auto result(source.GetDeterminant()); // Test naming single output slots: The GetDeterminant function names it's result slot "Determinant" auto output = TestMathFunction({ "Matrix3x3: Source" }, { Datum(source) }, { "Determinant: Number" }, { Datum(Data::NumberType()) }); EXPECT_TRUE(result.IsClose(Data::ToVectorFloat(*output[0].GetAs()))); } { // GetDiagonal auto source = Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 2.0, 3.0), Data::Vector3Type(4.0, 5.0, 6.0), Data::Vector3Type(7.0, 8.0, 9.0)); auto result(source.GetDiagonal()); auto output = TestMathFunction({ "Matrix3x3: Source", }, { Datum(source) }, { "Result: Vector3" }, { Datum(Data::Vector3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetElement auto source = Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 2.0, 4.0), Data::Vector3Type(4.0, 5.0, 6.0), Data::Vector3Type(7.0, 8.0, 9.0)); auto result(source.GetElement(2, 1)); auto output = TestMathFunction({ "Matrix3x3: Source", "Number: Row", "Number: Column" }, { Datum(source), Datum(2), Datum(1) }, { "Result: Number" }, { Datum(Data::NumberType()) }); EXPECT_TRUE(result.IsClose(Data::ToVectorFloat(*output[0].GetAs()))); } { // GetRow auto source = Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 2.0, 4.0), Data::Vector3Type(4.0, 5.0, 6.0), Data::Vector3Type(7.0, 8.0, 9.0)); auto result(source.GetRow(0)); auto output = TestMathFunction({ "Matrix3x3: Source", "Number: Row" }, { Datum(source), Datum(0) }, { "Result: Vector3" }, { Datum(Data::Vector3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetRows const Data::Vector3Type row1(1.0, 2.0, 3.0); const Data::Vector3Type row2(5.0, 16.5, 21.2); const Data::Vector3Type row3(-44.4, -72.1, 72.4); auto source = Data::Matrix3x3Type::CreateFromRows(row1, row2, row3); auto output = TestMathFunction( { "Matrix3x3: Source" }, { Datum(source) }, { "Row1: Vector3", "Row2: Vector3", "Row3: Vector3" }, { Datum(Data::Vector3Type::CreateZero()), Datum(Data::Vector3Type::CreateZero()), Datum(Data::Vector3Type::CreateZero()) }); EXPECT_TRUE(row1.IsClose(*output[0].GetAs())); EXPECT_TRUE(row2.IsClose(*output[1].GetAs())); EXPECT_TRUE(row3.IsClose(*output[2].GetAs())); } { // ToScale auto source = Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 2.0, 3.0), Data::Vector3Type(4.0, 1.0, -6.0), Data::Vector3Type(7.0, -8.0, 1.0)); auto result(source.RetrieveScale()); auto output = TestMathFunction({ "Matrix3x3: Source", }, { Datum(source) }, { "Result: Vector3" }, { Datum(Data::Vector3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Transpose auto source(Data::Matrix3x3Type::CreateFromRows( Data::Vector3Type(1.0, 2.0, 3.0), Data::Vector3Type(4.0, 5.0, 6.0), Data::Vector3Type(7.0, 8.0, 9.0))); auto result = source.GetTranspose(); auto output = TestMathFunction({ "Matrix3x3: Source" }, { Datum(source) }, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Zero auto result = Data::Matrix3x3Type::CreateZero(); auto output = TestMathFunction({}, {}, { "Result: Matrix3x3" }, { Datum(Data::Matrix3x3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } } TEST_F(ScriptCanvasTestFixture, Matrix4x4Nodes) { using namespace ScriptCanvas; using namespace Nodes; using namespace ScriptCanvas::Matrix4x4Nodes; { // FromColumns auto col1 = Data::Vector4Type(1.0, 2.0, 3.0, 4.0); auto col2 = Data::Vector4Type(5.0, 6.0, 7.0, 8.0); auto col3 = Data::Vector4Type(9.0, 10.0, 11.0, 12.0); auto col4 = Data::Vector4Type(13.0, 15.0, 15.0, 16.0); auto result(Data::Matrix4x4Type::CreateFromColumns(col1, col2, col3, col4)); auto output = TestMathFunction({ "Vector4: Column1", "Vector4: Column2", "Vector4: Column3", "Vector4: Column4" }, { Datum(col1), Datum(col2), Datum(col3), Datum(col4) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromDiagonal auto source = Data::Vector4Type(1.0, 1.0, 1.0, 1.0); auto result(Data::Matrix4x4Type::CreateDiagonal(source)); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(source) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromMatrix3x3 auto row1 = Data::Vector3Type(1.0, 2.0, 3.0); auto row2 = Data::Vector3Type(4.0, 5.0, 6.0); auto row3 = Data::Vector3Type(7.0, 8.0, 9.0); auto source = Data::Matrix3x3Type::CreateFromRows(row1, row2, row3); auto result(Data::Matrix4x4Type::CreateFromRows(Data::Vector4Type::CreateFromVector3(source.GetRow(0)), Data::Vector4Type::CreateFromVector3(source.GetRow(1)), Data::Vector4Type::CreateFromVector3(source.GetRow(2)), Data::Vector4Type(0.0, 0.0, 0.0, 1.0))); auto output = TestMathFunction({ "Matrix3x3: Source" }, { Datum(source) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromQuaternion auto rotation = Data::QuaternionType(1.0, 2.0, 3.0, 4.0); auto result(Data::Matrix4x4Type::CreateFromQuaternion(rotation)); auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(rotation) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromQuaternionAndTranslation auto rotation = Data::QuaternionType(1.0, 2.0, 3.0, 4.0); auto translation = Data::Vector3Type(10.0, -4.5, -16.10); auto result = Data::Matrix4x4Type::CreateFromQuaternionAndTranslation(rotation, translation); auto output = TestMathFunction({ "Quaternion: Rotation", "Vector3: Translation" }, { Datum(rotation), Datum(translation) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // FromProjection const auto verticalFov = Data::NumberType(4.0 / 3.0 * AZ::Constants::HalfPi); const auto aspectRatio = Data::NumberType(16.0 / 9.0); const auto nearDist = Data::NumberType(0.1); const auto farDist = Data::NumberType(10.0); auto result = Data::Matrix4x4Type::CreateProjection(Data::ToVectorFloat(verticalFov), Data::ToVectorFloat(aspectRatio), Data::ToVectorFloat(nearDist), Data::ToVectorFloat(farDist)); auto output = TestMathFunction({ "Number: Vertical FOV", "Number: Aspect Ratio", "Number: Near", "Number: Far" }, { Datum(verticalFov), Datum(aspectRatio), Datum(nearDist), Datum(farDist) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromProjectionFov const auto verticalFov = Data::NumberType(4.0 / 3.0 * AZ::Constants::HalfPi); const auto horizontalFov = Data::NumberType(5.0 / 6.0 * AZ::Constants::HalfPi); const auto nearDist = Data::NumberType(0.1); const auto farDist = Data::NumberType(10.0); auto result = Data::Matrix4x4Type::CreateProjectionFov(Data::ToVectorFloat(verticalFov), Data::ToVectorFloat(horizontalFov), Data::ToVectorFloat(nearDist), Data::ToVectorFloat(farDist)); auto output = TestMathFunction({ "Number: Vertical FOV", "Number: Horizontal FOV", "Number: Near", "Number: Far" }, { Datum(verticalFov), Datum(horizontalFov), Datum(nearDist), Datum(farDist) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromProjectionVolume const auto left = Data::NumberType(-10.0); const auto right = Data::NumberType(10.0); const auto bottom = Data::NumberType(0.0); const auto top = Data::NumberType(12.0); const auto nearDist = Data::NumberType(0.1); const auto farDist = Data::NumberType(10.0); auto result = Data::Matrix4x4Type::CreateProjectionOffset(Data::ToVectorFloat(left), Data::ToVectorFloat(right), Data::ToVectorFloat(bottom), Data::ToVectorFloat(top), Data::ToVectorFloat(nearDist), Data::ToVectorFloat(farDist)); auto output = TestMathFunction({ "Number: Left", "Number: Right", "Number: Bottom", "Number: Top", "Number: Near", "Number: Far" }, { Datum(left), Datum(right), Datum(bottom), Datum(top), Datum(nearDist), Datum(farDist) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // FromRotationXDegrees auto degrees = 45.0f; auto resultDegrees(Data::Matrix4x4Type::CreateRotationX(AZ::DegToRad(degrees))); auto outputDegrees = TestMathFunction({ "Number: Degrees" }, { Datum(degrees) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(resultDegrees.IsClose(*outputDegrees[0].GetAs())); } { // FromRotationYDegrees auto degrees = 30.0f; auto resultDegrees(Data::Matrix4x4Type::CreateRotationY(AZ::DegToRad(degrees))); auto outputDegrees = TestMathFunction({ "Number: Degrees" }, { Datum(degrees) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(resultDegrees.IsClose(*outputDegrees[0].GetAs())); } { // FromRotationZDegrees auto degrees = 60.0f; auto resultDegrees(Data::Matrix4x4Type::CreateRotationZ(AZ::DegToRad(degrees))); auto outputDegrees = TestMathFunction({ "Number: Degrees" }, { Datum(degrees) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(resultDegrees.IsClose(*outputDegrees[0].GetAs())); } { // FromRows auto row1 = Data::Vector4Type(1.0, 2.0, 3.0, 4.0); auto row2 = Data::Vector4Type(5.0, 6.0, 7.0, 8.0); auto row3 = Data::Vector4Type(9.0, 10.0, 11.0, 12.0); auto row4 = Data::Vector4Type(13.0, 15.0, 15.0, 16.0); auto result(Data::Matrix4x4Type::CreateFromRows(row1, row2, row3, row4)); auto output = TestMathFunction({ "Vector4: Row1", "Vector4: Row2", "Vector4: Row3", "Vector4: Row4" }, { Datum(row1), Datum(row2), Datum(row3), Datum(row4) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromScale auto scale = Data::Vector3Type(2.0, 2.0, 2.0); auto result(Data::Matrix4x4Type::CreateScale(scale)); auto output = TestMathFunction({ "Vector3: Scale" }, { Datum(scale) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromTransform auto transform = Data::TransformType::CreateFromRows( Data::Vector4Type(1.0, 0.0, 0.0, 0.0), Data::Vector4Type(0.0, 1.0, 0.0, 0.0), Data::Vector4Type(0.0, 0.0, 1.0, 0.0)); auto result = Data::Matrix4x4Type::CreateFromRows(transform.GetRow(0), transform.GetRow(1), transform.GetRow(2), Data::Vector4Type::CreateAxisW()); auto output = TestMathFunction({ "Transform: Transform" }, { Datum(transform) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromTranslation auto source = Data::Vector3Type(1.0, -1.0, 15.0); auto result(Data::Matrix4x4Type::CreateTranslation(source)); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Invert auto source = Data::Matrix4x4Type::CreateFromRows( Data::Vector4Type(1.0, 2.0, 3.0, 21.2), Data::Vector4Type(4.0, 1.0, 26.0, -45.8), Data::Vector4Type(7.0, -8.0, 1.0, 73.3), Data::Vector4Type(27.5, 36.8, 0.8, 14.0)); auto result(source.GetInverseFull()); auto output = TestMathFunction({ "Matrix4x4: Source", }, { Datum(source) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // IsCloseNode auto a(Data::Matrix4x4Type::CreateFromRows(Data::Vector4Type::CreateOne(), Data::Vector4Type::CreateOne(), Data::Vector4Type::CreateOne(), Data::Vector4Type::CreateOne())); auto b(Data::Matrix4x4Type::CreateFromRows(Data::Vector4Type(2.0, 2.0, 2.0, 2.0), Data::Vector4Type(2.0, 2.0, 2.0, 2.0), Data::Vector4Type(2.0, 2.0, 2.0, 2.0), Data::Vector4Type(2.0, 2.0, 2.0, 2.0))); auto c(Data::Matrix4x4Type::CreateFromRows(Data::Vector4Type(1.001, 1.001, 1.001, 1.001), Data::Vector4Type(1.001, 1.001, 1.001, 1.001), Data::Vector4Type(1.001, 1.001, 1.001, 1.001), Data::Vector4Type(1.001, 1.001, 1.001, 1.001))); bool resultFalse = a.IsClose(b); auto output = TestMathFunction({ "Matrix4x4: A", "Matrix4x4: B" }, { Datum(a), Datum(b) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); bool resultTrue = a.IsClose(b, Data::ToVectorFloat(2.1)); output = TestMathFunction({ "Matrix4x4: A", "Matrix4x4: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(2.1) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultTrue = a.IsClose(c); output = TestMathFunction({ "Matrix4x4: A", "Matrix4x4: B" }, { Datum(a), Datum(c) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultFalse = a.IsClose(b, Data::ToVectorFloat(0.9)); output = TestMathFunction({ "Matrix4x4: A", "Matrix4x4: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(0.9) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); } { // IsFinite auto source = Data::Matrix4x4Type::CreateFromRows( Data::Vector4Type(1.0, 2.0, 3.0, 21.2), Data::Vector4Type(4.0, 1.0, 26.0, -45.8), Data::Vector4Type(7.0, -8.0, std::numeric_limits::infinity(), 73.3), Data::Vector4Type(27.5, 36.8, 0.8, 14.0)); auto result = source.IsFinite(); auto output = TestMathFunction({ "Matrix4x4: Source" }, { Datum(source) }, { "Result: Boolean", }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } { // MultiplyByMatrix auto a(Data::Matrix4x4Type::CreateFromRows( Data::Vector4Type(1.0, 2.0, 3.0, 10.0), Data::Vector4Type(4.0, 5.0, 6.0, 20.0), Data::Vector4Type(7.0, 8.0, 9.0, 30.0), Data::Vector4Type(3.5, 9.1, 1.0, 17.98))); auto b(Data::Matrix4x4Type::CreateFromRows( Data::Vector4Type(-1.0, -2.0, 13.0, -0.0), Data::Vector4Type(14.0, 15.0, -6.0, +0.0), Data::Vector4Type(17.0, -8.0, 19.0, 1.0), Data::Vector4Type(4.1, -7.6, -11.3, 1.0))); auto result = a * b; auto output = TestMathFunction({ "Matrix4x4: A", "Matrix4x4: B" }, { Datum(a), Datum(b) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByVector auto source(Data::Matrix4x4Type::CreateFromRows( Data::Vector4Type(1.0, 2.0, 3.0, 10.0), Data::Vector4Type(4.0, 5.0, 6.0, 20.0), Data::Vector4Type(7.0, 8.0, 9.0, 30.0), Data::Vector4Type(3.5, 9.1, 1.0, 17.98))); Data::Vector4Type vector4(3.0); auto result = source * vector4; auto output = TestMathFunction({ "Matrix4x4: Source", "Vector4: Vector" }, { Datum(source), Datum(vector4) }, { "Result: Vector4" }, { Datum(Data::Vector4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetColumn auto source = Data::Matrix4x4Type::CreateFromColumns( Data::Vector4Type(1.0, 2.0, 3.0, 10.0), Data::Vector4Type(4.0, 5.0, 6.0, 20.0), Data::Vector4Type(7.0, 8.0, 9.0, 30.0), Data::Vector4Type(3.5, 9.1, 1.0, 40.0)); auto result(source.GetColumn(3)); auto output = TestMathFunction({ "Matrix4x4: Source", "Number: Column" }, { Datum(source), Datum(3) }, { "Result: Vector4" }, { Datum(Data::Vector4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetColumns const Data::Vector4Type col1(1.0, 2.0, 3.0, 5.0); const Data::Vector4Type col2(5.0, 16.5, 21.2, -1.2); const Data::Vector4Type col3(-44.4, -72.1, 72.4, 6.5); const Data::Vector4Type col4(2.7, 17.65, 2.3, 13.3); auto source = Data::Matrix4x4Type::CreateFromColumns(col1, col2, col3, col4); auto output = TestMathFunction( { "Matrix4x4: Source" }, { Datum(source) }, { "Column1: Vector4", "Column2: Vector4", "Column3: Vector4", "Column4: Vector4" }, { Datum(Data::Vector4Type::CreateZero()), Datum(Data::Vector4Type::CreateZero()), Datum(Data::Vector4Type::CreateZero()), Datum(Data::Vector4Type::CreateZero()) }); EXPECT_TRUE(col1.IsClose(*output[0].GetAs())); EXPECT_TRUE(col2.IsClose(*output[1].GetAs())); EXPECT_TRUE(col3.IsClose(*output[2].GetAs())); EXPECT_TRUE(col4.IsClose(*output[3].GetAs())); } { // GetDiagonal auto source = Data::Matrix4x4Type::CreateFromRows( Data::Vector4Type(10.0, 1.0, 2.0, 3.0), Data::Vector4Type(24.0, 4.0, 5.0, 6.0), Data::Vector4Type(40.0, 7.0, 8.0, 9.0), Data::Vector4Type(30.0, 10.0, 11.0, 12.0)); auto result(source.GetDiagonal()); auto output = TestMathFunction({ "Matrix4x4: Source", }, { Datum(source) }, { "Result: Vector4" }, { Datum(Data::Vector4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetElement auto source = Data::Matrix4x4Type::CreateFromRows( Data::Vector4Type(1.0, 2.0, 3.0, 10.0), Data::Vector4Type(4.0, 5.0, 6.0, 20.0), Data::Vector4Type(7.0, 8.0, 9.0, 30.0), Data::Vector4Type(3.5, 9.1, 1.0, 40.0)); auto result(source.GetElement(1, 3)); auto outputSuccess = TestMathFunction({ "Matrix4x4: Source", "Number: Row", "Number: Column" }, { Datum(source), Datum(1), Datum(3) }, { "Result: Number" }, { Datum(Data::NumberType()) }); auto outputFailure = TestMathFunction({ "Matrix4x4: Source", "Number: Row", "Number: Column" }, { Datum(source), Datum(2), Datum(2) }, { "Result: Number" }, { Datum(Data::NumberType()) }); EXPECT_TRUE(result.IsClose(Data::ToVectorFloat(*outputSuccess[0].GetAs()))); EXPECT_FALSE(result.IsClose(Data::ToVectorFloat(*outputFailure[0].GetAs()))); } { // GetRow auto source = Data::Matrix4x4Type::CreateFromRows( Data::Vector4Type(1.0, 2.0, 3.0, 10.0), Data::Vector4Type(4.0, 5.0, 6.0, 20.0), Data::Vector4Type(7.0, 8.0, 9.0, 30.0), Data::Vector4Type(3.5, 9.1, 1.0, 40.0)); auto result(source.GetRow(0)); auto output = TestMathFunction({ "Matrix4x4: Source", "Number: Row" }, { Datum(source), Datum(0) }, { "Result: Vector4" }, { Datum(Data::Vector4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetRows const Data::Vector4Type row1(1.0, 2.0, 3.0, 5.0); const Data::Vector4Type row2(5.0, 16.5, 21.2, -1.2); const Data::Vector4Type row3(-44.4, -72.1, 72.4, 6.5); const Data::Vector4Type row4(2.7, 17.65, 2.3, 13.3); auto source = Data::Matrix4x4Type::CreateFromRows(row1, row2, row3, row4); auto output = TestMathFunction( { "Matrix4x4: Source" }, { Datum(source) }, { "Row1: Vector4", "Row2: Vector4", "Row3: Vector4", "Row4: Vector4" }, { Datum(Data::Vector4Type::CreateZero()), Datum(Data::Vector4Type::CreateZero()), Datum(Data::Vector4Type::CreateZero()), Datum(Data::Vector4Type::CreateZero()) }); EXPECT_TRUE(row1.IsClose(*output[0].GetAs())); EXPECT_TRUE(row2.IsClose(*output[1].GetAs())); EXPECT_TRUE(row3.IsClose(*output[2].GetAs())); EXPECT_TRUE(row4.IsClose(*output[3].GetAs())); } { // ToScale auto source = Data::Matrix4x4Type::CreateFromRows( Data::Vector4Type(1.0, 2.0, 3.0, 4.5), Data::Vector4Type(4.0, 1.0, -6.0, -1.0), Data::Vector4Type(7.0, -8.0, 1.0, 1.0), Data::Vector4Type(0.0, 0.0, 0.0, 1.0)); auto result(source.RetrieveScale()); auto output = TestMathFunction({ "Matrix4x4: Source", }, { Datum(source) }, { "Result: Vector3" }, { Datum(Data::Vector3Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Transpose auto source = Data::Matrix4x4Type::CreateFromRows( Data::Vector4Type(1.0, 2.0, 3.0, 0.0), Data::Vector4Type(4.0, 5.0, 6.0, 6.0), Data::Vector4Type(7.0, 8.0, 9.0, -10.0), Data::Vector4Type(5.0, 8.0, 3.0, 1.0)); auto result = source.GetTranspose(); auto output = TestMathFunction({ "Matrix4x4: Source" }, { Datum(source) }, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Zero auto result = Data::Matrix4x4Type::CreateZero(); auto output = TestMathFunction({}, {}, { "Result: Matrix4x4" }, { Datum(Data::Matrix4x4Type::CreateZero()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } } TEST_F(ScriptCanvasTestFixture, OBBNodes) { using namespace ScriptCanvas; using namespace ScriptCanvas::Nodes; using namespace ScriptCanvas::OBBNodes; using namespace ScriptCanvas::Data; const Vector3Type outsideMax(222); const Vector3Type min3(-111, -111, -111); const Vector3Type max3(111, 111, 111); const Vector3Type minHalf3(min3 * 0.5f); const Vector3Type maxHalf3(max3 * 0.5f); auto obbRotated = OBBType::CreateFromPositionAndAxes(Vector3Type(10, 20, 30), Vector3Type(1, 0, 0), 10, Vector3Type(0, 1, 0), 30, Vector3Type(0, 0, 1), 20); auto transform = TransformType::CreateFromQuaternion(QuaternionType::CreateFromAxisAngle(Vector3Type(1, 1, 1).GetNormalized(), ToVectorFloat(AZ::DegToRad(30)))); obbRotated = transform * obbRotated; auto IsClose = [](const OBBType& lhs, const OBBType& rhs)->bool { return lhs.GetAxisX().IsClose(rhs.GetAxisX()) && lhs.GetAxisY().IsClose(rhs.GetAxisY()) && lhs.GetAxisZ().IsClose(rhs.GetAxisZ()) && lhs.GetPosition().IsClose(rhs.GetPosition()); }; {// FromAabbNode auto source = AABBType::CreateFromMinMax(Vector3Type(-1, -2, -3), Vector3Type(1, 2, 3)); auto output = TestMathFunction({ "AABB: Source" }, { Datum(source) }, { "Result: OBB" }, { Datum(OBBType()) }); auto result = OBBType::CreateFromAabb(source); EXPECT_TRUE(IsClose(result, (*output[0].GetAs()))); } {// FromPositionAndAxesNode auto output = TestMathFunction ({ "Vector3: Position", "Vector3: X-Axis", "Number: X Half-Length", "Vector3: Y-Axis", "Number: Y Half-Length", "Vector3: Z-Axis", "Number: Z Half-Length" } , { Datum(obbRotated.GetPosition()), Datum(obbRotated.GetAxisX()), Datum(obbRotated.GetHalfLengthX()), Datum(obbRotated.GetAxisY()), Datum(obbRotated.GetHalfLengthY()), Datum(obbRotated.GetAxisZ()), Datum(obbRotated.GetHalfLengthZ()) } , { "Result: OBB" } , { Datum(OBBType()) }); auto result = obbRotated; EXPECT_TRUE(IsClose(result, (*output[0].GetAs()))); } {// GetAxisXNode auto source = obbRotated; auto output = TestMathFunction({ "OBB: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(Vector3Type()) }); auto result = source.GetAxisX(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } {// GetAxisYNode auto source = obbRotated; auto output = TestMathFunction({ "OBB: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(Vector3Type()) }); auto result = source.GetAxisY(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } {// GetAxisZNode auto source = obbRotated; auto output = TestMathFunction({ "OBB: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(Vector3Type()) }); auto result = source.GetAxisZ(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT {// GetHalfLengthXNode auto source = obbRotated; auto output = TestMathFunction({ "OBB: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(NumberType()) }); float result = source.GetHalfLengthX(); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } {// GetHalfLengthYNode auto source = obbRotated; auto output = TestMathFunction({ "OBB: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(NumberType()) }); float result = source.GetHalfLengthY(); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } {// GetHalfLengthZNode auto source = obbRotated; auto output = TestMathFunction({ "OBB: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(NumberType()) }); float result = source.GetHalfLengthZ(); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } #endif {// GetPositionNode auto source = obbRotated; auto output = TestMathFunction({ "OBB: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(Vector3Type()) }); auto result = obbRotated.GetPosition(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } {// IsFiniteNode auto source = obbRotated; auto output = TestMathFunction({ "OBB: Source" }, { Datum(source) }, { "Result: Boolean" }, { Datum(BooleanType()) }); auto result = source.IsFinite(); EXPECT_TRUE(result); EXPECT_EQ(result, *output[0].GetAs()); } } TEST_F(ScriptCanvasTestFixture, PlaneNodes) { using namespace ScriptCanvas; using namespace Nodes; using namespace ScriptCanvas::PlaneNodes; using namespace ScriptCanvas::Data; const PlaneType source = PlaneType::CreateFromNormalAndDistance(Vector3Type::CreateOne().GetNormalized(), 12.0); const Vector4Type sourceVec4 = source.GetPlaneEquationCoefficients(); const Vector3Type point(33, 66, 99); const Vector3Type normal(Vector3Type(1, -2, 3).GetNormalized()); const float A = normal.GetX(); const float B = normal.GetY(); const float C = normal.GetZ(); const float D = 13.0f; auto IsClose = [](PlaneType lhs, PlaneType rhs) { return lhs.GetPlaneEquationCoefficients().IsClose(rhs.GetPlaneEquationCoefficients()); }; { // CreateFromCoefficientsNode auto result = PlaneType::CreateFromCoefficients(A, B, C, D); auto output = TestMathFunction({ "Number: A", "Number: B", "Number: C", "Number: D" }, { Datum(A),Datum(B),Datum(C),Datum(D) }, { "Result: Plane" }, { Datum(PlaneType()) }); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } { // CreateFromNormalAndDistanceNode auto result = PlaneType::CreateFromNormalAndDistance(normal, D); auto output = TestMathFunction({ "Vector3: Normal", "Number: Distance" }, { Datum(normal), Datum(D) }, { "Result: Plane" }, { Datum(PlaneType()) }); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } { // CreateFromNormalAndPointNode auto result = PlaneType::CreateFromNormalAndPoint(normal, point); auto output = TestMathFunction({ "Vector3: Normal", "Vector3: Point" }, { Datum(normal), Datum(point) }, { "Result: Plane" }, { Datum(PlaneType()) }); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } { // DistanceToPointNode auto result = source.GetPointDist(point); auto output = TestMathFunction({ "Plane: Source", "Vector3: Point" }, { Datum(source), Datum(point) }, { "Result: Number" }, { Datum(-1.0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // IsFiniteNode auto result = source.IsFinite(); auto output = TestMathFunction({ "Plane: Source" }, { Datum(source) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_TRUE(result); EXPECT_EQ(result, *output[0].GetAs()); } #if ENABLE_EXTENDED_MATH_SUPPORT { // ModDistanceNode auto result = source; result.SetDistance(D); auto output = TestMathFunction({ "Plane: Source", "Number: Distance" }, { Datum(source), Datum(D) }, { "Result: Plane" }, { Datum(PlaneType()) }); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } { // ModNormalNode auto result = source; result.SetNormal(normal); auto output = TestMathFunction({ "Plane: Source", "Vector3: Normal" }, { Datum(source), Datum(normal) }, { "Result: Plane" }, { Datum(PlaneType()) }); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } #endif { // GetDistanceNode auto result = source.GetDistance(); auto output = TestMathFunction({ "Plane: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(-1) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // GetNormalNode auto result = source.GetNormal(); auto output = TestMathFunction({ "Plane: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(Vector3Type(0, 0, 0)) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetPlaneEquationCoefficientsNode auto result = source.GetPlaneEquationCoefficients(); auto output = TestMathFunction({ "Plane: Source" }, { Datum(source) }, { "A: Number", "B: Number", "C: Number", "D: Number" }, { Datum(0),Datum(0),Datum(0),Datum(0) }); for (int i = 0; i < 4; ++i) { SC_EXPECT_FLOAT_EQ(result.GetElement(i), aznumeric_caster(*output[i].GetAs())); } } { // GetProjectedNode auto result = source.GetProjected(point); auto output = TestMathFunction({ "Plane: Source", "Vector3: Point" }, { Datum(source), Datum(point) }, { "Result: Vector3" }, { Datum(Vector3Type()) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // TransformNode TransformType transform = TransformType::CreateFromQuaternionAndTranslation(QuaternionType::CreateFromAxisAngle(Vector3Type(1, 1, 1).GetNormalized(), AZ::DegToRad(30)), Vector3Type(-100, 50, -25)); auto result = source.GetTransform(transform); auto output = TestMathFunction({ "Plane: Source", "Transform: Transform" }, { Datum(source), Datum(transform) }, { "Result: Plane" }, { Datum(PlaneType()) }); EXPECT_TRUE(IsClose(result, *output[0].GetAs())); } } TEST_F(ScriptCanvasTestFixture, TransformNodes) { using namespace ScriptCanvas; using namespace Nodes; using namespace ScriptCanvas::TransformNodes; using namespace ScriptCanvas::Data; const Vector3Type vector3Zero(0, 0, 0); const Vector3Type zero3(0, 0, 0); const Vector3Type vector3One(1, 1, 1); const Vector3Type xPos(1, 0, 0); const Vector3Type yPos(0, 1, 0); const Vector3Type zPos(0, 0, 1); const Vector3Type position(-10.1, 0.1, 10.1); const Vector3Type scale(-.66, .33, .66); const Vector4Type r0(1, 0, 0, -.5); const Vector4Type r1(0, 1, 0, 0.0); const Vector4Type r2(0, 0, 1, 0.5); const Vector4Type zero4(0, 0, 0, 0); const Vector3Type xPosish(1, .1, 0); const Vector3Type yPosish(0, 1, .1); const Vector3Type zPosish(.1, 0, 1); const Matrix3x3Type matrix3x3One(Matrix3x3Type::CreateFromValue(1)); const QuaternionType rotationOne(QuaternionType::CreateRotationZ(1)); const TransformType identity(TransformType::CreateIdentity()); const TransformType zero(TransformType::CreateZero()); const TransformType invertable(TransformType::CreateFromQuaternionAndTranslation(rotationOne, position)); const TransformType notOrthogonal(TransformType::CreateFromValue(3)); #if ENABLE_EXTENDED_MATH_SUPPORT { // ExtractScale auto source = TransformType::CreateScale(Vector3Type(-0.5f, .5f, 1.5f)); auto extracted = source; auto scale = extracted.ExtractScale(); auto output = TestMathFunction({ "Transform: Source" }, { Datum(source) }, { "Scale: Vector3", "Extracted: Transform" }, { Datum(vector3Zero), Datum(identity) }); auto scaleOutput = *output[0].GetAs(); auto extractedOutput = *output[1].GetAs(); EXPECT_TRUE(scale.IsClose(scaleOutput)); EXPECT_TRUE(extracted.IsClose(extractedOutput)); } #endif { // FromColumnsNode auto result = TransformType::CreateFromColumns(xPos, yPos, zPos, position); auto output0 = TestMathFunction({ "Vector3: Column 0", "Vector3: Column 1", "Vector3: Column 2", "Vector3: Column 3", }, { Datum(xPos), Datum(yPos), Datum(zPos), Datum(position) }, { "Result: Transform" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output0[0].GetAs())); } { // FromDiagonalNode auto output = TestMathFunction({ "Vector3: Diagonal" }, { Datum(vector3One) }, { "Result: Transform" }, { Datum(zero) }); auto result = TransformType::CreateDiagonal(vector3One); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromMatrix3x3Node auto output = TestMathFunction({ "Matrix3x3: Source" }, { Datum(matrix3x3One) }, { "Result: Transform" }, { Datum(zero) }); auto result = TransformType::CreateFromMatrix3x3(matrix3x3One); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromMatrix3x3AndTranslationNode auto output = TestMathFunction({ "Matrix3x3: Matrix", "Vector3: Translation" }, { Datum(matrix3x3One), Datum(position) }, { "Result: Transform" }, { Datum(zero) }); auto result = TransformType::CreateFromMatrix3x3AndTranslation(matrix3x3One, position); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromRotationNode auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(rotationOne) }, { "Result: Transform" }, { Datum(zero) }); auto result = TransformType::CreateFromQuaternion(rotationOne); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromRotationAndTranslationNode auto output = TestMathFunction({ "Quaternion: Rotation", "Vector3: Translation" }, { Datum(rotationOne), Datum(position) }, { "Result: Transform" }, { Datum(zero) }); auto result = TransformType::CreateFromQuaternionAndTranslation(rotationOne, position); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromRowsNode auto output = TestMathFunction({ "Vector4: Row 0", "Vector4: Row 1", "Vector4: Row 2", }, { Datum(r0), Datum(r1), Datum(r2) }, { "Result: Transform" }, { Datum(zero) }); auto result = TransformType::CreateFromRows(r0, r1, r2); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromScaleNode auto output = TestMathFunction({ "Vector3: Scale" }, { Datum(scale) }, { "Result: Transform" }, { Datum(zero) }); auto result = TransformType::CreateScale(scale); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromTranslationNode auto output = TestMathFunction({ "Vector3: Translation" }, { Datum(position) }, { "Result: Transform" }, { Datum(zero) }); auto result = TransformType::CreateTranslation(position); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromValueNode auto output = TestMathFunction({ "Number: Source" }, { Datum(3) }, { "Result: Transform" }, { Datum(zero) }); auto result = TransformType::CreateFromValue(ToVectorFloat(3)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // InvertOrthogonalNode auto output = TestMathFunction({ "Transform: Source" }, { Datum(invertable) }, { "Result: Transform" }, { Datum(zero) }); auto result = invertable.GetInverseFast(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // InvertSlowNode auto output = TestMathFunction({ "Transform: Source" }, { Datum(invertable) }, { "Result: Transform" }, { Datum(zero) }); auto result = invertable.GetInverseFull(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // IsCloseNode auto outputFalse = TestMathFunction({ "Transform: A", "Transform: B" }, { Datum(invertable), Datum(identity) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(invertable.IsClose(identity), *outputFalse[0].GetAs()); EXPECT_FALSE(invertable.IsClose(identity)); auto outputTrue = TestMathFunction({ "Transform: A", "Transform: B" }, { Datum(invertable), Datum(invertable) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(invertable.IsClose(invertable), *outputTrue[0].GetAs()); EXPECT_TRUE(invertable.IsClose(invertable)); } { // IsFiniteNode auto output = TestMathFunction({ "Transform: Source" }, { Datum(identity) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(identity.IsFinite(), *output[0].GetAs()); EXPECT_TRUE(identity.IsFinite()); } { // IsOrthogonalNode auto outputTrue = TestMathFunction({ "Transform: Source" }, { Datum(identity) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(identity.IsOrthogonal(), *outputTrue[0].GetAs()); EXPECT_TRUE(identity.IsOrthogonal()); auto outputFalse = TestMathFunction({ "Transform: Source" }, { Datum(notOrthogonal) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(notOrthogonal.IsOrthogonal(), *outputFalse[0].GetAs()); EXPECT_FALSE(notOrthogonal.IsOrthogonal()); } #if ENABLE_EXTENDED_MATH_SUPPORT { // Multiply3x3ByVector3Node auto output = TestMathFunction({ "Transform: Source", "Vector3: Multiplier" }, { Datum(notOrthogonal), Datum(scale) }, { "Result: Vector3" }, { Datum(zero3) }); auto result = notOrthogonal.Multiply3x3(scale); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // MultiplyByScaleNode auto output = TestMathFunction({ "Transform: Source", "Vector3: Scale" }, { Datum(notOrthogonal), Datum(scale) }, { "Result: Transform" }, { Datum(zero) }); auto result = TransformType(notOrthogonal); result.MultiplyByScale(scale); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByTransformNode auto output = TestMathFunction({ "Transform: A", "Transform: B" }, { Datum(notOrthogonal), Datum(notOrthogonal) }, { "Result: Transform" }, { Datum(zero) }); auto result = notOrthogonal * notOrthogonal; EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByVector3Node auto output = TestMathFunction({ "Transform: Source", "Vector3: Multiplier" }, { Datum(notOrthogonal), Datum(scale) }, { "Result: Vector3" }, { Datum(zero3) }); auto result = notOrthogonal * scale; EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByVector4Node const Vector4Type multiplier(4, 3, 2, 7); auto output = TestMathFunction({ "Transform: Source", "Vector4: Multiplier" }, { Datum(notOrthogonal), Datum(multiplier) }, { "Result: Vector4" }, { Datum(zero4) }); auto result = notOrthogonal * multiplier; EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // OrthogonalizeNode TransformType nearlyOrthogonal = TransformType::CreateFromColumns(xPosish, yPosish, zPosish, position); TransformType notOrthogonal = TransformType::CreateFromColumns(xPos, xPos, xPos, position); auto orthogonalResult = nearlyOrthogonal.GetOrthogonalized(); auto orthogonalOutput = *TestMathFunction({ "Transform: Source" }, { Datum(nearlyOrthogonal) }, { "Result: Transform" }, { Datum(notOrthogonal) })[0].GetAs(); EXPECT_TRUE(orthogonalResult.IsClose(orthogonalOutput)); EXPECT_TRUE(orthogonalResult.IsOrthogonal()); EXPECT_TRUE(orthogonalOutput.IsOrthogonal()); auto notOrthogonalResult = notOrthogonal.GetOrthogonalized(); auto notOrthogonalOutput = *TestMathFunction({ "Transform: Source" }, { Datum(notOrthogonal) }, { "Result: Transform" }, { Datum(identity) })[0].GetAs(); EXPECT_TRUE(notOrthogonalResult.IsClose(notOrthogonalOutput)); EXPECT_FALSE(notOrthogonalResult.IsOrthogonal()); EXPECT_FALSE(notOrthogonalOutput.IsOrthogonal()); } { // RotationXDegreesNode auto output = TestMathFunction({ "Number: Degrees" }, { Datum(30) }, { "Result: Transform" }, { Datum(identity) }); auto result = TransformType::CreateRotationX(AZ::DegToRad(30)); auto outputTM = *output[0].GetAs(); EXPECT_TRUE(result.IsClose(outputTM)); } { // RotationYDegreesNode auto output = TestMathFunction({ "Number: Degrees" }, { Datum(30) }, { "Result: Transform" }, { Datum(identity) }); auto result = TransformType::CreateRotationY(AZ::DegToRad(30)); auto outputTM = *output[0].GetAs(); EXPECT_TRUE(result.IsClose(outputTM)); } { // RotationZDegreesNode auto output = TestMathFunction({ "Number: Degrees" }, { Datum(30) }, { "Result: Transform" }, { Datum(identity) }); auto result = TransformType::CreateRotationZ(AZ::DegToRad(30)); auto outputTM = *output[0].GetAs(); EXPECT_TRUE(result.IsClose(outputTM)); } { // GetColumnNode for (int i = 0; i < 4; ++i) { auto output = TestMathFunction({ "Transform: Source", "Number: Column" }, { Datum(invertable), Datum(i) }, { "Result: Vector3" }, { Datum(zero3) }); auto result = invertable.GetColumn(i); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } } { // GetColumnsNode auto output = TestMathFunction({ "Transform: Source" }, { Datum(invertable) }, { "Column 0: Vector3", "Column 1: Vector3", "Column 2: Vector3", "Column 3: Vector3" }, { Datum(zero3), Datum(zero3), Datum(zero3), Datum(zero3) }); Vector3Type x, y, z, position; invertable.GetColumns(&x, &y, &z, &position); EXPECT_TRUE(x.IsClose(*output[0].GetAs())); EXPECT_TRUE(y.IsClose(*output[1].GetAs())); EXPECT_TRUE(z.IsClose(*output[2].GetAs())); EXPECT_TRUE(position.IsClose(*output[3].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // ToDeterminant3x3Node auto output = TestMathFunction({ "Transform: Source" }, { Datum(invertable) }, { "Result: Number" }, { Datum(0) }); auto result = invertable.GetDeterminant3x3(); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } #endif { // GetElementNode for (int row(0); row < 3; ++row) { for (int col(0); col < 4; ++col) { auto output = TestMathFunction({ "Transform: Source", "Number: Row", "Number: Column" }, { Datum(invertable), Datum(row), Datum(col) }, { "Result: Number" }, { Datum(0) }); auto result = invertable.GetElement(row, col); float resultFloat = invertable.GetElement(row, col); float outputFloat = aznumeric_caster(*output[0].GetAs()); SC_EXPECT_FLOAT_EQ(resultFloat, outputFloat); } } } #if ENABLE_EXTENDED_MATH_SUPPORT { // ToPolarDecompositionNode auto output = TestMathFunction({ "Transform: Source" }, { Datum(notOrthogonal) }, { "Orthogonal: Transform", "Symmetric: Transform" }, { Datum(zero), Datum(zero) }); TransformType orth, symm; notOrthogonal.GetPolarDecomposition(&orth, &symm); auto output0TM = *output[0].GetAs(); EXPECT_TRUE(orth.IsClose(output0TM)); auto output1TM = *output[1].GetAs(); EXPECT_TRUE(symm.IsClose(output1TM)); } { // ToPolarDecompositionOrthogonalOnlyNode auto output = TestMathFunction({ "Transform: Source" }, { Datum(notOrthogonal) }, { "Result: Transform" }, { Datum(zero) }); auto result = notOrthogonal.GetPolarDecomposition(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // GetRowNode for (int i = 0; i < 3; ++i) { auto output = TestMathFunction({ "Transform: Source", "Number: Row" }, { Datum(invertable), Datum(i) }, { "Result: Vector4" }, { Datum(zero4) }); auto result = invertable.GetRow(i); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } } { // GetRowsNode auto output = TestMathFunction({ "Transform: Source" }, { Datum(invertable) }, { "Row 0: Vector4", "Row 1: Vector4", "Row 2: Vector4" }, { Datum(zero4), Datum(zero4), Datum(zero4) }); Vector4Type r0, r1, r2; invertable.GetRows(&r0, &r1, &r2); EXPECT_TRUE(r0.IsClose(*output[0].GetAs())); EXPECT_TRUE(r1.IsClose(*output[1].GetAs())); EXPECT_TRUE(r2.IsClose(*output[2].GetAs())); } { // ToScaleNode auto output = TestMathFunction({ "Transform: Source" }, { Datum(notOrthogonal) }, { "Result: Vector3" }, { Datum(zero3) }); auto result = notOrthogonal.RetrieveScale(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetTranslationNode auto output = TestMathFunction({ "Transform: Source" }, { Datum(notOrthogonal) }, { "Result: Vector3" }, { Datum(zero3) }); auto result = notOrthogonal.GetTranslation(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // TransposeNode auto output = TestMathFunction({ "Transform: Source" }, { Datum(notOrthogonal) }, { "Result: Transform" }, { Datum(zero) }); auto result = notOrthogonal.GetTranspose(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // Transpose3x3Node auto output = TestMathFunction({ "Transform: Source" }, { Datum(notOrthogonal) }, { "Result: Transform" }, { Datum(zero) }); auto result = notOrthogonal.GetTranspose3x3(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // TransposedMultiply3x3Node auto output = TestMathFunction({ "Transform: Source", "Vector3: Transpose" }, { Datum(notOrthogonal), Datum(scale) }, { "Result: Vector3" }, { Datum(zero3) }); auto result = notOrthogonal.TransposedMultiply3x3(scale); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // ZeroNode auto output = TestMathFunction({}, {}, { "Result: Transform" }, { Datum(identity) }); auto result = TransformType::CreateZero(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif // Missing Nodes: // Transpose3x3Node } // Transform Test TEST_F(ScriptCanvasTestFixture, Vector2Nodes) { using namespace ScriptCanvas; using namespace Nodes; using namespace ScriptCanvas::Vector2Nodes; Data::Vector2Type zero(0, 0); Data::Vector2Type one(1.f, 1.f); Data::Vector2Type negativeOne(-1.f, -1.f); { // Absolute Data::Vector2Type source(-1, -1); Data::Vector2Type absolute = source.GetAbs(); auto output = TestMathFunction({ "Vector2: Source" }, { Datum(source) }, { "Result: Vector2" }, { Datum(source) }); EXPECT_TRUE(absolute.IsClose(*output[0].GetAs())); } { // Add Data::Vector2Type a(1, 1); Data::Vector2Type b(1, 1); Data::Vector2Type c = a + b; auto output = TestMathFunction({ "Vector2: A", "Vector2: B" }, { Datum(a), Datum(b) }, { "Result: Vector2" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // Clamp Data::Vector2Type source(-10, 20); Data::Vector2Type min(1, 1); Data::Vector2Type max(1, 1); auto result = source.GetClamp(min, max); auto output = TestMathFunction({ "Vector2: Source", "Vector2: Min", "Vector2: Max" }, { Datum(source), Datum(min), Datum(max), }, { "Result: Vector2" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Distance Data::Vector2Type a(1, 2); Data::Vector2Type b(-3, -2); auto result = a.GetDistance(b); auto output = TestMathFunction({ "Vector2: A", "Vector2: B" }, { Datum(a), Datum(b) }, { "Result: Number" }, { Datum(0.0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // DistanceSqr Data::Vector2Type a(1, 2); Data::Vector2Type b(-3, -2); auto result = a.GetDistanceSq(b); auto output = TestMathFunction({ "Vector2: A", "Vector2: B" }, { Datum(a), Datum(b) }, { "Result: Number" }, { Datum(0.0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // DivideByNumber Data::Vector2Type a(1, 2); Data::NumberType b(3.0); auto result = a / Data::ToVectorFloat(b); auto output = TestMathFunction({ "Vector2: Source", "Number: Divisor" }, { Datum(a), Datum(b) }, { "Result: Vector2" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // DivideByVector Data::Vector2Type a(1, 1); Data::Vector2Type b(2, 2); Data::Vector2Type c = a / b; auto output = TestMathFunction({ "Vector2: Numerator", "Vector2: Divisor" }, { Datum(a), Datum(b) }, { "Result: Vector2" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // Dot Data::Vector2Type a(1, 2); Data::Vector2Type b(-3, -2); auto result = a.Dot(b); auto output = TestMathFunction({ "Vector2: A", "Vector2: B" }, { Datum(a), Datum(b) }, { "Result: Number" }, { Datum(0.0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // From Element const Data::Vector2Type source(1, 2); for (int index = 0; index < 2; ++index) { auto result = source; result.SetElement(index, 4.0f); auto output = TestMathFunction({ "Vector2: Source", "Number: Index", "Number: Value" }, { Datum(source), Datum(index), Datum(4.0) }, { "Result: Vector2" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } } { // FromLength Data::Vector2Type source(1, 2); Data::NumberType length(10); auto result = source; result.SetLength(Data::ToVectorFloat(length)); auto output = TestMathFunction({ "Vector2: Source", "Number: Length" }, { Datum(source), Datum(length) }, { "Result: Vector2" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // FromValues Data::NumberType x(1); Data::NumberType y(2); auto result = Data::Vector2Type(Data::ToVectorFloat(x), Data::ToVectorFloat(y)); auto output = TestMathFunction({ "Number: X", "Number: Y" }, { Datum(x), Datum(y) }, { "Result: Vector2", }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // GetElements auto source = Vector2Type(1, 2); auto output = TestMathFunction({ "Vector2: Source" }, { Datum(source) }, { "X: Number", "Y: Number" }, { Datum(0), Datum(0) }); SC_EXPECT_FLOAT_EQ(source.GetX(), aznumeric_caster(*output[0].GetAs())); SC_EXPECT_FLOAT_EQ(source.GetY(), aznumeric_caster(*output[1].GetAs())); } #endif { // IsClose Data::Vector2Type a(1, 1); Data::Vector2Type b(2, 2); Data::Vector2Type c(1.09, 1.09); bool resultFalse = a.IsClose(b); auto output = TestMathFunction({ "Vector2: A", "Vector2: B" }, { Datum(a), Datum(b) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); bool resultTrue = a.IsClose(b, Data::ToVectorFloat(2.1)); output = TestMathFunction({ "Vector2: A", "Vector2: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(2.1) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultTrue = a.IsClose(c); output = TestMathFunction({ "Vector2: A", "Vector2: B" }, { Datum(a), Datum(c) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultFalse = a.IsClose(b, Data::ToVectorFloat(0.9)); output = TestMathFunction({ "Vector2: A", "Vector2: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(0.9) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); } { // IsFinite Data::Vector2Type sourceFinite(1, 1); auto result = sourceFinite.IsFinite(); auto output = TestMathFunction({ "Vector2: Source" }, { Datum(sourceFinite) }, { "Result: Boolean", }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } { // IsNormal Data::Vector2Type normal(1.f, 0.f); Data::Vector2Type nearlyNormal(1.001f, 0.0f); Data::Vector2Type notNormal(10.f, 0.f); { auto result = normal.IsNormalized(); auto output = TestMathFunction({ "Vector2: Source" }, { Datum(normal) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); } { auto result = nearlyNormal.IsNormalized(); auto output = TestMathFunction({ "Vector2: Source" }, { Datum(nearlyNormal) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); result = nearlyNormal.IsNormalized(2.0f); output = TestMathFunction({ "Vector2: Source", "Number: Tolerance" }, { Datum(nearlyNormal), Datum(2.0f) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); } { auto result = notNormal.IsNormalized(); auto output = TestMathFunction({ "Vector2: Source" }, { Datum(notNormal) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); result = notNormal.IsNormalized(12.0f); output = TestMathFunction({ "Vector2: Source", "Number: Tolerance" }, { Datum(notNormal), Datum(12.0f) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } } { // IsZero auto result = zero.IsZero(); auto output = TestMathFunction({ "Vector2: Source" }, { Datum(zero) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); result = one.IsZero(); output = TestMathFunction({ "Vector2: Source" }, { Datum(one) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } { // Length Data::Vector2Type source(1, 2); auto result = source.GetLength(); auto output = TestMathFunction({ "Vector2: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // LengthSquared Data::Vector2Type source(1, 2); auto result = source.GetLengthSq(); auto output = TestMathFunction({ "Vector2: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // Lerp Data::Vector2Type from(0.f, 0.f); Data::Vector2Type to(1.f, 1.f); Data::NumberType t(0.5); auto result = from.Lerp(to, Data::ToVectorFloat(t)); auto output = TestMathFunction({ "Vector2: From", "Vector2: To", "Number: T" }, { Datum(from), Datum(to), Datum(t) }, { "Result: Vector2" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Max Data::Vector2Type a(-1, -1); Data::Vector2Type b(1, 1); auto result = a.GetMax(b); auto output = TestMathFunction({ "Vector2: A", "Vector2: B" }, { Datum(a), Datum(b) }, { "Result: Vector2" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Min Data::Vector2Type a(-1, -1); Data::Vector2Type b(1, 1); auto result = a.GetMin(b); auto output = TestMathFunction({ "Vector2: A", "Vector2: B" }, { Datum(a), Datum(b) }, { "Result: Vector2" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // ModXNode Data::Vector2Type a(1, 2); Data::NumberType b(0); auto output = TestMathFunction({ "Vector2: Source", "Number: X" }, { Datum(a), Datum(b) }, { "Result: Vector2" }, { Datum(zero) }); auto result = a; result.SetX(Data::ToVectorFloat(b)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); EXPECT_FALSE(result.IsClose(a)); } { // ModYNode Data::Vector2Type a(1, 2); Data::NumberType b(0); auto output = TestMathFunction({ "Vector2: Source", "Number: Y" }, { Datum(a), Datum(b) }, { "Result: Vector2" }, { Datum(zero) }); auto result = a; result.SetY(Data::ToVectorFloat(b)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); EXPECT_FALSE(result.IsClose(a)); } #if ENABLE_EXTENDED_MATH_SUPPORT { // MultiplyAdd Data::Vector2Type a(2, 2); Data::Vector2Type b(3, 3); Data::Vector2Type c(4, 4); auto result = a.GetMadd(b, c); auto output = TestMathFunction({ "Vector2: A", "Vector2: B", "Vector2: C" }, { Datum(a), Datum(b), Datum(c) }, { "Result: Vector2" }, { Datum(a) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // MultiplyByNumber Data::Vector2Type a(1, 2); Data::NumberType b(3.0); auto result = a * Data::ToVectorFloat(b); auto output = TestMathFunction({ "Vector2: Source", "Number: Multiplier" }, { Datum(a), Datum(b) }, { "Result: Vector2" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByVector Data::Vector2Type a(1, 1); Data::Vector2Type b(2, 2); Data::Vector2Type c = a * b; auto output = TestMathFunction({ "Vector2: Source", "Vector2: Multiplier" }, { Datum(a), Datum(b) }, { "Result: Vector2" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // Negate Data::Vector2Type source = one; auto output = TestMathFunction({ "Vector2: Source" }, { Datum(source) }, { "Result: Vector2" }, { Datum(zero) }); auto result = -source; EXPECT_TRUE(result.IsClose(*output[0].GetAs())); source = negativeOne; output = TestMathFunction({ "Vector2: Source" }, { Datum(source) }, { "Result: Vector2" }, { Datum(zero) }); result = -source; EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Normalize Data::Vector2Type source = one; auto output = TestMathFunction({ "Vector2: Source" }, { Datum(source) }, { "Result: Vector2" }, { Datum(zero) }); auto result = source.GetNormalizedSafe(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // NormalizeWithLength Data::Vector2Type source = one; auto output = TestMathFunction({ "Vector2: Source" }, { Datum(source) }, { "Normalized: Vector2", "Length: Number" }, { Datum(zero), Datum(0) }); auto result = source.NormalizeSafeWithLength(); EXPECT_TRUE(source.IsClose(*output[0].GetAs())); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[1].GetAs())); } #endif { // Project Data::Vector2Type a(1, 1); Data::Vector2Type b(-2, -2); auto output = TestMathFunction({ "Vector2: A", "Vector2: B" }, { Datum(a), Datum(b) }, { "Result: Vector2" }, { Datum(a) }); a.Project(b); EXPECT_TRUE(a.IsClose(*output[0].GetAs())); } { // Slerp Data::Vector2Type from(1.f, 0.f); Data::Vector2Type to(0.f, 1.f); Data::NumberType t(0.5); auto slerp = from.Slerp(to, static_cast(Data::ToVectorFloat(t))); auto outputSlerp = TestMathFunction({ "Vector2: From", "Vector2: To", "Number: T" }, { Datum(from), Datum(to), Datum(t) }, { "Result: Vector2" }, { Datum(zero) }); EXPECT_TRUE(slerp.IsClose(*outputSlerp[0].GetAs())); auto lerp = from.Lerp(to, static_cast(Data::ToVectorFloat(t))); auto outputLerp = TestMathFunction({ "Vector2: From", "Vector2: To", "Number: T" }, { Datum(from), Datum(to), Datum(t) }, { "Result: Vector2" }, { Datum(zero) }); EXPECT_TRUE(lerp.IsClose(*outputLerp[0].GetAs())); EXPECT_FALSE(lerp.IsClose(slerp)); EXPECT_FALSE((*outputLerp[0].GetAs()).IsClose(*outputSlerp[0].GetAs())); } { // Subtract Data::Vector2Type a(1, 1); Data::Vector2Type b(2, 2); Data::Vector2Type c = a - b; auto output = TestMathFunction({ "Vector2: A", "Vector2: B" }, { Datum(a), Datum(b) }, { "Result: Vector2" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // GetElement const Data::Vector2Type source(1, 2); for (int index = 0; index < 2; ++index) { float result = aznumeric_caster(Data::FromVectorFloat(source.GetElement(index))); auto output = TestMathFunction({ "Vector2: Source", "Number: Index" }, { Datum(source), Datum(index) }, { "Result: Number" }, { Datum(0) }); float outputNumber = aznumeric_caster(*output[0].GetAs()); SC_EXPECT_FLOAT_EQ(result, outputNumber); } } { // ToPerpendicular Data::Vector2Type source(3, -1); auto output = TestMathFunction({ "Vector2: Source" }, { Datum(source) }, { "Result: Vector2" }, { Datum(zero) }); auto result = source.GetPerpendicular(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } } // Test Vector2Node TEST_F(ScriptCanvasTestFixture, Vector3Nodes) { using namespace ScriptCanvas; using namespace Nodes; using namespace ScriptCanvas::Vector3Nodes; Data::Vector3Type zero(0, 0, 0); Data::Vector3Type one(1.f, 1.f, 1.f); Data::Vector3Type negativeOne(-1.f, -1.f, -1.f); { // Absolute Data::Vector3Type source(-1, -1, -1); Data::Vector3Type absolute = source.GetAbs(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(source) }); EXPECT_TRUE(absolute.IsClose(*output[0].GetAs())); } { // Add Data::Vector3Type a(1, 1, 1); Data::Vector3Type b(1, 1, 1); Data::Vector3Type c = a + b; auto output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // AngleMod Data::Vector3Type source(1, 1, 1); Data::Vector3Type result = source.GetAngleMod(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(source) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // BuildTangentBasis Data::Vector3Type source, tangent, bitangent; source = Data::Vector3Type(1, 1, 1); source.NormalizeSafe(); source.BuildTangentBasis(tangent, bitangent); auto output = TestMathFunction({ "Vector3: Normal" }, { Datum(source) }, { "Tangent: Vector3", "Bitangent: Vector3" }, { Datum(zero), Datum(zero) }); EXPECT_TRUE(tangent.IsClose(*output[0].GetAs())); EXPECT_TRUE(bitangent.IsClose(*output[1].GetAs())); } { // Clamp Data::Vector3Type source(-10, 20, 1); Data::Vector3Type min(1, 1, 1); Data::Vector3Type max(1, 1, 1); auto result = source.GetClamp(min, max); auto output = TestMathFunction({ "Vector3: Source", "Vector3: Min", "Vector3: Max" }, { Datum(source), Datum(min), Datum(max), }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // Cosine Data::Vector3Type source(1.5, 1.5, 1.5); auto result = source.GetCos(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // CrossXAxis Data::Vector3Type source(1, 1, 1); auto result = source.CrossXAxis(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // CrossYAxis Data::Vector3Type source(1, 1, 1); auto result = source.CrossYAxis(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // CrossZAxis Data::Vector3Type source(1, 1, 1); auto result = source.CrossZAxis(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // Distance Data::Vector3Type a(1, 2, 3); Data::Vector3Type b(-3, -2, -1); auto result = a.GetDistance(b); auto output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(a), Datum(b) }, { "Result: Number" }, { Datum(0.0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // DistanceSqr Data::Vector3Type a(1, 2, 3); Data::Vector3Type b(-3, -2, -1); auto result = a.GetDistanceSq(b); auto output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(a), Datum(b) }, { "Result: Number" }, { Datum(0.0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // DivideByNumber Data::Vector3Type a(1, 2, 3); Data::NumberType b(3.0); auto result = a / Data::ToVectorFloat(b); auto output = TestMathFunction({ "Vector3: Source", "Number: Divisor" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // DivideByVector Data::Vector3Type a(1, 1, 1); Data::Vector3Type b(2, 2, 2); Data::Vector3Type c = a / b; auto output = TestMathFunction({ "Vector3: Numerator", "Vector3: Divisor" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // Dot Data::Vector3Type a(1, 2, 3); Data::Vector3Type b(-3, -2, -1); auto result = a.Dot(b); auto output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(a), Datum(b) }, { "Result: Number" }, { Datum(0.0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // From Element const Data::Vector3Type source(1, 2, 3); for (int index = 0; index < 3; ++index) { auto result = source; result.SetElement(index, 4.0f); auto output = TestMathFunction({ "Vector3: Source", "Number: Index", "Number: Value" }, { Datum(source), Datum(index), Datum(4.0) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } } { // FromLength Data::Vector3Type source(1, 2, 3); Data::NumberType length(10); auto result = source; result.SetLength(Data::ToVectorFloat(length)); auto output = TestMathFunction({ "Vector3: Source", "Number: Length" }, { Datum(source), Datum(length) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // FromValues Data::NumberType x(1); Data::NumberType y(2); Data::NumberType z(3); auto result = Data::Vector3Type(Data::ToVectorFloat(x), Data::ToVectorFloat(y), Data::ToVectorFloat(z)); auto output = TestMathFunction({ "Number: X", "Number: Y", "Number: Z" }, { Datum(x), Datum(y), Datum(z) }, { "Result: Vector3", }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // IsCloseNode Data::Vector3Type a(1, 1, 1); Data::Vector3Type b(2, 2, 2); Data::Vector3Type c(1.001, 1.001, 1.001); bool resultFalse = a.IsClose(b); auto output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(a), Datum(b) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); bool resultTrue = a.IsClose(b, Data::ToVectorFloat(2.1)); output = TestMathFunction({ "Vector3: A", "Vector3: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(2.1) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultTrue = a.IsClose(c); output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(a), Datum(c) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultFalse = a.IsClose(b, Data::ToVectorFloat(0.9)); output = TestMathFunction({ "Vector3: A", "Vector3: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(0.9) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); } { // IsFinite Data::Vector3Type sourceFinite(1, 1, 1); auto result = sourceFinite.IsFinite(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(sourceFinite) }, { "Result: Boolean", }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } { // IsNormal Data::Vector3Type normal(1.f, 0.f, 0.f); Data::Vector3Type nearlyNormal(1.001f, 0.0f, 0.0f); Data::Vector3Type notNormal(10.f, 0.f, 0.f); { auto result = normal.IsNormalized(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(normal) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); } { auto result = nearlyNormal.IsNormalized(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(nearlyNormal) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); result = nearlyNormal.IsNormalized(2.0f); output = TestMathFunction({ "Vector3: Source", "Number: Tolerance" }, { Datum(nearlyNormal), Datum(2.0f) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); } { auto result = notNormal.IsNormalized(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(notNormal) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); result = notNormal.IsNormalized(12.0f); output = TestMathFunction({ "Vector3: Source", "Number: Tolerance" }, { Datum(notNormal), Datum(12.0f) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } } { // IsPerpendicular Data::Vector3Type x(1.f, 0.f, 0.f); Data::Vector3Type y(0.f, 1.f, 0.f); auto result = x.IsPerpendicular(x); auto output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(x), Datum(x) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); result = x.IsPerpendicular(y); output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(x), Datum(y) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); } { // IsZero auto result = zero.IsZero(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(zero) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); result = one.IsZero(); output = TestMathFunction({ "Vector3: Source" }, { Datum(one) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } { // Length Data::Vector3Type source(1, 2, 3); auto result = source.GetLength(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // LengthReciprocal Data::Vector3Type source(1, 2, 3); auto result = source.GetLengthReciprocal(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // LengthSquared Data::Vector3Type source(1, 2, 3); auto result = source.GetLengthSq(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // Lerp Data::Vector3Type from(0.f, 0.f, 0.f); Data::Vector3Type to(1.f, 1.f, 1.f); Data::NumberType t(0.5); auto result = from.Lerp(to, Data::ToVectorFloat(t)); auto output = TestMathFunction({ "Vector3: From", "Vector3: To", "Number: T" }, { Datum(from), Datum(to), Datum(t) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Max Data::Vector3Type a(-1, -1, -1); Data::Vector3Type b(1, 1, 1); auto result = a.GetMax(b); auto output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Min Data::Vector3Type a(-1, -1, -1); Data::Vector3Type b(1, 1, 1); auto result = a.GetMin(b); auto output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // ModXNode Data::Vector3Type a(1, 2, 3); Data::NumberType b(0); auto output = TestMathFunction({ "Vector3: Source", "Number: X" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(zero) }); auto result = a; result.SetX(Data::ToVectorFloat(b)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); EXPECT_FALSE(result.IsClose(a)); } { // ModYNode Data::Vector3Type a(1, 2, 3); Data::NumberType b(0); auto output = TestMathFunction({ "Vector3: Source", "Number: Y" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(zero) }); auto result = a; result.SetY(Data::ToVectorFloat(b)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); EXPECT_FALSE(result.IsClose(a)); } { // ModZNode Data::Vector3Type a(1, 2, 3); Data::NumberType b(0); auto output = TestMathFunction({ "Vector3: Source", "Number: Z" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(zero) }); auto result = a; result.SetZ(Data::ToVectorFloat(b)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); EXPECT_FALSE(result.IsClose(a)); } #if ENABLE_EXTENDED_MATH_SUPPORT { // MultiplyAdd Data::Vector3Type a(2, 2, 2); Data::Vector3Type b(3, 3, 3); Data::Vector3Type c(4, 4, 4); auto result = a.GetMadd(b, c); auto output = TestMathFunction({ "Vector3: A", "Vector3: B", "Vector3: C" }, { Datum(a), Datum(b), Datum(c) }, { "Result: Vector3" }, { Datum(a) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif { // MultiplyByNumber Data::Vector3Type a(1, 2, 3); Data::NumberType b(3.0); auto result = a * Data::ToVectorFloat(b); auto output = TestMathFunction({ "Vector3: Source", "Number: Multiplier" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByVector Data::Vector3Type a(1, 1, 1); Data::Vector3Type b(2, 2, 2); Data::Vector3Type c = a * b; auto output = TestMathFunction({ "Vector3: Source", "Vector3: Multiplier" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // Negate Data::Vector3Type source = one; auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(zero) }); auto result = -source; EXPECT_TRUE(result.IsClose(*output[0].GetAs())); source = negativeOne; output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(zero) }); result = -source; EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Normalize Data::Vector3Type source = one; auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(zero) }); auto result = source.GetNormalizedSafe(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // NormalizeWithLength Data::Vector3Type source = one; auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Normalized: Vector3", "Length: Number" }, { Datum(zero), Datum(0) }); auto result = source.NormalizeSafeWithLength(); EXPECT_TRUE(source.IsClose(*output[0].GetAs())); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[1].GetAs())); } #endif { // Project Data::Vector3Type a(1, 1, 1); Data::Vector3Type b(-2, -2, -2); auto output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(a) }); a.Project(b); EXPECT_TRUE(a.IsClose(*output[0].GetAs())); } { // Reciprocal Data::Vector3Type source(2, 2, 2); Data::Vector3Type result = source.GetReciprocal(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(source) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // Sine Data::Vector3Type source(.75, .75, .75); Data::Vector3Type result = source.GetSin(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(source) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // SineCosine Data::Vector3Type source(.75, .75, .75); Data::Vector3Type sine, cosine; source.GetSinCos(sine, cosine); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Sine: Vector3", "Cosine: Vector3" }, { Datum(source), Datum(source) }); EXPECT_TRUE(sine.IsClose(*output[0].GetAs())); EXPECT_TRUE(cosine.IsClose(*output[1].GetAs())); } #endif { // Slerp Data::Vector3Type from(0.f, 0.f, 0.f); Data::Vector3Type to(1.f, 1.f, 1.f); Data::NumberType t(0.5); auto slerp = from.Slerp(to, Data::ToVectorFloat(t)); auto outputSlerp = TestMathFunction({ "Vector3: From", "Vector3: To", "Number: T" }, { Datum(from), Datum(to), Datum(t) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(slerp.IsClose(*outputSlerp[0].GetAs())); auto lerp = from.Lerp(to, Data::ToVectorFloat(t)); auto outputLerp = TestMathFunction({ "Vector3: From", "Vector3: To", "Number: T" }, { Datum(from), Datum(to), Datum(t) }, { "Result: Vector3" }, { Datum(zero) }); EXPECT_TRUE(lerp.IsClose(*outputLerp[0].GetAs())); EXPECT_NE(lerp, slerp); EXPECT_NE(*outputLerp[0].GetAs(), *outputSlerp[0].GetAs()); } { // Subtract Data::Vector3Type a(1, 1, 1); Data::Vector3Type b(2, 2, 2); Data::Vector3Type c = a - b; auto output = TestMathFunction({ "Vector3: A", "Vector3: B" }, { Datum(a), Datum(b) }, { "Result: Vector3" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // GetElement const Data::Vector3Type source(1, 2, 3); for (int index = 0; index < 3; ++index) { float result = aznumeric_caster(Data::FromVectorFloat(source.GetElement(index))); auto output = TestMathFunction({ "Vector3: Source", "Number: Index" }, { Datum(source), Datum(index) }, { "Result: Number" }, { Datum(0) }); float outputNumber = aznumeric_caster(*output[0].GetAs()); SC_EXPECT_FLOAT_EQ(result, outputNumber); } } #if ENABLE_EXTENDED_MATH_SUPPORT { // XAxisCross Data::Vector3Type source(.75, .75, .75); auto result = source.XAxisCross(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(source) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // YAxisCross Data::Vector3Type source(.75, .75, .75); auto result = source.YAxisCross(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(source) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // ZAxisCross Data::Vector3Type source(.75, .75, .75); auto result = source.ZAxisCross(); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(source) }, { "Result: Vector3" }, { Datum(source) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #endif } // Test Vector3Node TEST_F(ScriptCanvasTestFixture, Vector4Nodes) { using namespace ScriptCanvas; using namespace Nodes; using namespace ScriptCanvas::Vector4Nodes; Data::Vector4Type zero(0, 0, 0, 0); Data::Vector4Type one(1.f, 1.f, 1.f, 1.f); Data::Vector4Type negativeOne(-1.f, -1.f, -1.f, -1.f); { // Absolute Data::Vector4Type source(-1, -1, -1., -1.); Data::Vector4Type absolute = source.GetAbs(); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(source) }, { "Result: Vector4" }, { Datum(source) }); EXPECT_TRUE(absolute.IsClose(*output[0].GetAs())); } { // Add Data::Vector4Type a(1, 1, 1, 1); Data::Vector4Type b(1, 1, 1, 1); Data::Vector4Type c = a + b; auto output = TestMathFunction({ "Vector4: A", "Vector4: B" }, { Datum(a), Datum(b) }, { "Result: Vector4" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // DivideByNumber Data::Vector4Type a(1, 2, 3, 4); Data::NumberType b(3.0); auto result = a / Data::ToVectorFloat(b); auto output = TestMathFunction({ "Vector4: Source", "Number: Divisor" }, { Datum(a), Datum(b) }, { "Result: Vector4" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // DivideByVector Data::Vector4Type a(1, 1, 1, 1); Data::Vector4Type b(2, 2, 2, 2); Data::Vector4Type c = a / b; auto output = TestMathFunction({ "Vector4: Numerator", "Vector4: Divisor" }, { Datum(a), Datum(b) }, { "Result: Vector4" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // Dot Data::Vector4Type a(1, 2, 3, 4); Data::Vector4Type b(-4, -3, -2, -1); auto result = a.Dot(b); auto output = TestMathFunction({ "Vector4: A", "Vector4: B" }, { Datum(a), Datum(b) }, { "Result: Number" }, { Datum(0.0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // Dot3 Data::Vector4Type a(1, 2, 3, 4); Data::Vector3Type b(-4, -3, -2); auto result = a.Dot3(b); auto output = TestMathFunction({ "Vector4: A", "Vector3: B" }, { Datum(a), Datum(b) }, { "Result: Number" }, { Datum(0.0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // From Element const Data::Vector4Type source(1, 2, 3, 4); for (int index = 0; index < 4; ++index) { auto result = source; result.SetElement(index, 5.0f); auto output = TestMathFunction({ "Vector4: Source", "Number: Index", "Number: Value" }, { Datum(source), Datum(index), Datum(5.0) }, { "Result: Vector4" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } } #endif { // FromValues Data::NumberType x(1); Data::NumberType y(2); Data::NumberType z(3); Data::NumberType w(4); auto result = Data::Vector4Type(Data::ToVectorFloat(x), Data::ToVectorFloat(y), Data::ToVectorFloat(z), Data::ToVectorFloat(w)); auto output = TestMathFunction({ "Number: X", "Number: Y", "Number: Z", "Number: W" }, { Datum(x), Datum(y), Datum(z), Datum(w) }, { "Result: Vector4", }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // GetElements auto source = Vector4Type(1, 2, 3, 4); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(source) }, { "X: Number", "Y: Number", "Z: Number", "W: Number" }, { Datum(0), Datum(0), Datum(0), Datum(0) }); SC_EXPECT_FLOAT_EQ(source.GetX(), aznumeric_caster(*output[0].GetAs())); SC_EXPECT_FLOAT_EQ(source.GetY(), aznumeric_caster(*output[1].GetAs())); SC_EXPECT_FLOAT_EQ(source.GetZ(), aznumeric_caster(*output[2].GetAs())); SC_EXPECT_FLOAT_EQ(source.GetW(), aznumeric_caster(*output[3].GetAs())); } #endif { // IsCloseNode Data::Vector4Type a(1, 1, 1, 1); Data::Vector4Type b(2, 2, 2, 2); Data::Vector4Type c(1.001, 1.001, 1.001, 1.001); bool resultFalse = a.IsClose(b); auto output = TestMathFunction({ "Vector4: A", "Vector4: B" }, { Datum(a), Datum(b) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); bool resultTrue = a.IsClose(b, Data::ToVectorFloat(2.1)); output = TestMathFunction({ "Vector4: A", "Vector4: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(2.1) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultTrue = a.IsClose(c); output = TestMathFunction({ "Vector4: A", "Vector4: B" }, { Datum(a), Datum(c) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultFalse = a.IsClose(b, Data::ToVectorFloat(0.9)); output = TestMathFunction({ "Vector4: A", "Vector4: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(0.9) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); } { // IsFinite Data::Vector4Type sourceFinite(1, 1, 1, 1); auto result = sourceFinite.IsFinite(); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(sourceFinite) }, { "Result: Boolean", }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } { // IsNormal Data::Vector4Type normal(1.f, 0.f, 0.f, 0.f); Data::Vector4Type nearlyNormal(1.001f, 0.0f, 0.0f, 0.f); Data::Vector4Type notNormal(10.f, 0.f, 0.f, 0.f); { auto result = normal.IsNormalized(); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(normal) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); } { auto result = nearlyNormal.IsNormalized(); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(nearlyNormal) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); result = nearlyNormal.IsNormalized(2.0f); output = TestMathFunction({ "Vector4: Source", "Number: Tolerance" }, { Datum(nearlyNormal), Datum(2.0f) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); } { auto result = notNormal.IsNormalized(); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(notNormal) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); result = notNormal.IsNormalized(12.0f); output = TestMathFunction({ "Vector4: Source", "Number: Tolerance" }, { Datum(notNormal), Datum(12.0f) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } } { // IsZero auto result = zero.IsZero(); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(zero) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); result = one.IsZero(); output = TestMathFunction({ "Vector4: Source" }, { Datum(one) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } { // Length Data::Vector4Type source(1, 2, 3, 4); auto result = source.GetLength(); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // LengthReciprocal Data::Vector4Type source(1, 2, 3, 4); auto result = source.GetLengthReciprocal(); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // LengthSquared Data::Vector4Type source(1, 2, 3, 4); auto result = source.GetLengthSq(); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // ModXNode Data::Vector4Type a(1, 2, 3, 4); Data::NumberType b(0); auto output = TestMathFunction({ "Vector4: Source", "Number: X" }, { Datum(a), Datum(b) }, { "Result: Vector4" }, { Datum(zero) }); auto result = a; result.SetX(Data::ToVectorFloat(b)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); EXPECT_FALSE(result.IsClose(a)); } { // ModYNode Data::Vector4Type a(1, 2, 3, 4); Data::NumberType b(0); auto output = TestMathFunction({ "Vector4: Source", "Number: Y" }, { Datum(a), Datum(b) }, { "Result: Vector4" }, { Datum(zero) }); auto result = a; result.SetY(Data::ToVectorFloat(b)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); EXPECT_FALSE(result.IsClose(a)); } { // ModZNode Data::Vector4Type a(1, 2, 3, 4); Data::NumberType b(0); auto output = TestMathFunction({ "Vector4: Source", "Number: Z" }, { Datum(a), Datum(b) }, { "Result: Vector4" }, { Datum(zero) }); auto result = a; result.SetZ(Data::ToVectorFloat(b)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); EXPECT_FALSE(result.IsClose(a)); } { // ModWNode Data::Vector4Type a(1, 2, 3, 4); Data::NumberType b(0); auto output = TestMathFunction({ "Vector4: Source", "Number: W" }, { Datum(a), Datum(b) }, { "Result: Vector4" }, { Datum(zero) }); auto result = a; result.SetW(Data::ToVectorFloat(b)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); EXPECT_FALSE(result.IsClose(a)); } { // MultiplyByNumber Data::Vector4Type a(1, 2, 3, 4); Data::NumberType b(3.0); auto result = a * Data::ToVectorFloat(b); auto output = TestMathFunction({ "Vector4: Source", "Number: Multiplier" }, { Datum(a), Datum(b) }, { "Result: Vector4" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByVector Data::Vector4Type a(1, 1, 1, 1); Data::Vector4Type b(2, 2, 2, 2); Data::Vector4Type c = a * b; auto output = TestMathFunction({ "Vector4: Source", "Vector4: Multiplier" }, { Datum(a), Datum(b) }, { "Result: Vector4" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // Negate Data::Vector4Type source = one; auto output = TestMathFunction({ "Vector4: Source" }, { Datum(source) }, { "Result: Vector4" }, { Datum(zero) }); auto result = -source; EXPECT_TRUE(result.IsClose(*output[0].GetAs())); source = negativeOne; output = TestMathFunction({ "Vector4: Source" }, { Datum(source) }, { "Result: Vector4" }, { Datum(zero) }); result = -source; EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Normalize Data::Vector4Type source = one; auto output = TestMathFunction({ "Vector4: Source" }, { Datum(source) }, { "Result: Vector4" }, { Datum(zero) }); auto result = source.GetNormalizedSafe(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // NormalizeWithLength Data::Vector4Type source = one; auto output = TestMathFunction({ "Vector4: Source" }, { Datum(source) }, { "Normalized: Vector4", "Length: Number" }, { Datum(zero), Datum(0) }); auto result = source.NormalizeSafeWithLength(); EXPECT_TRUE(source.IsClose(*output[0].GetAs())); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[1].GetAs())); } #endif { // Reciprocal Data::Vector4Type source(2, 2, 2, 2); Data::Vector4Type result = source.GetReciprocal(); auto output = TestMathFunction({ "Vector4: Source" }, { Datum(source) }, { "Result: Vector4" }, { Datum(source) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Subtract Data::Vector4Type a(1, 1, 1, 1); Data::Vector4Type b(2, 2, 2, 2); Data::Vector4Type c = a - b; auto output = TestMathFunction({ "Vector4: A", "Vector4: B" }, { Datum(a), Datum(b) }, { "Result: Vector4" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // GetElement const Data::Vector4Type source(1, 2, 3, 4); for (int index = 0; index < 4; ++index) { float result = aznumeric_caster(Data::FromVectorFloat(source.GetElement(index))); auto output = TestMathFunction({ "Vector4: Source", "Number: Index" }, { Datum(source), Datum(index) }, { "Result: Number" }, { Datum(0) }); float outputNumber = aznumeric_caster(*output[0].GetAs()); SC_EXPECT_FLOAT_EQ(result, outputNumber); } } // Missing Nodes: // HomogenizeNode // FromVector3AndNumberNode } // Test Vector4Node TEST_F(ScriptCanvasTestFixture, QuaternionNodes) { using namespace ScriptCanvas; using namespace Nodes; using namespace ScriptCanvas::QuaternionNodes; const Data::QuaternionType esclates(0.125, 0.25, 0.50, 0.75); const Data::QuaternionType negativeOne(-1.f, -1.f, -1.f, -1.f); const Data::QuaternionType one(1.f, 1.f, 1.f, 1.f); const Data::QuaternionType zero(0, 0, 0, 0); const Data::QuaternionType identity(Data::QuaternionType::CreateIdentity()); { // Add Data::QuaternionType a(1, 1, 1, 1); Data::QuaternionType b(1, 1, 1, 1); Data::QuaternionType c = a + b; auto output = TestMathFunction({ "Quaternion: A", "Quaternion: B" }, { Datum(a), Datum(b) }, { "Result: Quaternion" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // Conjugate Data::QuaternionType source = esclates; auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(source) }, { "Result: Quaternion" }, { Datum(zero) }); auto result = esclates.GetConjugate(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // DivideByNumber Data::QuaternionType a(1, 2, 3, 4); Data::NumberType b(3.0); auto result = a / Data::ToVectorFloat(b); auto output = TestMathFunction({ "Quaternion: Numerator", "Number: Divisor" }, { Datum(a), Datum(b) }, { "Result: Quaternion" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Dot Data::QuaternionType a(1, 2, 3, 4); Data::QuaternionType b(-4, -3, -2, -1); auto result = a.Dot(b); auto output = TestMathFunction({ "Quaternion: A", "Quaternion: B" }, { Datum(a), Datum(b) }, { "Result: Number" }, { Datum(0.0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // From AxisAngleDegrees const Vector3Type axis = Vector3Type(1, 1, 1).GetNormalized(); const float angle(2.0); auto result = QuaternionType::CreateFromAxisAngle(axis, AZ::DegToRad(angle)); auto output = TestMathFunction({ "Vector3: Axis", "Number: Degrees" }, { Datum(axis), Datum(angle) }, { "Result: Quaternion" }, { Datum(identity) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // From Element const Data::QuaternionType source(1, 2, 3, 4); for (int index = 0; index < 4; ++index) { auto result = source; result.SetElement(index, 5.0f); auto output = TestMathFunction({ "Quaternion: Source", "Number: Index", "Number: Value" }, { Datum(source), Datum(index), Datum(5.0) }, { "Result: Quaternion" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } } #endif { // FromMatrix3x3 const Matrix3x3Type matrix = Matrix3x3Type::CreateFromValue(3.0); auto result = QuaternionType::CreateFromMatrix3x3(matrix); auto output = TestMathFunction({ "Matrix3x3: Source" }, { Datum(matrix) }, { "Result: Quaternion" }, { Datum(identity) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromMatrix4x4 const Matrix4x4Type matrix = Matrix4x4Type::CreateFromValue(3.0); auto result = QuaternionType::CreateFromMatrix4x4(matrix); auto output = TestMathFunction({ "Matrix4x4: Source" }, { Datum(matrix) }, { "Result: Quaternion" }, { Datum(identity) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // FromTransform const TransformType transform = TransformType::CreateFromValue(3.0); auto result = QuaternionType::CreateFromTransform(transform); auto output = TestMathFunction({ "Transform: Source" }, { Datum(transform) }, { "Result: Quaternion" }, { Datum(identity) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // FromVector3 const Vector3Type vector3 = Vector3Type(3, 3, 3); auto result = QuaternionType::CreateFromVector3(vector3); auto output = TestMathFunction({ "Vector3: Source" }, { Datum(vector3) }, { "Result: Quaternion" }, { Datum(identity) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } // Note: This is just raw setting the elements to the value, it is not creating from axis and angle // There is another method which does create from axis angle. { // FromVector3AndValueNode const Vector3Type axis = Vector3Type(1, 1, 1).GetNormalized(); const float angle(2.0); auto result = QuaternionType::CreateFromVector3AndValue(axis, angle); auto output = TestMathFunction({ "Vector3: Imaginary", "Number: Real" }, { Datum(axis), Datum(angle) }, { "Result: Quaternion" }, { Datum(identity) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // GetElements auto source = QuaternionType(1, 2, 3, 4); auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(source) }, { "X: Number", "Y: Number", "Z: Number", "W: Number" }, { Datum(0), Datum(0), Datum(0), Datum(0) }); SC_EXPECT_FLOAT_EQ(source.GetX(), aznumeric_caster(*output[0].GetAs())); SC_EXPECT_FLOAT_EQ(source.GetY(), aznumeric_caster(*output[1].GetAs())); SC_EXPECT_FLOAT_EQ(source.GetZ(), aznumeric_caster(*output[2].GetAs())); SC_EXPECT_FLOAT_EQ(source.GetW(), aznumeric_caster(*output[3].GetAs())); } #endif { // InvertFullNode const QuaternionType source = QuaternionType::CreateFromVector3AndValue(AZ::Vector3(1, 1, 1), 3); auto result = source.GetInverseFull(); auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(source) }, { "Result: Quaternion" }, { Datum(identity) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // IsCloseNode Data::QuaternionType a(1, 1, 1, 1); Data::QuaternionType b(2, 2, 2, 2); Data::QuaternionType c(1.001, 1.001, 1.001, 1.001); bool resultFalse = a.IsClose(b); auto output = TestMathFunction({ "Quaternion: A", "Quaternion: B" }, { Datum(a), Datum(b) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); bool resultTrue = a.IsClose(b, Data::ToVectorFloat(2.1)); output = TestMathFunction({ "Quaternion: A", "Quaternion: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(2.1) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultTrue = a.IsClose(c); output = TestMathFunction({ "Quaternion: A", "Quaternion: B" }, { Datum(a), Datum(c) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(resultTrue, *output[0].GetAs()); resultFalse = a.IsClose(b, Data::ToVectorFloat(0.9)); output = TestMathFunction({ "Quaternion: A", "Quaternion: B", "Number: Tolerance" }, { Datum(a), Datum(b), Datum(0.9) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(resultFalse, *output[0].GetAs()); } { // IsFinite Data::QuaternionType sourceFinite(1, 1, 1, 1); auto result = sourceFinite.IsFinite(); auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(sourceFinite) }, { "Result: Boolean", }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } { // IsIdentityNode auto result = identity.IsIdentity(); auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(identity) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); result = zero.IsIdentity(); output = TestMathFunction({ "Quaternion: Source" }, { Datum(zero) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } { // IsZero auto result = zero.IsZero(); auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(zero) }, { "Result: Boolean" }, { Datum(false) }); EXPECT_EQ(result, *output[0].GetAs()); result = one.IsZero(); output = TestMathFunction({ "Quaternion: Source" }, { Datum(one) }, { "Result: Boolean" }, { Datum(true) }); EXPECT_EQ(result, *output[0].GetAs()); } { // Length Data::QuaternionType source(1, 2, 3, 4); auto result = source.GetLength(); auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // LengthReciprocal Data::QuaternionType source(1, 2, 3, 4); auto result = source.GetLengthReciprocal(); auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // LengthSquared Data::QuaternionType source(1, 2, 3, 4); auto result = source.GetLengthSq(); auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // Lerp Data::QuaternionType from(zero); Data::QuaternionType to(Data::QuaternionType::CreateFromAxisAngle(AZ::Vector3(1, 1, 1).GetNormalized(), 0.75)); Data::NumberType t(0.5); auto result = from.Lerp(to, Data::ToVectorFloat(t)); auto output = TestMathFunction({ "Quaternion: From", "Quaternion: To", "Number: T" }, { Datum(from), Datum(to), Datum(t) }, { "Result: Quaternion" }, { Datum(identity) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByNumber Data::QuaternionType a(1, 2, 3, 4); Data::NumberType b(3.0); auto result = a * Data::ToVectorFloat(b); auto output = TestMathFunction({ "Quaternion: Source", "Number: Multiplier" }, { Datum(a), Datum(b) }, { "Result: Quaternion" }, { Datum(zero) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // MultiplyByRotation Data::QuaternionType a(1, 1, 1, 1); Data::QuaternionType b(2, 2, 2, 2); Data::QuaternionType c = a * b; auto output = TestMathFunction({ "Quaternion: A", "Quaternion: B" }, { Datum(a), Datum(b) }, { "Result: Quaternion" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // Negate Data::QuaternionType source = one; auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(source) }, { "Result: Quaternion" }, { Datum(zero) }); auto result = -source; EXPECT_TRUE(result.IsClose(*output[0].GetAs())); source = negativeOne; output = TestMathFunction({ "Quaternion: Source" }, { Datum(source) }, { "Result: Quaternion" }, { Datum(zero) }); result = -source; EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Normalize Data::QuaternionType source = one; auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(source) }, { "Result: Quaternion" }, { Datum(zero) }); auto result = source.GetNormalized(); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // NormalizeWithLength Data::QuaternionType source = one; auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(source) }, { "Normalized: Quaternion", "Length: Number" }, { Datum(zero), Datum(0) }); auto result = source.NormalizeWithLength(); EXPECT_TRUE(source.IsClose(*output[0].GetAs())); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[1].GetAs())); } #endif { // RotationXDegreesNode auto output = TestMathFunction({ "Number: Degrees" }, { Datum(30) }, { "Result: Quaternion" }, { Datum(identity) }); auto result = QuaternionType::CreateRotationX(AZ::DegToRad(30)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // RotationYDegreesNode auto output = TestMathFunction({ "Number: Degrees" }, { Datum(30) }, { "Result: Quaternion" }, { Datum(identity) }); auto result = QuaternionType::CreateRotationY(AZ::DegToRad(30)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // RotationZDegreesNode auto output = TestMathFunction({ "Number: Degrees" }, { Datum(30) }, { "Result: Quaternion" }, { Datum(identity) }); auto result = QuaternionType::CreateRotationZ(AZ::DegToRad(30)); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // ShortestArcNode Data::Vector3Type from(-1, 0, 0); Data::Vector3Type to(1, 1, 1); auto result = QuaternionType::CreateShortestArc(from, to); auto output = TestMathFunction({ "Vector3: From", "Vector3: To" }, { Datum(from), Datum(to) }, { "Result: Quaternion" }, { Datum(identity) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Slerp Data::QuaternionType from(zero); Data::QuaternionType to(Data::QuaternionType::CreateFromAxisAngle(AZ::Vector3(1, 1, 1).GetNormalized(), 0.75)); Data::NumberType t(0.5); auto result = from.Slerp(to, Data::ToVectorFloat(t)); auto output = TestMathFunction({ "Quaternion: From", "Quaternion: To", "Number: T" }, { Datum(from), Datum(to), Datum(t) }, { "Result: Quaternion" }, { Datum(identity) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // SquadNode Data::QuaternionType from(Data::QuaternionType::CreateFromAxisAngle(Vector3Type(-1, 0, 0).GetNormalized(), 0.75)); Data::QuaternionType to(Data::QuaternionType::CreateFromAxisAngle(Vector3Type(1, 1, 1).GetNormalized(), 0.75)); Data::QuaternionType out(Data::QuaternionType::CreateFromAxisAngle(Vector3Type(1, 0, 1).GetNormalized(), 0.75)); Data::QuaternionType in(Data::QuaternionType::CreateFromAxisAngle(Vector3Type(1, 1, 0).GetNormalized(), 0.75)); Data::NumberType t(0.5); auto result = from.Squad(to, in, out, Data::ToVectorFloat(t)); auto output = TestMathFunction({ "Quaternion: From", "Quaternion: To", "Quaternion: In", "Quaternion: Out", "Number: T" }, { Datum(from), Datum(to), Datum(in), Datum(out), Datum(t) }, { "Result: Quaternion" }, { Datum(identity) }); EXPECT_TRUE(result.IsClose(*output[0].GetAs())); } { // Subtract Data::QuaternionType a(1, 1, 1, 1); Data::QuaternionType b(2, 2, 2, 2); Data::QuaternionType c = a - b; auto output = TestMathFunction({ "Quaternion: A", "Quaternion: B" }, { Datum(a), Datum(b) }, { "Result: Quaternion" }, { Datum(a) }); EXPECT_TRUE(c.IsClose(*output[0].GetAs())); } { // ToAngleDegreesNode Data::QuaternionType source(Data::QuaternionType::CreateFromAxisAngle(Vector3Type(-1, 0, 0).GetNormalized(), 0.75)); auto output = TestMathFunction({ "Quaternion: Source" }, { Datum(source) }, { "Result: Number" }, { Datum(0) }); float result = AZ::RadToDeg(source.GetAngle()); SC_EXPECT_FLOAT_EQ(result, aznumeric_caster(*output[0].GetAs())); } { // CreateFromEulerAnglesNode Data::QuaternionType baseValue = AZ::ConvertEulerDegreesToQuaternion(AZ::Vector3(1.0f,2.0f,3.0f)); auto output = TestMathFunction({ "Number: Pitch", "Number: Roll", "Number: Yaw" }, { Datum(1.0f), Datum(2.0f), Datum(3.0f) }, { "Result: Quaternion" }, { Datum(AZ::Quaternion()) }); EXPECT_TRUE(baseValue.IsClose(*output[0].GetAs())); } #if ENABLE_EXTENDED_MATH_SUPPORT { // GetElement const Data::QuaternionType source(1, 2, 3, 4); for (int index = 0; index < 4; ++index) { float result = aznumeric_caster(Data::FromVectorFloat(source.GetElement(index))); auto output = TestMathFunction({ "Quaternion: Source", "Number: Index" }, { Datum(source), Datum(index) }, { "Result: Number" }, { Datum(0) }); float outputNumber = aznumeric_caster(*output[0].GetAs()); SC_EXPECT_FLOAT_EQ(result, outputNumber); } } #endif // Missing Units Tests: // ModXNode // ModYNode // ModZNode // ModWNode // ToImaginary } // Test QuaternionNodes TEST_F(ScriptCanvasTestFixture, RandomNodes) { using namespace ScriptCanvas; const int testIterations = 10; auto transform = Data::TransformType::CreateFromRows(Data::Vector4Type(1.f, 0.f, 0.f, 0.f), Data::Vector4Type(0.f, 1.f, 0.f, 0.f), Data::Vector4Type(0.f, 0.f, 1.f, 0.f)); { // RandomColor const Data::ColorType min(0.1f, 0.3f, 0.5f, 0.7f); const Data::ColorType max(0.2f, 0.4f, 0.6f, 0.8f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Color: Min", "Color: Max" }, { Datum(min), Datum(max) }, { "Result: Color" }, { Datum(Data::ColorType()) }); auto value = *output[0].GetAs(); EXPECT_TRUE(value.GetR() >= 0.1f && value.GetR() <= 0.2f); EXPECT_TRUE(value.GetG() >= 0.3f && value.GetG() <= 0.4f); EXPECT_TRUE(value.GetB() >= 0.5f && value.GetB() <= 0.6f); EXPECT_TRUE(value.GetA() >= 0.7f && value.GetA() <= 0.8f); } } { // RandomGrayscale const float minColor = 96.f; const float maxColor = 192.f; const float minColorNormalized = minColor / 255.f; const float maxColorNormalized = maxColor / 255.f; for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Number: Min", "Number: Max" }, { Datum(minColor), Datum(maxColor) }, { "Result: Color" }, { Datum(Data::ColorType()) }); auto value = *output[0].GetAs(); EXPECT_TRUE((value.GetR() == value.GetG()) && value.GetR() == value.GetB()); EXPECT_TRUE(value.GetR() >= minColorNormalized && value.GetR() <= maxColorNormalized); } } { // RandomInteger for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Number: Min", "Number: Max" }, { Datum(9), Datum(99) }, { "Result: Number" }, { Datum(Data::NumberType()) }); auto value = *output[0].GetAs(); EXPECT_TRUE(value >= 9); EXPECT_TRUE(value <= 99); } } { // RandomNumber for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Number: Min", "Number: Max" }, { Datum(9.f), Datum(99.f) }, { "Result: Number" }, { Datum(Data::NumberType()) }); auto value = *output[0].GetAs(); EXPECT_TRUE(value >= 9); EXPECT_TRUE(value <= 99); } } { // RandomPointInBox Data::Vector3Type dimensions(10.f, 100.f, 1000.f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Vector3: Dimensions" }, { Datum(dimensions) }, { "Result: Vector3" }, { Datum(Data::Vector3Type()) }); auto value = *output[0].GetAs(); EXPECT_TRUE((value.GetX() >= -5.f) && (value.GetX() <= 5.f)); EXPECT_TRUE((value.GetY() >= -50.f) && (value.GetY() <= 50.f)); EXPECT_TRUE((value.GetZ() >= -500.f) && (value.GetZ() <= 500.f)); } } { // RandomPointOnCircle Data::NumberType radius(10.f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Number: Radius" }, { Datum(radius) }, { "Result: Vector3" }, { Datum(Data::Vector3Type()) }); auto value = *output[0].GetAs(); float lenSq = value.GetLengthSq(); SC_EXPECT_FLOAT_EQ(lenSq, aznumeric_cast(radius * radius)); } } { // RandomPointInCone Data::NumberType radius(10.f); Data::NumberType angleInDegrees(45.f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Number: Radius", "Number: Angle" }, { Datum(radius), Datum(angleInDegrees) }, { "Result: Vector3" }, { Datum(Data::Vector3Type()) }); auto value = *output[0].GetAs(); float dot = value.Dot(Data::Vector3Type(0.f, 0.f, 1.f)); EXPECT_TRUE(dot >= 0.f); EXPECT_TRUE(dot <= radius); } } { // RandomPointInCylinder Data::NumberType radius(10.f); Data::NumberType height(100.f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Number: Radius", "Number: Height" }, { Datum(radius), Datum(height) }, { "Result: Vector3" }, { Datum(Data::Vector3Type()) }); auto value = *output[0].GetAs(); float lenXYsq = Data::Vector2Type(value.GetX(), value.GetY()).GetLengthSq(); EXPECT_TRUE(lenXYsq <= (radius * radius)); float dotZ = value.Dot(Data::Vector3Type(0.f, 0.f, 1.f)); EXPECT_TRUE(dotZ >= -(0.5f * height)); EXPECT_TRUE(dotZ <= (0.5f * height)); } } { // RandomPointInCircle Data::NumberType radius(10.f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Number: Radius" }, { Datum(radius) }, { "Result: Vector3" }, { Datum(Data::Vector3Type()) }); auto value = *output[0].GetAs(); float dot = value.Dot(Data::Vector3Type(0.f, 0.f, 1.f)); float lenSq = value.GetLengthSq(); EXPECT_TRUE(dot == 0.f); EXPECT_TRUE(lenSq <= (radius * radius)); } } { // RandomPointInSphere Data::NumberType radius(10.f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Number: Radius" }, { Datum(radius) }, { "Result: Vector3" }, { Datum(Data::Vector3Type()) }); auto value = *output[0].GetAs(); float lenSq = value.GetLengthSq(); EXPECT_TRUE(lenSq <= (radius * radius)); } } { // RandomPointInSquare Data::Vector2Type dimensions(10.f, 100.f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Vector2: Dimensions" }, { Datum(dimensions) }, { "Result: Vector3" }, { Datum(Data::Vector3Type()) }); auto value = *output[0].GetAs(); float dot = value.Dot(Data::Vector3Type(0.f, 0.f, 1.f)); EXPECT_TRUE(dot == 0.f); EXPECT_TRUE((value.GetX() >= -(0.5f * dimensions.GetX())) && (value.GetX() <= (0.5f * dimensions.GetX()))); EXPECT_TRUE((value.GetY() >= -(0.5f * dimensions.GetY())) && (value.GetY() <= (0.5f * dimensions.GetY()))); } } { // RandomPointOnSphere Data::NumberType radius(10.f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Number: Radius" }, { Datum(radius) }, { "Result: Vector3" }, { Datum(Data::Vector3Type()) }); auto value = *output[0].GetAs(); float lenSq = value.GetLengthSq(); SC_EXPECT_FLOAT_EQ(lenSq, aznumeric_cast(radius * radius)); } } { // RandomUnitVector2 for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({}, {}, { "Result: Vector2" }, { Datum(Data::Vector2Type()) }); auto value = *output[0].GetAs(); float lenSq = value.GetLengthSq(); SC_EXPECT_FLOAT_EQ(lenSq, 1.f); } } { // RandomUnitVector3 for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({}, {}, { "Result: Vector3" }, { Datum(Data::Vector3Type()) }); auto value = *output[0].GetAs(); float lenSq = value.GetLengthSq(); SC_EXPECT_FLOAT_EQ(lenSq, 1.f); } } { // RandomVector2 const Data::Vector2Type min(0.1f, 0.3f); const Data::Vector2Type max(0.2f, 0.4f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Vector2: Min", "Vector2: Max" }, { Datum(min), Datum(max) }, { "Result: Vector2" }, { Datum(Data::Vector2Type()) }); auto value = *output[0].GetAs(); EXPECT_TRUE(value.GetX() >= min.GetX() && value.GetX() <= max.GetX()); EXPECT_TRUE(value.GetY() >= min.GetY() && value.GetY() <= max.GetY()); } } { // RandomVector3 const Data::Vector3Type min(0.1f, 0.3f, 0.5f); const Data::Vector3Type max(0.2f, 0.4f, 0.6f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Vector3: Min", "Vector3: Max" }, { Datum(min), Datum(max) }, { "Result: Vector3" }, { Datum(Data::Vector3Type()) }); auto value = *output[0].GetAs(); EXPECT_TRUE(value.GetX() >= min.GetX() && value.GetX() <= max.GetX()); EXPECT_TRUE(value.GetY() >= min.GetY() && value.GetY() <= max.GetY()); EXPECT_TRUE(value.GetZ() >= min.GetZ() && value.GetZ() <= max.GetZ()); } } { // RandomVector4 const Data::Vector4Type min(0.1f, 0.3f, 0.5f, 0.7f); const Data::Vector4Type max(0.2f, 0.4f, 0.6f, 0.8f); for (int i = 0; i < testIterations; ++i) { auto output = TestMathFunction({ "Vector4: Min", "Vector4: Max" }, { Datum(min), Datum(max) }, { "Result: Vector4" }, { Datum(Data::Vector4Type()) }); auto value = *output[0].GetAs(); EXPECT_TRUE(value.GetX() >= min.GetX() && value.GetX() <= max.GetX()); EXPECT_TRUE(value.GetY() >= min.GetY() && value.GetY() <= max.GetY()); EXPECT_TRUE(value.GetZ() >= min.GetZ() && value.GetZ() <= max.GetZ()); EXPECT_TRUE(value.GetW() >= min.GetW() && value.GetW() <= max.GetW()); } } } // Test RandomNodes TEST_F(ScriptCanvasTestFixture, MathOperations_Graph) { RunUnitTestGraph("LY_SC_UnitTest_MathOperations"); } TEST_F(ScriptCanvasTestFixture, MathCustom_Graph) { RunUnitTestGraph("LY_SC_UnitTest_UnitTest_MathCustom"); }