The source is me
But in all seriousness I talk about it here in more detail and give a possible explanation for why its the case:
(PSA) The Neon material is one of the fastest materials - Development Discussion - DevForum | Roblox
The best repro I have is my own game which I linked in the replies there, and, its where I ended up figuring this out. Really the easiest way to test this is to generate a very large grid of parts with the SmoothPlastic or Plastic material with their faces all on Smooth. If you switch all of these parts to Neon, you should see a pretty noticeable boost in your FPS. I’ve had six or seven people test this out already on varying hardwares, and, they’ve confirmed its the case for them.
Here’s a brief summary on why I think this is the case:
- Plastic parts have specular highlights & normal mapping and such, Neon parts don’t
- Neon parts only have Ambient Occlusion applied to them (on higher settings)
- The behaviour of how Neon is rendered was changed during FIB when Roblox introduced HDR: Future Is Bright: Phase 1 Released - Updates / Announcements - DevForum | Roblox
- This HDR behaviour essentially means colors brighter than
1 can exist and will have a bloom effect applied to them. (That also means that just by darkening the color of Neon parts you should be able to get the original color of your parts exactly)
- In conclusion, the cost for rendering Neon parts is theoretically just the cost for rendering a flat colored object + AO on higher graphics settings. The glow/bloom is a post processing effect which is applied per pixel and doesn’t cost that much.
@Enk514 Part instancing does not remove the cost of rendering extra triangles. Part instancing is an optimization that reduces the cost for rendering the same mesh data. It still costs more frame time to render 100 parts vs 10 parts, its just that with Part instancing it costs a lot less to render the same 100 parts than it did before. The triangle count is still absolutely a problem when it comes to FPS lag.
@Michel2003g I apologize for not responding before. Unfortunately, there isn’t a way to get rid of physics throttling. Physics throttling is primarily caused by low server heartbeat or low player FPS. Since the issue isn’t FPS lag like I thought it was, I would actually recommend doing the opposite of what I said in this case. Rather than setting all dropper parts to be simulated server side, you can set them all to be simulated client side. This would allow exploiters to control the physics of those parts, but, for a tycoon game that’s not too big of a deal. Just make sure that those parts have collision groups that don’t collide with players.
Alternatively, you could just not use Roblox physics at all, and instead simulate your dropped parts yourself. That would allow you to completely disable collisions so there isn’t any physics cost at all, you won’t get throttling, and, since Roblox is adding some optimizations with CanTouch, if CanTouch and CanCollide are both off, and the part is Anchored, it will pretty much cost nothing.
One way you could do this is to anchor your dropped parts and on Heartbeat move the object
conveyor.AssemblyLinearVelocity * frameTime to simulate the conveyor movement. You could do a ray cast below each dropped part to find the conveyor below it, and, if you don’t find a conveyor or you find a part with no velocity you could just use what ever the last conveyor’s velocity was. The initial previous conveyor velocity could just be 0 0 0 that way if you’re spawning the part off the conveyor initially you won’t get any errors.
If you want the part to fall, when you raycast, you can start simulating the part falling when there is no conveyor. You can store its speed in
AssemblyLinearVelocity. You could just use some basic physics and subtract
droppedPart:GetMass() * workspace.Gravity from its Y velocity. (E.g.
droppedPart.AssemblyLinearVelocity += Vector3.new(0, -droppedPart:GetMass() * workspace.Gravity, 0).
And, lastly, so that the part doesn’t float above the conveyor, you could calculate the correct height for your dropped part with
conveyor.Position + Vector3.new(0, conveyor.Size.Y + droppedPart.Size.Y, 0)/2 (from the center of the conveyor, you add half its Y size to get the top. Then you add half the dropped part’s size since you want the bottom of the dropped part to be touching that height, not the center. You can just set the part’s CFrame to
CFrame.new(part.Position.X, calculatedHeight, part.Position.Z) in your heartbeat loop.