Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom vertex attributes in SceneKit

I'm using SceneKit to generate some custom geometry. This is working fine, but I'm struggling to find a way to include custom vertex attributes. Specifically, I'm looking to include an additional SCNVector3 per vertex.

I've found plenty of examples which make use of shaderModifiers to include GLSL/Metal code that relies upon custom uniform values, but haven't come across a way of including vertex attributes. Is this possible with SceneKit, or is my thinking backwards?

like image 952
ndg Avatar asked Nov 27 '25 00:11

ndg


2 Answers

To make custom geometry, you use SCNGeometrySource objects to provide the vertex position, normal, and texture coordinate attributes using a buffer or Data object full of values, then pass your geometry sources to the SCNGeometry init(sources:elements:) initializer.

When you create an SCNGeometrySource, you associate it with a "semantic" which is analogous to the GL/Metal vertex attribute. To create a custom vertex attribute, just give it a custom semantic. (In ObjC, SCNGeometrySourceSemantic is just a typedef for NSString, so you can provide your own string name. In Swift, SCNGeometrySource.Semantic is an enum-like struct that you can extend create new members with String raw values.)

To use your custom vertex attribute in a custom shader program, use setSemantic(_:forSymbol:options:) for GL shaders and (I think) handleBinding(ofBufferNamed:frequency:handler:) for Metal shaders.

like image 126
rickster Avatar answered Nov 29 '25 16:11

rickster


there doesn't seem to be a way to access custom geometry sources in shader modifiers. That said, if your data fits into a float4 you can pass that data through SCNGeometrySourceSemanticColor.

The Fox sample code uses the same technique to animate blades of grass. The displacement amount is baked into grayscale vertex colors as shown in the picture below.

Data baked into the vertex colors

Finally the following shader modifier reads the value of _geometry.color and makes sure to reset it to pure white so that the stored data doesn't affect the final color of the object.

 float offset = _geometry.color.x * (sin(1.2 * u_time + (_geometry.position.x+ _geometry.position.z)*4.0) + 0.5) * 0.02;
_geometry.position.x += offset;
_geometry.color.xyz = vec3(1.0);
like image 23
mnuages Avatar answered Nov 29 '25 15:11

mnuages



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!