1#include "VectorFieldSystem.h"
2#include "VectorFieldRenderer.h"
5#include "ViewContext.h"
6#include "Resources/MaterialManager.h"
7#include "Resources/ModelManager.h"
8#include "Systems/ComponentSystem.h"
9#include "Systems/Core/CameraSystem.h"
10#include "Systems/Core/SceneSystem.h"
11#include "Systems/Core/TransformSystem.h"
13#include "Math/RayBoxIntersection.h"
19namespace Cogs::Core::VectorField
29 if (!entityComponent)
return false;
32 if (component != entityComponent)
35 Cogs::Geometry::BoundingBox myBounds;
36 if (
getBounds(context, myBounds, ignoreVisibility)) {
51 if (!ignoreVisibility) {
53 if (sceneComp->
visible ==
false)
return false;
57 auto &worldMatrix = context->transformSystem->getLocalToWorld(transComp);
59 bounds.min = glm::vec3(FLT_MAX);
60 bounds.max = glm::vec3(FLT_MIN);
62 if(component->positions)
63 count = component->positions.
size();
64 for(
size_t i=0; i<count; i++){
65 glm::vec3 p = component->positions[i];
66 glm::vec3 d = component->directions[i];
68 if(component->animation){
69 float ih = fmod(sin(i/(
float)count)*43758.5453f, 1.0f);
70 float t = fmod(data.time+ih, 1.0f);
71 if(component->animation && component->animationUseSpeed)
72 t = data.time_offset_speed.size() ? data.time_offset_speed[i] : 0.0f;
73 float anim_scale = component->scale*component->length*component->animationScale;
74 pos += d*anim_scale*(t-0.5f);
77 glm::vec4 pos_w = worldMatrix*glm::vec4(pos, 1.0);
78 pos = glm::vec3(pos_w);
79 if(!std::isnan(pos.x)) bounds.min.x = std::min(bounds.min.x, pos.x);
80 if(!std::isnan(pos.y)) bounds.min.y = std::min(bounds.min.y, pos.y);
81 if(!std::isnan(pos.z)) bounds.min.z = std::min(bounds.min.z, pos.z);
82 if(!std::isnan(pos.x)) bounds.max.x = std::max(bounds.max.x, pos.x);
83 if(!std::isnan(pos.y)) bounds.max.y = std::max(bounds.max.y, pos.y);
84 if(!std::isnan(pos.z)) bounds.max.z = std::max(bounds.max.z, pos.z);
87 glm::vec4 pos_w = worldMatrix*glm::vec4(pos + d*component->scale, 1.0);
88 pos = glm::vec3(pos_w);
89 if(!std::isnan(pos.x)) bounds.min.x = std::min(bounds.min.x, pos.x);
90 if(!std::isnan(pos.y)) bounds.min.y = std::min(bounds.min.y, pos.y);
91 if(!std::isnan(pos.z)) bounds.min.z = std::min(bounds.min.z, pos.z);
92 if(!std::isnan(pos.x)) bounds.max.x = std::max(bounds.max.x, pos.x);
93 if(!std::isnan(pos.y)) bounds.max.y = std::max(bounds.max.y, pos.y);
94 if(!std::isnan(pos.z)) bounds.max.z = std::max(bounds.max.z, pos.z);
97 float r = 2.0f*component->scale;
98 bounds.min -= glm::vec3(r);
99 bounds.max += glm::vec3(r);
100 return !isEmpty(bounds);
105 const glm::vec2& normPosition,
111 std::vector<RayPicking::RayPickHit>& hits)
133 auto &worldMatrix = context->transformSystem->getLocalToWorld(transComp);
135 auto & cameraData = context->cameraSystem->getData(&camera);
136 auto M = cameraData.inverseViewMatrix*glm::inverse(cameraData.rawProjectionMatrix);
138 auto aH = M * glm::vec4(normPosition, 0.0f, 1.f);
139 auto bH = M * glm::vec4(normPosition, 0.5f, 1.f);
140 auto cam_pos = (1.f / aH.w)*glm::vec3(aH);
141 auto forward_point = (1.f / bH.w)*glm::vec3(bH);
142 auto cam_dir = forward_point - cam_pos;
144 glm::vec3 cam_dir_n = glm::normalize(cam_dir);
146 glm::vec3 intersection;
147 if(!Geometry::intersect(data.bbox, cam_pos, cam_dir, intersection,
true)) {
151 size_t count = component->positions.
size();
152 for(
size_t i=0; i<count; i++){
153 glm::vec3 cp = component->positions[i];
154 glm::vec3 cd = component->directions[i];
156 if(component->animation){
157 float ih = fmod(sin(i/(
float)count)*43758.5453f, 1.0f);
158 float t = fmod(data.time+ih, 1.0f);
159 if(component->animation && component->animationUseSpeed)
160 t = data.time_offset_speed.size() ? data.time_offset_speed[i] : 0.0f;
161 float anim_scale = component->scale*component->length*component->animationScale;
162 pos += cd*anim_scale*(t-0.5f);
164 glm::vec4 pos_w_a = worldMatrix*glm::vec4(pos, 1.0);
165 glm::vec3 dir = glm::mat3(worldMatrix)*(cd*component->scale*component->length);
166 glm::vec3 pos_a = glm::vec3(pos_w_a)/pos_w_a.w;
167 glm::vec3 dir_norm = glm::normalize(dir);
169 float r = 0.05f*component->scale*component->tailScale;
172 float l = glm::length(cd)*component->scale*component->length;
173 if(std::isnan(r) || std::isinf(r))
continue;
174 if(std::isnan(l) || std::isinf(l))
continue;
175 if(r < 0.01 || l < 0.01)
continue;
177 glm::vec3 p_norm = glm::cross(cam_dir_n, dir_norm);
178 float pn = glm::length(p_norm);
179 if(pn < 0.05f)
continue;
181 float d1 = glm::dot(p_norm, pos_a);
182 float d2 = glm::dot(p_norm, cam_pos);
183 float dist = fabsf(d1-d2);
184 if(dist > r)
continue;
187 glm::vec3 n_norm = glm::normalize(glm::cross(cam_dir_n, p_norm));
188 glm::mat3 vs = glm::transpose(glm::mat3(cam_dir_n, p_norm, n_norm));
189 glm::vec3 vs_pos = vs*(pos_a - cam_pos);
190 glm::vec3 vs_dir = vs*dir;
192 float t = -vs_pos.z/vs_dir.z;
193 if(t > 1.0 || t < 0.0)
continue;
194 intersection = pos_a+t*dir;
196 glm::vec4 clipPos = cameraData.rawViewProjection * glm::vec4(intersection, 1.f);
197 if ((-clipPos.w > clipPos.z) && (clipPos.z > clipPos.w)) {
201 glm::vec4 viewPos = cameraData.viewMatrix * glm::vec4(glm::vec3(intersection), 1.f);
202 float viewDist = -viewPos.z;
205 if (hits[0].isBehind(ordinal, viewDist)) {
231 data.getBounds->getBounds(
context, data.bbox);
236 auto material =
context->materialManager->loadMaterial(
"Materials/VectorMaterial.material");
237 context->materialManager->processLoading();
238 material_instance_cap =
context->materialInstanceManager->createMaterialInstance(material);
239 material_instance_cap->setPermutation(
"Cap");
240 material_instance_base =
context->materialInstanceManager->createMaterialInstance(material);
241 material_instance_base->setPermutation(
"Base");
256 std::vector<VertexElement> format{
262 data.pos_format = Cogs::VertexFormats::createVertexFormat(format.data(), format.size());
264 data.buffer_count = 0;
265 data.getBounds = std::make_unique<VectorFieldBounds>(
this, comp);
266 data.rayPick = std::make_unique<VectorFieldPick>(
this, comp);
275 if(data.getBounds)
context->
bounds->removeBoundsExtension(data.getBounds.get());
ComponentType * getComponent() const
Container for components, providing composition of dynamic entities.
T * getComponent() const
Get a pointer to the first component implementing the given type in the entity.
virtual ComponentHandle createComponent()
Create a new component instance.
Context * context
Pointer to the Context instance the system lives in.
virtual void initialize(Context *context)
Initialize the system.
virtual void destroyComponent(ComponentHandle)
Destroy the component held by the given handle.
void update()
Updates the system state to that of the current frame.
ComponentPool< ComponentType > pool
Pool of components managed by the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
class IRenderer * renderer
Renderer.
std::unique_ptr< class Bounds > bounds
Bounds service instance.
std::unique_ptr< class RayPicking > rayPicking
RayPicking service instance.
virtual void registerExtension(IRendererExtension *extension)=0
Register an extension with the renderer.
Base component for all rendering content.
constexpr bool isVisibleInLayer(RenderLayers layerMask) const
Check if the entity should be visible in the given layer mask.
Contains information on how the entity behaves in the scene.
bool visible
If the entity this component is a member of should be visible.
bool pickable
If the entity this component is a member of should be pickable.
void getBounds(Context *context, Cogs::Geometry::BoundingBox &bounds) final
Expand bounds including bounds of all entities in this system in world coordinates.
bool pickCamera(Context *context, const CameraComponent &camera, const glm::vec2 &normPosition, float, float, PickingFlags pickingFlags, PicksReturned returnFlag, const RayPicking::RayPickFilter &filter, std::vector< RayPicking::RayPickHit > &hits) override
Do a ray pick from a normalized screen space position in the camera direction and return all hits.
PicksReturned
* Options for returning picking hits.
@ Closest
Return just the closest hit.
PickingFlags
Options for COGS picking.
@ ReturnChildEntity
Return ID if sub-entity picked, not set: return root parent entity.
Contains geometry calculations and generation.
@ InstanceData
Per instance data.
@ InstanceVector
Instance vector semantic.
Handle to a Component instance.
ComponentType * resolveComponent() const
size_t size() const
Gets the size of the buffer in number of elements of type T.
bool isUnwantedType(const ComponentModel::Component &comp) const
Helper function used to determine if a given component belongs to an accepted entity type.
RenderLayers layerMask
Limit picking to the specified render layers. Pick all layers by default.
ComponentModel::ComponentHandle createComponent() override
void destroyComponent(ComponentHandle component) override
void initialize(Context *context) override
Initialize the system.
Vertex element structure used to describe a single data element in a vertex for the input assembler.