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)
132 auto &worldMatrix = context->transformSystem->getLocalToWorld(transComp);
134 auto & cameraData = context->cameraSystem->getData(&camera);
135 auto M = cameraData.inverseViewMatrix*glm::inverse(cameraData.rawProjectionMatrix);
137 auto aH = M * glm::vec4(normPosition, 0.0f, 1.f);
138 auto bH = M * glm::vec4(normPosition, 0.5f, 1.f);
139 auto cam_pos = (1.f / aH.w)*glm::vec3(aH);
140 auto forward_point = (1.f / bH.w)*glm::vec3(bH);
141 auto cam_dir = forward_point - cam_pos;
143 glm::vec3 cam_dir_n = glm::normalize(cam_dir);
145 glm::vec3 intersection;
146 if(!Geometry::intersect(data.bbox, cam_pos, cam_dir, intersection,
true)) {
150 size_t count = component->positions.
size();
151 for(
size_t i=0; i<count; i++){
152 glm::vec3 cp = component->positions[i];
153 glm::vec3 cd = component->directions[i];
155 if(component->animation){
156 float ih = fmod(sin(i/(
float)count)*43758.5453f, 1.0f);
157 float t = fmod(data.time+ih, 1.0f);
158 if(component->animation && component->animationUseSpeed)
159 t = data.time_offset_speed.size() ? data.time_offset_speed[i] : 0.0f;
160 float anim_scale = component->scale*component->length*component->animationScale;
161 pos += cd*anim_scale*(t-0.5f);
163 glm::vec4 pos_w_a = worldMatrix*glm::vec4(pos, 1.0);
164 glm::vec3 dir = glm::mat3(worldMatrix)*(cd*component->scale*component->length);
165 glm::vec3 pos_a = glm::vec3(pos_w_a)/pos_w_a.w;
166 glm::vec3 dir_norm = glm::normalize(dir);
168 float r = 0.05f*component->scale*component->tailScale;
171 float l = glm::length(cd)*component->scale*component->length;
172 if(std::isnan(r) || std::isinf(r))
continue;
173 if(std::isnan(l) || std::isinf(l))
continue;
174 if(r < 0.01 || l < 0.01)
continue;
176 glm::vec3 p_norm = glm::cross(cam_dir_n, dir_norm);
177 float pn = glm::length(p_norm);
178 if(pn < 0.05f)
continue;
180 float d1 = glm::dot(p_norm, pos_a);
181 float d2 = glm::dot(p_norm, cam_pos);
182 float dist = fabsf(d1-d2);
183 if(dist > r)
continue;
186 glm::vec3 n_norm = glm::normalize(glm::cross(cam_dir_n, p_norm));
187 glm::mat3 vs = glm::transpose(glm::mat3(cam_dir_n, p_norm, n_norm));
188 glm::vec3 vs_pos = vs*(pos_a - cam_pos);
189 glm::vec3 vs_dir = vs*dir;
191 float t = -vs_pos.z/vs_dir.z;
192 if(t > 1.0 || t < 0.0)
continue;
193 intersection = pos_a+t*dir;
195 glm::vec4 clipPos = cameraData.rawViewProjection * glm::vec4(intersection, 1.f);
196 if ((-clipPos.w > clipPos.z) && (clipPos.z > clipPos.w)) {
200 glm::vec4 viewPos = cameraData.viewMatrix * glm::vec4(glm::vec3(intersection), 1.f);
201 float viewDist = -viewPos.z;
204 if (viewDist < hits[0].distance) {
230 data.getBounds->getBounds(
context, data.bbox);
235 auto material =
context->materialManager->loadMaterial(
"Materials/VectorMaterial.material");
236 context->materialManager->processLoading();
237 material_instance_cap =
context->materialInstanceManager->createMaterialInstance(material);
238 material_instance_cap->setPermutation(
"Cap");
239 material_instance_base =
context->materialInstanceManager->createMaterialInstance(material);
240 material_instance_base->setPermutation(
"Base");
255 std::vector<VertexElement> format{
261 data.pos_format = Cogs::VertexFormats::createVertexFormat(format.data(), format.size());
263 data.buffer_count = 0;
264 data.getBounds = std::make_unique<VectorFieldBounds>(
this, comp);
265 data.rayPick = std::make_unique<VectorFieldPick>(
this, comp);
274 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.