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

[SFML3.1 OpenGL] Poprawna Rotacja Sześcianu

Ostatnio zmodyfikowano 2026-10-19 23:41
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
[SFML3.1 OpenGL] Poprawna Rotacja Sześcianu
» 2026-10-19 20:43:05
Cześć Wam! :D
Piszę sobie program w SFML3 i OpenGL, który ma renderować 3 sześciany. Na lewy przycisk można przesuwać sześciany, zaś na prawy je obracać. Chciałbym napisać taką funkcję, która pozwala chwycić i obrócić sześcian zgodnie z przesunięciem kursora - czyli dosłownie "złap i obróć". Niesty gdy obrócę sześcian o 180 stopni w osi Z to potem źle obraca w osi Y. Kiedyś ktoś wspominał na tym forum ten problem i go zlekceważyłem... No więc przepraszam - problem powrócił :P

SFML3.1 OpenGL - Cubes



C/C++
void Model3D::handleEvent( const sf::Event & event ) {
   
   
static sf::Vector2i offset( 0.0f, 0.0f );
   
static sf::Vector2i rotationOffset( 0.0f, 0.0f );
   
static sf::Vector2f startRotation = sf::Vector2f( _rx, _ry );
   
   
auto size = Main::render_window->getSize();
   
auto mouse = Main::cursor->_position;
   
   
float aspect =( float )( size.x ) / size.y;
   
float distance = 5.0f - _z;
   
   
float halfHeight = distance * std::tan( 30.0f * 3.14159265f / 180.0f );
   
float halfWidth = halfHeight * aspect;
   
   
float mouseX =( 2.0f * mouse.x / size.x - 1.0f ) * halfWidth;
   
float mouseY =( 1.0f - 2.0f * mouse.y / size.y ) * halfHeight;
   
   
if( scene->_hovered == this->shared_from_this() ) {
       
if( const auto * mbp = event.getIf < sf::Event::MouseButtonPressed >(); mbp ) {
           
           
scene->_pressed = this->shared_from_this();
           
           
if( mbp->button == sf::Mouse::Button::Left ) {
               
offset.x = mouseX - _x;
               
offset.y = mouseY - _y;
           
}
           
           
if( mbp->button == sf::Mouse::Button::Right ) {
               
rotationOffset = Main::cursor->_position;
               
startRotation = sf::Vector2f( _rx, _ry );
           
}
        }
    }
   
   
if( scene->_pressed == this->shared_from_this() ) {
       
if( sf::Mouse::isButtonPressed( sf::Mouse::Button::Left ) ) {
           
_x = mouseX - offset.x;
           
_y = mouseY - offset.y;
       
}
       
       
if( sf::Mouse::isButtonPressed( sf::Mouse::Button::Right ) ) {
           
auto delta = Main::cursor->_position - rotationOffset;
           
           
_ry = startRotation.y + delta.x * 0.5f;
           
_rx = startRotation.x + delta.y * 0.5f;
       
}
    }
   
   
if( const auto * mbr = event.getIf < sf::Event::MouseButtonReleased >(); mbr ) {
       
if( scene->_pressed == this->shared_from_this() )
           
 scene->_pressed = nullptr;
       
   
}
}

C/C++
void Mesh3D::draw( bool isHighlighted, float x, float y, float z, float rx, float ry, float rz ) {
   
   
glPushMatrix();
   
   
glTranslatef( x, y, z );
   
glRotatef( rx, 1.f, 0.f, 0.f );
   
glRotatef( ry, 0.f, 1.f, 0.f );
   
glRotatef( rz, 0.f, 0.f, 1.f );
   
   
glEnable( GL_TEXTURE_2D );
   
( isHighlighted ) ? glColor3f( 1.0f, 1.0f, 1.f )
        :
glColor3f( 0.75f, 0.75f, 0.75f );
   
glBindTexture( GL_TEXTURE_2D, _texture ? _texture->_texture->getNativeHandle()
        :
0 );
   
   
glBegin( GL_TRIANGLES );
   
   
for( auto & vertex: _vertices ) {
       
       
glNormal3f( vertex._nx, vertex._ny, vertex._nz );
       
glTexCoord2f( vertex._u, 1.0f - vertex._v );
       
glVertex3f( vertex._x, vertex._y, vertex._z );
       
   
}
   
   
glEnd();
   
   
glBindTexture( GL_TEXTURE_2D, 0 );
   
   
glPopMatrix();
}
P-184780
tBane
Temat założony przez niniejszego użytkownika
» 2026-10-19 23:40:15
Trzeba zastosować kwaterniony:

C/C++
#pragma once

#include <array>
#include <cmath>

struct Quaternion {
   
float w = 1.f;
   
float x = 0.f;
   
float y = 0.f;
   
float z = 0.f;
   
   
Quaternion operator *( const Quaternion & q ) const {
       
return {
           
w * q.w - x * q.x - y * q.y - z * q.z,
           
w * q.x + x * q.w + y * q.z - z * q.y,
           
w * q.y - x * q.z + y * q.w + z * q.x,
           
w * q.z + x * q.y - y * q.x + z * q.w
        };
   
}
   
   
void normalize() {
       
const float length = std::sqrt( w * w + x * x + y * y + z * z );
       
       
if( length > 0.f ) {
           
w /= length;
           
x /= length;
           
y /= length;
           
z /= length;
       
}
    }
   
   
std::array < float, 16 > matrix() const {
       
// Układ kolumnowy wymagany przez OpenGL.
       
return {
           
1.f - 2.f *( y * y + z * z ), 2.f *( x * y + w * z ), 2.f *( x * z - w * y ), 0.f,
           
2.f *( x * y - w * z ), 1.f - 2.f *( x * x + z * z ), 2.f *( y * z + w * x ), 0.f,
           
2.f *( x * z + w * y ), 2.f *( y * z - w * x ), 1.f - 2.f *( x * x + y * y ), 0.f,
           
0.f, 0.f, 0.f, 1.f
       
};
   
}
}
;

C/C++
if( const auto * moved = event.getIf < sf::Event::MouseMoved >();
moved && sf::Mouse::isButtonPressed( sf::Mouse::Button::Right ) )
{
   
const auto delta = moved->position - _lastRotationMouse;
   
_lastRotationMouse = moved->position;
   
   
const float dx = static_cast < float >( delta.x );
   
const float dy = static_cast < float >( delta.y );
   
const float length = std::hypot( dx, dy );
   
   
if( length > 0.f ) {
       
constexpr float sensitivity = 0.5f; // Stopnie na piksel.
       
constexpr float toRadians = 3.14159265f / 180.f;
       
       
const float halfAngle =
       
length * sensitivity * toRadians * 0.5f;
       
       
const float s = std::sin( halfAngle ) / length;
       
       
const Quaternion deltaRotation {
           
std::cos( halfAngle ),
           
dy * s,
           
dx * s,
           
0.f
       
};
       
       
_rotation = deltaRotation * _rotation;
       
_rotation.normalize();
   
}
}

C/C++
void Mesh3D::draw( bool isHighlighted, float x, float y, float z, const Quaternion & rotation ) {
   
   
// ... Za translate
   
   
const auto matrix = rotation.matrix();
   
glMultMatrixf( matrix.data() );
   
   
//...
   
P-184782
« 1 »
  Strona 1 z 1