- Home /
How to make a portal effect texture?
I have seen games that has --> this <-- type of effect. I like how it parallaxes as the player moves as it creates this large space within a small space. *cough *TARDIS *cough So does anyone know what this effect is called and how do you create this effect?
Answer by Eno-Khaon · Jan 13, 2016 at 11:42 PM
Well, the effect in your picture (I honestly haven't actually seen it in motion, but I'm 90% sure I know what the effect is) can be reproduced in a multitude of ways... all of which require shader support.
So, I'll go over a general two ways in which that can be reproduced:
1) The area "beyond the portal" as it were, is presented as a Cubemap. The coordinate of the Cubemap read to be displayed on-screen would be determined by the camera direction to the pixel multiplied by an additional depth scalar (a float added to the shader). This would make the effect appear to be under the surface of the plane at any effective distance. An example of a cubemap reflection can be found here, but in this case, this would be a change from texCUBE(_Cube, IN.worldRefl).rgb
to an effective texCUBE(_Cube, normalize(IN.viewDir) * scale).rgb
.
2) Use two objects. The first object is the "portal" to display the "image" of the plane beneath it. It actually doesn't need to render anything. All it needs to do is have its position in the Rendering Queue changed. The second object is the "image" through the portal. It's simply a plane placed underneath, where its shader comes in the Rendering Queue after regular objects, but before the "portal". Then, set the "ZTest" on this shader to "Greater" (default is LEqual, or less than or equal).
Either of these can be modified by utilizing RenderTextures instead of preset images, but RenderTextures, cubes especially, are fairly computationally expensive to use.
So on the first option, I can create a cubemap, apply to the modified shader, make a material with the shader, paste onto a plane, and it will guaranteed me an awesome effect? I'll be testing this after I post.
How do I initialize "scale"? I don't write shader scripts often.
To just borrow the Cubemap Reflection surface shader example:
Shader "Custom/Portal" {
Properties {
_$$anonymous$$ainTex ("Texture", 2D) = "white" {}
_Cube ("Cubemap", CUBE) = "" {}
_Scale ("Cubemap Depth Scale", float) = 1.0
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRA$$anonymous$$
#pragma surface surf Lambert
struct Input {
float2 uv_$$anonymous$$ainTex;
float3 viewDir;
};
sampler2D _$$anonymous$$ainTex;
samplerCUBE _Cube;
float _Scale;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_$$anonymous$$ainTex, IN.uv_$$anonymous$$ainTex).rgb * 0.5;
o.Emission = texCUBE (_Cube, IN.viewDir * _Scale).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
Adding _Scale to the properties at the top and in the middle where it's declared as a "float" value are all that are needed to add customizable variables to shaders.
This Worked great when the camera is moving around. I am building it for a vr app and am trying to make my buttons look like a parallaxing image when your view moves and am wondering how to manipulate this to accomplish that
$$anonymous$$y goodness it works. Now what I need to do next is to add content inside the portal. I have read up that it is one texture recolored, layered a couple of times (which gives the parallax effect), rotated and moves forward very slowly. Although the scale seems to have no effect. How is that suppose to work?
Oh, wow. $$anonymous$$y head wasn't on straight when I was trying to think of that one. I had an idea and really didn't think it through before posting it.
Okay, well, its usage can still be implemented...
So with a few changes..,
Shader "Custom/Portal" {
Properties {
_$$anonymous$$ainTex ("Texture", 2D) = "white" {}
_Cube ("Cubemap", CUBE) = "" {}
_Scale ("Cubemap Depth Scale", float) = 1.0
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRA$$anonymous$$
#pragma surface surf Lambert
struct Input {
float2 uv_$$anonymous$$ainTex;
float3 viewDir;
float3 worldNormal;
};
sampler2D _$$anonymous$$ainTex;
samplerCUBE _Cube;
float _Scale;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_$$anonymous$$ainTex, IN.uv_$$anonymous$$ainTex).rgb * 0.5;
float3 cubeDirection = lerp(-IN.worldNormal, IN.viewDir, _Scale);
o.Emission = texCUBE (_Cube, cubeDirection).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
Okay, so what I did was take the cubemap coordinates and give them a range by interpolating between straight up/down and the direction the camera's looking: If you're looking at a flat plane, a scale value of 0 will appear to be one solid color. A scale of 1 will be what you currently see. Therefore, increasing the scale will appear to increase the depth of the image (for real, this time).
I completely forgot to think that one through the first time around...
You know what, it works. Though I noticed that "cubeDirection" is suppose to be a "float3" var. I like the warped star effect when the scale is set to 0.5 (I think IN.worldNormal is suppose to be positive).
Hey I appreciate the help you have given. Shaders really are a neat thing to play around.
Answer by thesleeve · Jan 14, 2016 at 10:38 AM
Do some research on non-Euclidian geometry. I know it's possible in Unity, but I have no idea how to do it. Here's an example in Unity that I found doing a quick search. http://puu.sh/bqHLQ/3671e5dcc7.gif
Your answer
Follow this Question
Related Questions
Using shaders for text effects (TextMesh) 0 Answers
Trying to achieve this color effect 0 Answers
Image Effects on MovieTexture 0 Answers
Muzzle Flash 1 Answer
Procedural or Animated Textur in AirAttack Zeppelin Wreck (IphoneGame)? 1 Answer