Reputation: 189
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
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
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
}
}
}
Upvotes: 1
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