ceteri
ceteri

Reputation: 189

How to apply cubemap to inverse of a sphere in Unity 3D

I am trying to apply a .jpg texture to the inside of a sphere primitive (an inverted sphere) to make a simple 3D photosphere for use in VR and i am having problems. I am using unity 5.4

I import the 360 degree panorama .jpg texture, set its texture type to cubemap and set its mapping to longitude/latitude (cylindrical).

I create a new material, the only cubemap shader i can find in the shader pulldown of the material is skybox/cubemap. I select this but it will not let me assign the material to the sphere. I can assign it to the background , but i need it on the sphere, what am i doing wrong? how can i get my cubemap texture onto a material that i can apply to my inverted sphere?

Upvotes: 1

Views: 3638

Answers (3)

Lan
Lan

Reputation: 26

Here's a non-shader solution in the form of a component that will invert the normals of the sphere for you, then you can simply apply any equirectangular texture as you've mentioned. I assume you need the inside of a sphere so you can interact with the actual geometry/areas in the panorama (that's why I wrote this up too).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshFilter))]
public class InvertNormals : BaseView
{
    void Start()
        {
            // Firstly, we grab this object's mesh filter component
            MeshFilter filter = gameObject.GetComponent<MeshFilter>();

            if (filter != null)
            {
                // Now that we have the mesh filter component, we can grab the
                topology itself...
                Mesh skyboxSphereMesh = filter.mesh;

                // ...and cache all of its normals into an array of Vector3 values
                Vector3[] normals = skyboxSphereMesh.normals;

                // We iterate over the array and negate (-x, -y, -z) each vector...
                // https://docs.unity3d.com/ScriptReference/Vector3-operator_subtract.html
                // ...then re-assign the value
                for (int i = 0; i < normals.Length; i++)
                    normals[i] = -normals[i];

                // Re-assign all of our inverted normal values to the mesh
                skyboxSphereMesh.normals = normals;

                // Now we need to iterate over all of the submeshes, each index
                // referring to a list of triangles/trigons, which refer to a set
                // of vertices in 3D space 
                for (int i = 0; i < skyboxSphereMesh.subMeshCount; i++)
                {
                    // Firstly, we cache the triangles...
                    int[] triangles = skyboxSphereMesh.GetTriangles(i);
                    // ...then iterate over the values, incrementing our count by 3 each time
                    for (int j = 0; j < triangles.Length; j += 3)
                    {
                        // We're offsetting the index array here and not the actual vertex array,
                        // this might cause problems with UVs down the line!
                        int temp = triangles[j + 0]; // Unity Forum magic per-vertex offset
                        triangles[j + 0] = triangles[j + 1];
                        triangles[j + 1] = temp;
                    }
                    // Re-assign the mesh with a new set of triangle indices at the current submesh
                    skyboxSphereMesh.SetTriangles(triangles, i);
               }
            }
        }
    }

Upvotes: 0

Wappenull
Wappenull

Reputation: 1389

Shader code credit goes to user Bgolus on Unity forum: https://forum.unity.com/threads/cube-mapped-sphere-aka-quad-sphere-asset.292860/#post-2708001

The shader code from that forum thread will allow rendering cubemap into sphere and cube.

The only addition I made to that code is to add Cull Front into the shader to make the mesh looks normal-inverted, and you can just use built-in sphere from Unity for the mesh.

Shader "Unlit/InverseCullCubeMapShader"
{
    Properties
    {
        _CubeMap( "Cube Map", Cube ) = "white" {}
    }
    SubShader
    {
        Pass 
        {
            Tags { "DisableBatching" = "True" }

            Cull Front

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
        
            samplerCUBE _CubeMap;
        
            struct v2f 
            {
                float4 pos : SV_Position;
                half3 uv : TEXCOORD0;
            };
        
            v2f vert( appdata_img v )
            {
                v2f o;
                o.pos = UnityObjectToClipPos( v.vertex );
                o.uv = v.vertex.xyz * half3(-1,1,1); // mirror so cubemap projects as expected
                return o;
            }
        
            fixed4 frag( v2f i ) : SV_Target 
            {
                return texCUBE( _CubeMap, i.uv );
            }
            ENDCG
        }
    }
}
Inverse sphere skybox

Upvotes: 1

ina
ina

Reputation: 19534

Here is a shader that may help

Shader "Flipping Normals" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }
    SubShader {

        Tags { "RenderType" = "Opaque" }

        Cull Off

        CGPROGRAM

        #pragma surface surf Lambert vertex:vert
        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
            float4 color : COLOR;
        };

        void vert(inout appdata_full v) {
            v.normal.xyz = v.normal * -1;
        }

        void surf (Input IN, inout SurfaceOutput o) {
             fixed3 result = tex2D(_MainTex, IN.uv_MainTex);
             o.Albedo = result.rgb;
             o.Alpha = 1;
        }

        ENDCG

    }

      Fallback "Diffuse"
}

Upvotes: 1

Related Questions