Ruud033 Posted June 2, 2015 Share Posted June 2, 2015 (edited) Heya people, Im trying to add collision to foliage by spawning a DynamicSMActor_Spawnable actor which has collision on it. (with the proper dimensions etc.) The problem is that, right now in the code, it spawns ALL of the actors at once in the level once the game has started using "PostBeginPlay ()". This gives a lot of lag and performance issues. PostBeginPlayevent PostBeginPlay () Called by the engine pretty soon after the Actor has been spawned or the game has begun. Most actors use PostBeginPlay() to initialize their UnrealScript values. The actor's PhysicsVolume and Zone are valid but the actor is not yet in any State. 1 way of fixing this is culling them out, I have not succeeded in this just yet, so that's why I made this post. I'm currently approaching the issue in 2 ways namely: 1. Spawning all actors at once and culling them out afterwards (working on this) 2. Spawning the actor once visible I have a question about method 2 and will go deeper into this. I have found a function that might do the job here: PostRenderForsimulated event PostRenderFor (PlayerController PC, Canvas Canvas, Object.Vector CameraPosition, Object.Vector CameraDir) This function is only called if the Actor is visible as determined by the LocalPlayer's GetActorVisibility function, or either if bPostRenderIfNotVisible is true. To use this functionality your HUD instance must have bDrawOverlays set to true and your Actor must have registered itself by calling its player HUD AddPostRenderedActor function. This function is called by NativePostRenderFor whom's origin is instigated by the HUD class. I do not really understand this function, when does it fire and what do I need to put in the brackets for it to fire when foliage is visible? For example: Should it be like PostRenderFor (InstancedFoliageActor) and not more? I don't know how to fill this in. The part where this should be inserted is inside a volume. The volume spawns a "BlockingMesh" which is an extent. First of, here's the BlockingMesh code: class BlockingMesh extends DynamicSMActor_Spawnable; defaultproperties { Begin Object Name=StaticMeshComponent0 HiddenGame = true //we don't wanna draw this, it's just used to test collision BlockRigidBody=true //DynamicSMActors have collision disabled by default End object bCollideActors=true //same here bTickIsDisabled = true //greatly improves performance on the game thread } This is interesting but, I want to control the spawning rate of these blocking meshes so I have to be in the volume code, here's the volume code: /** Creates collision for foliage instances inside the volume */ class FoliageCollisionVolume extends Volume placeable; static final function vector MatrixGetScale(Matrix TM) { local Vector s; s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2); s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2); s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2); return s; } function PostBeginPlay() { local InstancedFoliageActor ac; local InstancedStaticMeshComponent comp; local vector loc, scale; local Rotator rot; local BlockingMesh CreatedBlockingMesh; local int i, j; super.PostBeginPlay(); //look for the InstancedFoliageActor foreach AllActors(class'InstancedFoliageActor',ac) { //iterate through the various foliage components for(i=0; i { comp = ac.InstancedStaticMeshComponents[i]; if (comp.StaticMesh.BodySetup != none) { //iterate through the various meshes in this component, if it has a collision model for (j=0; j { //decompose the instance's transform matrix loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform); if (ContainsPoint(loc)) //check if this instance is within the volume { rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform); scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform); CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot); CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh); CreatedBlockingMesh.SetDrawScale3D(scale); } } } } } } As you can see, I use the PostBeginPlay() function here, which means all of the foliage get's the DynamicSMActor_Spawnable right at the beginning of the level attached to it. What if, I can transform this spawn rate to something more performance friendly like, say: spawn when the foliage is visible (not culled) I intend to use the PostRenderFor function, so I think the code will look like this: /** Creates collision for foliage instances inside the volume */ class FoliageCollisionVolume extends Volume placeable; static final function vector MatrixGetScale(Matrix TM) { local Vector s; s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2); s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2); s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2); return s; } function PostRenderFor (InstancedFoliageActor) { local InstancedFoliageActor ac; local InstancedStaticMeshComponent comp; local vector loc, scale; local Rotator rot; local BlockingMesh CreatedBlockingMesh; local int i, j; super.PostRenderFor (InstancedFoliageActor); //look for the InstancedFoliageActor foreach AllActors(class'InstancedFoliageActor',ac) { //iterate through the various foliage components for(i=0; i { comp = ac.InstancedStaticMeshComponents[i]; if (comp.StaticMesh.BodySetup != none) { //iterate through the various meshes in this component, if it has a collision model for (j=0; j { //decompose the instance's transform matrix loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform); if (ContainsPoint(loc)) //check if this instance is within the volume { rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform); scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform); CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot); CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh); CreatedBlockingMesh.SetDrawScale3D(scale); } } } } } } Please give me some feedback on this. I don't know much about code and triggers.. I can see the logic in this and can do a process analysis but I'm not a coder. I took my knowledge and logic from http://wiki.beyondunreal.com/UE3:Actor_events_%28UDK%29 I think the idea is pretty much explained. I'd like to see your input. Edit: I was thinking like, what if I register the touch volume event and THEN spawn the collision for the piece of forest? I'd also have to remove the collision again when it untouches (for performance sake) /** Creates collision for foliage instances inside the volume */ class FoliageCollisionVolume extends Volume placeable; static final function vector MatrixGetScale(Matrix TM) { local Vector s; s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2); s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2); s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2); return s; } function Touch (Actor Rx_Actor) { local InstancedFoliageActor ac; local InstancedStaticMeshComponent comp; local vector loc, scale; local Rotator rot; local BlockingMesh CreatedBlockingMesh; local int i, j; super.Touch (Actor Rx_Actor); //look for the InstancedFoliageActor foreach AllActors(class'InstancedFoliageActor',ac) { //iterate through the various foliage components for(i=0; i { comp = ac.InstancedStaticMeshComponents[i]; if (comp.StaticMesh.BodySetup != none) { //iterate through the various meshes in this component, if it has a collision model for (j=0; j { //decompose the instance's transform matrix loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform); if (ContainsPoint(loc)) //check if this instance is within the volume { rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform); scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform); CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot); CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh); CreatedBlockingMesh.SetDrawScale3D(scale); } } } } } } Just how do I remove this afterwards? Would like to see your input on this. Edited June 2, 2015 by Guest Quote Link to comment Share on other sites More sharing options...
Totem Arts Staff kenz3001 Posted June 2, 2015 Totem Arts Staff Share Posted June 2, 2015 your better off just using normal actors Quote Link to comment Share on other sites More sharing options...
Totem Arts Staff Handepsilon Posted June 2, 2015 Totem Arts Staff Share Posted June 2, 2015 Agreed, constant dynamic spawning and killing is more consuming than placing collision boxes and leave them be Quote Link to comment Share on other sites More sharing options...
Ruud033 Posted June 2, 2015 Author Share Posted June 2, 2015 Pessimists. @Hande, Maybe, lets put it to the test! I'd just like to try this out first before I get to the time consuming placing static mesh actors and rescaling the crap. I know that is A solution, however I do not want to give up just yet on this. If this turns out to work in the end, we'll have a new fast and easy way of having trees in the map. with collision. I would like RypeL to check the code and say if it's doable or not.. Quote Link to comment Share on other sites More sharing options...
Ruud033 Posted June 2, 2015 Author Share Posted June 2, 2015 GOT IT TO WORK!! AWESOME! And the performance is magnificent! I've used method 1 This is what it looks like in the editor (yes that is foliage, i'm not cheating) Standing up close (within 1000 Unreal Units) I've set the MaxDrawDistance in the script via code. Standing a bit further away (more than 1000) 1000 Unreal Units was a value I just randomly picked, but seems to suit just fine. You only load a small amount of collision mesh near the foliage, this is awesome!!! Quote Link to comment Share on other sites More sharing options...
Ruud033 Posted June 2, 2015 Author Share Posted June 2, 2015 The two scripts I use: BlockingMesh.uc //============================================================================= // FoliageCollisionVolume: a vehicle collision solution // used to collide certain classes of actors // primary use is to provide collision for non-zero extent traces around static meshes // Created by Pinheiro, https://forums.epicgames.com/threads/913559-How-to-enable-collision-on-foliage //============================================================================= class BlockingMesh extends DynamicSMActor_Spawnable; defaultproperties { Begin Object Name=StaticMeshComponent0 HiddenGame = true //we don't wanna draw this, it's just used to test collision BlockRigidBody=true //DynamicSMActors have collision disabled by default CastShadow=false MaxDrawDistance = 500 bAllowCullDistanceVolume=true End object bCollideActors=true //same here bTickIsDisabled = true //greatly improves performance on the game thread } and FoliageCollisionVolume.uc /** Creates collision for foliage instances inside the volume */ class FoliageCollisionVolume extends Volume placeable; static final function vector MatrixGetScale(Matrix TM) { local Vector s; s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2); s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2); s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2); return s; } function PostBeginPlay() { local InstancedFoliageActor ac; local InstancedStaticMeshComponent comp; local vector loc, scale; local Rotator rot; local BlockingMesh CreatedBlockingMesh; local int i, j; super.PostBeginPlay(); //look for the InstancedFoliageActor foreach AllActors(class'InstancedFoliageActor',ac) { //iterate through the various foliage components for(i=0; i { comp = ac.InstancedStaticMeshComponents[i]; if (comp.StaticMesh.BodySetup != none) { //iterate through the various meshes in this component, if it has a collision model for (j=0; j { //decompose the instance's transform matrix loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform); if (ContainsPoint(loc)) //check if this instance is within the volume { rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform); scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform); CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot); CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh); CreatedBlockingMesh.SetDrawScale3D(scale); } } } } } } Quote Link to comment Share on other sites More sharing options...
Ruud033 Posted June 2, 2015 Author Share Posted June 2, 2015 (edited) Just tested the first run in singleplayer. The script does not seem to work when all is built in singleplayer. Maybe it's got something to do with singleplayer as the fellas with the mutators also had issues with the PostBeginPlay() function. They had no issues on MP so I'm gonna test this in MP first. I'll edit this post to share knowledge. (it does work in the SDK) In MP I was also able to drive trough the trees, this is what the server said during compiling: Im gonna try n fix that Edit: Fixed Edited June 17, 2015 by Guest Quote Link to comment Share on other sites More sharing options...
RypeL Posted June 2, 2015 Share Posted June 2, 2015 Sometimes executing things in PostBeginPlay doesent work cause it can depend on things that are not fully initialized yet. Generally the game takes a short moment till every initialization code etc is executed. So you can try to add: SetTimer(0.5,false,'init'); <- into PostBeginPlay function init() { ... } This will result in your initialization code happening 0.5 secs after game start. Id try that first before trying to find other reasons why it doesent work in SP. Quote Link to comment Share on other sites More sharing options...
Ruud033 Posted June 2, 2015 Author Share Posted June 2, 2015 (edited) So it becomes?? ?? I have constant critical errors rebuilding this. Could you give an example by copy-pasting the code and inserting that in ? Edited June 3, 2015 by Guest Quote Link to comment Share on other sites More sharing options...
RoundShades Posted June 2, 2015 Share Posted June 2, 2015 The following are the errors he is getting, NOT IN COMPILER but in the game when trying to launch. We believe, he needs the volume's compiled script, in the server, when the map loads. Trying to do it now. [0080.37] Warning: Warning, CreateExport: Failed to load Outer for resource 'BrushComponent_8': FoliageCollisionVolume CNC-Crash_Site_small.TheWorld:PersistentLevel.FoliageCollisionVolume_0 [0080.37] Warning: Warning, CreateExport: Failed to load Outer for resource 'BrushComponent_9': FoliageCollisionVolume CNC-Crash_Site_small.TheWorld:PersistentLevel.FoliageCollisionVolume_1 [0080.37] Warning: Warning, CreateExport: Failed to load Outer for resource 'BrushComponent_16': FoliageCollisionVolume CNC-Crash_Site_small.TheWorld:PersistentLevel.FoliageCollisionVolume_2 [0080.37] Warning: Warning, CreateExport: Failed to load Outer for resource 'BrushComponent_10': FoliageCollisionVolume CNC-Crash_Site_small.TheWorld:PersistentLevel.FoliageCollisionVolume_3 [0080.37] Warning: Warning, CreateExport: Failed to load Outer for resource 'BrushComponent_8': FoliageCollisionVolume CNC-Crash_Site_small.TheWorld:PersistentLevel.FoliageCollisionVolume_4 [0080.3 Quote Link to comment Share on other sites More sharing options...
Ruud033 Posted June 2, 2015 Author Share Posted June 2, 2015 The following are the errors he is getting, NOT IN COMPILER but in the game when trying to launch. We believe, he needs the volume's compiled script, in the server, when the map loads. Trying to do it now.[0080.37] Warning: Warning, CreateExport: Failed to load Outer for resource 'BrushComponent_8': FoliageCollisionVolume CNC-Crash_Site_small.TheWorld:PersistentLevel.FoliageCollisionVolume_0 [0080.37] Warning: Warning, CreateExport: Failed to load Outer for resource 'BrushComponent_9': FoliageCollisionVolume CNC-Crash_Site_small.TheWorld:PersistentLevel.FoliageCollisionVolume_1 [0080.37] Warning: Warning, CreateExport: Failed to load Outer for resource 'BrushComponent_16': FoliageCollisionVolume CNC-Crash_Site_small.TheWorld:PersistentLevel.FoliageCollisionVolume_2 [0080.37] Warning: Warning, CreateExport: Failed to load Outer for resource 'BrushComponent_10': FoliageCollisionVolume CNC-Crash_Site_small.TheWorld:PersistentLevel.FoliageCollisionVolume_3 [0080.37] Warning: Warning, CreateExport: Failed to load Outer for resource 'BrushComponent_8': FoliageCollisionVolume CNC-Crash_Site_small.TheWorld:PersistentLevel.FoliageCollisionVolume_4 [0080.3 After compiling and adding to the cooked PC folder AND adding the mutator to the startup from the server we still get the yellow ish errors as before. What could be going wrong here (have loaded the non-settimer version btw, for testing purposes) Edit: Nevermind, I GOT IT TO WORK!! I forgot to re-reference something, slap me please. It works perfectly once the mutator file is installed.. awesome! gonna test this out fo sure. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.