바람과 같은 물리적 효과는 3D 세상의 벡터 필드: 영역에 의해 모델링되며 이 안에서는 정의된 힘이 물리적 오브젝트에 가해져 이를 특정한 방향으로 날리거나 밀어냅니다.
다음 중 하나의 방법으로 벡터 필드를 설정할 수 있습니다.
사전 작성된 엔티티 구성요소 및 스크립트 모듈 세트를 사용하여 Stingray 편집기 내부에서만. Stingray 편집기에서 벡터 필드 설정을 참조하십시오.
자체 사용자 정의된 Lua 스크립트 내에서. Lua에서 벡터 필드 설정을 참조하십시오.
일단 벡터 필드를 설정하고 게임 표준에서 활성화했다면 게임 내의 가시적인 오브젝트에 적용할 수 있습니다. 게임 오브젝트에 벡터 필드 적용을 참조하십시오.
Stingray 편집기에서 벡터 필드 설정하는 방법:
벡터 필드 효과를 나타내는 새 빈 엔티티를 생성합니다. 새 엔티티 자산 생성을 참조하십시오. Asset Browser에서 새 자산을 선택합니다.
한 수준에서 엔티티를 생성합니다. 벡트 필드의 효과를 볼 수 있도록 준비된 입자 효과가 아직 없는 경우 이를 설정하여 지금 생성할 수도 있습니다.
변환 구성요소를 엔티티에 추가합니다. 이는 3D 공간에서 벡터 필드의 배치, 방향 및 범위를 나타내게 됩니다.
표준에서 바람 효과가 중심이 되도록 하고 싶은 곳으로 엔티티를 이동하고, 벡터 필드가 다루도록 할 볼륨을 포괄하도록 엔티티를 조정하고, 필요한 경우 엔티티를 회전하여 바람의 방향을 제어합니다.
달성하려는 효과에 따라 사용 가능한 벡터 필드 구성요소 중 하나를 엔티티에 추가합니다.
효과의 강도와 속도를 제어하기 위해 구성요소의 특성을 구성합니다.
Effect 설정 참고: 입자 시스템 등 게임 내의 무언가에 벡터 필드가 영향을 미치도록 하고자 할 때마다 이 효과를 참조하는 방법으로 효과 이름을 사용하게 됩니다.
엔티티에 스크립트 구성요소를 추가합니다. Script 특성을 코어 리소스 폴더의, 위에 열거된 효과에 부합하도록 사전 작성된 다음 스크립트 중 하나를 가리키도록 설정합니다.
Lua에서 벡터 필드를 사용하려면 우선 .vector_field 리소스 파일에서 효과를 정의해야 합니다. 자세한 내용은 아래의 벡터 필드 효과 정의를 참조하십시오.
각 벡터 필드 효과는 stingray.VectorField 오브젝트에 의해 Lua에서 표현됩니다. 이러한 오브젝트 중 하나를 가져오려면 stingray.World.vector_field ()를 호출하여 "wind"와 같이 효과를 칭할 때 사용할 이름을 넘겨줍니다.
vectorfield.add( )를 통해 벡터 필드에 새 효과를 추가할 수 있습니다. 이 호출에서 효과를 정의하는 .vector_field 리소스의 이름을 입력하여 해당 효과에 대한 매개변수를 설정할 수도 있습니다. 또한 VectorField.change() 및 VectorField.remove()를 사용하여 효과를 변경하거나 제거할 수 있습니다.
벡터 필드가 스크립트 동작에 영향을 주도록 하려면 VectorField.evaluate()를 사용하여 일부 위치에서 벡터 필드를 평가할 수 있습니다.
현재 Stingray에서는 벡터 필드를 입자 효과나 동적 물리 액터에 적용할 수 있습니다.
예를 들어, 피어오르는 연기 기둥이 바람 방향으로 날려서 사라지는 효과를 원할 수도 있습니다.
벡터 필드가 입자 효과에 영향을 주도록 만드는 방법:
입자 효과에 Acceleration > Vector Field Wind 제어기를 추가합니다.
제어기의 Vector Field 특성을 벡터 필드 효과의 이름으로 설정합니다.
엔티티 구성요소를 사용해 벡터 필드를 설정한 경우 이는 벡터 필드 구성요소의 Effect 설정과 일치해야 합니다.
Lua에서 벡터 필드를 설정하는 경우 이는 stingray.World.vector_field()에 전달한 이름과 일치해야 합니다.
예를 들어, 강한 바람으로 인해 해당 수준의 가벼운 오브젝트가 지속적으로 흩날리게 하거나 대규모의 폭발을 트리거해 오브젝트를 해당 영역 밖으로 날려 버리고 싶을 수도 있습니다.
풍력을 적용하려면 Lua를 사용해야 하지만 엔티티와 구성요소를 사용해 바람 효과도 설정해야 합니다.
기본적으로 풍력은 물리적 오브젝트를 깨우지 않습니다. 바람이 해당 수준의 모든 오브젝트를 깨울 수 있다면 성능에 문제가 발생할 것입니다. 즉, 큰 폭발을 트리거하더라도 이미 잠들어 있는 모든 동적 액터에는 영향을 주지 않습니다. 이를 해결하기 위해 stingray.PhysicsWorld.wake_actors()를 사용하여 바람이나 폭발에 의해 영향을 받아야 하는 모든 동적 오브젝트가 깨어난 상태에서 벡터 필드의 풍력을 받도록 이러한 오브젝트를 깨울 수 있습니다.
벡터 필드가 물리적 오브젝트에 영향을 미치도록 하려면 stingray.PhysicsWorld.apply_wind() 함수를 호출해 벡터 필드에서 물리적 오브젝트로 풍력을 적용합니다. 이 함수에 적용하고자 하는 벡터 필드의 이름을 넘겨줍니다. 엔티티 구성요소를 사용해 벡터 필드를 설정한 경우 이는 벡터 필드 구성요소의 Effect 설정과 일치해야 합니다. Lua에서 벡터 필드를 설정하는 경우 이는 stingray.World.vector_field()에 전달한 이름과 일치해야 합니다.
참고: 계속적인 바람의 힘을 제공하려면 모든 프레임에 PhysicsWorld.apply_wind()를 호출해야 합니다.
벡터 필드 효과는 .vector_field 파일에 정의되어 있습니다. 이는 입력 위치에서 출력 바람을 계산하는 HLSL 유형의 언어로 작성되어 있습니다.
간단한 예:
const float4 value = float4(0,0,0,0); struct vf_in { float4 position : CHANNEL0; float4 wind : CHANNEL1; }; struct vf_out { float4 wind : CHANNEL1; }; void global(in vf_in in, out vf_out out) { out.wind = in.wind + value; }
이 효과는 공간의 각 점에 대해 상수 값을 반환합니다. 기본적으로 value는 (0,0,0,0), 즉 바람이 전혀 없는 것으로 설정되지만, 재생될 때 스크립트가 효과에 정의된 전역 변수를 덮어 쓸 수 있습니다. 따라서 스크립트가 이를 다음과 같이 재생할 수 있습니다.
VectorField.add(vf, "global", {value = Vector3(2,0,0)})
이렇게 하면 전체 수준에 x 방향으로 2m/s의 바람이 생성됩니다.
효과의 마지막 행 참고:
out.wind = in.wind + value;
이는 효과가 적용되기 전에 존재하는 모든 바람에 이 효과를 통한 바람이 추가되는 것을 의미합니다. 효과가 스택되도록 하기 위해 효과 코드에 항상 이 마지막 행을 넣어야 합니다. 이러면 사용자가 여러 바람 효과를 재생하는 경우 보려는 효과는 이러한 개별 바람 효과의 총합이 됩니다.
벡터 필드 언어는 HLSL처럼 보이지만 실제로는 표시하는 방법에 매우 엄격한 완전히 별개의 파서에 의해 구문 분석됩니다. 전역 변수는 이 예에서와 같이 정의되어야 합니다. 단 하나의 함수만 있어야 하며 예와 같이 in 및 out 매개변수로 이루어져야 합니다(원하는 대로 함수를 호출할 수는 있음). HLSL에서 작동한다는 것이 이 언어에서 반드시 작동해야 함을 의미하지는 않습니다.
구조 정의 vf_in 및 vf_out은 벡터 필드 효과의 입력 및 출력 매개변수를 정의합니다. 이들은 예와 같이 표시되지만 원하는 경우 다른 이름을 사용할 수 있습니다.
기본적으로 벡터 필드 효과는 표준의 어디에든 적용됩니다. 제한된 영역에만 적용되는 벡터 필드 효과를 만들려면 해당 영역 외부의 점에 대해 (0,0,0,0)을 반환하도록 명시적으로 효과를 작성해야 합니다.
이전 효과처럼 작동하지만 특정 구에만 적용되는 효과를 작성해보겠습니다. (구조 정의는 모든 효과에서 동일하므로 나머지 예에서는 그대로 두겠습니다.)
const float4 value = float4(0,0,0,0); const float4 center = float4(0,0,0,0); const float4 radius = float4(1,1,1,1); void global_sphere(in vf_in in, out vf_out out) { float4 r = in.position - center; float4 distance = dot(radius, radius) - dot(r,r); float4 wind = select_gt_0(distance, value); out.wind = in.wind + wind; }
여기서 distance는 해당 항목이 구 안에 있는 경우 >0으로, 구 밖에 있는 경우 <0으로 계산합니다. 그런 다음 select_gt_0() 함수를 사용하여 distance > 0인 경우 value에 wind를 설정하고 그렇지 않은 경우에는 value를 (0,0,0,0)으로 설정합니다.
효과를 재생할 때 효과의 브로드페이즈(Broadphase) 제거에 사용되는 효과에 AABB를 지정합니다. 최상의 결과를 얻으려면 이 AABB는 효과 함수가 0이 아닌 영역과 일치해야 합니다. 그렇지 않으면 비효율적인 제거를 얻게 됩니다.
특별 상수 time을 사용하여 시간 의존 효과를 생성할 수 있습니다. 이 상수는 자동으로 벡터 필드 시스템에 의해 효과가 재생된 시점부터 해당 시점까지의 시간으로 설정됩니다. 다음은 이를 사용하여 사인곡선(sinusodial) 바람을 구현하는 예입니다.
const float4 amplitude = float4(1,1,1,0); const float4 wave_vector = float4(1,0,0,0); const float4 frequency = float4(1,1,1,0); const float4 phase = float4(0,0,0,0); const float4 time = float4(0,0,0,0); void sine(in vf_in in, out vf_out out) { out.wind = in.wind + amplitude * sin( dot(wave_vector, in.position) + frequency*time + phase ); }
벡터 언어는 루프 또는 If 문을 지원하지 않습니다. 다음 표현식을 사용할 수 있습니다.
+ - * /
구성요소별 더하기, 빼기, 곱하기, 나누기.
dot(a, b)
a 및 b의 내적을 계산하고 이를 결과의 모든 구성요소에 할당합니다.
cross(a, b)
a 및 b의 외적을 계산합니다. 외적의 w 구성요소는 항상 0입니다.
select_gt_0(a, b)
a > 0인 구성요소에 b를 갖고 다른 구성요소에 0을 갖는 벡터를 반환합니다.
normalize(a)
정규화된 값을 반환합니다.
sin(a)
구성요소에서 a의 각 구성요소의 사인이 있는 벡터를 반환합니다.
벡터 필드 정의에 대한 일부 추가적인 예는 core/entities/vector_fields에서 .vector_field 파일을 참조하십시오. 이러한 정의는 Stingray 편집기의 벡터 필드 설정에서 설명된 벡터 필드 엔티티와 스크립트의 기초를 제공하지만 사용자가 Lua에서 생성하는 VectorField 오브젝트에 그러한 효과를 추가하는 데 사용할 수도 있습니다.