Facebook icon
Twitter icon
LinkedIn icon

How to Make an Ice Shader in Ventuz with HLSL Node

A short tutorial how to create a realistic ice shader. The manual is dedicated to advanced Ventuz users

We would like to show you how to make an ice shader in Ventuz using HLSL node. When you look at a piece of ice, you can see that it is a little bit transparent, and the image seen through the object is quite distorted and bent. This effect is caused by the refraction of light at the interface between air and ice. The light rays change the direction of propagation of a wave, because the IOR (index of refraction) of these two mediums is different. The IOR of air is 1.00029 and IOR of ice is 1.31.

In a typical 3D software (such as 3DS Max, Cinema 4D, and Blender) we can easily simulate tracing the path of light and get a photorealistic shader of ice but these programs do not work in real time. So to make an ice shader that works in real time, we recommend using a normal map to fake distortion of the image behind the object. All we need are three textures: Diffuse Map (colour of the object) Normal Map (to simulate distortion on the surface) and Refraction Map (the image behind the object. You can use RenderTarget node to render everything on the scene that is behind the object and put it into the shader).

Here is the code for how to prepare samplers to get fields for importing these textures into the HLSL shader:


texture colorTex;

sampler colorTexture = sampler_state


Texture = ;



texture normalTex;

sampler normalTexture = sampler_state


Texture = ;



texture refractionText;

sampler refractionTexture = sampler_state


Texture = ;


The structure for VS_Input and VS_OUTPUT should be as shown below:

struct VS_Input{

float4 position : POSITION;

float2 tex : TEXCOORD0;

float3 Normal : NORMAL;


The PixelInputType structure has a new refractionPosition variable for the refraction vertex coordinates that will be passed into the pixel shader.

struct VS_OUTPUT


float4 position : SV_POSITION;

float2 tex : TEXCOORD0;

float4 refractionPosition : TEXCOORD1;

float3 Normal : TEXCOORD2;

float3 ViewVec : TEXCOORD3;

float3 Light : TEXCOORD4;


The most important part is the Pixel Shader Section. We need to modify the texture of the image that is behind the object. I used a refractionIndex to change texture coordinates in both axes.Then, after normalisation of the normal map, you can modify the refract texture coordinates using a prepared normal map and refractionScale multiplier if you would like to have more control of the refraction texture scale.

refractTexCoord.x = float(Input.refractionPosition.x/Input.refractionPosition.w/refractionIndex);

refractTexCoord.y = float(-Input.refractionPosition.y/Input.refractionPosition.w/refractionIndex);

normalMap = tex2D(normalTexture, Input.tex);

normal = ( * 2.0f) - 1.0f;

refractTexCoord = refractTexCoord + (normal.xy * refractionScale);

refractionColor = tex2D(refractionTexture, refractTexCoord);

textureColor = tex2D(colorTexture, Input.tex);

To achieve a more realistic shader we used the Fresnel effect, which we had made earlier:

float4 fresnel = Rzero + (1.0f-Rzero) * pow(1.0f-dot(Input.Normal, Input.ViewVec), fresnel_strenght);

And the final lines:

return lerp(refractionColor, textureColor, 1-fresnel) + SpecularColor;

Here is the whole code of this script: GitHub