I need a less costly method to multiplying these CFrames

I want to dial down the script activity caused by multiplying two CFrames 300 times every 60th of a second.

For my script to be useable I need to dial down the script activity to a minimum of 5%, any lower would be outstanding and way better then what I’ll settle for. Currently it is at 5.7% - 6.3%.

I have tried multiple different solutions but to no avail. Cannot remember what exactly they were as my memory has forgotten about them because they didn’t work.

-- < MAIN CAUSE OF high Script Activity
workspace:BulkMoveTo(GrassFolder, NewMultipliedOrientation, Enum.BulkMoveMode.FireCFrameChanged) -- both arrays have 300 values
-- >

^ The main cause of the script activity being so high. When this is disabled its at a consistent 1%.

v Below is the basics of how it works. At least what I believe you need to understand.

function UpdateGrassCalculations(i, GWX, GWZ)
	UpdateVel(XUpFolder, XVelFolder, VelChangeRateX, MaxVelX, MinVelX, i, "X")
	UpdateVel(ZUpFolder, ZVelFolder, VelChangeRateZ, MaxVelZ, MinVelZ, i, "Z")

	if (XUpFolder[i] == true and GrassOrientationX[i] >= XNewRotFolder[i]) or (ZUpFolder[i] == true and GrassOrientationZ[i] >= ZNewRotFolder[i]) 
		or (XUpFolder[i] == false and GrassOrientationX[i] <= XNewRotFolder[i]) or (ZUpFolder[i] == false and GrassOrientationZ[i] <= ZNewRotFolder[i]) then
		XNewRotFolder[i] = GWX + math_random(-3,3)
		ZNewRotFolder[i] = GWZ + math_random(-3,3)
		if XNewRotFolder[i] >= GrassOrientationX[i] then
			XUpFolder[i] = true
		else
			XUpFolder[i] = false
		end
		if ZNewRotFolder[i] >= GrassOrientationZ[i] then
			ZUpFolder[i] = true
		else
			ZUpFolder[i] = false
		end
	end
	
	GrassOrientationX[i] += XVelFolder[i]
	GrassOrientationZ[i] += ZVelFolder[i]
	NewOrientation[i] = CFrame_Angles(math_rad(GrassOrientationX[i]),0,math_rad(GrassOrientationZ[i]))
end

function MoveOrientation(i,o)
	NewMultipliedOrientation[i] = initalStemCFrameFolder[i] * NewOrientation[o]
end

game:GetService("RunService").RenderStepped:Connect(function(Step)
        for o = 1, GroupsAmount, 1 do
	        UpdateGrassCalculations(o, GWX, GWZ)
        	changeO = o - 1
        	for i = (GroupRatio * (o - 1)) + 1, GroupRatio * o, 1 do
	        	if TickActive[i] == true and GrassReady[i] == true then
	        		MoveOrientation(i,o)
	        	end
        	end
        end
        -- < MAIN CAUSE OF Script Activity
        workspace:BulkMoveTo(GrassFolder, NewMultipliedOrientation, Enum.BulkMoveMode.FireCFrameChanged)
        -- >
end

I am looking for tips or directions to where I could get the information I need.

It’d help to have more info about what you’re trying to do but I’ll give you my initial thoughts.

In absence of other information about your script, the most likely reason the activity rate is so high is because you’re connecting to a RunService event. What seems to be happening is you’re multiplying 300+ CFrames ever RenderStep asynchronously because you’ve created the signal connection which fires every ~0.017s - which means the next batch of 300+ CFrame calculations will start before the last was completed. This is probably intentional on your end but I don’t think there’s any good way to mitigate the resource costs of doing this.

If you’re only looking to reduce the script rate, replacing the RunService signal connection with a while loop + RunService yields to create synchronicity should reduce the script rate.

This
game:GetService("RunService").RenderStepped:Connect(function(Step)
	for o = 1, GroupsAmount, 1 do
		UpdateGrassCalculations(o, GWX, GWZ)
		changeO = o - 1
		for i = (GroupRatio * (o - 1)) + 1, GroupRatio * o, 1 do
			if TickActive[i] == true and GrassReady[i] == true then
				MoveOrientation(i,o)
			end
		end
	end
end)

Would turn into

This
local RunService = game:GetService("RunService")

while true do
	for o = 1, GroupsAmount, 1 do
		UpdateGrassCalculations(o, GWX, GWZ)
		changeO = o - 1
		
		for i = (GroupRatio * (o - 1)) + 1, GroupRatio * o, 1 do
			if TickActive[i] == true and GrassReady[i] == true then
				MoveOrientation(i, o)
			end
		end
	end
	
	RunService.RenderStepped:Wait()
end

However with your current setup I’d imagine this might slow down whatever animations you’re trying to do… making grass appear to flow in the wind I’m guessing? Despite this it should decrease the script activity rate, which is what you said you’re looking for.

cc @Quasiduck in case I got anything wrong here and/or there’s a better solution

Thank you for the help!

I finished converting it over and it all worked fine, however it didn’t change the script activity and surprisingly didn’t change how smooth the animation is. I always appreciate the help!

I believe boat bomber had a similar grass Shake script wind shake. From there I can say you should definitely look into WorldRoot | Roblox Creator Documentation to optimize the amount of CFrames changes for a large amount of parts like in this I believe. Not sure about how octrees was used. But yeah hope this helps.

1 Like

I’ve already tried using windshake for the grass in the past but it didn’t give nearly the same realistic or smooth effect as my current system.
I haven’t considered looking into WorldRoot:BulkMoveTo yet, so I’ll definitely look into it now.

Thanks for the info!

Alright I got it working, however it didn’t change the script activity by much. Before it was at 6.8% - 7.6% now its at 6.4% - 7.3%. I will definitely continue to use this as it did lower it by about 7% of the percentage it was.
The version I have up was a quick addition, and there may be easier ways to go about this but I don’t know what those would be.

Thank you for the info, as it did help a small bit and I greatly appreciate people trying to help!

Hmm, nice going but to continue the spirit of copying boatbomber , for the bulk move to try doing this like what Boat bomber has done again:

workspace:BulkMoveTo(updateObjects, cfTable, Enum.BulkMoveMode.FireCFrameChanged)

This should prevent unnecessary events from firing if I’m interpreting correctly as it only fires CFrameChanged?? documentation not very clear on this though try it out.

BulkMoveMode

Enums

Name Value Description
### FireAllEvents 0
### FireCFrameChanged

Anyways for what boat bomber has done it seems like only objects that are looking where the camera is looking (in a radius? in front of the camera are updating) using octrees:

	local camera = workspace.CurrentCamera
	local cameraCF = camera and camera.CFrame

	debug.profilebegin("Octree Search")
	local updateObjects = self.Octree:RadiusSearch(cameraCF.Position + (cameraCF.LookVector * 115), 120)

This could greatly limit the number of objects being CFramed and improve performance as well.

1 Like

I got the Enum.BulkMoveMode.FireCFrameChanged in now and it did lower activity by 10% of what it was earlier. However I can’t get the:

local updateObjects = self.Octree:RadiusSearch(cameraCF.Position + (cameraCF.LookVector * 115), 120)

to work as it keeps asking what “self” is. I don’t know what it is and it wants to classify it as a global variable.

“Self” usually refers to the table that the calling function is inside of.

When using the : operator with a table (usually a module), it will give you access to the self keyword which will basically be the module table.

What I’ll try and do is create a Module using the Octree Module for the purpose of only searching for objects called on.
Will be the second time I’ve tried to code a Module so I doubt it’ll go well.

Thanks for the info!