I’m currently working on a project where I’m trying to implement a floor plane grid using a custom vertex and fragment shader. I came across a helpful example and decided to adapt it for my use in VTK.
A couple questions I have:
- Are the points defined in vtkPoints correctly passed as the vertexAttribute “a_position” ?
- I attempted to set the uniforms using the
VTKShaderProperty
of the actor object, but I’m not entirely sure if this is the correct approach. - Likewise I attempted to set the shader code using “SetVertexShaderCode” and “SetFragmentShaderCode” on the ShaderPropery object. is this correct?
The code i tried:
#include <iostream>
#include <array>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2) // VTK was built with vtkRenderingOpenGL2
VTK_MODULE_INIT(vtkInteractionStyle)
VTK_MODULE_INIT(vtkRenderingFreeType)
// VTK includes
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkPolyData.h>
#include <vtkPoints.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include "vtkMatrix4x4.h"
#include <vtkShaderProperty.h>
#include <vtkUniforms.h>
using namespace std;
const char * vertexShaderCode = "#version 150 \
\
uniform mat4 u_view_matrix; \
uniform mat4 u_projection_matrix; \
\
uniform mat4 u_view_matrix_inv;\
uniform mat4 u_projection_matrix_inv;\
\
uniform float u_grid_spacing;\
\
in vec3 a_position;\
\
out vec3 nearPoint;\
out vec3 farPoint;\
\
vec3 UnprojectPoint(float x, float y, float z) {\
vec4 unprojectedPoint = u_view_matrix_inv * u_projection_matrix_inv * vec4(x, y, z, 1.0);\
return unprojectedPoint.xyz / unprojectedPoint.w;\
}\
\
void main() {\
vec3 p = a_position;\
nearPoint = UnprojectPoint(p.x, p.y, 0.0).xyz; // unprojecting on the near plane\
farPoint = UnprojectPoint(p.x, p.y, 1.0).xyz; // unprojecting on the far plane\
gl_Position = vec4(p, 1.0); // using directly the clipped coordinates\
}";
const char * fragmentShaderCode = "#version 150 \
\
in vec3 nearPoint; \
in vec3 farPoint; \
\
uniform mat4 u_view_matrix; \
uniform mat4 u_projection_matrix; \
\
uniform mat4 u_view_matrix_inv; \
uniform mat4 u_projection_matrix_inv; \
\
uniform float u_grid_spacing; \
\
out vec4 f_color; \
\
vec4 grid(vec3 fragPos3D, float scale) { \
vec2 coord = fragPos3D.xz * scale * 1/u_grid_spacing ; \
\
// anti aliasing using screen-space partial deribatives \
vec2 derivative = fwidth(coord); \
vec2 grid = abs(fract(coord - 0.5) - 0.5) / derivative; \
float line = min(grid.x, grid.y); \
float minimumz = min(derivative.y, 1); \
float minimumx = min(derivative.x, 1); \
vec4 color = vec4(0.2, 0.2, 0.2, 1.0 - min(line, 1.0)); \
\
float axis_line_width = u_grid_spacing * 10; \
\
\
\
return color; \
} \
\
float computeDepth(vec3 pos) { \
float far=gl_DepthRange.far; float near=gl_DepthRange.near; \
vec4 clip_space_pos = u_projection_matrix * u_view_matrix * vec4(pos.xyz, 1.0); \
float ndc_depth = clip_space_pos.z / clip_space_pos.w; \
float depth = (((far-near) * ndc_depth) + near + far) / 2.0; \
return depth; \
} \
\
float computeLinearDepth(vec3 pos) { \
float near = 0.01; \
float far = 100; \
vec4 clip_space_pos = u_projection_matrix * u_view_matrix * vec4(pos.xyz, 1.0); \
float clip_space_depth = (clip_space_pos.z / clip_space_pos.w) * 2.0 - 1.0; // put back between -1 and 1 \
float linearDepth = (2.0 * near * far) / (far + near - clip_space_depth * (far - near)); // get linear value between 0.01 and 100 \
return linearDepth / far; // normalize \
} \
\
void main(void) { \
float t = -nearPoint.y / (farPoint.y - nearPoint.y); \
vec3 fragPos3D = nearPoint + t * (farPoint - nearPoint); \
\
gl_FragDepth = computeDepth(fragPos3D); \
\
float gridFadeSpeed = 16; \
float linearDepth = computeLinearDepth(fragPos3D); \
float fading = max(0, (0.5 - linearDepth * gridFadeSpeed)); \
\
f_color = grid(fragPos3D, 1, true); \
f_color += grid(fragPos3D, 0.1, true); \
\
f_color.a *= fading; \
}";
int main()
{
// A renderer and render window.
vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->AddRenderer(renderer);
renderWindow->SetWindowName("Grid Example");
// An interactor
vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindow->Render();
vtkNew<vtkInteractorStyleTrackballCamera> style;
renderWindowInteractor->SetInteractorStyle(style);
vtkNew<vtkPoints> points;
points->InsertNextPoint( 1, 1, 0);
points->InsertNextPoint(-1, -1, 0);
points->InsertNextPoint(-1, 1, 0);
points->InsertNextPoint(-1, -1, 0);
points->InsertNextPoint( 1, 1, 0);
points->InsertNextPoint( 1, -1, 0);
vtkNew<vtkPolyData> grid;
grid->SetPoints(points);
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputData(grid);
vtkSmartPointer<vtkActor> gridActor = vtkSmartPointer<vtkActor>::New();
gridActor->SetMapper(mapper);
vtkCamera* camera = renderer->GetActiveCamera();
vtkMatrix4x4* viewMatrix = camera->GetViewTransformMatrix();
vtkMatrix4x4* viewMatrixInverted = vtkMatrix4x4::New();
vtkMatrix4x4::Invert(viewMatrix, viewMatrixInverted);
float* viewMatrixArr = new float[16];
float* viewMatrixArrInv = new float[16];
for (size_t i=0;i<16;++i) viewMatrixArr[i] = static_cast<float>(viewMatrix->GetData()[i]);
for (size_t i=0;i<16;++i) viewMatrixArrInv[i] = static_cast<float>(viewMatrixInverted->GetData()[i]);
vtkMatrix4x4* projMatrix = camera->GetProjectionTransformMatrix(renderer);
vtkMatrix4x4* projMatrixInverted = vtkMatrix4x4::New();
vtkMatrix4x4::Invert(projMatrix, projMatrixInverted);
float* projMatrixArr = new float[16];
float* projMatrixInvArr = new float[16];
for (size_t i=0;i<16;++i) projMatrixArr[i] = static_cast<float>(projMatrix->GetData()[i]);
for (size_t i=0;i<16;++i) projMatrixInvArr[i] = static_cast<float>(projMatrixInverted->GetData()[i]);
vtkShaderProperty* sp = gridActor->GetShaderProperty();
sp->GetVertexCustomUniforms()->SetUniformMatrix4x4("u_view_matrix", viewMatrixArr);
sp->GetVertexCustomUniforms()->SetUniformMatrix4x4("u_projection_matrix", viewMatrixArrInv);
sp->GetVertexCustomUniforms()->SetUniformMatrix4x4("u_view_matrix_inv", viewMatrixArr);
sp->GetVertexCustomUniforms()->SetUniformMatrix4x4("u_projection_matrix_inv", projMatrixInvArr);
sp->GetVertexCustomUniforms()->SetUniformf("u_grid_spacing", 10.0f);
sp->SetVertexShaderCode(vertexShaderCode);
sp->SetFragmentShaderCode(fragmentShaderCode);
gridActor->GetProperty()->ShadingOn();
// Add the actors to the scene.
renderer->AddActor(gridActor);
// Begin mouse interaction.
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
This is how the final result should look.
Could you please provide insights into the recommended method for achieving this? Your guidance would be greatly appreciated.