Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: How to DRAW custom shapes?  (Read 2656 times)

0 Members and 1 Guest are viewing this topic.

Poki027

  • Newbie
  • *
  • Posts: 1
    • View Profile
    • Email
How to DRAW custom shapes?
« on: January 15, 2022, 01:32:45 pm »
Hi! I'm trying to make a 3D engine with SFML, and for now it's going quite well.
I'm using a single "cube" to test out different things, which was just a sf::VertexArray.
The problem appears once I want to use multiple cubes since I have to use nested for loops (one for the number of cubes, one for the 8 vertices of the cubes) or just one for loop, but either way, I want to avoid doing it like that since it doesn't feel expandable and easy to use. I would like to be able to instantiate the cubes like this for example:
sf::VertexArray cubes(sf::Cubes, 10); // create 10 cubes
 
and then draw them like so:
window.draw(cubes);
 
I can't understand how to set up custom shapes tho and https://www.sfml-dev.org/tutorials/2.0/graphics-shape.php doesn't really help me.

This is the current cube code:
struct Cube
{
        float scale;
        Vector3 pos;
        Vector3 vertexLocal[8] =
        {
                // Front face
                Vector3(-1.0, -1.0,  1.0),
                Vector3(1.0, -1.0,  1.0),
                Vector3(1.0,  1.0,  1.0),
                Vector3(-1.0,  1.0,  1.0),

                // Back face
                Vector3(-1.0, -1.0, -1.0),
                Vector3(1.0,  -1.0, -1.0),
                Vector3(1.0,  1.0, -1.0),
                Vector3(-1.0, 1.0, -1.0)                         
        };             
        Vector3 vertexGlobal[8];
        float vertexDistances[8];
       
        Cube(const float _scale)
        {
                scale = _scale;
                for(int v = 0; v < 8; v++)
                {
                        vertexGlobal[v] = Vector3(vertexLocal[v].x + pos.x, vertexLocal[v].y + pos.y, vertexLocal[v].z + pos.z);                               
                        vertexDistances[v] = sqrt((vertexLocal[v].x - pos.x)*(vertexLocal[v].x - pos.x) + (vertexLocal[v].y - pos.y)*(vertexLocal[v].y - pos.y) + (vertexLocal[v].z - pos.z)*(vertexLocal[v].z - pos.z));
                        vertexGlobal[v] *= scale;
                        vertexDistances[v] *= scale;
                        //vertexGlobal[i] = Vector3(vertexGlobal[i].x / 2, vertexGlobal[i].y / 2, vertexGlobal[i].z / 2);
                        vertexGlobal[v].UpdateVector();
                }              
        }
       
        void UpdateCube()
        {
                for(int i = 0; i < 8; i++)
                {
                        vertexGlobal[i] = Vector3(vertexLocal[i].x + pos.x, vertexLocal[i].y + pos.y, vertexLocal[i].z + pos.z);
                        vertexGlobal[i] *= scale;
                        vertexGlobal[i].UpdateVector();
                        vertexLocal[i].UpdateVector();
                }              
        }
};

And this is how I'm showing the vertices on the screen:
class Camera
{
        public:
                float nearClippingPlane, farClippingPlane, fieldOfView, focalLength;
                Vector3 position, rotation, resolution;
                vector<Vector3> verticesOnScreen, verticesOffScreen;
               
                Camera(float _nearClippingPlane, float _farClippingPlane, float focal, Vector3 res)
                {
                        nearClippingPlane = _nearClippingPlane;
                        farClippingPlane = _farClippingPlane;
                        focalLength = focal;
                        fieldOfView = 2 * atan(res.x / (2 * focal));
                        resolution = res;
                       
                        if(!verticesOnScreen.empty())
                                verticesOnScreen.clear();
                        if(!verticesOffScreen.empty())
                                verticesOffScreen.clear();     
                }
               
                Camera()
                {
                        nearClippingPlane = 1.0f;
                        farClippingPlane = 100.0f;
                        fieldOfView = 60.0f;
                        resolution = Vector3(W_SCREEN, H_SCREEN, 0);
                }
               
                Vector3 WorldToCamera(Vector3 vertex)
                {
                        //cout << "WorldToCamera: " << vertex.x << " : " << scaleFactor << endl;
                        vertex += position;
                        vertex.UpdateVector();
                        vertex.z *= -1; //invert the camera's view (or else it would appear we are looking "through" a mirror)
                        if(vertex.z < nearClippingPlane + position.z) //if the vertex's z coordinate is smaller than the near clipping plane's
                                vertex.z = nearClippingPlane;                           // distance from the camera, clip the vertex's z to the value of near clipping plane's distance
                        //treat camera's position as 0, 0, 0 if using verToCam variable
                        vertex.x *= (focalLength / vertex.z);
                        vertex.y *= (focalLength / vertex.z);
                        //cout << "wtc" << endl;
                        //cout << "WorldToCamera: " << output.x << " : " << scaleFactor << endl;
                        return vertex;
                }      
               
                sf::Vector2f CameraToScreen(Vector3 vertex)
                {
                        Vector3 cam = WorldToCamera(vertex);
                        cam.UpdateVector();
                        //cout << "CameraToScreen: " << cam.x << endl;
                        return sf::Vector2f(-cam.x + W_SCREEN/2, -cam.y + H_SCREEN/2); //center the coords to the screen and return them
                }
};
 
I'm still a bit new to posting on forums, so if you need more information, just ask and I'll provide.
« Last Edit: January 15, 2022, 01:35:43 pm by Poki027 »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: How to DRAW custom shapes?
« Reply #1 on: January 18, 2022, 07:14:59 am »
Note that SFML's graphics module only supports 2D rendering.
If you want to do anything 3D, you have to either do some shader or CPU math trickery to make it look like 3D or use OpenGL directly.

For custom shapes, check out the tutorial on shapes: https://www.sfml-dev.org/tutorials/2.5/graphics-shape.php
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/