I have a vertex buffer object containing vertex data for a model. However the layout is a bit weird. The vertex uses 4 x uint_8 for the position and 4 x int_8 for the normal data. The texture position data is appended at the end, with 4 x uint_8 representing a float value, that I can access with a offset value. Using 8 bytes would give me 2 float values that i can use in a vec2 for texture coordinates.
The layout is basically [ [4 x uint_8 (vertex pos)] | [ 4 x int_8 (vertex_normal) ] | ... (alternating pos and norm) | [ 4x uint_8 ] (byte data for float value)].
In my hit shader I read the buffer as an array of int_8 and I am able to read the vertex data without problems. However I can't seem to find a way to construct a float value out of the 4 bytes used to represent it.
I can of course change the stucture of the data, but I have legacy code that relies on this structure and changing it would break the rest of the program. I could also create a new vertex buffer, but since I already have the data and can read it without problems it would only take up more space and would be redundant in my opinion.
There is probably a way to define the structure before, so that buffer information has the right format in the shader. I know that you can set a format for the vertex input in a pipeline, but since this is a raytracing pipeline, I possibly cannot use this feature. But maybe I am wrong.
So the final question is: Is it possible to construct a float value out of 4 uint_8 values in a glsl shader, or should I consider changing the vertex buffer? Or is there maybe another way to define the data?
I have found a solution that works for me.
Basically I use two layouts with the same set and binding, except for the textures and normals the buffer is read as an array of int8 values. The buffer in the second layout is read as an array of vec2s. Since the buffer reads the original byte data it can pack it into a vec2 correctly.
So for example the byte data
[31, 133, 27, 63, 84, 224, 75, 63]
would give me a vec2 of
(0.6075, 0.7964)
which is what I wanted.
Of course this solution is not perfect, but for now it is enough. If you know any prettier solutions, feel free to share them!
Related
I'm trying to convert a program written in C using legacy OpenGL Fixed Pipeline commands.
I'm stuck trying to pass some data into a Vertex Shader. I'm trying to use the latest 4.5 commands and I have managed to pass in my array of vertex coordinates "vertices[]" to the Vertex Shader using
glCreateVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
glCreateBuffers(1, &vertex_buffer);
glNamedBufferStorage(vertex_buffer, sizeof(verticies), verticies, GL_DYNAMIC_STORAGE_BIT);
glVertexArrayVertexBuffer(vertex_array_object, 0, vertex_buffer, 0, sizeof(float)*3);
glVertexArrayAttribFormat(vertex_array_object,0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribBinding(vertex_array_object,0,0);
glEnableVertexArrayAttrib(vertex_array_object,0);
This all works fine and I can render the vertices as points.
As well as passing the vertices I also need to pass an additional block of 4 values for each vertex which I then want to pass from the Vertex Shader to a Geometry Shader. The values I need to pass are in an array of structures (1 per vertex) where the structure is defined as
typedef struct { /* Vertex vector data structure */
unsigned char v; /* Scaled magnitude value " */
char x; /* X Component of direction cosine */
char y; /* Y " " " " */
char z; /* Z " " " " */
} NVD;
I can't easily change this structure as it's used in lots of other places in the code.
Inside the vertex shader I need the 4 values as integers in the ranges
v (0->255)
x,y,z (-127 > 127)
I can't easily change this structure as it's used in lots of other places in the code.
Well, you're going to have to because you can't use structs as interface variables between shader stages. You can pass the data along as a single ivec4, with each component storing the value you want. Though really, you should just pass the floating-point values you compute in the shader; it's going to be 128-bits per-vertex either way, so no point in taking the time to quantize the data.
If the size of this data is shown through profiling to be an actual problem (and using a GS at all is far more likely to be the performance problem), you can encode the data in a single uint for passing to the GS, then unpacking it on the other end.
I have a buffer containing 6 values, the first three being position and the other three are the color of the vertex. I want to modify those values in the compute shader, but only positions, not the color. I achieved this by using Image Load/Store, but I used all vertex data, not only a part of it (one attribute). So basically I don't know how to get only one attribute in compute shader, and modify it, and write it back to the buffer.
This is the code that worked for one (and only) attribute.
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
glGenTextures(1, &position_tbo);
glBindTexture(GL_TEXTURE_BUFFER, position_tbo);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, position_buffer);
glsl:
layout (local_size_x = 128) in;
layout (rgba32f, binding = 0) uniform imageBuffer position_buffer;
void main(void)
{
vec4 pos = imageLoad(position_buffer, int(gl_GlobalInvocationID.x));
pos.xyz = (translation * vec4(pos.xyz, 1.0)).xyz;
imageStore(position_buffer, int(gl_GlobalInvocationID.x), pos);
}
So how do I store only part of the vertex data into pos, not all attributes? Where do I specify what attribute goes into pos? And if I imageStore some specific attribute back to the buffer, am I sure that only that part of the buffer will be changed (the attribute I want to modify) and other attributes will remain the same?
Vertex Array State defined by functions like glVertexAttribPointer() is only relevant when drawing with the graphics pipeline. It defines the mapping from buffer elements to input vertex attributes. It does not have any effect in compute mode.
It is you yourself who defines the layout of your vertex buffer(s) and sets up the Vertex Array accordingly. Thus, you necessarily know where in your buffer to find which component of which attribute. If you didn't then you couldn't ever use the buffer to draw anything either.
I'm not sure why exactly you chose to use image load/store to access your vertex data in your compute shader. I would suggest simply binding it as a shader storage buffer. Assuming your buffers just contain a bunch of floats, the probably simplest approach would be to just interpret them as an array of floats in your compute shader:
layout(std430, binding = 0) buffer VertexBuffer
{
float vertex_data[];
};
You can then just access the i-th float in your buffer as vertex_data[i] in your compute shader via a normal index, just like any other array…
Apart from all that, I should point out that the glVertexAttribPointer() call in your code above sets up the buffer for only one vertex attribute consisting of 4 floats rather than two attributes of 3 floats each.
According to a reference that I've been reading, some planar YUV formats (e.g. UYVY) use macropixels which contain data for multiple pixels - specifically, in the case of UYVY, luma values per pixel and U and V samples for every other horizontal pixel.
What I don't see described is what value should be used for video when the dimensions are not divisible by 2. For example, if a frame's width in pixels is odd, should the last macropixel on each line wrap onto the next line, or should the second Y value be assumed to be ignored during decoding? Is there a standard for what that Y value should be set to (e.g. zero)?
If the macropixels do wrap, then what should be the case for the final macropixel in frame sizes with an odd pixel count, such as 51x51?
I asked about this on #ffmpeg on Freenode IRC, and a kind person named iive gave me some answers.
Each line is treated separately, so there's no wrapping of values in a macropixel from one line to the next. In the case of an odd frame width, the Y value from the last pixel is duplicated. So, if you've got a pixel with YUV values of [123, 45, 67] at the end of a line, the UYVY macropixel would have values of [45, 123, 67, 123].
There may also be padding at the end of each line's data, in order to align each frame line to a boundary so that SIMD instructions only need to operate on aligned data. This depends on the exact format you're using.
In the book learning opencv there's a question in chapter 3 :
Create a two dimensional matrix with three channels of type byte with data size 100-by-100 and initialize all the values to 0.
Use the pointer element to access cvptr2D to point to the middle 'green' channel.Draw the rectangle between 20,5 and 40,20.
I've managed to do the first part, but I can't get my head around second part. Here's what I've done so far :
/*
Create a two dimensional matrix with three channels of type byte with data size 100- by-100 and initialize all the values to 0.
Use the pointer element to access cvptr2D to point to the middle 'green' channel.Draw `enter code here`the rectangle between 20,5 and 40,20.
*/
void ex10_question3(){
CvMat* m = cvCreateMat(100,100,CV_8UC3);
CvSetZero(m); // initialize to 0.
uchar* ptr = cvPtr2D(m,0,1); // if RGB, then start from first RGB pair, Green.
cvAdd(m,r);
cvRect r(20,5,20,15);
//cvptr2d returns a pointer to a particular row element.
}
I was considering adding both the rect and matrix, but obviously that won't work because a rect is just co-ordinates, and width/height. I'm unfamiliar with cvPtr2D(). How can I visualise what the exercise wants me to do and can anyone give me a hint in the right direction? The solution must be in C.
From my understanding with interleaved RGB channels the 2nd channel will always be the channel of interest. (array index : 1,4,6..)
So that's the direction where the winds blow from...
First of all, the problem is the C API. This API is still present for legacy reasons, but will soon become obsolete. If you are serious about OpenCV please refer to C++ API. The official tutorials are great source of information.
To further target your question, this would be implementation of your question in C++.
cv::Mat canvas = cv::Mat::zero(100,100, CV_8UC3); // create matrix of bytes, filled with 0
std::vector<cv::Mat> channels(3); // prepare storage for splitting
split(canvas, channels); // split matrix to single channels
rectangle(channels[1], ...); // draw rectangle [I don't remember exact params]
merge(channels, canvas); // merge the channels together
If you only need to draw green rectangle, it's actually much easier:
cv::Mat canvas = cv::Mat::zero(100,100, CV_8UC3); // create matrix of bytes, filled with 0
rectangle(canvas, ..., Scalar(0,255,0)); // draw green rectangle
Edit:
To find out how to access single pixels in image using C++ API please refer to this answer:
https://stackoverflow.com/a/8139210/892914
Try this code:
cout<<"Chapter 3. Task 3."<<'\n';
CvMat *Mat=cvCreateMat(100, 100, CV_8UC3);
cvZero(Mat);
for(int J=5; J<=20; J++)
for(int I=20; I<40; I++)
(*(cvPtr2D(Mat, J, I)+1))=(uchar)(255);
cvNamedWindow("Chapter 3. Task 3", CV_WINDOW_FREERATIO);
cvShowImage("Chapter 3. Task 3", Mat);
cvWaitKey(0);
cvReleaseMat(&Mat);
cvDestroyAllWindows;
I am trying to solve numerically a set of partial differential equations in three dimensions. In each of the equations the next value of the unknown in a point depends on the current value of each unknown in the closest points.
To write an efficient code I need to keep the points close in the three dimensions close in the (one-dimensional) memory space, so that each value is called from memory just once.
I was thinking of using octtrees, but I was wondering if someone knows a better method.
Octtrees are the way to go. You subdivide the array into 8 octants:
1 2
3 4
---
5 6
7 8
And then lay them out in memory in the order 1, 2, 3, 4, 5, 6, 7, 8 as above. You repeat this recursively within each octant until you get down to some base size, probably around 128 bytes or so (this is just a guess -- make sure to profile to determine the optimal cutoff point). This has much, much better cache coherency and locality of reference than the naive layout.
One alternative to the tree-method: Use the Morton-Order to encode your data.
In three dimension it goes like this: Take the coordinate components and interleave each bit two zero bits. Here shown in binary: 11111b becomes 1001001001b
A C-function to do this looks like this (shown for clarity and only for 11 bits):
int morton3 (int a)
{
int result = 0;
int i;
for (i=0; i<11; i++)
{
// check if the i'th bit is set.
int bit = a&(1<<i);
if (bit)
{
// if so set the 3*i'th bit in the result:
result |= 1<<(i*3);
}
}
return result;
}
You can use this function to combine your positions like this:
index = morton3 (position.x) +
morton3 (position.y)*2 +
morton3 (position.z)*4;
This turns your three dimensional index into a one dimensional one. Best part of it: Values that are close in 3D space are close in 1D space as well. If you access values close to each other frequently you will also get a very nice speed-up because the morton-order encoding is optimal in terms of cache locality.
For morton3 you better not use the code above. Use a small table to look up 4 or 8 bits at a time and combine them together.
Hope it helps,
Nils
The book Foundations of Multidimensional and Metric Data Structures can help you decide which data structure is fastest for range queries: octrees, kd-trees, R-trees, ...
It also describes data layouts for keeping points together in memory.