
Tue, 01/14/2025 - 16:45
Hi!
I'm trying to use custom shaders with OCCT to learn how to use this kind of libraries.
At this moment, I know how to create a vertexShader and fragmentShader from a file and attach them to a new shaderProgram.
Also, I am able to push different variables, and those are received correctly in the shader.
My doubt is how can I create a custom vertex attribute buffer linked to a location.
I have found the object "Graphic3d_ShaderAttributeList" and I have this code:
{
int customAttrLocation = 5;
Handle(Graphic3d_ShaderAttribute) attr = new Graphic3d_ShaderAttribute("customAttrVal", customAttrLocation);
Graphic3d_ShaderAttributeList theAttributes(NCollection_BaseAllocator::CommonBaseAllocator());
theAttributes.Append(attr);
ShaderProg->SetVertexAttributes(theAttributes);
}
Even if this code is correct (which I don't really know) I cannot find a way to fill this attribute buffer with actual data. I would like to fill it with Float values for different purposes.
I have enabled attribute location in my GLSL files using --> #extension GL_ARB_explicit_attrib_location : enable
Any help on how to fill my custom attribute buffer with values?
Thanks!!
Wed, 01/15/2025 - 08:51
You need to pass vertex attributes within
Graphic3d_Buffer
passed toGraphic3d_Group::AddPrimitiveArray()
:The simplest way to realize how this buffer can be initialized is to look into
src/Graphic3d/Graphic3d_ArrayOfPrimitives.cxx
. You will need to addGraphic3d_TOA_CUSTOM
attribute (referring to location index within the shader program) within array ofGraphic3d_Attribute
passed toGraphic3d_Buffer::Init()
and initialize data for it within the buffer using one of available interfaces, which you'll find more convenient to you (basically speaking - through memory aliasing and offsets, the way how VBO are defined in OpenGL).Wed, 01/15/2025 - 18:04
EDIT: Don't bother reading the post, already found why my attribute buffer was not working, i used the incorrect size to fill it... Thanks for the hints btw!!
Hi!
Thanks for the response, i think i'm starting to understand how OCCT is working here. Although i have a problem in the execution of what you said.
Until now, my Compute() routine was working correctly with this code:
###############
Handle(Graphic3d_Group) grupo = mpPrs->CurrentGroup();
Handle(Graphic3d_ArrayOfTriangles) aPArray = StdPrs_ShadedShape::FillTriangles(mShape, Standard_False, aDummy, aDummy, aDummy);
if (!aPArray.IsNull())
{
grupo->SetClosed(true);
grupo->SetPrimitivesAspect(CADdrawer->ShadingAspect()->Aspect());
grupo->AddPrimitiveArray(Graphic3d_TOPA_TRIANGLES, aPArray->Indices(), aPArray->Attributes(), aPArray->Bounds(), true);
}
###############
After your reply I thought about creating my own attribute buffer, filling it mannually with the same values found in "aPArray->Attributes()".
I verified that the Attributes buffer only contains 2 attributes, Position and Normals, so I created a buffer with those and then copied the data byte-to-byte ( I know this is not optimal, it's just to understand the flow of the buffer creation)
This is the resulting code I wrote:
###############
Handle(Graphic3d_Group) grupo = mpPrs->CurrentGroup();
Handle(Graphic3d_ArrayOfTriangles) aPArray = StdPrs_ShadedShape::FillTriangles(mShape, Standard_False, aDummy, aDummy, aDummy);
if (!aPArray.IsNull())
{
// Create my own buffer with same attributes
const Handle(NCollection_BaseAllocator)& allocator = Graphic3d_Buffer::DefaultAllocator();
const Handle(Graphic3d_Buffer) newAttrBuffer = new Graphic3d_Buffer(allocator);
Graphic3d_Attribute atri[2];
atri[0].Id = Graphic3d_TOA_POS;
atri[0].DataType = Graphic3d_TOD_VEC3;
atri[1].Id = Graphic3d_TOA_NORM;
atri[1].DataType = Graphic3d_TOD_VEC3;
int nbAttribs = 2;
newAttrBuffer->Init(aPArray->VertexNumber(), atri, nbAttribs);
// Fill new buffer with the same data for each attribute, to generate the same drawing
int dummyInd;
Standard_Size posStride, oldPstride, normStride, oldNstride;
const Standard_Byte* oldPosData = aPArray->Attributes()->AttributeData(Graphic3d_TOA_POS, dummyInd, oldPstride);
const Standard_Byte* oldNormData = aPArray->Attributes()->AttributeData(Graphic3d_TOA_NORM, dummyInd, oldNstride);
int attributesTam = aPArray->Attributes()->Size() / aPArray->Attributes()->NbAttributes;
for (int i = 0; i < attributesTam; i += 1)
{
newAttrBuffer->ChangeAttributeData(Graphic3d_TOA_POS, dummyInd, posStride)[i] = oldPosData[i];
newAttrBuffer->ChangeAttributeData(Graphic3d_TOA_NORM, dummyInd, normStride)[i] = oldNormData[i];
}
grupo->SetClosed(true);
grupo->SetPrimitivesAspect(CADdrawer->ShadingAspect()->Aspect());
grupo->AddPrimitiveArray(Graphic3d_TOPA_TRIANGLES, aPArray->Indices(), newAttrBuffer, aPArray->Bounds(), true);
}
###############
If the code was correct, my assumtion is that I should obtain the same results as in the previous code, but for some reason when using the new attribute buffer I obtain no result in my viewer.
Maybe I'm forgetting to set something in the new buffer? Or maybe the byte-to-byte copy is not correct?
I can't figure this out, no error message is shown and during debug execution all routines seem to execute correctly.
Thanks in advance!!
Wed, 01/15/2025 - 19:30
Graphic3d_Buffer::AttributeData()
returns a pointer to beginning of attribute data in the buffer. So that the following loop and assignment make no sense to me:Instead, you need to returned
stride
multiplied by vertex index (from 0) as an offset from the beginning of this pointer, alias it actual per-attribute per-vertex layout (e.g. cast pointer toGraphic3d_Vec3*
in case ofGraphic3d_TOD_VEC3
) and assign data by values. Have a deeper look at methods inGraphic3d_ArrayOfPrimitives
like::SetVertexNormal()
and::SetVertice()
:In case of interleaved attributes (which is default), you may also define a structure holding all per-vertex attributes at once and work with it: