Interior Mapping

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.

Shader

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'


Shader "buildingshader" {
    Properties {
        _wallFrequencies ("Wall freq", Vector) = (1,1,1)
       
        _ceilingTexture  ("Ceiling texture", 2D) = "white" { TexGen EyeLinear }
        _floorTexture ("Floor texture", 2D) = "red" { TexGen EyeLinear }
        _wallXYTexture ("wallXY texture", 2D) = "black" { TexGen EyeLinear }
        _wallZYTexture ("wallZY texture", 2D) = "green" { TexGen EyeLinear }
        _noiseTexture( "Noise texture", 2D) = "green" { TexGen EyeLinear }
       
    }
    SubShader {
         Pass {
        
             CGPROGRAM
       
            #pragma target 3.0
            #pragma exclude_renderers xbox360
            #pragma vertex vert
            #pragma fragment frag
           
            #include "UnityCG.cginc"
           
            struct v2f {
           
                float4 pos:    SV_POSITION;
                float2 uv:TEXCOORD0;
                float3 positionCopy:TEXCOORD1;
                float4 lighting:TEXCOORD2;
            };

            float3 _wallFrequencies;
            float _lightThreshold;
           
            v2f vert (appdata_base v)
            {
                v2f o;
               
                o.pos = mul (UNITY_MATRIX_MVP, v.vertex) ;
                o.uv = v.texcoord /** float2(_uvMultiplier.xy)*/;

                o.positionCopy = mul(unity_ObjectToWorld, v.vertex); //float3(v.vertex.xyz);
                                           
                // Calculate lighting on the exterior of the building with a hard-coded directed light.
                float lightStrength = dot(v.normal, float3(0.5, 0.33166, 0.8));
                o.lighting = saturate(lightStrength) * float4(1, 1, 0.9, 1) * (1-_lightThreshold);
               
                // Add some ambient lighting.
                o.lighting += float4(0.3, 0.3, 0.4, 1);
               
                return o;
            }

           
            sampler2D _ceilingTexture;
            sampler2D _floorTexture;
            sampler2D _wallXYTexture;
            sampler2D _wallZYTexture;
            sampler2D _noiseTexture;
           
            half4 frag (v2f i) : COLOR
            {
                //position in object space
                float4 objPos = mul(unity_ObjectToWorld, float4(0,0,0,1));
                float3 mama = i.positionCopy - objPos.xyz;

                float3 direction = i.positionCopy - _WorldSpaceCameraPos;
       
                //multiply by 0.999 to prevent last wall from beeing displayed. Fix this?
                float3 corner = floor(i.positionCopy *_wallFrequencies * 0.999);
                float3 walls = corner + step(float3(0, 0, 0), direction);
                walls /= _wallFrequencies;
                corner /= _wallFrequencies;
               
                float3 rayFractions = (float3(walls.x, walls.y,walls.z) - _WorldSpaceCameraPos) / direction;
                float2 intersectionXY = (_WorldSpaceCameraPos + rayFractions.z * direction).xy;
                float2 intersectionXZ = (_WorldSpaceCameraPos + rayFractions.y * direction).xz;
                float2 intersectionZY = (_WorldSpaceCameraPos + rayFractions.x * direction).zy;
               
                float4 ceilingColour = tex2D(_ceilingTexture, intersectionXZ);
                float4 floorColour = tex2D(_floorTexture, intersectionXZ);
                float4 verticalColour = lerp(floorColour, ceilingColour, step(0, direction.y));
               
                //random texture on wall xy
                float zNoise = tex2D(_noiseTexture, float2(corner.z/64,0)).r;
                float yNoise = tex2D(_noiseTexture, float2(corner.y/64 + zNoise,0)).r;
                float noiseXY = tex2D(_noiseTexture, float2(corner.x/64 + yNoise,0)).r;
           
                noiseXY = floor(noiseXY * 4) / 4;
                float2 atlasIndexXY;
                atlasIndexXY[0] = floor(noiseXY * 2) / 2;
                atlasIndexXY[1] = (noiseXY - atlasIndexXY[0]) * 2;
               
                //put the intersection into room space, so that it comes within [0, 1]
                intersectionXY = (intersectionXY - corner.xy) * _wallFrequencies.xy;
               
                //use the texture coordinate to read from the correct texture in the atlas
                float4 wallXYColour = 0.8 * tex2D(_wallXYTexture, intersectionXY);
               
                //random texture on wall ZY
                float zNoise2 = tex2D(_noiseTexture, float2(corner.z/64,0)).g;
                float yNoise2 = tex2D(_noiseTexture, float2(corner.y/64 + zNoise2,0)).g;
                float noiseZY = tex2D(_noiseTexture, float2(corner.x/64 + yNoise2,0)).g;
                float2 atlasIndexZY;
                atlasIndexZY[0] = floor(noiseZY * 2) / 2;
                atlasIndexZY[1] = 0;//(noiseZY - atlasIndexZY[0]) * 2;
               
                //put the intersection into room space, so that it comes within [0, 1]
                intersectionZY = (intersectionZY - corner.zy) * _wallFrequencies.zy;
               
                //use the texture coordinate to read from the correct texture in the atlas
                float4 wallZYColour = 0.8 * tex2D(_wallZYTexture, intersectionZY);
       
                //decide wich wall is closest to camera
                float xVSz = step(rayFractions.x, rayFractions.z);
                float4 interiorColour = lerp(wallXYColour, wallZYColour, xVSz);
                float rayFraction_xVSz = lerp(rayFractions.z, rayFractions.x, xVSz);
               
                //calculate variation in the lighting per room
                float3 noises = float3(
                    tex2D(_noiseTexture, float2(corner.x, corner.y)/64).r,
                    tex2D(_noiseTexture, float2(corner.z, corner.x)/64).r,
                    tex2D(_noiseTexture, float2(corner.y, corner.z)/64).r
                );
               
                float lightVariation = step((noises.x + noises.y + noises.z)/3, _lightThreshold*0.6f)* 0.3 + noises.x;
               
                float xzVSy = step(rayFraction_xVSz, rayFractions.y);
                //floor/ceiling or walls
                interiorColour = lerp(verticalColour, interiorColour, xzVSy)* lightVariation;
               
                //blend colors
                float4 wallColour = /*diffuseColour * */i.lighting;
                float4 windowColour = /*cubeColour + */interiorColour;
               
                //return half4(i.positionCopy.xyz, 1);
                return interiorColour;
                //return lerp(wallColour, windowColour, diffuseColour.a);
               
            }

            ENDCG  
        }
    }
}

I remember having replied to another interior mapping thread a while ago. I’m not sure how useful this is for you, but I assume posting the link won’t hurt:

@Peter77 will check your thread again. Read through it before, but maybe I can get some more information by reading it again :wink:

@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).

Hey guys,

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

Shader Code

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'


Shader "buildingshader" {
    Properties {
        _wallFrequencies ("Wall freq", Vector) = (1,1,1)
       
        _ceilingTexture  ("Ceiling texture", 2D) = "white"
        _floorTexture ("Floor texture", 2D) = "red"
        _wallXYTexture ("wallXY texture", 2D) = "black"
        _wallZYTexture ("wallZY texture", 2D) = "green"
       
    }
    SubShader {
         Pass {
        
             CGPROGRAM
       
            #pragma target 3.0
            #pragma exclude_renderers xbox360
            #pragma vertex vert
            #pragma fragment frag
           
            #include "UnityCG.cginc"
           
            struct v2f {
           
                float4 pos:    SV_POSITION;
                float2 uv:TEXCOORD0;
                float3 positionCopy:TEXCOORD1;
                float4 lighting:TEXCOORD2;
            };

            float3 _wallFrequencies;
            float _lightThreshold;
           
            v2f vert (appdata_tan v)
            {
                v2f o;
               
                o.pos = mul (UNITY_MATRIX_MVP, v.vertex) ;
                o.uv = v.texcoord /** float2(_uvMultiplier.xy)*/;
               
                //o.positionCopy = mul(unity_ObjectToWorld, v.vertex);
                o.positionCopy = float3(v.vertex.xyz);
                                           
                // Calculate lighting on the exterior of the building with a hard-coded directed light.
                float lightStrength = dot(v.normal, float3(0.5, 0.33166, 0.8));
                o.lighting = saturate(lightStrength) * float4(1, 1, 0.9, 1) * (1-_lightThreshold);
               
                // Add some ambient lighting.
                o.lighting += float4(0.3, 0.3, 0.4, 1);
               
                return o;
            }

           
            sampler2D _ceilingTexture;
            sampler2D _floorTexture;
            sampler2D _wallXYTexture;
            sampler2D _wallZYTexture;
           
            half4 frag (v2f i) : COLOR
            {
                float3 camObjPos = mul(unity_WorldToObject, _WorldSpaceCameraPos);
                float3 direction = i.positionCopy - camObjPos;
       
                //multiply by 0.999 to prevent last wall from beeing displayed. Fix this?
                float3 corner = floor(i.positionCopy *_wallFrequencies * 0.999);
                float3 walls = corner + step(float3(0, 0, 0), direction);
                walls /= _wallFrequencies;
                corner /= _wallFrequencies;
               
                float3 rayFractions = (float3(walls.x, walls.y,walls.z) - camObjPos) / direction;
                float2 intersectionXY = (camObjPos + rayFractions.z * direction).xy;
                float2 intersectionXZ = (camObjPos + rayFractions.y * direction).xz;
                float2 intersectionZY = (camObjPos + rayFractions.x * direction).zy;
               
                float4 ceilingColour = tex2D(_ceilingTexture, intersectionXZ);
                float4 floorColour = tex2D(_floorTexture, intersectionXZ);
                float4 verticalColour = lerp(floorColour, ceilingColour, step(0, direction.y));
                           
                //put the intersection into room space, so that it comes within [0, 1]
                intersectionXY = (intersectionXY - corner.xy) * _wallFrequencies.xy;
               
                //use the texture coordinate to read from the correct texture in the atlas
                float4 wallXYColour = 0.8 * tex2D(_wallXYTexture, intersectionXY);
                               
                //put the intersection into room space, so that it comes within [0, 1]
                intersectionZY = (intersectionZY - corner.zy) * _wallFrequencies.zy;
               
                //use the texture coordinate to read from the correct texture in the atlas
                float4 wallZYColour = 0.8 * tex2D(_wallZYTexture, intersectionZY);
       
                //decide wich wall is closest to camera
                float xVSz = step(rayFractions.x, rayFractions.z);
                float4 interiorColour = lerp(wallXYColour, wallZYColour, xVSz);
                float rayFraction_xVSz = lerp(rayFractions.z, rayFractions.x, xVSz);
               
                float xzVSy = step(rayFraction_xVSz, rayFractions.y);
                //floor/ceiling or walls
                interiorColour = lerp(verticalColour, interiorColour, xzVSy);
               
                //blend colors
                float4 wallColour = /*diffuseColour * */i.lighting;
                float4 windowColour = /*cubeColour + */interiorColour;
               
                return interiorColour* i.lighting;
            }

            ENDCG  
        }
    }
}

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.

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.

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.

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 :wink:

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.

1 Like

Really great stuff. I think I might have to start learning more shader specific stuff :slight_smile:

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 :wink:
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”?) :eyes:

Emil Persson’s Cube Map based interior mapping

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.

// Adapted to Unity from http://www.humus.name/index.php?page=3D&ID=80
Shader "Custom/InteriorMapping - Cubemap"
{
    Properties
    {
        _RoomCube ("Room Cube Map", Cube) = "white" {}
        [Toggle(_USEOBJECTSPACE)] _UseObjectSpace ("Use Object Space", Float) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #pragma shader_feature _USEOBJECTSPACE
         
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
                float4 tangent : TANGENT;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
            #ifdef _USEOBJECTSPACE
                float3 uvw : TEXCOORD0;
            #else
                float2 uv : TEXCOORD0;
            #endif
                float3 viewDir : TEXCOORD1;
            };

            samplerCUBE _RoomCube;
            float4 _RoomCube_ST;

            // psuedo random
            float3 rand3(float co){
                return frac(sin(co * float3(12.9898,78.233,43.2316)) * 43758.5453);
            }
         
            v2f vert (appdata v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

            #ifdef _USEOBJECTSPACE
                // slight scaling adjustment to work around "noisy wall" when frac() returns a 0 on surface
                o.uvw = v.vertex * _RoomCube_ST.xyx * 0.999 + _RoomCube_ST.zwz;

                // get object space camera vector
                float4 objCam = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0));
                o.viewDir = v.vertex.xyz - objCam.xyz;

                // adjust for tiling
                o.viewDir *= _RoomCube_ST.xyx;
            #else
                // uvs
                o.uv = TRANSFORM_TEX(v.uv, _RoomCube);

                // get tangent space camera vector
                float4 objCam = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0));
                float3 viewDir = v.vertex.xyz - objCam.xyz;
                float tangentSign = v.tangent.w * unity_WorldTransformParams.w;
                float3 bitangent = cross(v.normal.xyz, v.tangent.xyz) * tangentSign;
                o.viewDir = float3(
                    dot(viewDir, v.tangent.xyz),
                    dot(viewDir, bitangent),
                    dot(viewDir, v.normal)
                    );

                // adjust for tiling
                o.viewDir *= _RoomCube_ST.xyx;
            #endif
                return o;
            }
         
            fixed4 frag (v2f i) : SV_Target
            {
            #ifdef _USEOBJECTSPACE
                // room uvws
                float3 roomUVW = frac(i.uvw);

                // raytrace box from object view dir
                float3 pos = roomUVW * 2.0 - 1.0;
                float3 id = 1.0 / i.viewDir;
                float3 k = abs(id) - pos * id;
                float kMin = min(min(k.x, k.y), k.z);
                pos += kMin * i.viewDir;

                // randomly flip & rotate cube map for some variety
                float3 flooredUV = floor(i.uvw);
                float3 r = rand3(flooredUV.x + flooredUV.y + flooredUV.z);
                float2 cubeflip = floor(r.xy * 2.0) * 2.0 - 1.0;
                pos.xz *= cubeflip;
                pos.xz = r.z > 0.5 ? pos.xz : pos.zx;
            #else
                // room uvs
                float2 roomUV = frac(i.uv);

                // raytrace box from tangent view dir
                float3 pos = float3(roomUV * 2.0 - 1.0, 1.0);
                float3 id = 1.0 / i.viewDir;
                float3 k = abs(id) - pos * id;
                float kMin = min(min(k.x, k.y), k.z);
                pos += kMin * i.viewDir;

                // randomly flip & rotate cube map for some variety
                float2 flooredUV = floor(i.uv);
                float3 r = rand3(flooredUV.x + 1.0 + flooredUV.y * (flooredUV.x + 1));
                float2 cubeflip = floor(r.xy * 2.0) * 2.0 - 1.0;
                pos.xz *= cubeflip;
                pos.xz = r.z > 0.5 ? pos.xz : pos.zx;
            #endif

                // sample room cube map
                fixed4 room = texCUBE(_RoomCube, pos.xyz);
                return fixed4(room.rgb, 1.0);
            }
            ENDCG
        }
    }
}

Test cubemap:
2751518--198473--colored_cube.png

2751518--198479--interiormapping-2dAtlas.jpg
Andrew Willmott’s SimCity 5 style texture atlas interior mapping

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.

Shader "Custom/InteriorMapping - 2D Atlas"
{
    Properties
    {
        _RoomTex ("Room Atlas RGB (A - back wall fraction)", 2D) = "white" {}
        _Rooms ("Room Atlas Rows&Cols (XY)", Vector) = (1,1,0,0)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
         
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
                float4 tangent : TANGENT;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 tangentViewDir : TEXCOORD1;
            };

            sampler2D _RoomTex;
            float4 _RoomTex_ST;
            float2 _Rooms;
         
            v2f vert (appdata v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _RoomTex);

                // get tangent space camera vector
                float4 objCam = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0));
                float3 viewDir = v.vertex.xyz - objCam.xyz;
                float tangentSign = v.tangent.w * unity_WorldTransformParams.w;
                float3 bitangent = cross(v.normal.xyz, v.tangent.xyz) * tangentSign;
                o.tangentViewDir = float3(
                    dot(viewDir, v.tangent.xyz),
                    dot(viewDir, bitangent),
                    dot(viewDir, v.normal)
                    );
                o.tangentViewDir *= _RoomTex_ST.xyx;
                return o;
            }

            // psuedo random
            float2 rand2(float co){
                return frac(sin(co * float2(12.9898,78.233)) * 43758.5453);
            }
         
            fixed4 frag (v2f i) : SV_Target
            {
                // room uvs
                float2 roomUV = frac(i.uv);
                float2 roomIndexUV = floor(i.uv);

                // randomize the room
                float2 n = floor(rand2(roomIndexUV.x + roomIndexUV.y * (roomIndexUV.x + 1)) * _Rooms.xy);
                roomIndexUV += n;

                // get room depth from room atlas alpha
                fixed farFrac = tex2D(_RoomTex, (roomIndexUV + 0.5) / _Rooms).a;
                float depthScale = 1.0 / (1.0 - farFrac) - 1.0;

                // raytrace box from view dir
                float3 pos = float3(roomUV * 2 - 1, -1);
                // pos.xy *= 1.05;
                i.tangentViewDir.z *= -depthScale;
                float3 id = 1.0 / i.tangentViewDir;
                float3 k = abs(id) - pos * id;
                float kMin = min(min(k.x, k.y), k.z);
                pos += kMin * i.tangentViewDir;

                // 0.0 - 1.0 room depth
                float interp = pos.z * 0.5 + 0.5;

                // account for perspective in "room" textures
                // assumes camera with an fov of 53.13 degrees (atan(0.5))
                float realZ = saturate(interp) / depthScale + 1;
                interp = 1.0 - (1.0 / realZ);
                interp *= depthScale + 1.0;
             
                // iterpolate from wall back to near wall
                float2 interiorUV = pos.xy * lerp(1.0, farFrac, interp);
                interiorUV = interiorUV * 0.5 + 0.5;

                // sample room atlas texture
                fixed4 room = tex2D(_RoomTex, (roomIndexUV + interiorUV.xy) / _Rooms);
                return fixed4(room.rgb, 1.0);
            }
            ENDCG
        }
    }
}

Single tile version for basic debugging. Note it looks faded out here because it’s alpha value is 50%!
2751518--198476--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.
2751518--198477--interior_2d_Atlas.png

Both of these could be made better in several ways, especially with better art.

15 Likes

Someone should add this into the wiki

This is brilliant! Especially this “SimCity5 style”. But how to apply fog?

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.

1 Like

Fog is kinda trivial to add.

Look here: shaders : what is the use of UNITY_FOG_COORDS, UNITY_TRANSFER_FOG, UNITY_APPLY_FOG - Questions & Answers - Unity Discussions

1 Like

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 :stuck_out_tongue:

1 Like

Cool. Copy pasting stuff until they work is a good way to start learning about shaders :slight_smile:

1 Like

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?..

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).

@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.

4 Likes

Saw this on asset store Fake Interiors FREE | VFX Shaders | Unity Asset Store

2 Likes