Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

jak napisać strzałki gizmo dla sześcianu

Ostatnio zmodyfikowano 2026-03-12 09:11
Autor Wiadomość
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
C/C++
#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 ];
   
}
   
   
// przesuniêcie wszystkich punktów
   
void move( float dx, float dy, float dz )
   
{
       
for( auto & p: v )
       
{
           
p.x += dx;
           
p.y += dy;
           
p.z += dz;
       
}
    }
   
   
// przesuniêcie wybranych punktów
   
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; // <-- DODAJ
};
// --- Ostrosłup (na podstawie kwadratu) ---
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; // <-- DODAJ
};

// --- Stożek ---
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; // <-- DODAJ
};

// --- Walec ---
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; // <-- DODAJ
};

// --- Elipsoida (uogólniona sfera) ---
class Ellipsoid {
public:
   
Vertices vertices;
   
GLuint texture;
   
Point position, rotation;
   
Point radii; // promienie x, y, z
   
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; // <-- DODAJ
};

#endif
plik cpp
C/C++
#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 )
{ }


// indeksy œcian
const int Cube::faces[ 6 ][ 4 ] =
{
    {
4, 5, 6, 7 }, // front
   
{ 0, 3, 2, 1 }, // back
   
{ 0, 4, 7, 3 }, // left
   
{ 1, 2, 6, 5 }, // right
   
{ 3, 7, 6, 2 }, // top
   
{ 0, 1, 5, 4 } // bottom
};


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 ); // kolor linii
   
glLineWidth( 2.0f );
   
   
glBegin( GL_LINES );
   
// każda ściana po 4 wierzchołki
   
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 );
}
// --- OSTROSŁUP ---
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;
   
// Wierzchołki: 0-3 podstawa, 4 szczyt
   
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 );
   
// Ściany boczne
   
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();
   
// Podstawa
   
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 );
   
   
// podstawa
   
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 );
   
}
   
   
// krawędzie do szczytu
   
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 );
}
// --- STOŻEK ---
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 } ); // Szczyt (index 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 );
   
   
// okrąg podstawy
   
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();
   
   
// linie do szczytu
   
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 );
}
// --- WALEC ---
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 } ); // Góra
       
vertices.v.push_back( { vx, - hh, vz } ); // Dół
   
}
}

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();
   
   
// --- BOK WALCA ---
   
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();
   
   
   
// --- GÓRNA PODSTAWA ---
   
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();
   
   
   
// --- DOLNA PODSTAWA ---
   
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();
   
   
// górny okrąg
   
glBegin( GL_LINE_LOOP );
   
for( int i = 0; i < count; i += 2 )
       
 glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z );
   
   
glEnd();
   
   
// dolny okrąg
   
glBegin( GL_LINE_LOOP );
   
for( int i = 1; i < count; i += 2 )
       
 glVertex3f( vertices[ i ].x, vertices[ i ].y, vertices[ i ].z );
   
   
glEnd();
   
   
// pionowe linie
   
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 );
}
// --- ELIPSOIDA ---
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; // szerokość
       
for( int j = 0; j <= segments; j++ )
       
{
           
float lon =( float ) j / segments * 2.0f * M_PI; // długość
           
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
P-183913
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.
P-183916
« 1 »
  Strona 1 z 1