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.
Related
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!
I'm trying to play around with image manipulation in C and I want to be able to read and write pixels on an SDL Surface. (I'm loading a bmp to a surface to get the pixel data) I'm having some trouble figuring out how to properly use the following functions.
SDL_CreateRGBSurfaceFrom();
SDL_GetRGB();
SDL_MapRGB();
I have only found examples of these in c++ and I'm having a hard time implementing it in C because I don't fully understand how they work.
so my questions are:
how do you properly retrieve pixel data using GetRGB? + How is the pixel addressed with x, y cordinates?
What kind of array would I use to store the pixel data?
How do you use SDL_CreateRGBSurfaceFrom() to draw the new pixel data back to a surface?
Also I want to access the pixels individually in a nested for loop for y and x like so.
for(int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
// get/put the pixel data
}
}
First have a look at SDL_Surface.
The parts you're interested in:
SDL_PixelFormat*format
int w, h
int pitch
void *pixels
What else you should know:
On position x, y (which must be greater or equal to 0 and less than w, h) the surface contains a pixel.
The pixel is described by the format field, which tells us, how the pixel is organized in memory.
The Remarks section of SDL_PixelFormat gives more information on the used datatype.
The pitch field is basically the width of the surface multiplied by the size of the pixel (BytesPerPixel).
With the function SDL_GetRGB, one can easily convert a pixel of any format to a RGB(A) triple/quadruple.
SDL_MapRGB is the reverse of SDL_GetRGB, where one can specify a pixel as RGB(A) triple/quadruple to map it to the closest color specified by the format parameter.
The SDL wiki provides many examples of the specific functions, i think you will find the proper examples to solve your problem.
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.
Implementing GPU-based particle system using the algorithm in this paper:
http://www.gamasutra.com/view/feature/130535/building_a_millionparticle_system.php?print=1
There are two things i can't understand:
Why use a stack or a heap to store available particle index?
If a particle dead at time t, then it will start its life from zero at time t+1. There is a parameter N to control the number of particles on the screen. If I can reuse all particles, why do I care all the index of available particle and even use a heap to store it?
To update velocities and position, it said, "The actual simulation is implemented in a fragment shader. The shader is executed for each pixel of the render target by rendering a screen-sized quad...." If I want the particles to be drawn as points, do I need to change the quad to points? Why quad? How can it draw for points?
.
The term "particle is dead" is a term, that only describes the semantical dead of a particle. From the GPU's point of view, all particles are live at all time and all particles will be calculated in each frame. (Or at least, particles 0 to N will be processed, but even the dead ones).
Once the CPU "detects", that a particle is dead (e.g. it's age is 5 seconds or so) the index for that particle needs to be remembered so new particles can reuse that particle index. This can be done in many different ways, two obvious ways are stacks or heaps.
A special data structure to store those dead particle indices is only necessary, if the max ages of particles differ. If they don't differ, you can just implement a ring buffer. But most of the time, you will use this particle engine for all kinds of particles, and those might have variable time to live values. Then you need those data structures.
The algorithm uses the fragment shader to do velocity calculations. It reads data from one texture (that contains x/y/z coordinates instead of r/g/b color information) and writes to a different texture (that also contains x/y/z coordinates instead of r/g/b color information), uses a 1:1 mapping between source and target texture and renders the whole source texture to the target texture. This has nothing to do with the actual particles that will be rendered later in step 6. Render Particles.
Or in other words: "screen-sized quad" is actually a wrong term here, it should read "texture-sized quad" because at this point, nothing is drawn to the screen at all. The target texture (i.e. the texture, that will hold the new position information) IS the screen.
/edit just again:
OK, maybe rephrase the document:
You have a struct:
struct color {
float r, g, b;
};
and a few #defines:
#define vector color
#define x r
#define y g
#define z b
And you have a few arrays for your particles:
#define NP 1024 * 1024
struct vector particle_pos[2][NP];
struct vector particle_vel[2][NP];
uint32_t particle_birth_tick[NP];
// Double buffering - gonne have to remember, where
// we read from and where we write to:
struct vector * particle_pos_r = particle_pos[0];
struct vector * particle_pos_w = particle_pos[1];
struct vector * particle_vel_r = particle_vel[0];
struct vector * particle_vel_w = particle_vel[1];
Now:
Process Birth and Death
#define TTL 5 * 25 // 5 seconds * 25 simulation steps per second.
for (size_t i = 0; i < NP; ++i) {
if (particle_birth_tick[i] + TTL == current_tick) {
particle_pos_r[i].x = somewhere behind viewer;
particle_pos_r[i].y = somewhere behind viewer;
particle_pos_r[i].z = somewhere behind viewer;
particle_vel_r[i].x = 0;
particle_vel_r[i].y = 0;
particle_vel_r[i].z = 0;
free_list.add(i);
}
}
void add_particle(struct vector p, struct vector v) {
size_t i = free_list.pop_any();
particle_pos_r[i] = p;
particle_vel_r[i] = v;
}
Update Velocities
for (size_t i = 0; i < 1024 * 1024; ++i) {
particle_vel_w[i].x = do_calculations(particle_vel_r[i].x)
particle_vel_w[i].y = do_calculations(particle_vel_r[i].y)
particle_vel_w[i].z = do_calculations(particle_vel_r[i].z)
}
swap(particle_vel_r, particle_vel_w);
Update Positions
for (size_t i = 0; i < 1024 * 1024; ++i) {
particle_pos_w[i].x = particle_pos_r[i].x + particle_vel_r[i].x;
particle_pos_w[i].y = particle_pos_r[i].y + particle_vel_r[i].y;
particle_pos_w[i].z = particle_pos_r[i].z + particle_vel_r[i].z;
}
swap(particle_pos_r, particle_pos_w);
Sort for Alpha Blending
sort a bit...
Transfer Texture Data to Vertex Data
copy the pos texture into a vbo
Render Particles
actually draw particles
The interesting point here is, that steps 2-5 all happen exclusively on the GPU (Step 1 happens on both, GPU and CPU). And hence the term "rendering". Because that loops in 2 and 3 just "render" the "texture" particle_vel_r and/or particle_pos_r into the the "frame buffer" particle_vel_w or particle_pos_w completely filling the frame buffer "screen-sized quad" with the source texture.
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;