# Is it possible to dynamically reduce the number particles based on distance from camera?

I want to render an animation in which a car drives along a certain stretch of road. To one side there is a grass field, but this is quite big, both in the direction perpendicular to the car, and along the direction of travel. I don't have enough memory to put highly detailed grass on the whole field, so I was wondering if it was possible to reduce the number of grass strands based on the distance from the camera.

Or maybe there are other tricks to achieving this?

You can use a script that calculates the distance of each vertex in your grass field from the camera at each frame, and updates a vertex group controlling your particle system's density accordingly.

To get this to work:

1. Your grass field needs to have a vertex group, with all vertices included (create then select all verts and press "Assign").
2. In your particle system, you need to set this vertex group as the Density group, with inverted weight (see the image below).
3. Make sure to replace the names of your grass field object, particle system and vertex group if needed in the script (they're called "Plane", "ParticleSystem" and "Group" in the code below).
4. Open a text editor window, create a new text file, copy the code there and press "Run Script".

Here's the code:

import bpy

def weight_from_distance( scene ):
floor = bpy.data.objects['Plane']  # <== REPLACE "Plane" with the name of your grass field object
cam   = bpy.data.objects['Camera']

vert_distances = [
( cam.location - floor.matrix_world @ v.co ).length for v in floor.data.vertices #Updated for 2.8+: Replaced '*' with '@'
]

maxDist = max( vert_distances )
minDist = min( vert_distances )

for i, d in enumerate( vert_distances ):
# Normalize distance and set as vertex weight
floor.data.vertices[i].groups[0].weight = ( d - minDist ) / ( maxDist - minDist )

pSysName      = 'ParticleSystem' # <== REPLACE with the name of your grass' particle system if needed
vertGroupName = 'Group'          # <== REPLACE with the name of your vertex group if needed

floor.particle_systems[ pSysName ].vertex_group_density = vertGroupName # Update / Refresh

bpy.app.handlers.frame_change_pre.append( weight_from_distance )

• Amazing work, thanks! I'm going to try and implement this as soon as I have time. I hope you the grass won't flicker too much between density variations, but I guess that will be a matter of fine tuning. Feb 23, 2016 at 17:42
• Sure :) Flickering could be an issue. Let me know how it worked for you, I'm curious if this will be actually useful or if a smarter solution is needed. Feb 23, 2016 at 17:43
• Basically this same result can be done with dynamic paint. Feb 23, 2016 at 22:08
• Makes sense, @PGmath. However, isn't object intersection required for this to work? (I guess you can parent a sphere to the camera to achieve this). By the way - might be worth another answer to demonstrate this. Feb 23, 2016 at 22:11
• @TLousky I think you do need an actual mesh for the DP brush. I'd use proximity instead of intersection though. Feb 23, 2016 at 22:23

I'm not sure if theres a way of achieving this.

But

You can hide the grass in 3d view mode if you want, but let it still be visible while rendering. Here's a picture:

Simply click on the little eyeball to hide the grass. You can press the camera if you want to hide it in render mode.

I'm not sure if this completely solves your problem, but I'm guessing it's the best way to go.

Happy blending!

• That doesn't work, as when I go and render my memory (16GB) overflows due to the millions of particles. Feb 23, 2016 at 13:40
• Sorry then. Don't know what to do... Feb 23, 2016 at 13:50