AP1994 Temat założony przez niniejszego użytkownika |
jak napisać strzałki gizmo dla sześcianu » 2026-03-11 19:10:44 mam kod: plik h #ifndef PART_H #define PART_H #include <initializer_list> #include <vector> #include <cmath> #include <gl/gl.h>
class Point { public: float x, y, z; Point(); Point( float x, float y, float z ); Point operator +( const Point & p ) const { return Point( x + p.x, y + p.y, z + p.z ); } Point operator -( const Point & p ) const { return Point( x - p.x, y - p.y, z - p.z ); } Point operator *( float s ) const { return Point( x * s, y * s, z * s ); } };
struct Vertices { public: std::vector < Point > v; Point & operator[ ]( size_t i ) { return v[ i ]; } const Point & operator[ ]( size_t i ) const { return v[ i ]; } void move( float dx, float dy, float dz ) { for( auto & p: v ) { p.x += dx; p.y += dy; p.z += dz; } } void move( float dx, float dy, float dz, std::initializer_list < int > index ) { for( std::vector < Point >::size_type i: index ) { if( i >= 0 && i < v.size() ) { v[ i ].x += dx; v[ i ].y += dy; v[ i ].z += dz; } } } auto begin() { return v.begin(); } auto end() { return v.end(); } };
class Cube { private: static const int faces[ 6 ][ 4 ]; public: Vertices vertices; GLuint texture; Point position; Point rotation; Point scale; Cube( float x, float y, float z, float w, float h, float d, GLuint tex ); void draw(); void positioning( float dx, float dy, float dz ); void rotate( float x, float y, float z ); void rescale( float sx, float sy, float sz ); void drawWireframe(); Point center() const; }; class Pyramid { public: Vertices vertices; GLuint texture; Point position, rotation; Pyramid( float x, float y, float z, float w, float h, GLuint tex ); void draw(); void drawWireframe(); void rotate( float rx, float ry, float rz ) { rotation = Point( rx, ry, rz ); } Point center() const; };
class Cone { public: Vertices vertices; GLuint texture; Point position, rotation; int segments; Cone( float x, float y, float z, float radius, float height, GLuint tex, int seg = 30 ); void draw(); void drawWireframe(); void rotate( float rx, float ry, float rz ) { rotation = Point( rx, ry, rz ); } Point center() const; };
class Cylinder { public: Vertices vertices; GLuint texture; Point position, rotation; int segments; Cylinder( float x, float y, float z, float radius, float height, GLuint tex, int seg = 30 ); void draw(); void drawWireframe(); void rotate( float rx, float ry, float rz ) { rotation = Point( rx, ry, rz ); } Point center() const; };
class Ellipsoid { public: Vertices vertices; GLuint texture; Point position, rotation; Point radii; int segments; Ellipsoid( float x, float y, float z, float rx, float ry, float rz, GLuint tex, int seg = 20 ); void draw(); void drawWireframe(); void rotate( float rx, float ry, float rz ) { rotation = Point( rx, ry, rz ); } Point center() const; };
#endif
plik cpp #include "part.h" static Point centroid( const Vertices & verts ) { float sx = 0, sy = 0, sz = 0; for( const auto & p: verts.v ) { sx += p.x; sy += p.y; sz += p.z; } int n = verts.v.size(); return Point( sx / n, sy / n, sz / n ); }
Point::Point() : x( 0 ) , y( 0 ) , z( 0 ) { } Point::Point( float x, float y, float z ) : x( x ) , y( y ) , z( z ) { }
const int Cube::faces[ 6 ][ 4 ] = { { 4, 5, 6, 7 }, { 0, 3, 2, 1 }, { 0, 4, 7, 3 }, { 1, 2, 6, 5 }, { 3, 7, 6, 2 }, { 0, 1, 5, 4 } };
Cube::Cube( float x, float y, float z, float w, float h, float d, GLuint tex ) { texture = tex; position = Point( x, y, z ); rotation = Point( 0, 0, 0 ); scale = Point( 1, 1, 1 ); float hw = w / 2; float hh = h / 2; float hd = d / 2; vertices.v = { { - hw, - hh, - hd }, { hw, - hh, - hd }, { hw, hh, - hd }, { - hw, hh, - hd }, { - hw, - hh, hd }, { hw, - hh, hd }, { hw, hh, hd }, { - hw, hh, hd } }; }
void Cube::draw() { glPushMatrix(); glTranslatef( position.x, position.y, position.z ); glRotatef( rotation.x, 1, 0, 0 ); glRotatef( rotation.y, 0, 1, 0 ); glRotatef( rotation.z, 0, 0, 1 ); glBindTexture( GL_TEXTURE_2D, texture ); glBegin( GL_QUADS ); float tex[ 4 ][ 2 ] = { { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } }; for( int f = 0; f < 6; f++ ) { for( int v = 0; v < 4; v++ ) { glTexCoord2f( tex[ v ][ 0 ], tex[ v ][ 1 ] ); glVertex3f( vertices[ faces[ f ][ v ] ].x, vertices[ faces[ f ][ v ] ].y, vertices[ faces[ f ][ v ] ].z ); } } glEnd(); glPopMatrix(); } void Cube::rescale( float sx, float sy, float sz ) { scale.x *= sx; scale.y *= sy; scale.z *= sz; for( auto & v: vertices ) v = Point( v.x * sx, v.y * sy, v.z * sz ); } void Cube::positioning( float dx, float dy, float dz ) { position.x += dx; position.y += dy; position.z += dz; for( auto & v: vertices ) v = v + Point( dx, dy, dz ); } void Cube::rotate( float x, float y, float z ) { rotation.x = x; rotation.y = y; rotation.z = z; } void Cube::drawWireframe() { glPushMatrix(); glTranslatef( position.x, position.y, position.z ); glRotatef( rotation.x, 1, 0, 0 ); glRotatef( rotation.y, 0, 1, 0 ); glRotatef( rotation.z, 0, 0, 1 ); glColor3f( 0.75f, 0.75f, 0.75f ); glLineWidth( 2.0f ); glBegin( GL_LINES ); for( int f = 0; f < 6; f++ ) { int i0 = faces[ f ][ 0 ]; int i1 = faces[ f ][ 1 ]; int i2 = faces[ f ][ 2 ]; int i3 = faces[ f ][ 3 ]; glVertex3f( vertices[ i0 ].x, vertices[ i0 ].y, vertices[ i0 ].z ); glVertex3f( vertices[ i1 ].x, vertices[ i1 ].y, vertices[ i1 ].z ); glVertex3f( vertices[ i1 ].x, vertices[ i1 ].y, vertices[ i1 ].z ); glVertex3f( vertices[ i2 ].x, vertices[ i2 ].y, vertices[ i2 ].z ); glVertex3f( vertices[ i2 ].x, vertices[ i2 ].y, vertices[ i2 ].z ); glVertex3f( vertices[ i3 ].x, vertices[ i3 ].y, vertices[ i3 ].z ); glVertex3f( vertices[ i3 ].x, vertices[ i3 ].y, vertices[ i3 ].z ); glVertex3f( vertices[ i0 ].x, vertices[ i0 ].y, vertices[ i0 ].z ); } glEnd(); glColor3f( 1.0f, 1.0f, 1.0f ); glPopMatrix(); } Point Cube::center() const { return centroid( vertices ); } Pyramid::Pyramid( float x, float y, float z, float w, float h, GLuint tex ) { texture = tex; position = Point( x, y, z ); rotation = Point( 0, 0, 0 ); float hw = w / 2.0f; float hh = h / 2.0f; vertices.v = { { - hw, - hh, hw }, { hw, - hh, hw }, { hw, - hh, - hw }, { - hw, - hh, - hw }, { 0, hh, 0 } }; }
void Pyramid::draw() { glPushMatrix(); glTranslatef( position.x, position.y, position.z ); glRotatef( rotation.x, 1, 0, 0 ); glRotatef( rotation.y, 0, 1, 0 ); glRotatef( rotation.z, 0, 0, 1 ); glBindTexture( GL_TEXTURE_2D, texture ); glBegin( GL_TRIANGLES ); int sides[ 4 ][ 3 ] = { { 0, 1, 4 }, { 1, 2, 4 }, { 2, 3, 4 }, { 3, 0, 4 } }; for( int i = 0; i < 4; i++ ) { glTexCoord2f( 0, 0 ); glVertex3f( vertices[ sides[ i ][ 0 ] ].x, vertices[ sides[ i ][ 0 ] ].y, vertices[ sides[ i ][ 0 ] ].z ); glTexCoord2f( 1, 0 ); glVertex3f( vertices[ sides[ i ][ 1 ] ].x, vertices[ sides[ i ][ 1 ] ].y, vertices[ sides[ i ][ 1 ] ].z ); glTexCoord2f( 0.5, 1 ); glVertex3f( vertices[ sides[ i ][ 2 ] ].x, vertices[ sides[ i ][ 2 ] ].y, vertices[ sides[ i ][ 2 ] ].z ); } glEnd(); glBegin( GL_QUADS ); glTexCoord2f( 0, 0 ); glVertex3f( vertices[ 0 ].x, vertices[ 0 ].y, vertices[ 0 ].z ); glTexCoord2f( 1, 0 ); glVertex3f( vertices[ 1 ].x, vertices[ 1 ].y, vertices[ 1 ].z ); glTexCoord2f( 1, 1 ); glVertex3f( vertices[ 2 ].x, vertices[ 2 ].y, vertices[ 2 ].z ); glTexCoord2f( 0, 1 ); glVertex3f( vertices[ 3 ].x, vertices[ 3 ].y, vertices[ 3 ].z ); glEnd(); glPopMatrix(); } void Pyramid::drawWireframe() { glPushMatrix(); glTranslatef( position.x, position.y, position.z ); glRotatef( rotation.x, 1, 0, 0 ); glRotatef( rotation.y, 0, 1, 0 ); glRotatef( rotation.z, 0, 0, 1 ); glColor3f( 0.75f, 0.75f, 0.75f ); glLineWidth( 2.0f ); glBegin( GL_LINES ); for( int i = 0; i < 4; i++ ) { int next =( i + 1 ) % 4; glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z ); glVertex3f( vertices[ next ].x, vertices[ next ].y, vertices[ next ].z ); } for( int i = 0; i < 4; i++ ) { glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z ); glVertex3f( vertices[ 4 ].x, vertices[ 4 ].y, vertices[ 4 ].z ); } glColor3f( 1.0f, 1.0f, 1.0f ); glEnd(); glPopMatrix(); } Point Pyramid::center() const { return centroid( vertices ); } Cone::Cone( float x, float y, float z, float r, float h, GLuint tex, int seg ) : segments( seg ) { texture = tex; position = Point( x, y, z ); rotation = Point( 0, 0, 0 ); float hh = h / 2.0f; vertices.v.push_back( { 0, hh, 0 } ); for( int i = 0; i <= segments; i++ ) { float ang =( float ) i / segments * 2.0f * M_PI; vertices.v.push_back( { r * cosf( ang ), - hh, r * sinf( ang ) } ); } }
void Cone::draw() { glPushMatrix(); glTranslatef( position.x, position.y, position.z ); glRotatef( rotation.x, 1, 0, 0 ); glRotatef( rotation.y, 0, 1, 0 ); glRotatef( rotation.z, 0, 0, 1 ); glBindTexture( GL_TEXTURE_2D, texture ); glBegin( GL_TRIANGLE_FAN ); glTexCoord2f( 0.5, 0.5 ); glVertex3f( vertices[ 0 ].x, vertices[ 0 ].y, vertices[ 0 ].z ); for( std::vector < Point >::size_type i = 1; i < vertices.v.size(); i++ ) { glTexCoord2f(( float ) i / segments, 0 ); glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z ); } glEnd(); glPopMatrix(); } void Cone::drawWireframe() { glPushMatrix(); glTranslatef( position.x, position.y, position.z ); glRotatef( rotation.x, 1, 0, 0 ); glRotatef( rotation.y, 0, 1, 0 ); glRotatef( rotation.z, 0, 0, 1 ); glColor3f( 0.75f, 0.75f, 0.75f ); glLineWidth( 2.0f ); glBegin( GL_LINE_LOOP ); for( std::vector < Point >::size_type i = 1; i < vertices.v.size(); i++ ) glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z ); glEnd(); glBegin( GL_LINES ); for( std::vector < Point >::size_type i = 1; i < vertices.v.size(); i++ ) { glVertex3f( vertices[ 0 ].x, vertices[ 0 ].y, vertices[ 0 ].z ); glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z ); } glEnd(); glColor3f( 1.0f, 1.0f, 1.0f ); glPopMatrix(); } Point Cone::center() const { return centroid( vertices ); } Cylinder::Cylinder( float x, float y, float z, float r, float h, GLuint tex, int seg ) : segments( seg ) { texture = tex; position = Point( x, y, z ); rotation = Point( 0, 0, 0 ); float hh = h / 2.0f; for( int i = 0; i <= segments; i++ ) { float ang =( float ) i / segments * 2.0f * M_PI; float vx = r * cosf( ang ), vz = r * sinf( ang ); vertices.v.push_back( { vx, hh, vz } ); vertices.v.push_back( { vx, - hh, vz } ); } }
void Cylinder::draw() { glPushMatrix(); glTranslatef( position.x, position.y, position.z ); glRotatef( rotation.x, 1, 0, 0 ); glRotatef( rotation.y, 0, 1, 0 ); glRotatef( rotation.z, 0, 0, 1 ); glBindTexture( GL_TEXTURE_2D, texture ); int count = vertices.v.size(); glBegin( GL_QUAD_STRIP ); for( int i = 0; i < count; i++ ) { glTexCoord2f(( float )( i / 2 ) / segments,( float )( i % 2 ) ); glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z ); } glEnd(); glBegin( GL_TRIANGLE_FAN ); glTexCoord2f( 0.5f, 0.5f ); glVertex3f( 0, vertices[ 0 ].y, 0 ); for( int i = 0; i < count; i += 2 ) { glTexCoord2f( 0.5f + 0.5f * vertices[ i ].x, 0.5f + 0.5f * vertices[ i ].z ); glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z ); } glVertex3f( vertices[ 0 ].x, vertices[ 0 ].y, vertices[ 0 ].z ); glEnd(); glBegin( GL_TRIANGLE_FAN ); glTexCoord2f( 0.5f, 0.5f ); glVertex3f( 0, vertices[ 1 ].y, 0 ); for( int i = 1; i < count; i += 2 ) { glTexCoord2f( 0.5f + 0.5f * vertices[ i ].x, 0.5f + 0.5f * vertices[ i ].z ); glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z ); } glVertex3f( vertices[ 1 ].x, vertices[ 1 ].y, vertices[ 1 ].z ); glEnd(); glPopMatrix(); } void Cylinder::drawWireframe() { glPushMatrix(); glTranslatef( position.x, position.y, position.z ); glRotatef( rotation.x, 1, 0, 0 ); glRotatef( rotation.y, 0, 1, 0 ); glRotatef( rotation.z, 0, 0, 1 ); glColor3f( 0.75f, 0.75f, 0.75f ); glLineWidth( 2.0f ); int count = vertices.v.size(); glBegin( GL_LINE_LOOP ); for( int i = 0; i < count; i += 2 ) glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z ); glEnd(); glBegin( GL_LINE_LOOP ); for( int i = 1; i < count; i += 2 ) glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z ); glEnd(); glBegin( GL_LINES ); for( int i = 0; i < count; i += 2 ) { glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z ); glVertex3f( vertices[ i + 1 ].x, vertices[ i + 1 ].y, vertices[ i + 1 ].z ); } glEnd(); glColor3f( 1.0f, 1.0f, 1.0f ); glPopMatrix(); } Point Cylinder::center() const { return centroid( vertices ); } Ellipsoid::Ellipsoid( float x, float y, float z, float rx, float ry, float rz, GLuint tex, int seg ) : radii( rx, ry, rz ) , segments( seg ) { texture = tex; position = Point( x, y, z ); rotation = Point( 0, 0, 0 ); for( int i = 0; i <= segments; i++ ) { float lat =( float ) i / segments * M_PI; for( int j = 0; j <= segments; j++ ) { float lon =( float ) j / segments * 2.0f * M_PI; vertices.v.push_back( { radii.x * sinf( lat ) * cosf( lon ), radii.y * cosf( lat ), radii.z * sinf( lat ) * sinf( lon ) } ); } } }
void Ellipsoid::draw() { glPushMatrix(); glTranslatef( position.x, position.y, position.z ); glRotatef( rotation.x, 1, 0, 0 ); glRotatef( rotation.y, 0, 1, 0 ); glRotatef( rotation.z, 0, 0, 1 ); glBindTexture( GL_TEXTURE_2D, texture ); for( int i = 0; i < segments; i++ ) { glBegin( GL_QUAD_STRIP ); for( int j = 0; j <= segments; j++ ) { int idx1 = i *( segments + 1 ) + j; int idx2 =( i + 1 ) *( segments + 1 ) + j; glTexCoord2f(( float ) j / segments,( float ) i / segments ); glVertex3f( vertices[ idx1 ].x, vertices[ idx1 ].y, vertices[ idx1 ].z ); glTexCoord2f(( float ) j / segments,( float )( i + 1 ) / segments ); glVertex3f( vertices[ idx2 ].x, vertices[ idx2 ].y, vertices[ idx2 ].z ); } glEnd(); } glPopMatrix(); } void Ellipsoid::drawWireframe() { glPushMatrix(); glTranslatef( position.x, position.y, position.z ); glRotatef( rotation.x, 1, 0, 0 ); glRotatef( rotation.y, 0, 1, 0 ); glRotatef( rotation.z, 0, 0, 1 ); glColor3f( 0.75f, 0.75f, 0.75f ); glLineWidth( 1.5f ); int cols = segments + 1; for( int i = 0; i < segments; i++ ) { glBegin( GL_LINE_STRIP ); for( int j = 0; j <= segments; j++ ) { int idx = i * cols + j; glVertex3f( vertices[ idx ].x, vertices[ idx ].y, vertices[ idx ].z ); } glEnd(); } for( int j = 0; j <= segments; j++ ) { glBegin( GL_LINE_STRIP ); for( int i = 0; i <= segments; i++ ) { int idx = i * cols + j; glVertex3f( vertices[ idx ].x, vertices[ idx ].y, vertices[ idx ].z ); } glEnd(); } glColor3f( 1.0f, 1.0f, 1.0f ); glPopMatrix(); } Point Ellipsoid::center() const { return centroid( vertices ); }
chciałem dodać strzałki do brył w moim kodzie takie jak w edytorach obiektów 3d ale za każdym razem coś mi nie działało po przesuwaniu rotacji lub skalowaniu |
DejaVu |
» 2026-03-12 09:11:26 ChatGPT 5.4 Thinking: Widzę od razu główny problem: u Ciebie bryła jest transformowana podwójnie — raz przez glTranslatef/glRotatef, a drugi raz przez ręczne modyfikowanie vertices w positioning() i rescale(). Przez to gizmo po przesunięciu/obrocie/skali zaczyna „odpływać” albo liczyć środek w złym miejscu.
Myślał przez 7s
Masz tu dwa źródła problemu i przez nie gizmo będzie się zawsze rozjeżdżać:
Mieszasz lokalne wierzchołki z transformacją świata
w draw() robisz:
glTranslatef(...); glRotatef(...);
ale w positioning() i rescale() dodatkowo modyfikujesz same vertices
center() liczy środek z lokalnych wierzchołków, a nie z pozycji obiektu w świecie
więc po przesunięciu / skali / obrocie środek gizma nie zgadza się z tym, co widać.
Najważniejsza zasada
Dla edytorowego gizma zrób tak jak w silnikach 3D:
vertices trzymaj zawsze w lokalnym układzie obiektu
position, rotation, scale trzymaj osobno
w draw() nakładaj transformacje przez macierz/OpenGL
gizmo rysuj na podstawie transformacji obiektu, nie na podstawie przerobionych wierzchołków
To rozwiązuje 90% problemów.
Co u Ciebie trzeba poprawić 1. Nie zmieniaj vertices przy przesuwaniu i skalowaniu
Zmień:
void Cube::positioning( float dx, float dy, float dz ) { position.x += dx; position.y += dy; position.z += dz; for( auto & v: vertices ) v = v + Point( dx, dy, dz ); }
na:
void Cube::positioning( float dx, float dy, float dz ) { position.x += dx; position.y += dy; position.z += dz; }
Zmień:
void Cube::rescale( float sx, float sy, float sz ) { scale.x *= sx; scale.y *= sy; scale.z *= sz; for( auto & v: vertices ) v = Point( v.x * sx, v.y * sy, v.z * sz ); }
na:
void Cube::rescale( float sx, float sy, float sz ) { scale.x *= sx; scale.y *= sy; scale.z *= sz; } 2. W draw() dodaj glScalef
Bo teraz zapisujesz scale, ale nigdzie go nie używasz.
Zmień Cube::draw() na:
void Cube::draw() { glPushMatrix();
glTranslatef( position.x, position.y, position.z );
glRotatef( rotation.x, 1, 0, 0 ); glRotatef( rotation.y, 0, 1, 0 ); glRotatef( rotation.z, 0, 0, 1 );
glScalef( scale.x, scale.y, scale.z );
glBindTexture( GL_TEXTURE_2D, texture );
glBegin( GL_QUADS ); float tex[ 4 ][ 2 ] = { { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } };
for( int f = 0; f < 6; f++ ) { for( int v = 0; v < 4; v++ ) { glTexCoord2f( tex[ v ][ 0 ], tex[ v ][ 1 ] ); glVertex3f( vertices[ faces[ f ][ v ] ].x, vertices[ faces[ f ][ v ] ].y, vertices[ faces[ f ][ v ] ].z ); } } glEnd();
glPopMatrix(); }
To samo w drawWireframe():
glTranslatef(...); glRotatef(...); glScalef( scale.x, scale.y, scale.z ); 3. center() dla sześcianu niech zwraca środek w świecie
Ponieważ sześcian ma lokalny środek w (0,0,0), najprościej:
Point Cube::center() const { return position; }
U Ciebie obecne:
Point Cube::center() const { return centroid( vertices ); }
zwraca środek lokalnej siatki, nie świata.
Jak narysować strzałki gizmo
Najprościej: osobna funkcja drawGizmo(const Point& c) rysująca 3 osie:
X — czerwony
Y — zielony
Z — niebieski
Na start wystarczą zwykłe linie + małe groty.
Dodaj do part.cpp void drawArrowLine(float x1, float y1, float z1, float x2, float y2, float z2) { glBegin(GL_LINES); glVertex3f(x1, y1, z1); glVertex3f(x2, y2, z2); glEnd(); }
I prostsza wersja gizma:
void drawGizmo(const Point& c, float size = 2.0f) { glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT); glDisable(GL_TEXTURE_2D); glLineWidth(3.0f);
glPushMatrix(); glTranslatef(c.x, c.y, c.z);
// Oś X - czerwona glColor3f(1.0f, 0.0f, 0.0f); drawArrowLine(0, 0, 0, size, 0, 0); drawArrowLine(size, 0, 0, size - 0.2f, 0.1f, 0); drawArrowLine(size, 0, 0, size - 0.2f, -0.1f, 0);
// Oś Y - zielona glColor3f(0.0f, 1.0f, 0.0f); drawArrowLine(0, 0, 0, 0, size, 0); drawArrowLine(0, size, 0, 0.1f, size - 0.2f, 0); drawArrowLine(0, size, 0, -0.1f, size - 0.2f, 0);
// Oś Z - niebieska glColor3f(0.0f, 0.5f, 1.0f); drawArrowLine(0, 0, 0, 0, 0, size); drawArrowLine(0, 0, size, 0.1f, 0, size - 0.2f); drawArrowLine(0, 0, size, -0.1f, 0, size - 0.2f);
glPopMatrix();
glPopAttrib(); } Jak tego używać dla Cube
Jeżeli chcesz, żeby gizmo było w środku sześcianu:
cube.draw(); drawGizmo(cube.center(), 2.0f);
Po poprawce:
Point Cube::center() const { return position; }
to będzie działało poprawnie dla przesuwania.
Co z rotacją i skalowaniem?
Tu są 2 warianty:
Wariant A — gizmo zawsze wyrównane do świata
Tak jak w wielu edytorach przy trybie world-space.
Wtedy:
rysujesz gizmo tylko przez glTranslatef(center.x, center.y, center.z)
bez rotacji obiektu
osie zawsze pokazują globalne X/Y/Z
To jest najprostsze i stabilne.
Twoje drawGizmo() już tak działa.
Wariant B — gizmo obraca się razem z obiektem
Wtedy w drawGizmo() trzeba też nałożyć rotację obiektu:
void drawGizmoObjectSpace(const Cube& cube, float size = 2.0f) { glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT); glDisable(GL_TEXTURE_2D); glLineWidth(3.0f);
glPushMatrix(); glTranslatef(cube.position.x, cube.position.y, cube.position.z); glRotatef(cube.rotation.x, 1, 0, 0); glRotatef(cube.rotation.y, 0, 1, 0); glRotatef(cube.rotation.z, 0, 0, 1);
// X glColor3f(1, 0, 0); drawArrowLine(0, 0, 0, size, 0, 0); drawArrowLine(size, 0, 0, size - 0.2f, 0.1f, 0); drawArrowLine(size, 0, 0, size - 0.2f, -0.1f, 0);
// Y glColor3f(0, 1, 0); drawArrowLine(0, 0, 0, 0, size, 0); drawArrowLine(0, size, 0, 0.1f, size - 0.2f, 0); drawArrowLine(0, size, 0, -0.1f, size - 0.2f, 0);
// Z glColor3f(0, 0.5f, 1); drawArrowLine(0, 0, 0, 0, 0, size); drawArrowLine(0, 0, size, 0.1f, 0, size - 0.2f); drawArrowLine(0, 0, size, -0.1f, 0, size - 0.2f);
glPopMatrix(); glPopAttrib(); }
Wywołanie:
cube.draw(); drawGizmoObjectSpace(cube, 2.0f); Dlaczego wcześniej się psuło
Bo w obecnym kodzie:
position przesuwa obiekt
vertices też przesuwasz
potem jeszcze glTranslatef(position...)
czyli obiekt jest przesunięty podwójnie.
Analogicznie przy skali:
skalujesz vertices
potem chcesz liczyć środek lub rysować gizmo względem obiektu
ale lokalna geometria już nie jest „czysta”
To powoduje chaos w:
środku obiektu
kierunkach osi
klikaniu/wyborze gizma
dalszej rotacji
Minimalny zestaw zmian, żeby ruszyło
Zrób dokładnie te 4 rzeczy:
1
positioning() — tylko zmiana position
2
rescale() — tylko zmiana scale
3
draw() i drawWireframe() — dodaj glScalef(scale.x, scale.y, scale.z)
4
center() dla Cube:
Point Cube::center() const { return position; } Uwaga o innych bryłach
Dla Pyramid, Cone, Cylinder, Ellipsoid też masz ten sam model:
lokalne wierzchołki
position
rotation
Jeżeli chcesz, żeby gizmo działało wszędzie spójnie, to dla wszystkich brył:
nie ruszaj vertices przy przesunięciu
środek świata licz z position, albo z position + lokalny_center_po_skali
Dla większości Twoich brył środek lokalny jest blisko (0,0,0), więc na start możesz dać po prostu:
Point Pyramid::center() const { return position; } Point Cone::center() const { return position; } Point Cylinder::center() const { return position; } Point Ellipsoid::center() const { return position; } Najlepsza architektura
Docelowo warto zrobić klasę bazową typu:
class Transform { public: Point position; Point rotation; Point scale; };
i każda bryła dziedziczy lub zawiera transform. Wtedy:
geometria = lokalna
transform = osobno
gizmo = działa identycznie dla każdej bryły
Gotowa, najprostsza wersja działania cube.positioning(1.0f, 0.0f, 0.0f); cube.rotate(0.0f, 45.0f, 0.0f); cube.rescale(1.5f, 1.0f, 1.0f);
cube.draw(); cube.drawWireframe(); drawGizmoObjectSpace(cube, 2.5f);
Jeżeli chcesz, mogę Ci od razu przepisać ten kod do gotowej wersji:
z poprawionym Cube,
wspólnym drawGizmo(...),
i wersją działającą też dla Pyramid, Cone, Cylinder, Ellipsoid.
|