如何使用点图元将纹理映射到参数方程式渲染的球体 [英] How to map texture to sphere that rendered by parametric equation using points primitive
问题描述
是否可以将由参数方程式生成并使用GL_POINTS原语渲染的纹理映射到Sphere?如果有可能,该怎么做?在我的代码中,我从网上复制了代码图像加载代码,并按指示进行加载.我没有遵循的一件事是为纹理坐标指定顶点,我不确定在用Sphere和GL_POINTS原语渲染时如何精确指定顶点.
我正在为项目使用旧版OpenGL2,并进行了太阳系模拟
这是代码的
以下代码通过堆叠许多光盘(层
)来创建一个球体.每个图层的周围都有 circumferenceTiles
个图块.U纹理坐标被包围在周围.V纹理坐标从球的南极缠绕到北极.
void CreateSphereMesh(int层,int圆周标题,std :: vector< float>& va,std :: vector< int> ia){const float pi = 3.1414927f;//创建顶点属性va.reserve((layers + 1)*(circumferenceTiles + 1)* 5);//5个浮点数:x,y,z,u,vfor(int il = 0; il< =层; ++ il){float layer_rel =(float)il/(float)layers;浮点数layer_ang =(1.0f-2.0f * layer_rel)* pi/2.0f;浮点数layer_sin = std :: sin(layer_ang);浮动layer_cos = std :: cos(layer_ang);对于(int ic = 0; ic< =圆周瓦片; ic ++){float circum_rel =(float)ic/(float)circumferenceTiles;浮点cricum_ang = circum_rel * 2.0f * pi-pi;float circum_sin = std :: sin(cricum_ang);float circum_cos = std :: cos(cricum_ang);va.push_back(layer_cos * circum_cos);//Xva.push_back(layer_cos * circum_sin);//yva.push_back(layer_sin);//zva.push_back(circum_rel);//你va.push_back(1.0f-layer_rel);//v}}//创建人脸索引ia.reserve(layers * circumferenceTiles * 6);for(int il = 0; il< layers; ++ il){for(int ic = 0; ic<圆周瓦片; ic ++){int i0 = il *(circumferenceTiles + 1)+ ic;int i1 = i0 + 1;int i3 = i0 +圆周瓦片+1;int i2 = i3 +1;int faces [] {i0,i1,i2,i0,i2,i3};ia.insert(ia.end(),faces +(il == 0?3:0),faces +(il == layers-1?3:6));}}}
固定函数点线的顶点数组对象可以这样指定:
GLuint vao;glGenVertexArrays(1,& vao);glBindVertexArray(vao);GLuint vbo;glGenBuffers(1,& vbo);glBindBuffer(GL_ARRAY_BUFFER,vbo);glBufferData(GL_ARRAY_BUFFER,va.size()* sizeof(* va.data()),va.data(),GL_STATIC_DRAW);Gluint ibo;glGenBuffers(1,& ibo);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ibo);glBufferData(GL_ELEMENT_ARRAY_BUFFER,ia.size()* sizeof(* ia.data()),ia.data(),GL_STATIC_DRAW);glVertexPointer(3,GL_FLOAT,5 * sizeof(* va.data()),0);glEnableClientState(GL_VERTEX_ARRAY);glTexCoordPointer(2,GL_FLOAT,5 * sizeof(* va.data()),(void *)(3 * sizeof(* va.data())));glEnableClientState(GL_TEXTURE_COORD_ARRAY);glBindVertexArray(0);glBindBuffer(GL_ARRAY_BUFFER,0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
对于现代OpenGL,必须这样定义通用顶点属性数据数组:
GLint avert_loc = ....;GLint atexc_loc = ....;glVertexAttribPointer(avert_loc,3,GL_FLOAT,GL_FALSE,5 * sizeof(* va.data()),0);glEnableVertexAttribArray(avert_loc);glVertexAttribPointer(atexc_loc,2,GL_FLOAT,GL_FALSE,5 * sizeof(* va.data()),(void *)(3 * sizeof(* va.data())));glEnableVertexAttribArray(atexc_loc);
完成绘图操作:
glEnable(GL_TEXTURE_2D);//仅适用于固定功能管道glBindVertexArray(vao);glDrawElements(GL_TRIANGLES,(GLsizei)ia.size(),GL_UNSIGNED_INT,0);glBindVertexArray(0);
预览:
Is it possible to map texture to Sphere that are generated by parametric equation and rendered using GL_POINTS primitive ? If it is possible, how is it be done and inside my code, I copy the code image loading code from the web and load it as it is instructed. One thing that I did not followed them is specifying the vertex for the texture coordinate, which I am not sure how to specify it exactly when render it with Sphere and with GL_POINTS primitive.
I am using the old OpenGL2 for my project and doing a solar system simulation
Here is the repository to the code and it is public
This is how I generate the sphere
// void Sphere::render () method, inside src/sphere.cpp - line 28
void Sphere::render () {
unsigned int angle = 0, angle2 = 0;
const double degree_to_rad = 3.14 / 180.0;
double value = .0, value2 = .0;
if ( this -> texture_file_name != "" ) {
glEnable ( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, this -> texture );
}
glBegin ( GL_POINTS );
for ( ; angle < 360; ++ angle ) {
value = angle * degree_to_rad;
for ( ; angle2 < 180; ++ angle2 ) {
value2 = angle2 * degree_to_rad;
/*/////////////////////////////////////////////
// do I need to do sth in here like glTexCoord2d ( ... ) ?
////////////////////////////////////////////*/
glVertex3d (
this -> calculateX ( value, value2 ),
this -> calculateY ( value, value2 ),
this -> calculateZ ( value )
);
}
angle2 = 0;
}
glEnd ();
if ( this -> texture_file_name != "" ) {
glDisable ( GL_TEXTURE_2D );
}
};
// void Sphere::draw () method, src/sphere.cpp - line 75
void Sphere::draw () {
glPushMatrix ();
glTranslated (
this -> coordinate [ 0 ],
this -> coordinate [ 1 ],
this -> coordinate [ 2 ]
);
glRotated (
this -> angle_degree,
this -> rotation [ 0 ],
this -> rotation [ 1 ],
this -> rotation [ 2 ]
);
this -> render ();
glPopMatrix ();
};
double Sphere::calculateX ( const double theta_degree_angle, const double phi_degree_angle ) {
return this -> radius * sin ( theta_degree_angle ) * cos ( phi_degree_angle );
};
double Sphere::calculateY ( const double theta_degree_angle, const double phi_degree_angle ) {
return this -> radius * sin ( theta_degree_angle ) * sin ( phi_degree_angle );
};
double Sphere::calculateZ ( const double theta_degree_angle ) {
return this -> radius * cos ( theta_degree_angle );
};
This is my loadTexture method
void Object::loadTexture () {
int & w = this -> texture_width, & h = this -> texture_height;
unsigned char * data = new unsigned char [ w * h * 3 ];
FILE * file;
try {
file = fopen ( this -> texture_file_name.c_str () , "rb" );
if ( !file ) return;
fread ( data, w * h * 3, 1, file );
fclose ( file );
} catch ( std::exception & error ) {
std::cout << "Loading Texture Error: " << error.what () << std::endl;
}
glGenTextures ( 1, & this -> texture );
glBindTexture ( GL_TEXTURE_2D, this -> texture );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
delete [] data;
};
void Object::setTexture ( const char * file_name, const int width, const int height ) {
this -> texture_file_name = file_name;
this -> texture_width = width;
this -> texture_height = height;
this -> loadTexture ();
};
This is my main.cpp
// main.cpp
// gloabl vars
NonStd::Sphere sun = NonStd::Sphere ( 10 );
NonStd::Sphere earth = NonStd::Sphere ( 3 );
NonStd::Sphere moon = NonStd::Sphere ( 1 );
NonStd::Object space = NonStd::Object ();
void render ();
void modelInit ();
void idle ();
void windowOnChange ( int width, int height );
void mouseOnDrag ( int x, int y );
int main ( int args_len, char ** args_context ) {
glutInit ( &args_len, args_context );
glutInitDisplayMode ( GLUT_SINGLE );
glutInitWindowSize ( WINDOW_WIDTH, WINDOW_HEIGHT );
glutInitWindowPosition ( 100, 100 );
glutCreateWindow ( "Solar System Simulation" );
glEnable ( GL_NORMALIZE );
glEnable ( GL_COLOR_MATERIAL );
// all models initialization
modelInit ();
// event handlers
glutDisplayFunc ( render );
glutReshapeFunc ( windowOnChange );
// glutMotionFunc ( mouseOnDrag );
// global idle func
glutIdleFunc ( idle );
glutMainLoop ();
return 0;
};
void render () {
glClearColor ( .2, .3, .5, .8 );
glClear ( GL_COLOR_BUFFER_BIT );
if ( sun.isObjectShown () ) {
sun.draw ();
}
if ( earth.isObjectShown () ) {
earth.draw ();
}
if ( moon.isObjectShown () ) {
moon.draw ();
}
glFlush ();
};
void modelInit () {
// object visibility default is false
sun.setVisible ( true );
// move to proper position to for object for better viewing
sun.translateZ ( -90.0 );
// set object texture
sun.setTexture ( "resources/earth.jpg", 100, 100 );
// spin default is false, toggle it for spinning
sun.toggleSpin ();
earth.setVisible ( true );
earth.translateZ ( -90.0 );
earth.translateX ( 26.0 );
earth.setTexture ( "resources/earth.jpg", 100, 100 );
earth.toggleSpin ();
earth.setSpinSpeed ( 2 );
moon.setVisible ( true );
moon.translateZ ( -90.0 );
moon.translateX ( 20.0 );
moon.setTexture ( "resources/earth.jpg", 100, 100 );
moon.toggleSpin ();
};
After I set the texture on my sphere object, the sphere turn into this yellow color and before setting the texture, it was white, does this mean the texture already set but I have not yet specify the texture coordinate for it ?
FYI: The project said it is 2D, but actually I am doing it in 3D just to clarify it.
A sphere can either be created by tessellating an existing object like a icosahedron, or by stacking discs.
Stacking discs:
The following code creates a sphere by stacking up a number of discs (layers
). Each layer has circumferenceTiles
tiles around its circum. The U texture coordinate is wrapped arund the circum. The V texture coordinate is wrapped from the south pole to the north pole of the sphere.
void CreateSphereMesh( int layers, int circumferenceTiles, std::vector<float> &va, std::vector<int> &ia )
{
const float pi = 3.1414927f;
// create the vertex attributes
va.reserve( (layers+1)*(circumferenceTiles+1)*5 ); // 5 floats: x, y, z, u, v
for ( int il = 0; il <= layers; ++ il )
{
float layer_rel = (float)il / (float)layers;
float layer_ang = (1.0f - 2.0f * layer_rel) * pi/2.0f ;
float layer_sin = std::sin( layer_ang );
float layer_cos = std::cos( layer_ang );
for ( int ic = 0; ic <= circumferenceTiles; ic ++ )
{
float circum_rel = (float)ic / (float)circumferenceTiles;
float cricum_ang = circum_rel * 2.0f*pi - pi;
float circum_sin = std::sin( cricum_ang );
float circum_cos = std::cos( cricum_ang );
va.push_back( layer_cos * circum_cos ); // x
va.push_back( layer_cos * circum_sin ); // y
va.push_back( layer_sin ); // z
va.push_back( circum_rel ); // u
va.push_back( 1.0f - layer_rel ); // v
}
}
// create the face indices
ia.reserve( layers*circumferenceTiles*6 );
for ( int il = 0; il < layers; ++ il )
{
for ( int ic = 0; ic < circumferenceTiles; ic ++ )
{
int i0 = il * (circumferenceTiles+1) + ic;
int i1 = i0 + 1;
int i3 = i0 + circumferenceTiles+1;
int i2 = i3 + 1;
int faces[]{ i0, i1, i2, i0, i2, i3 };
ia.insert(ia.end(), faces+(il==0?3:0), faces+(il==layers-1?3:6));
}
}
}
An vertex array object for the fixed function pipline can be specified like this:
GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
GLuint vbo;
glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, va.size()*sizeof(*va.data()), va.data(), GL_STATIC_DRAW );
GLuint ibo;
glGenBuffers( 1, &ibo );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, ia.size()*sizeof(*ia.data()), ia.data(), GL_STATIC_DRAW );
glVertexPointer( 3, GL_FLOAT, 5*sizeof(*va.data()), 0 );
glEnableClientState( GL_VERTEX_ARRAY );
glTexCoordPointer( 2, GL_FLOAT, 5*sizeof(*va.data()), (void*)(3*sizeof(*va.data())) );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glBindVertexArray( 0 );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
For modern OpenGL the generic vertex attribute data arrays have to be defined like this:
GLint avert_loc = ....;
GLint atexc_loc = ....;
glVertexAttribPointer( avert_loc, 3, GL_FLOAT, GL_FALSE, 5*sizeof(*va.data()), 0 );
glEnableVertexAttribArray( avert_loc );
glVertexAttribPointer( atexc_loc, 2, GL_FLOAT, GL_FALSE, 5*sizeof(*va.data()), (void*)(3*sizeof(*va.data())) );
glEnableVertexAttribArray( atexc_loc );
Finall the drawing operation:
glEnable( GL_TEXTURE_2D ); // for fixed function pipeline only
glBindVertexArray( vao );
glDrawElements( GL_TRIANGLES, (GLsizei)ia.size(), GL_UNSIGNED_INT, 0 );
glBindVertexArray( 0 );
Preview:
这篇关于如何使用点图元将纹理映射到参数方程式渲染的球体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!