Sphere Distort -- Wrap your models around small worlds.

Next time you want to make a game with small planets, save some time and effort from modeling scenery around a sphere. Sphere Distort takes regular Cartesian meshes and wraps them around the surface of a sphere. Now you can recycle some models from your non-spherical projects.

Just add the script, pick a radius, and remove the script to turn something like this:

1229836--51604--$62776897-6324-4658-ae79-021e5e149cb8_scaled.jpg

into something like this:

1229836--51607--$28012e8e-d4eb-4118-827e-88044f137c57_scaled.jpg

Demo

How would that look like if turned in a complete sphere? Would it be seamless (assuming the base was seamless on a 2D plane)?

If you take a square and distort it, the corners will wrap furthest because they are furthest from the center of the object. This causes the corners to touch at the south pole before the mesh makes a complete sphere. In order to make a sphere, your starting shape would have to be circular. Even then, Sphere Distort wouldn’t make it seamless. If you give the object an even smaller radius, it would continue to wrap past the south pole onto the other side.

Hello, I have just discovered this and think that is an awesome and great idea, and seems to be very good.

Can the distorted 3d model be exported to an external 3d software?

I wonder if the bending of the 3D object is just made during runtime with the script, or this can be converted into an exportable mesh? I mean that you can have a mesh with the 3D model converted and that you can export to an external 3D software or is only available with script and is just a visual effect?

Thanks very much

Is there going to be an update for the newer versions of Unity? I really could do with this asset. It is a really lovely concept.

For any that come across this later, here’s what I did to get this working (since all the links in this thread are broken in 2024). My use case was warping with respect to the sphere center, but that part can be removed.

Video of this in action.

    [ContextMenu("Deform")]
    public void DeformMesh()
    {
        var meshFilter = GetComponent<MeshFilter>();
        if (!originalMesh) originalMesh = meshFilter.sharedMesh;
        var mesh = Instantiate(originalMesh);
        Vector3[] originalVertices = mesh.vertices;
        var verts = new List<Vector3>();
        var axisWS = (transform.position - sphereOrigin).normalized;
        debugAxis = axisWS;
    
        for (int i = 0; i < originalVertices.Length; i++)
        {
            Vector3 vertexLS = originalVertices[i];
            Vector3 vertexWS = transform.TransformPoint(vertexLS);
            Vector3 dirWS = vertexWS - sphereOrigin;
        
            // Rotate about a point along the axis from the vertex to sphere center.
            Vector3 pivotWS = sphereOrigin + dirWS.normalized*sphereRadius;
            float angle = Vector3.Angle(dirWS, axisWS);
            Vector3 rotationAxis = Vector3.Cross(dirWS, axisWS).normalized;
            Quaternion rotation = Quaternion.AngleAxis(-angle, rotationAxis);
            Vector3 rotatedVertexWS = rotation * (vertexWS - pivotWS) + pivotWS;
        
            var deltaWS = (rotatedVertexWS - vertexWS);
            rotatedVertexWS = vertexWS + (axisWS*Vector3.Dot(deltaWS, axisWS));
        
            var rotatedVertexLS = transform.InverseTransformPoint(rotatedVertexWS);
        
            verts.Add(Vector3.Lerp(vertexLS, rotatedVertexLS, deformationStrength));
        }

        mesh.vertices = verts.ToArray();
        mesh.RecalculateNormals();
        mesh.RecalculateBounds();
        mesh.RecalculateTangents();

        meshFilter.sharedMesh = mesh;

        if (TryGetComponent(out MeshCollider collider))
        {
            collider.sharedMesh = mesh;
        }
    }

hey! would you be able to post the full code for this? it looks like it could help me solve an issue in my project but the code that was posted is missing some key variables

what you got looks incredible!!
if not its alright! :slight_smile:

For sure, here’s what I’m currently using for it. PlanetMesh can just be a transform

#define EDITOR_HELPERS

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Serialization;

public class EditorSpherifyMesh : MonoBehaviour
{
    public float deformationStrength = 1f;

    public float sphereRadius = 1;
    public Mesh originalMesh;
    public Transform OwningPivot; // If assigned, use Owner.position as the pivot instead of this.transform.position

    private Vector3 debugAxis;
    private PlanetMesh planet;
    public bool editorUpdate = false;

    private Vector3 sphereOrigin;

    
#if EDITOR_HELPERS
    void OnValidate()
    {
        if (!editorUpdate) return;
        DeformMesh();
    }
#endif
    
    [ContextMenu("Deform")]
    public void DeformMesh()
    {
        if(!planet) planet = PlanetSystem.NearestPlanetMesh(transform);
        sphereOrigin = planet.transform.position;
        
        var meshFilter = GetComponent<MeshFilter>();
        if (!originalMesh) originalMesh = meshFilter.sharedMesh;
        var mesh = Instantiate(originalMesh);
        Vector3[] originalVertices = mesh.vertices;
        var verts = new List<Vector3>();
        var axisWS = ((OwningPivot ? OwningPivot.transform.position : transform.position) - sphereOrigin).normalized;
        debugAxis = axisWS;
        
        for (int i = 0; i < originalVertices.Length; i++)
        {
            Vector3 vertexLS = originalVertices[i];
            Vector3 vertexWS = transform.TransformPoint(vertexLS);
            Vector3 dirWS = vertexWS - sphereOrigin;
            
            // Just Project directly onto the sphere
            //Vector3 projectedVertexWS = (sphereOrigin + dirWS.normalized * sphereRadius);
            //var projectedVertexLS = transform.InverseTransformPoint(projectedVertexWS);

            // Rotate about a point along the axis from the vertex to sphere center.
            Vector3 pivotWS = sphereOrigin + dirWS.normalized*sphereRadius; //or sphereOrigin for no offset
            float angle = Vector3.Angle(dirWS, axisWS);
            Vector3 rotationAxis = Vector3.Cross(dirWS, axisWS).normalized;
            Quaternion rotation = Quaternion.AngleAxis(-angle, rotationAxis);
            Vector3 rotatedVertexWS = rotation * (vertexWS - pivotWS) + pivotWS;
            
            var deltaWS = (rotatedVertexWS - vertexWS);
            rotatedVertexWS = vertexWS + (axisWS*Vector3.Dot(deltaWS, axisWS));
            
            var rotatedVertexLS = transform.InverseTransformPoint(rotatedVertexWS);
            
            verts.Add(Vector3.Lerp(vertexLS, rotatedVertexLS, deformationStrength));
        }

        mesh.vertices = verts.ToArray();
        mesh.RecalculateNormals();
        mesh.RecalculateBounds();
        mesh.RecalculateTangents();

        meshFilter.sharedMesh = mesh;

        if (TryGetComponent(out MeshCollider collider))
        {
            collider.sharedMesh = mesh;
        }
    }

    private void OnDrawGizmosSelected()
    {
        Gizmos.DrawWireSphere(sphereOrigin, sphereRadius*2);
    }
}