Open-source project
electronicarts/mesh2splat avatar
electronicarts/mesh2splat

Mesh2Splat: turning meshes into Gaussian splats in under a millisecond

Fast mesh to 3D gaussian splat conversion

953 stars91 forksC++NOASSERTION

At a glance

What is it?
Mesh2Splat is Electronic Arts' fast surface splatting converter that turns a 3D mesh into a 3D Gaussian Splatting model by exploiting the rasterizer's interpolator, avoiding the multi-minute dataset generation that the classical 3DGS pipeline needs, and it ships with its own 3DGS renderer.
Who is it for?
Use Mesh2Splat if you need a Gaussian splat representation of an existing mesh, whether because your renderer is 3DGS only, or because you want a geometry and texture informed starting point for a splat optimisation run, since the README reports conversion in under 0.5 ms on average against the minutes a classical 3DGS pipeline would take.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why mesh to splat conversion used to take minutes

The problem the project names is concrete. To get a 3D mesh into 3D Gaussian Splatting format the classical way, you have to generate a synthetic dataset: camera poses, image renders of the model, and an initial sparse point cloud, then feed all of that into a 3DGS pipeline. The README says that process can take several minutes, depending on the specific 3DGS pipeline and the model used.

Mesh2Splat takes a different route. Instead of rendering the model into images and optimising from those, it reads the geometry and texture information stored in the 3D model and produces a 3DGS representation in milliseconds. The README's framing question is worth repeating as the design brief: what if we wanted to represent a synthetic object in 3DGS format.

Three use cases follow from that shortcut, and they are listed in the README rather than implied. The first is 3DGS-only rendering pipelines, where the renderer cannot mix triangle meshes and Gaussians, so a mesh asset has to be converted to pure 3DGS to be drawn at all. The second is fast initialization for a 3DGS optimisation run, where a geometry and texture informed initial guess leads to faster convergence and better results than a random one. The third is enhancing a traditional renderer that supports 3DGS by converting selected assets only.

The audience is technical artists and graphics engineers who already work with splats and need meshes to enter that world cheaply.

Splatting by riding the rasterizer's interpolator

The core idea, as the README puts it, is to convert meshes into 3DGS models by exploiting the rasterizer's interpolator. That single sentence explains the whole design, including why the speed is possible.

A Gaussian splat is an oriented, scaled 3D ellipse. Rendering many of them is fast, but producing millions of them on the CPU and uploading them would be slow. This method instead lets the GPU's rasterization pipeline do the work: for each triangle, one 3D Gaussian is emitted per vertex, and the hardware interpolator generates one Gaussian per fragment in the orthogonal space. The vertex shader positions them with a line that deliberately reuses the normalized texture coordinates:

glsl
gl_Position = vec4(gs_in[i].normalizedUv * 2.0 - 1.0, 0.0, 1.0);

Because the interpolated value is a texture coordinate, the fragment stage can fetch the texture directly and attach the sampled data to the Gaussian it is about to produce. Each fragment then atomically appends one Gaussian into a shared SSBO, a shader storage buffer object.

The atomic append is what makes the approach work in parallel without a CPU round trip. There is no readback, no sorting pass on the CPU, no intermediate point cloud. The pipeline that a GPU already runs for rasterizing triangles is the pipeline that produces the splats.

The cost is that the method is bound to a GPU and to an OpenGL-compatible renderer. That constraint is why the build instructions start with a requirement for an OpenGL-compatible GPU and drivers.

Per triangle Jacobian math that sets the ellipse footprint

The per-triangle work determines how large each Gaussian is and how it is oriented, and the README documents it in enough detail to be reproducible.

The model is initialized from the 3D bounding box of the input, and a 2D covariance matrix is set up with sigma_x and sigma_y both around 0.65 and rho equal to zero, which is the isotropic starting case before per-triangle adjustment.

For each triangle primitive in the geometry shader stage, the steps are: apply a triplanar orthogonal projection onto the X, Y or Z face based on normal similarity and normalize into the range minus one to one; compute the Jacobian matrix from orthogonal UV space to 3D space, written as J = V times the inverse of UV; derive the 3D directions corresponding to the texture axes u and v and calculate the magnitudes of the 3D derivative vectors; multiply those lengths by the 2D Gaussian's standard deviation to obtain the scaling factors along the directions aligned with the surface.

The packed scale values that result are the logarithm of the length of Ju times sigma_x, the logarithm of the length of Jv times sigma_y, and a fixed log of 1e-7 for the third axis. Taking a logarithm of a scale is how the splat format stores it, and the near zero third axis is what flattens the Gaussian onto the surface, which is the surface splatting idea in one number.

Once scale and rotation are known for a triangle, one 3D Gaussian is emitted per vertex of that triangle, positioned at the vertex's 3D position, and the fragment stage does the texture fetches and the atomic append.

A renderer that ships with the converter

Mesh2Splat does not only convert. It comes with a 3DGS Renderer for viewing the conversion results, and the README describes its feature set in detail.

For visualisation it offers albedo, normals, depth, geometry, overdraw and PBR property views, which is the set of channels a graphics engineer needs to judge whether a conversion is correct rather than merely plausible. Shading of the Gaussians themselves is PBR based. Lighting is kept simple, with a point light and omnidirectional shadow mapping.

Two features are aimed at the developer rather than the viewer. Shader hot-reload lets you edit shaders and the 3DGS math and see the effect without a full rebuild. The mesh-Gaussian occlusion option, called the Enable mesh-gaussian depth test, uses the mesh as an occluder in the depth prepass to improve performance.

That last item is worth understanding as an engineering trade rather than a feature. It lets you keep the original mesh in the scene for occlusion while the visible surface is drawn as Gaussians, which avoids sorting issues in the depth test.

The renderer and converter are separate tools in one repository, and the src/ directory plus thirdParty/ directory and a CMakeLists.txt at the root are where the two live.

Converter limits: .glb only and three texture maps

The converter's own limits are stated plainly in the README, and they are the first things to check against your assets.

Input format: only .glb is supported for now. That is the glTF binary container, which in practice means a pipeline that has already exported to glTF works and one that works in OBJ or FBX does not.

Texture maps: three are handled, diffuse, metallic-roughness and normal. So a model whose look depends on other maps, an occlusion map or an emissive map for instance, will not carry all of its appearance information into the splat.

Quality is adjustable rather than fixed. The README states that the sampling density, which is conversion quality, can be tweaked in the settings via a slider. That is the knob that trades Gaussian count against fidelity, and it is the one control you will actually spend time with.

Relightability is listed as a feature on its own, and the condition attached to it matters: the Gaussians can be relit easily given a renderer that supports it. Whether a given downstream renderer can do that is a property of that renderer, not of the converted asset.

The example model in the README is credited to M. Pavlovic, the Sci-fi helmet model, 2024, provided by Quixel, under a CC Attribution Share Alike 3.0 licence, and the file is downloadable from the Khronos glTF sample assets. Note that the asset licence is separate from the licence of the code.

Building on Windows with CMake and Visual Studio

The build instructions are Windows first, and the prerequisites are specific enough to trip people up.

CMake 3.21.1 or newer is required, and the reason is given: older versions may default to unsupported generators, and versions such as 3.10 or 3.11 do not recognise Visual Studio 2022 and will fail to generate a solution. Visual Studio 2019 or 2022 must be installed with the Desktop development with C++ workload, and the note says to make sure the CMake version is compatible with the Visual Studio version. An OpenGL-compatible GPU and drivers are listed as a prerequisite too, which follows from the rasterizer based approach.

The build itself is two batch scripts at the repository root, run_build_debug.bat and run_build_release.bat. The instructions say to open a terminal in the project root and run one of them, then open the bin folder and run the executable, or open the build folder and open the .sln file. A tip in the same section says to use the release build if you only need the final executable in optimised mode.

The Linux instructions are thinner and, as published, incomplete. The dependency line in the README stops mid-word:

bash
sudo apt install buil

That truncation is in the source documentation, so anyone building on Linux has to reconstruct the package list themselves. The repository does carry the pieces a build needs, including CMakeLists.txt, src/, thirdParty/ and res/.

A custom licence, a citation file and an April last push

Two repository details matter for anyone planning to use this in a pipeline.

The first is the licence. The project records a custom licence that GitHub cannot classify, and the terms live in LICENSE.txt, with NOTICE.txt alongside it. This is not the MIT or Apache pattern that most open source readers expect, so the file itself has to be read before the code is vendored into a product. The homepage associated with the project is seed.ea.com, which places the work as coming from EA's research organisation rather than from a game team, and the presence of a CITATION.cff file at the repository root says that academic citation is an intended use.

The second is the activity level. The repository is not archived, and the last push was on 2026-04-22. The tagged releases are v1.2.0 on 2026-03-27, v1.1.0 on 2026-03-08, and v1.0.0 on 2025-04-02.

So there is a gap of nearly a year between 1.0.0 and 1.1.0, and then 1.2.0 followed about three weeks later. That gap is consistent with a research code release rather than a supported product, and it means you should expect to maintain your own fork if you need changes. The releases are also not accompanied by a changelog in the repository listing, so what changed between 1.1.0 and 1.2.0 has to be read out of the diff.

Editorial conclusion

Use Mesh2Splat if you need a Gaussian splat representation of an existing mesh, whether because your renderer is 3DGS only, or because you want a geometry and texture informed starting point for a splat optimisation run, since the README reports conversion in under 0.5 ms on average against the minutes a classical 3DGS pipeline would take. Do not adopt it as a general mesh importer, since only the .glb format is supported for now, and treat the reported timing as a figure from the project's own README rather than a guarantee for your assets. Before you build, verify two things: that your machine has an OpenGL compatible GPU with drivers, since the method depends on rasterizer interpolation, and that the terms in LICENSE.txt and NOTICE.txt suit your use, because the project records a custom licence rather than a standard identifier.

Frequently asked questions

What does Mesh2Splat do and how fast is it?

It converts a 3D mesh into a 3D Gaussian Splatting model by exploiting the rasterizer's interpolator, instead of generating the camera poses, renders and sparse point cloud that a classical 3DGS pipeline needs. The README reports conversion in under 0.5 ms on average.

Which input formats does Mesh2Splat support?

Only the .glb format is supported for now, as the converter section of the README states. Texture handling covers the diffuse, metallic-roughness and normal maps.

How do I build Mesh2Splat on Windows?

You need CMake 3.21.1 or newer for Visual Studio 2022 project generation, Visual Studio 2019 or 2022 with the Desktop development with C++ workload, and an OpenGL-compatible GPU. Run run_build_debug.bat or run_build_release.bat in the project root, then run the executable from bin or open the .sln file in build.

What does the Mesh2Splat renderer provide?

It offers albedo, normals, depth, geometry, overdraw and PBR property visualisation, PBR based Gaussian shading, a point light with omnidirectional shadow mapping, shader hot-reload, and an Enable mesh-gaussian depth test option that uses the mesh as an occluder in the depth prepass.

What licence is Mesh2Splat released under?

The repository records a custom licence that GitHub cannot classify, with the terms in LICENSE.txt and a NOTICE.txt beside it. The repository also carries a CITATION.cff file, and the last push was on 2026-04-22 with tagged releases v1.2.0, v1.1.0 and v1.0.0.

Official sources

  1. electronicarts/mesh2splat on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/electronicarts-mesh2splat.svg)](https://hysenlabs.com/projects/electronicarts-mesh2splat)

Was this useful?