I am modifying the excellent code provided in this answer Creating a 3D sphere in Opengl using Visual C++ to suit my needs, which is to draw it using GL_TRIANGLES and face culling like this:
GLCALL(glEnable(GL_CULL_FACE));
GLCALL(glCullFace(GL_BACK));
GLCALL(glFrontFace(GL_CCW));
I've managed to make the indices work for triangles, but I cant bloody figure out how to eliminate the cull face problem; as it is, it culls the wrong face using the indice setup I got below:
bool CreateSphereData(const float radius, const uint32_t rings, const uint32_t sectors, std::vector<float>& vertexData, std::vector<float>& normalData, std::vector<float>& texcoordData, std::vector<uint32_t>& indiceData)
{
if (radius <= 0 || rings <= 0 || sectors <= 0)
return false;
const float R = 1.0f / (float)(rings - 1);
const float S = 1.0f / (float)(sectors - 1);
const float pi = boost::math::constants::pi<float>();
const float pi_2 = pi / 2;
vertexData.resize(rings * sectors * 3);
normalData.resize(rings * sectors * 3);
texcoordData.resize(rings * sectors * 2);
auto v = vertexData.begin();
auto n = normalData.begin();
auto t = texcoordData.begin();
for (uint32_t r = 0; r < rings; r++)
{
for (uint32_t s = 0; s < sectors; s++)
{
const float y = sin(-pi_2 + pi * r * R);
const float x = cos(2 * pi * s * S) * sin(pi * r * R);
const float z = sin(2 * pi * s * S) * sin(pi * r * R);
*t++ = s*S;
*t++ = r*R;
*v++ = x * radius;
*v++ = y * radius;
*v++ = z * radius;
*n++ = x;
*n++ = y;
*n++ = z;
}
}
indiceData.resize(rings * sectors * 6);
auto i = indiceData.begin();
for (uint32_t r = 0; r < rings; r++)
{
for (uint32_t s = 0; s < sectors; s++)
{
*i++ = (r + 1) * sectors + s;
*i++ = r * sectors + s;
*i++ = r * sectors + (s + 1);
*i++ = (r + 1) * sectors + (s + 1);
*i++ = (r + 1) * sectors + s;
*i++ = r * sectors + (s + 1);
}
}
return true;
}
I am sure it is simple but I can't get it right. Any pointers?
EDIT/ANSWER:
Simply the following indices draws it correctly with setup mentioned above:
indiceData.resize(rings * sectors * 6);
auto i = indiceData.begin();
for (uint32_t r = 0; r < rings-1; r++)
{
for (uint32_t s = 0; s < sectors-1; s++)
{
*i++ = r * sectors + (s + 1);
*i++ = r * sectors + s;
*i++ = (r + 1) * sectors + s;
*i++ = r * sectors + (s + 1);
*i++ = (r + 1) * sectors + s;
*i++ = (r + 1) * sectors + (s + 1);
}
}
Related
I want to implement equivalent of matlab icdf function in C++, I have already found this useful post: https://www.johndcook.com/blog/cpp_phi_inverse/. But I want it with optional mu and sigma parameters as in matlab.
What I am supposed to change?
Inspired from https://gist.github.com/kmpm/1211922/6b7fcd0155b23c3dc71e6f4969f2c48785371292:
double inverse_of_normal_cdf(const double p, const double mu, const double sigma)
{
if (p <= 0.0 || p >= 1.0)
{
std::stringstream os;
os << "Invalid input argument (" << p
<< "); must be larger than 0 but less than 1.";
throw std::invalid_argument(os.str());
}
double r, val;
const double q = p - 0.5;
if (std::abs(q) <= .425) {
r = .180625 - q * q;
val =
q * (((((((r * 2509.0809287301226727 +
33430.575583588128105) * r + 67265.770927008700853) * r +
45921.953931549871457) * r + 13731.693765509461125) * r +
1971.5909503065514427) * r + 133.14166789178437745) * r +
3.387132872796366608)
/ (((((((r * 5226.495278852854561 +
28729.085735721942674) * r + 39307.89580009271061) * r +
21213.794301586595867) * r + 5394.1960214247511077) * r +
687.1870074920579083) * r + 42.313330701600911252) * r + 1);
}
else {
if (q > 0) {
r = 1 - p;
}
else {
r = p;
}
r = std::sqrt(-std::log(r));
if (r <= 5)
{
r += -1.6;
val = (((((((r * 7.7454501427834140764e-4 +
.0227238449892691845833) * r + .24178072517745061177) *
r + 1.27045825245236838258) * r +
3.64784832476320460504) * r + 5.7694972214606914055) *
r + 4.6303378461565452959) * r +
1.42343711074968357734)
/ (((((((r *
1.05075007164441684324e-9 + 5.475938084995344946e-4) *
r + .0151986665636164571966) * r +
.14810397642748007459) * r + .68976733498510000455) *
r + 1.6763848301838038494) * r +
2.05319162663775882187) * r + 1);
}
else { /* very close to 0 or 1 */
r += -5;
val = (((((((r * 2.01033439929228813265e-7 +
2.71155556874348757815e-5) * r +
.0012426609473880784386) * r + .026532189526576123093) *
r + .29656057182850489123) * r +
1.7848265399172913358) * r + 5.4637849111641143699) *
r + 6.6579046435011037772)
/ (((((((r *
2.04426310338993978564e-15 + 1.4215117583164458887e-7) *
r + 1.8463183175100546818e-5) * r +
7.868691311456132591e-4) * r + .0148753612908506148525)
* r + .13692988092273580531) * r +
.59983220655588793769) * r + 1);
}
if (q < 0.0) {
val = -val;
}
}
return mu + sigma * val;
}
I have written a function to convert an image in YUV420P to RGB but it is taking 30 millisecond to convert an image (size: 1280 x 720) into RGB, but when I am using ffmpeg function ( as this) to convert YUV image into RGB its taking only 2 millisecond for the same image. What is the problem with my code ? How can I optimize the code that I have written ??
My code is given below
int step = origImage->widthStep;
uchar *data = (uchar *)origImage->imageData;
int size = origImage->width * origImage->height;
IplImage* img1 = cvCreateImage(cvGetSize(origImage), IPL_DEPTH_8U, 3);
for (int i = 0; i<origImage->height; i++)
{
for (int j=0; j<origImage->width; j++)
{
float Y = data[i*step + j];
float U = data[ (int)(size + (i/2)*(step/2) + j/2) ];
float V = data[ (int)(size*1.25 + (i/2)*(step/2) + j/2)];
float R = Y + 1.402 * (V - 128);
float G = Y - 0.344 * (U - 128) - 0.714 * (V - 128);
float B = Y + 1.772 * (U - 128);
if (R < 0){ R = 0; } if (G < 0){ G = 0; } if (B < 0){ B = 0; }
if (R > 255 ){ R = 255; } if (G > 255) { G = 255; } if (B > 255) { B = 255; }
cvSet2D(img1, i, j,cvScalar(B,G,R));
}
}
Here, try this(should reduce to 25 milliseconds):
int step = origImage->widthStep;
uchar *data = (uchar *)origImage->imageData;
int size = origImage->width * origImage->height;
IplImage* img1 = cvCreateImage(cvGetSize(origImage), IPL_DEPTH_8U, 3);
int stepDb2=step /2;
float sizeMb1d25=size*1.25 ;
int origImagePTheight=origImage->height;
int origImagePTwidth=origImage->width;
for (int i = 0; i<origImagePTheight; i++)
{
float idb2=i/2;
int iStep=i*step;
for (int j=0; j<origImagePTwidth; j++)
{
float variable=idb2*stepDb2 + j/2;
float Y = data[iStep + j];
float U = -128 + data[ (int)(size + variable) ];
float V = -128 + data[ (int)(sizeMb1d25 + variable)];
float R = Y + 1.402 * V ;
float G = Y - 0.344 * U - 0.714 * V;
float B = Y + 1.772 * U;
R= R * !(R<0);
G= G * !(G<0);
B= B * !(B<0);
R=R*(!(R>255)) + 255 * (R>255);
G=G*(!(G>255)) + 255 * (G>255);
B=B*(!(B>255)) + 255 * (B>255);
cvSet2D(img1, i, j,cvScalar(B,G,R));
}
}
I want to modify the code for generating 3D sphere, so it uses triangles for drawing instead of quads. The problem is, as usual, that I get some error -- "vector iterator not incrementable". What's wrong with it?
SolidSphere(float radius, unsigned int rings, unsigned int sectors)
{
float const R = 1.0f / (float)(rings-1);
float const S = 1.0f / (float)(sectors-1);
int r, s;
vertices.resize(rings * sectors * 3);
normals.resize(rings * sectors * 3);
texcoords.resize(rings * sectors * 2);
std::vector<GLfloat>::iterator v = vertices.begin();
std::vector<GLfloat>::iterator n = normals.begin();
std::vector<GLfloat>::iterator t = texcoords.begin();
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
float const x = sinf(M_PI * r * R) * cosf(2 * M_PI * s * S);
float const y = sinf(-M_PI_2 + M_PI * r * R );
float const z = sinf(2.0f * M_PI * s * S) * sinf( M_PI * r * R );
*t++ = s*S;
*t++ = r*R;
*v++ = x * radius;
*v++ = y * radius;
*v++ = z * radius;
*n++ = x;
*n++ = y;
*n++ = z;
}
indices.resize(rings * sectors * 4);
std::vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings-1; r++) for(s = 0; s < sectors-1; s++) {
/* triangles -- not working!
*i++ = r * sectors + s;
*i++ = (r + 1) * sectors + (s + 1);
*i++ = r * sectors + (s + 1);
*i++ = r * sectors + s;
*i++ = (r + 1) * sectors + s;
*i++ = (r + 1) * sectors + (s + 1); */
/* quads */
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
}
}
Looks like your triangle-generator-version of the loop does(sectors-1) times (rings-1) iterations, each one increasing i six times, but you have resized the vector i iterates through to just (rings * sectors * 4), which was enough to the quad-generator-version of the loop.
Assuming the triangle version was ok, this adjust shall fix it:
indices.resize(rings * sectors * 6)
This kind of oversight generally arises when you code without drinking enough coffee. Or too much of it (graph showing the hyperbola boundaries when your code will actually fail, (mapping rings and sectors numbers to x and y) due to the fact that you are allocating more space then needed for the iterations).
Heres a pic of the problem:
And here is the wireframe:
As you can see from the pictures above, I have some sort of weird graphical issue and am not sure how to fix, I think somethings wrong with the code although noone else has had trouble with the code.
Code:
unsigned int rings = 12, sectors = 24;
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
int r, s;
vertices.resize(rings * sectors * 3);
normals.resize(rings * sectors * 3);
texcoords.resize(rings * sectors * 2);
std::vector<GLfloat>::iterator v = vertices.begin();
std::vector<GLfloat>::iterator n = normals.begin();
std::vector<GLfloat>::iterator t = texcoords.begin();
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
*t++ = s*S;
*t++ = r*R;
*v++ = x * getR();
*v++ = y * getR();
*v++ = z * getR();
*n++ = x;
*n++ = y;
*n++ = z;
}
indices.resize(rings * sectors * 4);
std:vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices.data());
glNormalPointer(GL_FLOAT, 0, normals.data());
glTexCoordPointer(2, GL_FLOAT, 0, texcoords.data());
glDrawElements(GL_QUADS, indices.size(), GL_UNSIGNED_SHORT, indices.data());
Code taken from (Creating a 3D sphere in Opengl using Visual C++)
indices will end up with indexes outside of vertices.
The last four values in indices will be:
*i++ = 11 * 24 + 23 = 287;
*i++ = 11 * 24 + (23 + 1) = 288;
*i++ = (11 + 1) * 24 + (23 + 1) = 312;
*i++ = (11 + 1) * 24 + 23 = 311;
but vertices only contains 288 vertexes. I assume why it works for other people is that glDrawElements might wrap the indexes in some implementations.
Trying to implement a sphere example code I found here on stackoverflow I have been running into problems. Note that I am not using the draw code, I am using the void SolidSphere function from this example to create my vertex data.
This is my code with some minor changes to the example that I refered to:
std::vector<GLfloat> vertices;
std::vector<GLfloat> normals;
std::vector<GLfloat> texcoords;
std::vector<GLushort> indices;
Sphere(shared_ptr<GL::Shader> _shader, shared_ptr<Material> _material, float radius, unsigned int rings, unsigned int sectors)
{
this->attachShader(_shader);
this->attachMaterial(_material);
/** Implementation from:
https://stackoverflow.com/questions/5988686/how-do-i-create-a-3d-sphere-in-opengl-using-visual-c?lq=1
**/
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
int r, s;
vertices.resize(rings * sectors * 3);
//normals.resize(rings * sectors * 3);
texcoords.resize(rings * sectors * 2);
std::vector<GLfloat>::iterator v = vertices.begin();
//std::vector<GLfloat>::iterator n = sphere_normals.begin();
std::vector<GLfloat>::iterator t = texcoords.begin();
for(r = 0; r < rings; r++) {
for(s = 0; s < sectors; s++) {
float const y = sin( -M_PI/2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
*t++ = s*S;
*t++ = r*R;
*v++ = x * radius;
*v++ = y * radius;
*v++ = z * radius;
//*n++ = x;
//*n++ = y;
//*n++ = z;
}
}
indices.resize(rings * sectors * 4);
std::vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings; r++) {
for(s = 0; s < sectors; s++) {
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
}
}
/************* THIS IS THE ADDED PART ********/
for (unsigned int i = 0; i < vertices.size(); i += 3) {
vertexCoords.push_back(glm::vec4(vertices[i], vertices[i+1], vertices[i+2], 1));
}
for (unsigned int i = 0; i < texcoords.size(); i += 2) {
textureCoords.push_back(glm::vec2(texcoords[i], texcoords[i+1]));
}
indexElements = indices;
cout << "Vertex vector size: " << vertexCoords.size() << endl;
cout << "Texture vector size: " << textureCoords.size() << endl;
cout << "Element index vector size: " << indexElements.size() << endl;
}
The only big change here is using M_PI / 2 instead of M_PI_2 and two loops that pushes the value into the format my code uses which is:
vector <glm::vec4> vertexCoords;
vector <glm::vec2> textureCoords;
vector <GLushort> indexElements;
Here is a picture of what I am rendering:
so I am seeing this last line on the top of the sphere..
Is it anything obvious I am doing wrong in this code that could cause this?
In this loop:
for(r = 0; r < rings; r++) {
for(s = 0; s < sectors; s++) {
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
}
}
you are accessing r+1 and s+1 which when r = rings - 1 and s = sectors - 1 (i.e. the last iteration of your loops) will be one higher than the data you have available.
This will be pointing to an uninitialised area of memory. This could contain anything, but in this case it appears to contain zeros which would explain the line going off to the origin.
As you are drawing the "next" quad you simply need to stop these loops one iteration earlier:
for(r = 0; r < rings-1; r++) {
for(s = 0; s < sectors-1; s++) {
You have only rings*sectors vertices but your indices go up to (rings-1+1)*sectors+(sectors-1+1)=rings*sectors+sectors. Which is exactly sectors number of vertices too much.
The problem is the output indices of bounds. Try to fix this part of the code so
indices.resize(rings * sectors * 4);
std::vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings-1; r++) {
for(s = 0; s < sectors-1; s++) {
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
}
}