Skip to content

scythianwizard/FaceworxTool

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FaceworxTool

Project forked from the original.

What is Faceworx?

https://www.looxis.de/en/looxis-faceworx-tool It used to be a somewhat popular tool for making 3D models of faces from front and profile pictures.

How to build Faceworx ?

I used Visual Studio C++ 2017, Windows 10, 64-bit.

  1. Install the repository
  2. Open the project
  3. You will be prompted to install some libraries for MFC, install them
  4. Install DirectX 10, add the library reference or add the files to the directory (Note: Even if the installation fails on Windows 10, you still get the .h and .lib files)
  5. Update the include path and library paths
  6. Change the name of/reference to the Directx9 specific files (eg: dxerr.lib to dxerr9.lib)
  7. Add #include to use unique_ptr instead of auto_ptr
  8. Add legacy_stdio_definitions.lib to the linker, or use #pragma comment(lib, "legacy_stdio_definitions.lib")
  9. If everything went well, the file should compile
  10. ???
  11. Profit (?) Maybe not. The program is very buggy.

Improvements/Addons/To-do

I would rather prefer to learn from it to rewrite it in something else, but please consider the following if you wish to update it. (There seems to be no discussion regarding this source code anywhere. Kind of sad.)

Bugs

  • Document the bugs/issues somewhere.
  • The program can literally not load its own file, possibly an issue with saving too? Tried different read/write modes, the problem seems to be completely different.
  • Obj export doesn't work. Might be an issue with MFC.

Bugs mentioned on the official site (Possibly related to the above bugs)

  • Obj export makes the texture black. (Mentioned on the site, but I cannot replicate it)
  • The tool does not seem to work under Windows 64bits. (Mentioned on the site, but if you follow the instructions above, it works fine)

Codebase/General

  • Update the references to libraries etc. (Original had no comments about this)
  • Detailed documentation for the code. (Original seems to be auto generated)
  • Comments to explain what is going on. (Most documentation and stackoverflow discussion about the directx functions is from the mid 2000s) - Perhaps ChatGPT can help with some basics?
  • Maybe add some exception catching code for the errors/bugs?

Cross platfrom

  • Switch from DirectX to OpenGL, reimplementing all DirectX functions to OpenGL (Yikes, a big task)
  • Switch from MFC to a crossplatform library for GUI
  • Decoupling of the GUI from core logics? Emscripten support?

Documentation for some key classes

  • LoopSubdivider.cpp and LoopSubdivider.h: These files may contain code related to generating the mesh data for the 3D model based on the reference images and feature markers.
  • texture_blender.cpp and texture_blender.h: These files may contain code related to blending the front and side textures onto a UV texture map for use in the 3D model.
  • pixeler.h: This file may contain code related to manipulating the pixel data for the front and side textures.
  • FrontView.cpp and SideView.cpp: These files likely contain code related to loading and displaying the reference images and placing/moving the facial feature markers.
  • 3DView.cpp: This file likely contains code related to generating and displaying the 3D model based on the modified facial feature markers.
  • obj_exporter.cpp: This file likely contains code related to exporting the 3D model to a file.
  • Settings.cpp: This file likely contains code related to managing user settings and preferences.

FrontView.cpp

  • The FrontView.cpp file defines the implementation of the CFrontView class, which is a subclass of the CImageView class. The CImageView class is a custom MFC (Microsoft Foundation Classes) control that provides basic functionality for displaying an image.
  • The CFrontView class adds some additional functionality specific to the front view of the face, such as setting the title of the window to "Front View" and implementing the GetSide function to return the value 0 to indicate that this is the front view.
  • The OnCreate function is called when the window is created and sets the title of the window to "Front View".
  • The OnDraw, AssertValid, Dump, and GetDocument functions are all inherited from the CImageView class and provide basic functionality for displaying the image.

SideView.cpp

  • This is an implementation of the CSideView class in the SideView.cpp file.
  • The CSideView class is a child of the CImageView class and is responsible for rendering a side view of a face model. It allows the user to manipulate blend zones by dragging nodes and lines.
  • The CSideView class defines several member functions:
    • CSideView::CSideView() is the class constructor, which initializes the m_nBlendNode and m_nBlendLine member variables to -1, and the m_bDrag member variable to false.
    • CSideView::~CSideView() is the class destructor.
    • CSideView::OnDraw() is an overridden function that is called by the framework to render the view. It calls the base class implementation of OnDraw().
    • CSideView::AssertValid() and CSideView::Dump() are diagnostic functions used in debug mode.
    • CSideView::GetSide() is a function that returns the integer value 1.
    • CSideView::Draw() is an overridden function that is responsible for drawing the side view of the face model. It first calls the base class implementation of Draw(), and then it checks if blending is enabled by checking the value of the m_bBlend member variable of the CFaceworxDoc class. If blending is enabled, it draws the blend zone using the CPointF coordinates in the m_nodes member variable and the m_fWidth member variable of the CFaceworxDoc::CBlendZone class. It uses CPen and CBrush objects to draw lines and nodes, and it translates the CPointF coordinates to CPoint coordinates using the TranslateCoords() function.
    • CSideView::HitTestBlendNode() is a function that takes a CPoint argument and returns an integer value. It is used to determine which node in the blend zone is being clicked on. It loops through each node in the blend zone and checks if the distance between the node and the given point is less than or equal to the BLEND_WIDTH_MIN constant. If a node is found, it returns the index of the node. If no node is found, it returns -1.
  • The CSideView class also defines a number of message handlers that respond to various events, including OnCaptureChanged(), OnKeyDown(), OnLButtonDown(), OnLButtonUp(), OnMouseMove(), OnRButtonDown(), and OnMouseLeave().

3DView.cpp:

  • This is a C++ file implementing the C3DView class, which is a view class used in a larger program called "Faceworx." It defines various methods for rendering a 3D view, as well as handling mouse input and device loss.
  • The C3DView class inherits from the CView class and implements the following methods:
    • C3DView(): the constructor for the class. Initializes various member variables.
    • ~C3DView(): the destructor for the class.
    • OnDraw(CDC* pDC): the method called by the framework to draw the view. Calls the Render method to do the actual rendering.
    • AssertValid() const and Dump(CDumpContext& dc) const: debugging methods that are only included in debug builds.
    • GetDocument() const: returns a pointer to the CFaceworxDoc object associated with the view.
    • RestoreDevice(): checks if the device has been lost and attempts to restore it if necessary.
    • Render(): performs the actual rendering of the 3D view. It sets various render states, material properties, lighting, and texture states before drawing the mesh. It also handles device loss and wireframe rendering.
  • The C3DView class also defines several event handler methods for mouse input, including OnLButtonDown, OnLButtonUp, OnRButtonDown, OnRButtonUp, and OnMouseMove. These methods update member variables and the current transformation matrix based on the user's input.
  • Overall, this file defines a class that is responsible for rendering a 3D view and handling user input for a larger program.
  • It contains event handlers for the left mouse button down, left mouse button up, middle mouse button down, middle mouse button up, and mouse move events.
  • The left mouse button down event handler checks whether 3D editing is enabled and whether the control key is pressed. If both conditions are met, it calls the ModifyAt function with the current mouse position and returns. If these conditions are not met, it checks whether the control key is pressed and if so, it displays some debug information about the intersection of the mouse position with the mesh.
  • The left mouse button up event handler simply releases the mouse capture if the m_bDrag flag is not set.
  • The middle mouse button down event handler sets the m_bDrag flag and saves the current mouse position if the mouse capture is not already set.
  • The middle mouse button up event handler releases the mouse capture if the m_bDrag flag is set.
  • The mouse move event handler first checks whether 3D editing is enabled and if so, it modifies the mesh vertices based on the distance between each vertex and the current intersection of the mouse with the mesh. It then checks whether the right mouse button and the control key are pressed, and if so, it moves the mesh vertices based on the distance between the current mouse position and the last saved mouse position. Finally, if the left mouse button is pressed, it calculates the rotation of the view based on the difference between the current mouse position and the last saved mouse position, and updates the rotation matrix. If the middle mouse button is pressed, it calculates the translation of the view based on the difference between the current mouse position and the last saved mouse position, and updates the translation matrix.

obj_exporter.cpp

  • This is the implementation of the obj_exporter class in C++ for exporting 3D models to the OBJ file format. The OBJ format is a simple, text-based file format that can be used to store 3D models consisting of triangles, and it is supported by many 3D modeling and rendering software applications.
    • The obj_exporter class has a constructor and a destructor, and it also includes a number of member functions. The constructor initializes some member variables, and the destructor does nothing.
    • The get_state_block function takes a Direct3D device and creates a Direct3D state block that contains the state information for the device. This state block is used later in the export process to render the model to a texture that can be saved as an image file.
    • The save_surface function takes a Direct3D surface and saves it as an image file. It first saves the surface to a temporary file, then loads it into a GDI+ Image object, and finally saves it as a JPEG file.

ExportDlg.cpp

  • This is an MFC dialog class that implements a file export dialog in a 3D modeling application.
  • The dialog allows the user to specify export options such as model detail, texture size, and texture quality.
  • The dialog contains three controls:
  • A combo box for selecting the model detail (low, medium, or high).
  • A combo box for selecting the texture size.
  • A slider for selecting the texture quality.
  • The OnInitDialog method initializes the combo boxes and slider with default values. The DoDataExchange method is used for exchanging data between the dialog controls and the class members. The DoModal method is used for displaying the dialog and returning the user's selection.
  • The LayoutControl method is a helper function for positioning a dialog control.
  • The CExportDlg class is derived from CFileDialog and is used to display a file dialog for selecting the export file.

Settings.cpp

  • This code defines the implementation of a class called CSettings that manages the settings of a program. The class has a member variable called ini_fn which holds the path of the configuration file voxelworx.ini. The constructor initializes ini_fn by getting the current directory and appending voxelworx.ini to it. It also initializes iInitialModelDetail to 1 and bRightButtonMoving to false.
  • The Load() method reads the settings from the configuration file and updates the member variables accordingly. It opens the file using _wfopen() and reads each line using fgets(). It then uses a macro called SWITCH() to compare the line with different setting names. If a match is found, it extracts the value from the line and updates the corresponding member variable.
  • The Save() method is incomplete and does not actually save any settings. It also tries to open the configuration file using _wfopen() but it should use "wt" instead of "rt" to open it for writing. It then uses fprintf() to write the values of bRightButtonMoving and iInitialModelDetail to the file. However, the format strings in fprintf() are missing the placeholders for the actual values. They should be "%s = %d\n" and "%s = %d\n", respectively.

LoopSubdivider.cpp

  • This is a C++ source code file for a loop subdivision algorithm implementation. The loop subdivision algorithm is a technique used in 3D computer graphics for generating a smooth and visually appealing surface from a coarse mesh.
  • The code defines a class called CLoopSubdivider that implements the loop subdivision algorithm. The class has a constructor and destructor, and a method called Init which takes an ID3DXMesh object and some other parameters as input. The ID3DXMesh object represents a mesh that is to be subdivided, and the other parameters are used to determine the adjacency information of the mesh.
  • The code also defines a function called SameVertex which takes an array of vertices (VERTEX*) and two vertex indices (i1 and i2) as input, and returns true if the two vertices are the same or very close in position.
  • The Init method first initializes some variables and data structures, and then loops through all the faces in the mesh to compute the adjacency information of the mesh. It creates a data structure called verts which stores information about each vertex in the mesh, such as its index, position, and whether it is a boundary vertex or not. It also creates a data structure called adjs which stores the adjacency information for each vertex.
  • The Init method loops through all the faces in the mesh, and for each face, it loops through all the edges of the face to determine the adjacent vertices. It adds the adjacent vertices to the adjs data structure for each vertex, and updates the verts data structure to mark boundary vertices.
  • The loop subdivision algorithm involves repeatedly subdividing the mesh by adding new vertices and faces, and updating the positions of the existing vertices based on the positions of their neighbors. The implementation of the loop subdivision algorithm is not shown in this code file, but it is likely implemented in other methods of the CLoopSubdivider class.

LoopSubdivider.h

  • This is the header file for a class called CLoopSubdivider, which appears to be related to mesh subdivision. Here are some key points about the file:
  • The file starts with a typedef for a VERT struct, which contains information about a vertex in the mesh. It has two different representations, one with arrays for the parents and across vertices, and one with an index and information about adjacent vertices.
  • The CLoopSubdivider class has an array of indices (m_Indices) and arrays of vertices (verts) and adjacent vertices (adjs). There are also some variables related to sharpening points.
  • The CLoopSubdivider class has functions for initialization (Init), subdivision (Subdivide), and finding nodes (FindNodes). It takes an input mesh and adjacency information and produces a subdivided output mesh.

texture_blender.cpp

  • This is a C++ code for blending two lines onto a Direct3D texture using a template-based blender struct. The code uses Direct3D9.
  • The texture_blender class has two public methods: texture_blender() and ~texture_blender(), which are the constructor and the destructor, respectively, both of which do nothing.
  • The blend() method is the main method of the class, which takes a IDirect3DTexture9 object, two CPointFArray objects representing the two lines to blend, and returns an HRESULT. The method locks the texture's first level, retrieves its description, and determines its pixel format. Then, based on the pixel format, the appropriate blender struct is called, which does the actual blending of the two lines onto the texture. Finally, the texture is unlocked, and the HRESULT is returned.
  • The blender struct is a template struct with four template parameters:
    • off: the offset (in bits) of the pixel component to be blended within the pixel.
    • len: the length (in bits) of the pixel component to be blended.
    • bytes: the number of bytes in a single pixel of the texture.
    • type: the data type of the pixel component to be blended (e.g., unsigned char, unsigned short, etc.).
    • The blender struct has a set() method template that sets the value of the pixel component to be blended within the pixel, based on whether the offset is a multiple of 8 bits or not. If it is, then the value is simply set to the input value. If not, then the pixel component is cleared, and then the input value is bitwise OR'd with the pixel component, shifted left by the offset number of bits.
  • The blender struct also has a blend() method that blends the two input lines onto the texture using the given off, len, bytes, and type parameters. For each row of pixels in the texture, the method computes the x-coordinates at which the two lines intersect that row. It then iterates through each pixel in that row and sets the value of the pixel component to be blended within the pixel, based on the distance from the intersection points of the two lines. The method uses the set() method template to set the value of the pixel component. The method takes care to handle the cases where the intersection points are outside the texture or where the two lines do not intersect at all.
  • Overall, the code blends two lines onto a Direct3D texture using a template-based blender struct, which is capable of handling different pixel formats.

Reimplementation of Faceworx in some other software

We would need to reimplement these features from scratch

  1. Loading and displaying the reference image
  2. Marker placement and manipulation
  3. 3D mesh generation
  4. Blending images into UV texture map
  5. Exporting the 3D model
  6. User settings and preferences
  7. Additional features

Here are brief descriptions of the features that need to be reimplemented

  1. Loading and displaying the reference image: The application should allow the user to upload an image and display it on the canvas. The image should be displayed in a way that allows the user to accurately place and manipulate markers on it.
  2. Marker placement and manipulation: The application should allow the user to place markers on the reference image. The markers should be draggable and resizable. The markers should be linked to each other to form a mesh.
  3. 3D mesh generation: The application should generate a 3D mesh based on the marker positions and connections. The mesh should accurately represent the shape of the face. The mesh should be generated using a reliable algorithm that can handle complex shapes.
  4. Blending images into UV texture map: The application should generate a UV texture map based on the marker positions and connections. The texture map should accurately represent the texture of the reference image on the 3D mesh. The texture map should be generated using a reliable algorithm that can handle complex shapes.
  5. Exporting the 3D model: The application should allow the user to export the 3D model in a common file format such as OBJ or FBX. The exported model should accurately represent the shape of the face and the texture map.
  6. User settings and preferences: The application should allow the user to configure settings such as camera angle and lighting. The application should save the user's settings between sessions.

In terms of JavaScript implementation, we will need to use JavaScript libraries such as Three.js for the 3D rendering and manipulation, and potentially other libraries for image processing and marker placement. You may also need to develop custom algorithms for the mesh and texture map generation.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C++ 95.2%
  • C 4.8%