Hi, I want to make a simple glass shader. I don’t need a light source, shading, specular, reflection… I need only refraction. An effect like in “predator” movie.
So I have a vertex shader with model normals (vNormal)… But what should I do in a fragment shader? How to make a refractive object in the fragment shader?
Thanks.
I found this one shader:
http://3dshaders.com/home/index.php?page=shop.product_details&flypage=shop.flypage&product_id=41&category_id=1&manufacturer_id=0&option=com_virtuemart&Itemid=34
But it refracts only a cubemap. But what about objects in a scene?
Oh, I think, I found one:
Vertex
[java]
//
// Vertex shader for environment mapping with an
// equirectangular 2D texture and refraction mapping
// with a background texture blended together using
// the fresnel terms
//
// Author: Jon Kennedy, based on the envmap shader by John Kessenich, Randi Rost
//
// Copyright © 2002-2006 3Dlabs Inc. Ltd.
//
// See 3Dlabs-License.txt for license information
//
varying vec3 Normal;
varying vec3 EyeDir;
varying vec4 EyePos;
varying float LightIntensity;
uniform vec3 LightPos;
void main(void)
{
gl_Position = ftransform();
Normal = normalize(gl_NormalMatrix * gl_Normal);
vec4 pos = gl_ModelViewMatrix * gl_Vertex;
EyeDir = pos.xyz;
EyePos = gl_ModelViewProjectionMatrix * gl_Vertex;
LightIntensity = max(dot(normalize(LightPos - EyeDir), Normal), 0.0);
}
[/java]
Fragment
[java]
//
// Fragment shader for environment mapping with an
// equirectangular 2D texture and refraction mapping
// with a background texture blended together using
// the fresnel terms
//
// Author: Jon Kennedy, based on the envmap shader by John Kessenich, Randi Rost
//
// Copyright © 2002-2006 3Dlabs Inc. Ltd.
//
// See 3Dlabs-License.txt for license information
//
const vec3 Xunitvec = vec3 (1.0, 0.0, 0.0);
const vec3 Yunitvec = vec3 (0.0, 1.0, 0.0);
uniform vec3 BaseColor;
uniform float Depth;
uniform float MixRatio;
// need to scale our framebuffer - it has a fixed width/height of 2048
uniform float FrameWidth;
uniform float FrameHeight;
uniform sampler2D EnvMap;
uniform sampler2D RefractionMap;
varying vec3 Normal;
varying vec3 EyeDir;
varying vec4 EyePos;
varying float LightIntensity;
void main (void)
{
// Compute reflection vector
vec3 reflectDir = reflect(EyeDir, Normal);
// Compute altitude and azimuth angles
vec2 index;
index.y = dot(normalize(reflectDir), Yunitvec);
reflectDir.y = 0.0;
index.x = dot(normalize(reflectDir), Xunitvec) * 0.5;
// Translate index values into proper range
if (reflectDir.z >= 0.0)
index = (index + 1.0) * 0.5;
else
{
index.t = (index.t + 1.0) * 0.5;
index.s = (-index.s) * 0.5 + 1.0;
}
// if reflectDir.z >= 0.0, s will go from 0.25 to 0.75
// if reflectDir.z < 0.0, s will go from 0.75 to 1.25, and
// that’s OK, because we’ve set the texture to wrap.
// Do a lookup into the environment map.
vec3 envColor = vec3 (texture2D(EnvMap, index));
// calc fresnels term. This allows a view dependant blend of reflection/refraction
float fresnel = abs(dot(normalize(EyeDir), Normal));
fresnel *= MixRatio;
fresnel = clamp(fresnel, 0.1, 0.9);
// calc refraction
vec3 refractionDir = normalize(EyeDir) - normalize(Normal);
// Scale the refraction so the z element is equal to depth
float depthVal = Depth / -refractionDir.z;
// perform the div by w
float recipW = 1.0 / EyePos.w;
vec2 eye = EyePos.xy * vec2(recipW);
// calc the refraction lookup
index.s = (eye.x + refractionDir.x * depthVal);
index.t = (eye.y + refractionDir.y * depthVal);
// scale and shift so we’re in the range 0-1
index.s = index.s / 2.0 + 0.5;
index.t = index.t / 2.0 + 0.5;
// as we’re looking at the framebuffer, we want it clamping at the edge of the rendered scene, not the edge of the texture,
// so we clamp before scaling to fit
float recip1k = 1.0 / 2048.0;
index.s = clamp(index.s, 0.0, 1.0 - recip1k);
index.t = clamp(index.t, 0.0, 1.0 - recip1k);
// scale the texture so we just see the rendered framebuffer
index.s = index.s * FrameWidth * recip1k;
index.t = index.t * FrameHeight * recip1k;
vec3 RefractionColor = vec3 (texture2D(RefractionMap, index));
// Add lighting to base color and mix
vec3 base = LightIntensity * BaseColor;
envColor = mix(envColor, RefractionColor, fresnel);
envColor = mix(envColor, base, 0.2);
gl_FragColor = vec4 (envColor, 1.0);
}
[/java]
I suggest taking a look at the simple water, maybee that helps not sure.
in jme for refraction we use an environment map.
The problem with dynamic object is that you have to recompute the map centered on the object on every frame (and the env map is a cube map so → 6 images to render).
You can do a processor that does that, but if you have several objects using this material, you’ll have to compute the cubeMap for each of them, which will result in a serious overhead.
A static map can do the trick though…
Another approach would be to use a post Filter. You render a first pass with the “cloaked” objects rendered as white and the other black (you can copy paste the BloomFilter code as it’s exactly doing this for glow).
On the second pass you mix this render with the rendered scene. For black pixels you use the rendered scene for white you use some fresnel distortion to compute refraction. (ya can grab fresnel code in the lighting material).
Thanks for replies!!!
I think a static cubemap will be best in my case (for refraction). Bu there is no refraction in the Lighting as I see. Only reflection is there. @nehon , where I can get refraction and how to change the amount of refraction? thanks!
Another task will be cubemap making within jme scene (for me). As in different places - different cubemap.
Something like: Refract = refract(I, N, RefractionCoefficent); ?
Inside of vertex shader.
yes fresnel term is used for both reflection and refraction.
The env map too.
IMO computing an envmap on each frame is a bit heavy for this effect… the post process way would be a lot faster.
Thanks for answering.
I’m not good in postProcessing yet. I will back to it later…
I think, distorted cubemap or distorted spherical map will be really cool for such effect for a while…
bohhh… there is no such thing as “not good in postProcessing”. You know your way around shaders and that’s the difficult part of post processing…you should give it a try really…
Once you said: “Hey, write your shaders by yourself”. And now I’m writing them.
I think I will listen to you again.
First steps to the glass shader:
http://dl.dropbox.com/u/26887202/123/ShaderBlow_glass.jpg
I’m pretty satisfied with the result. I also want to add:
- color multiplication (change a color of refraction)
- reflection.
The shader is in my repository: http://code.google.com/p/jme-glsl-shaders/
Looking really cool man. But will you please start using imgur.com? I’m tired of opening bloated imageshack pages
Really awesome! Wish I could write shaders like you. How long does it take? What’s the easiest way to start learning how to write shaders and how they works?(please dont link me to jME doc)
Wish there was a Hello Shader tutorial - showing how to write a simple shader and how to integrate them.
Thumbs up for you!
@erlend_sh , thanks for advise.
@iamcreasy , actually I’m not good in shaders as you think. I just know some basics of vertex and fragment shaders.
Basically I know:
Vertex shader - stores matrices(camera, world, normal, light), models vertices, uv coordinates, normals, tangents, binormals (for polygons).
Fragment shader - stores color of polygons (textures, simple colors).
JME Lighting and Unshaded shaders are very useful.
Just try to google: glsl shaders tutorials
Also here is a book with examples: Straight Talk Promo Code - More than 35 Deals | Zip2Save
And this page is vital: https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:jme3_shaders?s[]=shaders
Aslo, GLSL manual is very useful: http://www.opengl.org/documentation/glsl/
Hello Shader is Unshaded shader. It consists of:
Unshaded.vert - vertex shader
Unshaded.frag - fragment shader
Unshaded.j3md - material defenition
http://code.google.com/p/jmonkeyengine/source/browse/#svn%2Ftrunk%2Fengine%2Fsrc%2Fcore-data%2FCommon%2FMatDefs%2FMisc
I suggest making the glass material partly transparent.
@mifth after writing this 3 line, do I just have to write the following line to make it work?
[java]My_Object = new Material(assetManager, “assets/MatDefs/Misc/my_material.j3md”);[/java]
& is every-every shader is going to be this 3 file composition? or is it gonna vary depending on the shader?
another thing is, what’s the “assetsMaterials” folder for?
Thanks!
I think it will work.
But I use matrials instead of material defenitions. Just create a new material and use it.
Basically I have:
shader.vert – vertex shader
shader.frag – fragment shader
shader.j3md – material defenition
shader.j3m - material
Where did you find “assetsMaterials”?
‘Materials sub folder’ under ‘Assets folder’. What’s it for?