Jump to content

[FIXED] Need some help coding this!


Ruud033

Recommended Posts

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.

PostBeginPlay

event 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:

PostRenderFor

simulated 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 by Guest
Link to comment
Share on other sites

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..

Link to comment
Share on other sites

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)

45b3ce3222455da257fd12087d60afbc.jpg

Standing up close (within 1000 Unreal Units) I've set the MaxDrawDistance in the script via code.

df07dbe986053a21d97b2cd23366578c.jpg

Standing a bit further away (more than 1000)

84d51edb1d90d9bf624c979aea24abfd.jpg

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!!!

Link to comment
Share on other sites

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); 
                   } 
               } 
           } 
       } 
   } 
} 

Link to comment
Share on other sites

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:

6af83194d55826efa677ae00540b595f.png

Im gonna try n fix that

Edit: Fixed

Edited by Guest
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...