Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Want more efficiency in your development work? Sign up to receive weekly tech and creative know-how from Unity experts.
    Dismiss Notice
  4. Build games and experiences that can load instantly and without install. Explore the Project Tiny Preview today!
    Dismiss Notice
  5. Nominations have been announced for this years Unity Awards. Celebrate the wonderful projects made by your peers this year and get voting! Vote here!
    Dismiss Notice
  6. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  7. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Interior Mapping

Discussion in 'Shaders' started by Beinscheibe, Aug 7, 2016.

  1. Beinscheibe

    Beinscheibe

    Joined:
    Sep 24, 2013
    Posts:
    78
    Hey,

    for a project we need interior mapping for some windows (so it doesn't break the illusion).
    We found a shader based on Unity 4 here (http://www.inear.se/2011/02/interior-mapping-in-unity3d/) and I did my best on getting it to work in Unity 5.

    But as my shader (and math) knowledge is rather limited, it currently only works based on the World Position (so if you move the object, the walls stay where they were in the world and don't move with the object)..
    The problem is, that it's not really nice to use that way. What would be ideal (and what it might have done in the first place) would be, if the position of walls, ceiling and floor depends on the object and not the world position (hope you understand what I mean).

    If anyone could help us out here, it would be nice.

    Code (CSharp):
    1. // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    2.  
    3.  
    4. Shader "buildingshader" {
    5.     Properties {
    6.         _wallFrequencies ("Wall freq", Vector) = (1,1,1)
    7.        
    8.         _ceilingTexture  ("Ceiling texture", 2D) = "white" { TexGen EyeLinear }
    9.         _floorTexture ("Floor texture", 2D) = "red" { TexGen EyeLinear }
    10.         _wallXYTexture ("wallXY texture", 2D) = "black" { TexGen EyeLinear }
    11.         _wallZYTexture ("wallZY texture", 2D) = "green" { TexGen EyeLinear }
    12.         _noiseTexture( "Noise texture", 2D) = "green" { TexGen EyeLinear }
    13.        
    14.     }
    15.     SubShader {
    16.          Pass {
    17.        
    18.              CGPROGRAM
    19.        
    20.             #pragma target 3.0
    21.             #pragma exclude_renderers xbox360
    22.             #pragma vertex vert
    23.             #pragma fragment frag
    24.            
    25.             #include "UnityCG.cginc"
    26.            
    27.             struct v2f {
    28.            
    29.                 float4 pos:    SV_POSITION;
    30.                 float2 uv:TEXCOORD0;
    31.                 float3 positionCopy:TEXCOORD1;
    32.                 float4 lighting:TEXCOORD2;
    33.             };
    34.  
    35.             float3 _wallFrequencies;
    36.             float _lightThreshold;
    37.            
    38.             v2f vert (appdata_base v)
    39.             {
    40.                 v2f o;
    41.                
    42.                 o.pos = mul (UNITY_MATRIX_MVP, v.vertex) ;
    43.                 o.uv = v.texcoord /** float2(_uvMultiplier.xy)*/;
    44.  
    45.                 o.positionCopy = mul(unity_ObjectToWorld, v.vertex); //float3(v.vertex.xyz);
    46.                                            
    47.                 // Calculate lighting on the exterior of the building with a hard-coded directed light.
    48.                 float lightStrength = dot(v.normal, float3(0.5, 0.33166, 0.8));
    49.                 o.lighting = saturate(lightStrength) * float4(1, 1, 0.9, 1) * (1-_lightThreshold);
    50.                
    51.                 // Add some ambient lighting.
    52.                 o.lighting += float4(0.3, 0.3, 0.4, 1);
    53.                
    54.                 return o;
    55.             }
    56.  
    57.            
    58.             sampler2D _ceilingTexture;
    59.             sampler2D _floorTexture;
    60.             sampler2D _wallXYTexture;
    61.             sampler2D _wallZYTexture;
    62.             sampler2D _noiseTexture;
    63.            
    64.             half4 frag (v2f i) : COLOR
    65.             {
    66.                 //position in object space
    67.                 float4 objPos = mul(unity_ObjectToWorld, float4(0,0,0,1));
    68.                 float3 mama = i.positionCopy - objPos.xyz;
    69.  
    70.                 float3 direction = i.positionCopy - _WorldSpaceCameraPos;
    71.        
    72.                 //multiply by 0.999 to prevent last wall from beeing displayed. Fix this?
    73.                 float3 corner = floor(i.positionCopy *_wallFrequencies * 0.999);
    74.                 float3 walls = corner + step(float3(0, 0, 0), direction);
    75.                 walls /= _wallFrequencies;
    76.                 corner /= _wallFrequencies;
    77.                
    78.                 float3 rayFractions = (float3(walls.x, walls.y,walls.z) - _WorldSpaceCameraPos) / direction;
    79.                 float2 intersectionXY = (_WorldSpaceCameraPos + rayFractions.z * direction).xy;
    80.                 float2 intersectionXZ = (_WorldSpaceCameraPos + rayFractions.y * direction).xz;
    81.                 float2 intersectionZY = (_WorldSpaceCameraPos + rayFractions.x * direction).zy;
    82.                
    83.                 float4 ceilingColour = tex2D(_ceilingTexture, intersectionXZ);
    84.                 float4 floorColour = tex2D(_floorTexture, intersectionXZ);
    85.                 float4 verticalColour = lerp(floorColour, ceilingColour, step(0, direction.y));
    86.                
    87.                 //random texture on wall xy
    88.                 float zNoise = tex2D(_noiseTexture, float2(corner.z/64,0)).r;
    89.                 float yNoise = tex2D(_noiseTexture, float2(corner.y/64 + zNoise,0)).r;
    90.                 float noiseXY = tex2D(_noiseTexture, float2(corner.x/64 + yNoise,0)).r;
    91.            
    92.                 noiseXY = floor(noiseXY * 4) / 4;
    93.                 float2 atlasIndexXY;
    94.                 atlasIndexXY[0] = floor(noiseXY * 2) / 2;
    95.                 atlasIndexXY[1] = (noiseXY - atlasIndexXY[0]) * 2;
    96.                
    97.                 //put the intersection into room space, so that it comes within [0, 1]
    98.                 intersectionXY = (intersectionXY - corner.xy) * _wallFrequencies.xy;
    99.                
    100.                 //use the texture coordinate to read from the correct texture in the atlas
    101.                 float4 wallXYColour = 0.8 * tex2D(_wallXYTexture, intersectionXY);
    102.                
    103.                 //random texture on wall ZY
    104.                 float zNoise2 = tex2D(_noiseTexture, float2(corner.z/64,0)).g;
    105.                 float yNoise2 = tex2D(_noiseTexture, float2(corner.y/64 + zNoise2,0)).g;
    106.                 float noiseZY = tex2D(_noiseTexture, float2(corner.x/64 + yNoise2,0)).g;
    107.                 float2 atlasIndexZY;
    108.                 atlasIndexZY[0] = floor(noiseZY * 2) / 2;
    109.                 atlasIndexZY[1] = 0;//(noiseZY - atlasIndexZY[0]) * 2;
    110.                
    111.                 //put the intersection into room space, so that it comes within [0, 1]
    112.                 intersectionZY = (intersectionZY - corner.zy) * _wallFrequencies.zy;
    113.                
    114.                 //use the texture coordinate to read from the correct texture in the atlas
    115.                 float4 wallZYColour = 0.8 * tex2D(_wallZYTexture, intersectionZY);
    116.        
    117.                 //decide wich wall is closest to camera
    118.                 float xVSz = step(rayFractions.x, rayFractions.z);
    119.                 float4 interiorColour = lerp(wallXYColour, wallZYColour, xVSz);
    120.                 float rayFraction_xVSz = lerp(rayFractions.z, rayFractions.x, xVSz);
    121.                
    122.                 //calculate variation in the lighting per room
    123.                 float3 noises = float3(
    124.                     tex2D(_noiseTexture, float2(corner.x, corner.y)/64).r,
    125.                     tex2D(_noiseTexture, float2(corner.z, corner.x)/64).r,
    126.                     tex2D(_noiseTexture, float2(corner.y, corner.z)/64).r
    127.                 );
    128.                
    129.                 float lightVariation = step((noises.x + noises.y + noises.z)/3, _lightThreshold*0.6f)* 0.3 + noises.x;
    130.                
    131.                 float xzVSy = step(rayFraction_xVSz, rayFractions.y);
    132.                 //floor/ceiling or walls
    133.                 interiorColour = lerp(verticalColour, interiorColour, xzVSy)* lightVariation;
    134.                
    135.                 //blend colors
    136.                 float4 wallColour = /*diffuseColour * */i.lighting;
    137.                 float4 windowColour = /*cubeColour + */interiorColour;
    138.                
    139.                 //return half4(i.positionCopy.xyz, 1);
    140.                 return interiorColour;
    141.                 //return lerp(wallColour, windowColour, diffuseColour.a);
    142.                
    143.             }
    144.  
    145.             ENDCG  
    146.         }
    147.     }
    148. }
    149.  
     
  2. Peter77

    Peter77

    Joined:
    Jun 12, 2013
    Posts:
    2,805
  3. Beinscheibe

    Beinscheibe

    Joined:
    Sep 24, 2013
    Posts:
    78
    @Peter77 will check your thread again. Read through it before, but maybe I can get some more information by reading it again ;)

    @gurayg thanks. I know about this asset but 50$ just for this is a bit much in my opinion (and I would love to set textures for sides and not using a cubemap).

    I will try to get something working. Maybe I will find a way to fix it. We will see. I might even start from scratch in Shaderforge, as this shader is no surface shader (Rendered in Forward Pass).
     
  4. Beinscheibe

    Beinscheibe

    Joined:
    Sep 24, 2013
    Posts:
    78
    Hey guys,

    I tried my best to get it working (also removed some unused stuff for now).
    Here is the code.

    Code (CSharp):
    1. // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
    2.  
    3. // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    4.  
    5.  
    6. Shader "buildingshader" {
    7.     Properties {
    8.         _wallFrequencies ("Wall freq", Vector) = (1,1,1)
    9.        
    10.         _ceilingTexture  ("Ceiling texture", 2D) = "white"
    11.         _floorTexture ("Floor texture", 2D) = "red"
    12.         _wallXYTexture ("wallXY texture", 2D) = "black"
    13.         _wallZYTexture ("wallZY texture", 2D) = "green"
    14.        
    15.     }
    16.     SubShader {
    17.          Pass {
    18.        
    19.              CGPROGRAM
    20.        
    21.             #pragma target 3.0
    22.             #pragma exclude_renderers xbox360
    23.             #pragma vertex vert
    24.             #pragma fragment frag
    25.            
    26.             #include "UnityCG.cginc"
    27.            
    28.             struct v2f {
    29.            
    30.                 float4 pos:    SV_POSITION;
    31.                 float2 uv:TEXCOORD0;
    32.                 float3 positionCopy:TEXCOORD1;
    33.                 float4 lighting:TEXCOORD2;
    34.             };
    35.  
    36.             float3 _wallFrequencies;
    37.             float _lightThreshold;
    38.            
    39.             v2f vert (appdata_tan v)
    40.             {
    41.                 v2f o;
    42.                
    43.                 o.pos = mul (UNITY_MATRIX_MVP, v.vertex) ;
    44.                 o.uv = v.texcoord /** float2(_uvMultiplier.xy)*/;
    45.                
    46.                 //o.positionCopy = mul(unity_ObjectToWorld, v.vertex);
    47.                 o.positionCopy = float3(v.vertex.xyz);
    48.                                            
    49.                 // Calculate lighting on the exterior of the building with a hard-coded directed light.
    50.                 float lightStrength = dot(v.normal, float3(0.5, 0.33166, 0.8));
    51.                 o.lighting = saturate(lightStrength) * float4(1, 1, 0.9, 1) * (1-_lightThreshold);
    52.                
    53.                 // Add some ambient lighting.
    54.                 o.lighting += float4(0.3, 0.3, 0.4, 1);
    55.                
    56.                 return o;
    57.             }
    58.  
    59.            
    60.             sampler2D _ceilingTexture;
    61.             sampler2D _floorTexture;
    62.             sampler2D _wallXYTexture;
    63.             sampler2D _wallZYTexture;
    64.            
    65.             half4 frag (v2f i) : COLOR
    66.             {
    67.                 float3 camObjPos = mul(unity_WorldToObject, _WorldSpaceCameraPos);
    68.                 float3 direction = i.positionCopy - camObjPos;
    69.        
    70.                 //multiply by 0.999 to prevent last wall from beeing displayed. Fix this?
    71.                 float3 corner = floor(i.positionCopy *_wallFrequencies * 0.999);
    72.                 float3 walls = corner + step(float3(0, 0, 0), direction);
    73.                 walls /= _wallFrequencies;
    74.                 corner /= _wallFrequencies;
    75.                
    76.                 float3 rayFractions = (float3(walls.x, walls.y,walls.z) - camObjPos) / direction;
    77.                 float2 intersectionXY = (camObjPos + rayFractions.z * direction).xy;
    78.                 float2 intersectionXZ = (camObjPos + rayFractions.y * direction).xz;
    79.                 float2 intersectionZY = (camObjPos + rayFractions.x * direction).zy;
    80.                
    81.                 float4 ceilingColour = tex2D(_ceilingTexture, intersectionXZ);
    82.                 float4 floorColour = tex2D(_floorTexture, intersectionXZ);
    83.                 float4 verticalColour = lerp(floorColour, ceilingColour, step(0, direction.y));
    84.                            
    85.                 //put the intersection into room space, so that it comes within [0, 1]
    86.                 intersectionXY = (intersectionXY - corner.xy) * _wallFrequencies.xy;
    87.                
    88.                 //use the texture coordinate to read from the correct texture in the atlas
    89.                 float4 wallXYColour = 0.8 * tex2D(_wallXYTexture, intersectionXY);
    90.                                
    91.                 //put the intersection into room space, so that it comes within [0, 1]
    92.                 intersectionZY = (intersectionZY - corner.zy) * _wallFrequencies.zy;
    93.                
    94.                 //use the texture coordinate to read from the correct texture in the atlas
    95.                 float4 wallZYColour = 0.8 * tex2D(_wallZYTexture, intersectionZY);
    96.        
    97.                 //decide wich wall is closest to camera
    98.                 float xVSz = step(rayFractions.x, rayFractions.z);
    99.                 float4 interiorColour = lerp(wallXYColour, wallZYColour, xVSz);
    100.                 float rayFraction_xVSz = lerp(rayFractions.z, rayFractions.x, xVSz);
    101.                
    102.                 float xzVSy = step(rayFraction_xVSz, rayFractions.y);
    103.                 //floor/ceiling or walls
    104.                 interiorColour = lerp(verticalColour, interiorColour, xzVSy);
    105.                
    106.                 //blend colors
    107.                 float4 wallColour = /*diffuseColour * */i.lighting;
    108.                 float4 windowColour = /*cubeColour + */interiorColour;
    109.                
    110.                 return interiorColour* i.lighting;
    111.             }
    112.  
    113.             ENDCG  
    114.         }
    115.     }
    116. }
    117.  

    Now if the object is at Position (0,0,0) in the World, it looks like it's supposed to do:


    But if I move the object to like (0,1,0) in the world, it's already starting to shift:


    As I already said, my shader knowledge is rather "basic". I tried different stuff with object/world space for both object and camera but couldn't get this to work.
    Is there someone who can help me out of this? Any help appreciated.
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    5,331
    Curious, why no cubemap? It simplifies a ton of code. Alternatively there's the SimCity 5 method which is slightly more complicated but let's you have random rooms of varying depths with a single texture.
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    5,331
    Oh, and for the problem you're having with the offset, try:

    float3 camObjPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0)).xyz;

    _WorldSpaceCameraPos is a float3 so your mul is being treated like a rotation instead of a translation.
     
  7. Beinscheibe

    Beinscheibe

    Joined:
    Sep 24, 2013
    Posts:
    78
    If it's easier, I might consider it. But as I have nothing to base on currently, I think this method is what I have to stick to.
    If there is something you can point me to, I'm open for it ^^

    Will try that, thanks.
    EDIT:
    Works perfectly. Thanks ;)
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    5,331
    There's a lot of code for choosing which texture to use in the original version of the shader, and you sample all 3 textures all the time. It also means the transitions between walls and floor / ceiling are always sharp.

    For the cubemap method is shown off here:
    http://www.humus.name/index.php?page=3D&ID=80

    It's written in HLSL, but isn't quite the same as Unity's setup for tangents. It also uses cubemap arrays which Unity doesn't support so you can't quite do the full version of this.

    The SimCity 5 method is hinted at in in this talk:
    http://www.andrewwillmott.com/talks/from-aaa-to-indie

    You start with something like the method used in Emil Persson's example (humus), plus some additional math to adjust the float3 position inside the box into an unwrapped float2 uv. I just worked out the math for all of this recently and can post a basic versions of the shaders for both Emil's cubemap and SimCity's atlas.
     
    Last edited: Aug 14, 2016
    CallHimX likes this.
  9. Beinscheibe

    Beinscheibe

    Joined:
    Sep 24, 2013
    Posts:
    78
    Really great stuff. I think I might have to start learning more shader specific stuff :)

    Basic versions for one (or both) of these might come in handy and would maybe help learning more about Unity's shaders and also about the technique itself (at least on my side). Also I would love to see (and play around with) them too ;)
    I also finally converted the 3 texture version into shader forge, so I was able to easily add stuff we need in our project.
    (Did I say it feels great if you finally understand more of how the shader does things instead of just saying "well it somehow works"?) o_O
     
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    5,331
    interiormapping-cubemap.jpg

    Just does the interior mapping with no additional effects (exterior walls, random lighting, etc.). Does do a random flip / rotation which effectively recreates the basic look of the cube map array version, but not the actual functionality as Emil was lazy and just used the same 6 textures over and over to create 8 "unique" cube maps.


    Code (CSharp):
    1. // Adapted to Unity from http://www.humus.name/index.php?page=3D&ID=80
    2. Shader "Custom/InteriorMapping - Cubemap"
    3. {
    4.     Properties
    5.     {
    6.         _RoomCube ("Room Cube Map", Cube) = "white" {}
    7.         [Toggle(_USEOBJECTSPACE)] _UseObjectSpace ("Use Object Space", Float) = 0.0
    8.     }
    9.     SubShader
    10.     {
    11.         Tags { "RenderType"="Opaque" }
    12.         LOD 100
    13.  
    14.         Pass
    15.         {
    16.             CGPROGRAM
    17.             #pragma vertex vert
    18.             #pragma fragment frag
    19.  
    20.             #pragma shader_feature _USEOBJECTSPACE
    21.          
    22.             #include "UnityCG.cginc"
    23.  
    24.             struct appdata
    25.             {
    26.                 float4 vertex : POSITION;
    27.                 float2 uv : TEXCOORD0;
    28.                 float3 normal : NORMAL;
    29.                 float4 tangent : TANGENT;
    30.             };
    31.  
    32.             struct v2f
    33.             {
    34.                 float4 pos : SV_POSITION;
    35.             #ifdef _USEOBJECTSPACE
    36.                 float3 uvw : TEXCOORD0;
    37.             #else
    38.                 float2 uv : TEXCOORD0;
    39.             #endif
    40.                 float3 viewDir : TEXCOORD1;
    41.             };
    42.  
    43.             samplerCUBE _RoomCube;
    44.             float4 _RoomCube_ST;
    45.  
    46.             // psuedo random
    47.             float3 rand3(float co){
    48.                 return frac(sin(co * float3(12.9898,78.233,43.2316)) * 43758.5453);
    49.             }
    50.          
    51.             v2f vert (appdata v)
    52.             {
    53.                 v2f o;
    54.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    55.  
    56.             #ifdef _USEOBJECTSPACE
    57.                 // slight scaling adjustment to work around "noisy wall" when frac() returns a 0 on surface
    58.                 o.uvw = v.vertex * _RoomCube_ST.xyx * 0.999 + _RoomCube_ST.zwz;
    59.  
    60.                 // get object space camera vector
    61.                 float4 objCam = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0));
    62.                 o.viewDir = v.vertex.xyz - objCam.xyz;
    63.  
    64.                 // adjust for tiling
    65.                 o.viewDir *= _RoomCube_ST.xyx;
    66.             #else
    67.                 // uvs
    68.                 o.uv = TRANSFORM_TEX(v.uv, _RoomCube);
    69.  
    70.                 // get tangent space camera vector
    71.                 float4 objCam = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0));
    72.                 float3 viewDir = v.vertex.xyz - objCam.xyz;
    73.                 float tangentSign = v.tangent.w * unity_WorldTransformParams.w;
    74.                 float3 bitangent = cross(v.normal.xyz, v.tangent.xyz) * tangentSign;
    75.                 o.viewDir = float3(
    76.                     dot(viewDir, v.tangent.xyz),
    77.                     dot(viewDir, bitangent),
    78.                     dot(viewDir, v.normal)
    79.                     );
    80.  
    81.                 // adjust for tiling
    82.                 o.viewDir *= _RoomCube_ST.xyx;
    83.             #endif
    84.                 return o;
    85.             }
    86.          
    87.             fixed4 frag (v2f i) : SV_Target
    88.             {
    89.             #ifdef _USEOBJECTSPACE
    90.                 // room uvws
    91.                 float3 roomUVW = frac(i.uvw);
    92.  
    93.                 // raytrace box from object view dir
    94.                 float3 pos = roomUVW * 2.0 - 1.0;
    95.                 float3 id = 1.0 / i.viewDir;
    96.                 float3 k = abs(id) - pos * id;
    97.                 float kMin = min(min(k.x, k.y), k.z);
    98.                 pos += kMin * i.viewDir;
    99.  
    100.                 // randomly flip & rotate cube map for some variety
    101.                 float3 flooredUV = floor(i.uvw);
    102.                 float3 r = rand3(flooredUV.x + flooredUV.y + flooredUV.z);
    103.                 float2 cubeflip = floor(r.xy * 2.0) * 2.0 - 1.0;
    104.                 pos.xz *= cubeflip;
    105.                 pos.xz = r.z > 0.5 ? pos.xz : pos.zx;
    106.             #else
    107.                 // room uvs
    108.                 float2 roomUV = frac(i.uv);
    109.  
    110.                 // raytrace box from tangent view dir
    111.                 float3 pos = float3(roomUV * 2.0 - 1.0, 1.0);
    112.                 float3 id = 1.0 / i.viewDir;
    113.                 float3 k = abs(id) - pos * id;
    114.                 float kMin = min(min(k.x, k.y), k.z);
    115.                 pos += kMin * i.viewDir;
    116.  
    117.                 // randomly flip & rotate cube map for some variety
    118.                 float2 flooredUV = floor(i.uv);
    119.                 float3 r = rand3(flooredUV.x + 1.0 + flooredUV.y * (flooredUV.x + 1));
    120.                 float2 cubeflip = floor(r.xy * 2.0) * 2.0 - 1.0;
    121.                 pos.xz *= cubeflip;
    122.                 pos.xz = r.z > 0.5 ? pos.xz : pos.zx;
    123.             #endif
    124.  
    125.                 // sample room cube map
    126.                 fixed4 room = texCUBE(_RoomCube, pos.xyz);
    127.                 return fixed4(room.rgb, 1.0);
    128.             }
    129.             ENDCG
    130.         }
    131.     }
    132. }
    133.  
    Test cubemap:
    colored_cube.png

    interiormapping-2dAtlas.jpg
    Started with something like the above cube map based interior mapping shader, but uses a single 2D texture atlas with variable room depth. Room depth is stored in the alpha channel of the atlas texture. For a cube shaped room the back wall should be 1/2 the size of the visible tile, and a value of 128 in the alpha channel. If you render these out you want to use a camera with a horizontal FOV of 53.13 degrees a room width back from the opening.

    Code (CSharp):
    1. Shader "Custom/InteriorMapping - 2D Atlas"
    2. {
    3.     Properties
    4.     {
    5.         _RoomTex ("Room Atlas RGB (A - back wall fraction)", 2D) = "white" {}
    6.         _Rooms ("Room Atlas Rows&Cols (XY)", Vector) = (1,1,0,0)
    7.     }
    8.     SubShader
    9.     {
    10.         Tags { "RenderType"="Opaque" }
    11.         LOD 100
    12.  
    13.         Pass
    14.         {
    15.             CGPROGRAM
    16.             #pragma vertex vert
    17.             #pragma fragment frag
    18.          
    19.             #include "UnityCG.cginc"
    20.  
    21.             struct appdata
    22.             {
    23.                 float4 vertex : POSITION;
    24.                 float2 uv : TEXCOORD0;
    25.                 float3 normal : NORMAL;
    26.                 float4 tangent : TANGENT;
    27.             };
    28.  
    29.             struct v2f
    30.             {
    31.                 float4 pos : SV_POSITION;
    32.                 float2 uv : TEXCOORD0;
    33.                 float3 tangentViewDir : TEXCOORD1;
    34.             };
    35.  
    36.             sampler2D _RoomTex;
    37.             float4 _RoomTex_ST;
    38.             float2 _Rooms;
    39.          
    40.             v2f vert (appdata v)
    41.             {
    42.                 v2f o;
    43.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    44.                 o.uv = TRANSFORM_TEX(v.uv, _RoomTex);
    45.  
    46.                 // get tangent space camera vector
    47.                 float4 objCam = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0));
    48.                 float3 viewDir = v.vertex.xyz - objCam.xyz;
    49.                 float tangentSign = v.tangent.w * unity_WorldTransformParams.w;
    50.                 float3 bitangent = cross(v.normal.xyz, v.tangent.xyz) * tangentSign;
    51.                 o.tangentViewDir = float3(
    52.                     dot(viewDir, v.tangent.xyz),
    53.                     dot(viewDir, bitangent),
    54.                     dot(viewDir, v.normal)
    55.                     );
    56.                 o.tangentViewDir *= _RoomTex_ST.xyx;
    57.                 return o;
    58.             }
    59.  
    60.             // psuedo random
    61.             float2 rand2(float co){
    62.                 return frac(sin(co * float2(12.9898,78.233)) * 43758.5453);
    63.             }
    64.          
    65.             fixed4 frag (v2f i) : SV_Target
    66.             {
    67.                 // room uvs
    68.                 float2 roomUV = frac(i.uv);
    69.                 float2 roomIndexUV = floor(i.uv);
    70.  
    71.                 // randomize the room
    72.                 float2 n = floor(rand2(roomIndexUV.x + roomIndexUV.y * (roomIndexUV.x + 1)) * _Rooms.xy);
    73.                 roomIndexUV += n;
    74.  
    75.                 // get room depth from room atlas alpha
    76.                 fixed farFrac = tex2D(_RoomTex, (roomIndexUV + 0.5) / _Rooms).a;
    77.                 float depthScale = 1.0 / (1.0 - farFrac) - 1.0;
    78.  
    79.                 // raytrace box from view dir
    80.                 float3 pos = float3(roomUV * 2 - 1, -1);
    81.                 // pos.xy *= 1.05;
    82.                 i.tangentViewDir.z *= -depthScale;
    83.                 float3 id = 1.0 / i.tangentViewDir;
    84.                 float3 k = abs(id) - pos * id;
    85.                 float kMin = min(min(k.x, k.y), k.z);
    86.                 pos += kMin * i.tangentViewDir;
    87.  
    88.                 // 0.0 - 1.0 room depth
    89.                 float interp = pos.z * 0.5 + 0.5;
    90.  
    91.                 // account for perspective in "room" textures
    92.                 // assumes camera with an fov of 53.13 degrees (atan(0.5))
    93.                 float realZ = saturate(interp) / depthScale + 1;
    94.                 interp = 1.0 - (1.0 / realZ);
    95.                 interp *= depthScale + 1.0;
    96.              
    97.                 // iterpolate from wall back to near wall
    98.                 float2 interiorUV = pos.xy * lerp(1.0, farFrac, interp);
    99.                 interiorUV = interiorUV * 0.5 + 0.5;
    100.  
    101.                 // sample room atlas texture
    102.                 fixed4 room = tex2D(_RoomTex, (roomIndexUV + interiorUV.xy) / _Rooms);
    103.                 return fixed4(room.rgb, 1.0);
    104.             }
    105.             ENDCG
    106.         }
    107.     }
    108. }
    109.  
    Single tile version for basic debugging. Note it looks faded out here because it's alpha value is 50%!
    interior_2d.png

    A 4x2 atlas with varying room lengths (1/2 room, cube, 2x length, 4x length) and lit / unlit variants. Again looks funny because of the alpha.
    interior_2d_Atlas.png

    Both of these could be made better in several ways, especially with better art.
     
    Last edited: Aug 14, 2016
  11. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,270
    Someone should add this into the wiki
     
  12. K0ndor

    K0ndor

    Joined:
    Mar 12, 2015
    Posts:
    8
    This is brilliant! Especially this "SimCity5 style". But how to apply fog?
     
  13. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    5,331
    Well, these shaders are just proof of concept to show off the technique so they're intentionally missing features like fog, exterior walls, and real lighting. Those are left as an exercise for the reader to add. If you want more features there are assets on the store or you can learn how to write shaders yourself.
     
    K0ndor likes this.
  14. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    5,076
  15. K0ndor

    K0ndor

    Joined:
    Mar 12, 2015
    Posts:
    8
    WHAAA, I DID IT.
    Sorry. Thank you AcidArrow. I was all like <insert picture "I have no idea what I'm doing - dog in front of computer">, copying and pasting and renaming and semanticizing and watching everything turn pink with my each attempt, but eventually everything jumped into it's place.

    I'm still missing exterior walls, but now I have hope that I MIGHT be able to add them. New year just started, and I already modified complicated shader, wows :p
     
    Alverik likes this.
  16. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    5,076
    Cool. Copy pasting stuff until they work is a good way to start learning about shaders :)
     
    K0ndor likes this.
  17. Alverik

    Alverik

    Joined:
    Apr 15, 2016
    Posts:
    377
    Hi, sorry to be a bother, but could we see the final code? I know very little about a shader coding, and I don't know how I'd add this extra stuff myself...

    By the way, you mentioned you copy pasted stuff? from where?...
     
  18. K0ndor

    K0ndor

    Joined:
    Mar 12, 2015
    Posts:
    8
    Everywhere. Forum topics, other shaders, my previous failed attempts, scraps of decrypted transmissions from Pleiades sector.
    Shader works and I'm using it for game I'm developing. I still see a way it might be improved, and I might get on it. But one thing is clear for me: I was a noob with shaders (still am), but nevertheless I was able to achieve something with sheer stubborness and a little bit of invention. Everything you need is here (internet). You just have to get on it. Call me names but I have no intention of making this completly effortless for you (or anybody that might want it by now).
     
  19. Alverik

    Alverik

    Joined:
    Apr 15, 2016
    Posts:
    377
    @K0ndor Call me names, but that wouldn't have been a helpful answer even more than a year ago, when I still hadn't dealt with the situation myself. If you are going to answer more than a year later at least give better advice, not just plain "do it yourself, I don't want to help". I answer enough noob programmers questions about c# myself, but I at least have the decency to provide some more advice or at least apologize for not being able to help.
     
  20. chin

    chin

    Joined:
    Feb 15, 2011
    Posts:
    7
  21. OP3NGL

    OP3NGL

    Joined:
    Dec 10, 2013
    Posts:
    226
    can someone convert "Emil Persson's Cube Map based interior mapping" shader into amplify/shaderforge/unity shader nodes?
     
  22. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,542