LightsprintSDK 2021.08.08
Vertex buffer

Vertex buffer is designed for storage of per-vertex data for single object.

Suitable for

global or direct or indirect illumination ambient occlusion bent normals
static objects YES YES YES
dynamic objects NO YES YES
realtime calculated illumination YES NO NO
precalculated illumination YES YES YES

Advantages

  • Compact representation. It requires only few bytes per vertex. Samples store illumination as 3 floats, but it can be switched to 4 bytes, arbitrary compression can be added.
  • Fast rendering. No sampler resources are consumed. It can be arbitrarily postprocessed in vertex shader. You can have multiple layers of precalculated indirect illumination and mix them at no cost in vertex shader according to changes in scene.
  • There is no need to change your lightning equation, simply use our ambient data instead of constant ambient.
  • If you don't precompute bent normals, ambient lighting values don't depend on view angle, so rendering is very fast.
  • If you do precompute bent normals, normal maps work great even in shadows, knowing direction of incoming indirect light.

Disadvantages

  • Details are missing in areas without vertices. For good results, you have to add vertices to places where you miss details.
  • Seams around T vertices and other degenerated geometries. You have to make your meshes clean, avoid degeneracies.
  • Long narrow triangles (needles) often create visible artifacts. This is often problem also for physical engine, so your 3d artisis probably know they should avoid needles.

Interface

Instances

Rendering with

  • Stream data from vertex buffer into vertex shader, interpret them in shader appropriately as light level, ambient occlusion or bent normal.

Examples

  • Generic example:
    Creating vertex buffer.
    vertexBuffer = rr::RRBuffer::create(rr::BT_VERTEX_BUFFER,numVertices,1,1,rr::BF_RGBF,true,nullptr);
    static RRBuffer * create(RRBufferType type, unsigned width, unsigned height, unsigned depth, RRBufferFormat format, bool scaled, const unsigned char *data)
    Creates buffer in system memory. See reset() for parameter details. Returns nullptr when parameters a...
    @ BF_RGBF
    Floating point RGB, 96bits per pixel. High precision, suitable for any data, but some old GPUs don't ...
    Definition RRBuffer.h:94
    @ BT_VERTEX_BUFFER
    Vertex buffer, 1d array of width elements. Used for object's realtime indirect lighting,...
    Definition RRBuffer.h:83
  • OpenGL example:
    Rendering with per vertex ambient.
    rr::RRSolver* dynamicSolver;
    GLuint program;
    ...
    // set program created from shaders below
    glUseProgram(program);
    // get vertex buffer with indirect illumination
    rr::RRBuffer* vertexBuffer = object->illumination.getLayer(0);
    // enable stream with color values
    glEnableClientState(GL_COLOR_ARRAY);
    // set pointer to color data for first vertex
    glColorPointer(3, GL_FLOAT, 0, vertexBuffer->lock(rr::BL_READ));
    // render primitives
    glDrawElements...
    // cleanup
    vertexBuffer->unlock();
    glDisableClientState(GL_COLOR_ARRAY);
    Buffer, array of elements.
    Definition RRBuffer.h:168
    virtual unsigned char * lock(RRBufferLock lock)
    Locks the buffer for accessing array of all elements at once. Not mandatory, may return nullptr.
    Global illumination solver for interactive applications.
    Definition RRSolver.h:58
    @ BL_READ
    Lock for reading only.
    Definition RRBuffer.h:107
    Using ambient value in GLSL vertex shader:
    varying vec3 ambientLight;
    void vertexShader()
    {
    ...
    ambientLight = gl_Color;
    }
    Using ambient value in GLSL fragment shader:
    varying vec3 ambientLight;
    void fragmentShader()
    {
    ...
    gl_FragColor = ... + materialColor * vec4(ambientLight.xyz,0.0);
    }
  • Direct3D 9 example:
    Rendering with per vertex ambient.
    IDirect3DDevice9* device;
    IDirect3DPixelShader9* vertexShader;
    IDirect3DPixelShader9* pixelShader;
    // adapt your vertex declaration, let your mesh read data from stream 0
    // and add e.g. COLOR1 read from stream 1
    IDirect3DVertexDeclaration9* vertexDeclaration;
    device->CreateVertexDeclaration(description, &vertexDeclaration);
    ...
    // create d3d vertex buffer and fill it with vertexBuffer->lock() data
    rr::RRBuffer* vertexBuffer = object->illumination.getLayer(0);
    IDirect3DVertexBuffer9* d3dBuffer = ...;
    // to prevent data duplication and copying, implement RRBuffer
    // that stores vertex data directly into d3d vertex buffer
    ...
    // set rendering pipeline to use shaders below
    device->SetPixelShader(vertexShader);
    device->SetPixelShader(pixelShader);
    // activate previously created vertex declaration
    device->SetVertexDeclaration(vertexDeclaration);
    // set pointer to your mesh (vertices, possibly normals etc.) in stream 0
    device->SetStreamSource(0, ...);
    // set pointer to vertex illumination data in stream 1
    device->SetStreamSource(1, d3dBuffer, ...);
    // render primitives
    device->DrawPrimitive...
    // cleanup
    device->SetStreamSource(1, nullptr, 0, 0);
    device->SetStreamSource(0, nullptr, 0, 0);
    Using ambient value in HLSL vertex shader:
    void vertexShader(in float3 iAmbientLight: COLOR1,
    ..., out float3 oAmbientLight: COLOR1)
    {
    ...
    oAmbientLight = iAmbientLight;
    }
    Using ambient value in HLSL pixel shader:
    void pixelShader(in float3 iAmbientLight: COLOR1,
    ..., out float4 oColor: COLOR)
    {
    ...
    oColor = ... + materialColor * float4(iAmbientLight,0);
    }
  • Alternatively, applying colors from vertex buffer could be done in fixed pipeline, without shaders, but it is beyond scope of this documentation.
  • See Direct3D, OpenGL or your engine documentation for more details on streaming per vertex data to vertex shader and rendering with ambient light, ambient occlusion or bent normals.