-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improved UBO/SSBO implementation #1317
Conversation
Suggestion about the API: class MyStruct implements BufferStruct {
@BufferIndex(index = 0)
public float a;
@BufferIndex(index = 1)
protected Vector3f b;
} That way you don't need a wrapper or "complex" API if you want to update values. bo.updateAllData(s);
bo.updateData(s, 0);
bo.updateData(s, 0, 1); // equivalent to updateAllData in this example Yes it shifts "responsibility" down to the user to know what values have been changed this frame, but wouldn't the user know anyway? I just feel accessing fields directly feels a lot more native than having wrapper classes and having to call .get() and .set() on them. |
Mhh.. you would need to remember the order of all the fields for that, the StructField is there to provide an api for someone who is not familiar with the internals. I believe the lower level should use the StructFields since they provide a more flexible and solid api, however, we could implement those "unwrapped" structs as an abstraction layer on top of it, maybe with a StaticStruct interface that assumes fields will never change and then wrap the fields internally into StructFields with reflection, it should be pretty trivial to extend the StructUtils.getFromClass to do that. Another thing we can do to improve this is getting rid of the get() method that might be confusing, it was originally there as a convenience method to return
but i think it probably makes more sense for the developer to do it outside of the "struct", in the code that is binding it to the material, that's why i didn't include it in the small "how to". |
Is this a candidate for v3.5.0? |
I think this should essentially be two commits, because the fixes for the Buffer implementation should probably be ported into 3.4 (if we even do a maintenance release, that is), because that's fundamentally broken, but different from a new buffer API. For instance, the parameters that are passed to the methods are just wrong. Regarding the features of this PR, I've found two more things in my usecase: Arrays and nested objects. Consider: struct PointLight {
vec3 Position;
vec4 Color;
float Radius;
};
const int NR_POINTLIGHTS = 32;
uniform PointLight m_PointLights[NR_POINTLIGHTS]; A) Would this be one UBO with an array or would this be 32 UBOs of PointLight? Another thing I thought about though, is: Does a good change detection and updateBufferRange even make sense, considering UBOs are typically smaller than 64 kIB and in the worst case of changing every second (interlaced) element, we'd have one update call per element, instead of just swapping the whole (maximum) 64 kiB at once. Anyway, other ideas I had were using a |
Resurrecting this PR. public static class CameraStruct implements Struct<Void>{
public final StructField<Vector2f> frustumNearFar=new StructField<Vector2f>(0,new Vector2f());
public final StructField<Vector2f> resolutionInverse=new StructField<Vector2f>(1,new Vector2f());
public final StructField<Vector2f> resolution=new StructField<Vector2f>(2,new Vector2f());
public final StructField<Matrix4f> viewMatrix=new StructField<Matrix4f>(3,new Matrix4f());
public final StructField<Matrix4f> projectionMatrix=new StructField<Matrix4f>(4,new Matrix4f());
public final StructField<Matrix4f> viewProjectionMatrix=new StructField<Matrix4f>(5,new Matrix4f());
public final StructField<Matrix4f> viewMatrixInverse=new StructField<Matrix4f>(6,new Matrix4f());
public final StructField<Matrix4f> projectionMatrixInverse=new StructField<Matrix4f>(7,new Matrix4f());
public final StructField<Matrix4f> viewProjectionMatrixInverse=new StructField<Matrix4f>(8,new Matrix4f());
public final StructField<Vector4f> viewPort=new StructField<Vector4f>(9,new Vector4f());
public final StructField<Float> aspect=new StructField<Float>(10,0f);
public final StructField<Vector3f> cameraPosition=new StructField<Vector3f>(11,new Vector3f());
public final StructField<Vector3f> cameraDirection=new StructField<Vector3f>(12,new Vector3f());
public final StructField<Vector3f> cameraLeft=new StructField<Vector3f>(13,new Vector3f());
public final StructField<Vector3f> cameraUp=new StructField<Vector3f>(14,new Vector3f());
@Override public Void get() {return null;}
}
public static class TimerStruct implements Struct<Void>{
public final StructField<Float> speed=new StructField<Float> (0,0f);
public final StructField<Float> time=new StructField<Float> (1,0f);
public final StructField<Integer> intTime=new StructField<Integer> (2,0);
public final StructField<Float> tpf=new StructField<Float> (3,0f);
public final StructField<Float> frameRate=new StructField<Float> (4,0f);
public final StructField<Vector2f> deltaTime=new StructField<Vector2f> (5,new Vector2f());
@Override public Void get() {return null;}
}
public static class GeometryStruct implements Struct<Void>{
public final StructField<Matrix4f> worldMatrix=new StructField<Matrix4f> (0,new Matrix4f());
public final StructField<Matrix4f> worldViewMatrix=new StructField<Matrix4f>(1,new Matrix4f());
public final StructField<Matrix3f> normalMatrix=new StructField<Matrix3f>(2,new Matrix3f());
public final StructField<Matrix3f> worldNormalMatrix=new StructField<Matrix3f>(3,new Matrix3f());
public final StructField<Matrix4f> worldViewProjMatrix=new StructField<Matrix4f>(4,new Matrix4f());
public final StructField<Matrix4f> worldMatrixInv=new StructField<Matrix4f>(5,new Matrix4f());
public final StructField<Matrix3f> worldMatrixInvTrsp=new StructField<Matrix3f>(6,new Matrix3f());
public final StructField<Matrix4f> worldViewMatrixInv=new StructField<Matrix4f>(7,new Matrix4f());
public final StructField<Matrix4f> worldViewProjMatrixInv=new StructField<Matrix4f>(8,new Matrix4f());
public final StructField<Matrix3f> normalMatrixInv=new StructField<Matrix3f>(9,new Matrix3f());
@Override public Void get() {return null;}
} #extension GL_ARB_explicit_attrib_location : enable
#define bindUBO(type,name) layout (std140) uniform bo_##name { \
type name;\
}
#define bindSSBO(type,name) layout (std140) buffer bo_##name { \
type name;\
}
struct Camera{
vec2 frustumNearFar;
vec2 resolutionInverse;
vec2 resolution;
mat4 viewMatrix;
mat4 projectionMatrix;
mat4 viewProjectionMatrix;
mat4 viewMatrixInverse;
mat4 projectionMatrixInverse;
mat4 viewProjectionMatrixInverse;
vec4 viewPort;
float aspect;
vec3 cameraPosition;
vec3 cameraDirection;
vec3 cameraLeft;
vec3 cameraUp;
};
struct Geometry{
mat4 worldMatrix;
mat4 worldViewMatrix;
mat3 normalMatrix;
mat3 worldNormalMatrix;
mat4 worldViewProjMatrix;
mat4 worldMatrixInv;
mat3 worldMatrixInvTrsp;
mat4 worldViewMatrixInv;
mat4 worldViewProjMatrixInv;
mat3 normalMatrixInv;
};
#if defined INSTANCING
in mat4 inInstanceData;
#endif
mat4 Geometry_getWorldMatrix(in Geometry geo){
#if defined INSTANCING
mat4 worldMatrix = mat4(vec4(inInstanceData[0].xyz, 0.0),
vec4(inInstanceData[1].xyz, 0.0),
vec4(inInstanceData[2].xyz, 0.0),
vec4(inInstanceData[3].xyz, 1.0));
return worldMatrix;
#else
return geo.worldMatrix;
#endif
}
vec3 Geometry_transformWorldNormal(in Geometry geo,in vec3 normal){
#if defined INSTANCING
vec4 quat = vec4(inInstanceData[0].w, inInstanceData[1].w,inInstanceData[2].w, inInstanceData[3].w);
return normal + vec3(2.0) * cross(cross(normal, quat.xyz) + vec3(quat.w) * normal, quat.xyz);
#else
return normalize(geo.worldNormalMatrix*normal);
#endif
}
struct Timer{
float speed;
float time;
int intTime;
float tpf;
float frameRate;
vec2 deltaTime;
};
Arrays of structs are not implemented in this pr |
I reworked this and made a new PR: #1782 |
This fixes some bugs on the current UBO/SSBO implementation and extends/rewrites part of it to be more user friendly.
Usage: