The number of instances is determined by calling node.setInstanceCount(n)
Objects instancing should be done by hardware, I am using the geometry shader only to show its potential.
As I am currently testing some updates not yet available, in the shader system, the code is not going to work out of the box. Especially since I am passing an array of float4, and I got rid of the k_ prefix for the uniform parameters. However we hope to have this updates committed in the source soon.
I’ve moved the thread into the Code Snipplets forum, as it didn’t appear to me that there were particular scripting issues with this code, correct me if I’m wrong.
thanks!
i’m still a noob in Cg -and therefor have little use for the code- , but things like this are pushing forward the whole project, which is very motivating.
I am glad it’s helpful. Remember that for instancing you should consider to use setInstanceCount and :INSTANCEID instead of the geometry shader. We kind of talked about it in this post:
- As I am currently testing some updates not yet available, in the shader system, the code is not going to work out of the box. Especially since I am passing an array of float4, and I got rid of the k_ prefix for the uniform parameters. However we hope to have this updates committed in the source soon.
We just committed these new features in the CVS, with them this shader will work as it is.
Note that the hardware instancing only runs on NVIDIA 8-series cards or newer. It will not work on ATI since the drivers do not support the necessary Cg profile.
It does work on ATI cards if you use a GLSL shader and apply this patch: [url]gp4vp shader profile not available - Win7, Radeon HD4890].
Maybe we could get that included in the official build?
Python
from pandac.PandaModules import loadPrcFileData
loadPrcFileData('', 'basic-shaders-only 0')
loadPrcFileData('', 'sync-video 0')
loadPrcFileData('', 'show-frame-rate-meter 1')
from direct.actor.Actor import Actor
from direct.showbase.DirectObject import DirectObject
from direct.interval.IntervalGlobal import Sequence
import direct.directbase.DirectStart
from pandac.PandaModules import Point3, Vec4, PTAVecBase4, Shader
class World(DirectObject):
def __init__(self):
self.accept("escape", __import__("sys").exit, [0])
self.model = Actor('panda-model', {'walk': 'panda-walk4'})
self.model.setScale(0.005)
self.model.flattenLight()
self.model.setPos(-2.7,300,-5)
self.model.loop('walk')
self.model.reparentTo(render)
interval = self.model.posInterval(20, Point3(-2.7, 200, -5), startPos=Point3(-2.7, 300, -5))
sequence = Sequence(interval)
sequence.loop()
k = 256
offsets = PTAVecBase4.emptyArray(k);
count = 0
for i in range(10):
for j in range(k/10):
offsets[count] = Vec4(i * 3, j * -8, 0, 0)
count += 1
self.model.setShaderInput('offsets', offsets)
self.model.setShader(Shader.load('instance.cg'))
self.model.setInstanceCount(k)
w = World()
run()
Is hardware instancing considered advanced shader in Panda3d terms? (so will it work only on newer hardware?)
I’m going with geometry batching for my forest, but having 1 geom is always better.
BTW, Ive heard you have to implement your own culling. How can you do that? Should you just attach a bounding box to each instance somehow?
I’d consider it an advanced shader, but there are still many GPU generations support it.
The method you suggested won’t work as there will only be one node to attach a bounding volume to.
You could write a geometry shader that does frustum intersection for every triangle and discards a triangle if it’s out of view. If you can’t afford a geometry shader, you could have a position assigned to every instance and a global radius for the object, and do an intersection test between the frustum and the sphere with that instance’s position and the global radius.
You’ll need to write that code yourself, in the shader.
Well, probably you would still get some performance improvement from using instancing and doing no culling at all (apply an OmniBoundingVolume to the model). It is still reducing the number of geoms which is usually the performance bottleneck, and trading for more triangles drawn which is usually OK.
I use it for moving objects which I cannot otherwise combine.
Well, I was thinking of using this for my forest. But this means it will decrease the geom count to few, but will have the opposite effect on the vertex count, which can go over million like this.
And I think if I had the knowledge to write a shader to handle the culling, I could write an instancing shader myself.
BTW, for moving objects have you tried rigidbodycombiner? It basically makes a single geom and attaches a joint to each object and moves them instead.
Many modern graphics cards can handle millions of vertices without sweating. You should try it and see what kind of performance you get.
The RigidBodyCombiner helps for small-to-moderate scenes, but because it’s entirely implemented on the CPU, it doesn’t do a good job with lots of vertices.
You could divide up your forest into groups of trees, each of which is flattened or uses hw instancing. If you use hw instancing, then create a bounding sphere or box enclosing this group of trees. This way you can get some rough culling while still limiting the number of geoms.