hotline-rs 0.3.2

A high-performance, hot-reload graphics engine.
Documentation
//
// 2d texture with bindless lookup
//

float4 ps_texture2d(vs_output input) : SV_Target {
    float2 tc = input.texcoord.xy;
    float4 albedo = textures[draw_indices.x].Sample(sampler_wrap_linear, tc);
    albedo *= albedo.a;

    return albedo;
}

//
// cubemap with bindless lookup
// 

float4 ps_cubemap(vs_output input) : SV_Target {
    float4 col = cubemaps[draw_indices.x]
        .SampleLevel(sampler_wrap_linear, input.normal, draw_indices.y);

    col.a = 1.0;
    return col;
}

//
// texture 2d array with bindless lookup
//

float4 ps_texture2d_array(vs_output input) : SV_Target {
    float2 tc = float2(input.texcoord.x, input.texcoord.y);

    float4 col = texture_arrays[draw_indices.x]
        .Sample(sampler_wrap_linear, float3(tc, draw_indices.y));

    if(col.a < 0.2) {
        discard;
    }

    return col;
}

//
// texture 3d with bindless lookup and ray marching
//

vs_output vs_texture3d(vs_input_mesh input) {
    vs_output output;

    float3x4 wm = world_matrix;
    
    float4 pos = float4(input.position.xyz, 1.0);
    pos.xyz = mul(wm, pos);

    output.position = mul(view_projection_matrix, pos);
    output.world_pos = pos;
    output.texcoord = float4(input.position, 0.0);
    output.colour = float4(input.normal.xyz, 1.0);
    output.normal = input.normal.xyz;
    
    return output;
}


ps_output ps_volume_texture_ray_march_sdf(vs_output input) {
    ps_output output;

    float3 v = input.texcoord.xyz;
    float3 chebyshev_norm = chebyshev_normalize(v);
    float3 uvw = chebyshev_norm * 0.5 + 0.5;
    
    float max_samples = 64.0;

    float3x3 inv_rot;
    inv_rot[0] = world_matrix[0].xyz;
    inv_rot[1] = world_matrix[1].xyz;
    inv_rot[2] = world_matrix[2].xyz;
    inv_rot = transpose(inv_rot);

    float3 ray_dir = normalize(input.world_pos.xyz - view_position.xyz);
                    
    ray_dir = mul(inv_rot, ray_dir);
    ray_dir = normalize(ray_dir);
                    
    float3 vddx = ddx( uvw );
    float3 vddy = ddy( uvw );
    
    float3 scale = float3(
        length(world_matrix[0].xyz), 
        length(world_matrix[1].xyz), 
        length(world_matrix[2].xyz)
    ) * 2.0;
        
    float d = volume_textures[draw_indices.x].SampleGrad(sampler_wrap_linear, uvw, vddx, vddy).r;
    
    float3 col = float3( 0.0, 0.0, 0.0 );
    float3 ray_pos = input.world_pos.xyz;
    float taken = 0.0;
    float3 min_step = (scale / max_samples); 
    
    for( int s = 0; s < int(max_samples); ++s )
    {        
        taken += 1.0 / max_samples;
                
        d = volume_textures[draw_indices.x].SampleGrad(sampler_wrap_linear, uvw, vddx, vddy).r;
            
        float3 step = ray_dir.xyz * float3(d / scale) * 0.5;
        
        uvw += step;
 
        if(uvw.x >= 1.0 || uvw.x <= 0.0)
            discard;
        
        if(uvw.y >= 1.0 || uvw.y <= 0.0)
            discard;
        
        if(uvw.z >= 1.0 || uvw.z <= 0.0)
            discard;
            
        if( d <= 0.3 )
            break;
    }
    float vd = (1.0 - d);
    output.colour.rgb = float3(vd*vd,vd*vd, vd*vd);
    output.colour.rgb = float3(taken, taken, taken);
    output.colour.a = 1.0;

    return output;
}

ps_output ps_volume_texture_ray_march(vs_output input) {
    ps_output output;
    
    float depth = 1.0;
    float max_samples = 256.0;
        
    float3 v = input.texcoord.xyz;
    float3 chebyshev_norm = chebyshev_normalize(v);
    float3 uvw = chebyshev_norm * 0.5 + 0.5;
    
    float3x3 inv_rot;
    inv_rot[0] = world_matrix[0].xyz;
    inv_rot[1] = world_matrix[1].xyz;
    inv_rot[2] = world_matrix[2].xyz;
    inv_rot = transpose(inv_rot);
        
    float3 ray_dir = normalize(input.world_pos.xyz - view_position.xyz);    
    ray_dir = mul( inv_rot, ray_dir );
    
    float3 ray_step = chebyshev_normalize(ray_dir.xyz) / max_samples;
                
    float depth_step = 1.0 / max_samples;
    
    float3 vddx = ddx( uvw );
    float3 vddy = ddy( uvw );
    
    for(int s = 0; s < int(max_samples); ++s )
    {
        output.colour = 
            volume_textures[draw_indices.x].SampleGrad(sampler_wrap_linear, uvw, vddx, vddy);
        
        if(output.colour.a != 0.0)
            break;
        
        depth -= depth_step;
        uvw += ray_step;
        
        if(uvw.x > 1.0 || uvw.x < 0.0)
            discard;
            
        if(uvw.y > 1.0 || uvw.y < 0.0)
            discard;
            
        if(uvw.z > 1.0 || uvw.z < 0.0)
            discard;
        
        if(s == int(max_samples)-1)
            discard;
    }
    
    output.colour.rgb *= lerp( 0.5, 1.0, depth );
            
    return output;
}

//
// compute shader writes noise to a 3D texture
//

[numthreads(8, 8, 8)]
void cs_write_texture3d(uint3 did : SV_DispatchThreadID) {
    float3 dim = float3(64.0, 64.0, 64.0);
    float3 grid_pos = did.xyz * 2.0 - float3(64.0, 64.0, 64.0);

    float4 sphere;
    float d = 1.0;

    float nxz = voronoise(did.xz / 8.0, 1.0, 0.0);
    float nxy = voronoise(did.xy / 8.0, 1.0, 0.0);
    float nyz = voronoise(did.yz / 8.0, 1.0, 0.0);

    float3 n = normalize(grid_pos);

    float nn = 
        abs(dot(n, float3(0.0, 1.0, 0.0))) * nxz 
        + abs(dot(n, float3(0.0, 0.0, 1.0))) * nxy
        + abs(dot(n, float3(1.0, 0.0, 0.0))) * nyz;

    rw_volume_textures[resources.input0.index][did.xyz] = float4(nn, 0.0, 0.0, nn < 0.9 ? 0.0 : 1.0);
}

//
// reflection
//

float4 ps_cubemap_reflect(vs_output input) : SV_Target {
    // cubemap space z is inverted, so we must invert z of the ray and also the z of the normal
    float3 rd = normalize(input.world_pos.xyz - view_position.xyz) * float3(1.0, 1.0, -1.0);
    float3 n = normalize(input.normal.xyz * float3(1.0, 1.0, -1.0));
    float3 r = reflect(rd, n);

    float4 col = cubemaps[draw_indices.x].SampleLevel(sampler_wrap_linear, r, draw_indices.y);

    col.a = 1.0;
    return col;
}