hdr.asm

src/5.advanced_lighting/6.hdr/hdr.asm · 199 lines

;---------------------------------------------------------------------------------------------------
; 6. HDR
;---------------------------------------------------------------------------------------------------
; A render target of 8-bit colour clamps everything to 0..1, so a light two hundred times brighter
; than another can only reach "white", and the detail around it is gone. Rendering into a 16-bit
; float target keeps the real values; a last pass then squeezes them into what the screen can show.
; That squeeze is tone mapping:
;
;   exposure   1 - exp(-color * exposure): like a camera's exposure, low values show the bright end
;              of the tunnel, high values the dark end
;
; The tunnel has one very bright white light at the far end and three dim coloured ones near the
; camera. Without tone mapping the far end is a flat white wall; with it the wood grain shows there
; too.
;
;   Tab         tone mapping on / off (off: values clamped at 1)
;   Up / Down   exposure
include rt.inc
include d3d11.inc
include macros.asm
include math.asm
include learn\window.asm
include learn\shader.asm
include learn\gpu.asm
include learn\cube.asm
include learn\camera.asm
include learn\transforms.asm
include learn\srgb.asm

;---------------------------------------------------------------------------------------------------
.data
;---------------------------------------------------------------------------------------------------
; Mirror `cbuffer lights` in lighting.hlsl and `cbuffer tone` in hdr.hlsl.
lights_constants struct
    positions vec4 4 dup(<>)
    colors vec4 4 dup(<>)
lights_constants ends

tone_constants struct
    exposure real4 ?
    enabled dword ?
    pad dword 2 dup(?)
tone_constants ends

align 4
camera_start vec3 <0.0, 0.0, 1.0>
tunnel_center vec3 <0.0, 0.0, -25.0>
tunnel_size vec3 <5.0, 5.0, 55.0>

align 16
t transforms <>
lights lights_constants <>
; lighting info: one bright light at the far end, three dim coloured ones near the camera
light_positions vec4 <0.0, 0.0, -49.5, 0.0>, <-1.4, -1.9, -9.0, 0.0>, <0.0, -1.8, -4.0, 0.0>, <0.8, -1.7, -6.0, 0.0>
light_colors vec4 <200.0, 200.0, 200.0, 0.0>, <0.1, 0.0, 0.0, 0.0>, <0.0, 0.0, 0.2, 0.0>, <0.0, 0.1, 0.0, 0.0>
tone tone_constants <1.0, 1>
tunnel mat4 <>
scratch mat4 <>
s shader <>
hdr_shader shader <>
cam camera <>
hdr_target render_target <>
align 8
hdr_depth qword 0
cube_vb qword 0
transforms_buffer qword 0
lights_buffer qword 0
tone_buffer qword 0
wood qword 0
sampler qword 0

; timing
delta_time real4 0.0
last_frame real4 0.0

;---------------------------------------------------------------------------------------------------
.code
;---------------------------------------------------------------------------------------------------
align 16
main proc
    invoke window_create, "LearnD3D11  (Tab: tone mapping on / off, Up / Down: exposure)"
    ; The back buffer is viewed as sRGB: what the shaders write is linear, and the view
    ; gamma-encodes it on the way in (5.2).
    call window_use_srgb

    invoke create_sampler, D3D11_FILTER_ANISOTROPIC, D3D11_TEXTURE_ADDRESS_WRAP
    mov sampler, rax
    vcall context, ID3D11DeviceContext_PSSetSamplers, 0, 1, ADDR sampler

    ; build and compile shaders
    ; -------------------------
    invoke shader_create, ADDR s, "src/5.advanced_lighting/6.hdr/lighting.hlsl", ADDR cube_layout, cube_layout_count
    invoke shader_create, ADDR hdr_shader, "src/5.advanced_lighting/6.hdr/hdr.hlsl", 0, 0

    ; set up vertex data and textures
    ; -------------------------------
    invoke create_buffer, D3D11_BIND_VERTEX_BUFFER, ADDR cube_vertices, cube_vertices_size
    mov cube_vb, rax
    invoke create_constant_buffer, sizeof transforms
    mov transforms_buffer, rax
    invoke create_constant_buffer, sizeof lights_constants
    mov lights_buffer, rax
    invoke create_constant_buffer, sizeof tone_constants
    mov tone_buffer, rax
    invoke filesystem_path, "resources/textures/wood.png"
    invoke load_texture, rax, 1
    mov wood, rax

    lea rcx, cam
    lea rdx, camera_start
    movf xmm2, -90.0
    movf xmm3, 0.0
    call camera_create

    ; configure floating point framebuffer
    ; ------------------------------------
    invoke create_render_target, ADDR hdr_target, scr_width, scr_height, DXGI_FORMAT_R16G16B16A16_FLOAT, 1
    invoke create_depth_buffer, scr_width, scr_height, 1
    mov hdr_depth, rax

    ; lighting info
    ; -------------
    invoke mem_copy, ADDR lights.positions, ADDR light_positions, 4 * sizeof vec4
    invoke mem_copy, ADDR lights.colors, ADDR light_colors, 4 * sizeof vec4
    invoke update_buffer, lights_buffer, ADDR lights, sizeof lights_constants

    ; the tunnel: a long box around the camera, seen from inside
    invoke m4_translate, ADDR tunnel, ADDR tunnel_center
    invoke m4_scale, ADDR scratch, ADDR tunnel_size
    invoke m4_mul, ADDR tunnel, ADDR tunnel, ADDR scratch

    render_loop:
        call window_poll
        test eax, eax
        jz render_loop_done

        call get_time
        movss xmm1, xmm0
        subss xmm0, last_frame
        movss delta_time, xmm0
        movss last_frame, xmm1

        invoke camera_process_input, ADDR cam, ADDR delta_time
        ; mode 0 tone maps, mode 1 shows the values clamped
        invoke window_mode, 2
        mov ecx, 1
        sub ecx, eax
        mov tone.enabled, ecx
        invoke key_down, VK_UP
        test eax, eax
        jz not_up
            movss xmm0, tone.exposure
            addss xmm0, delta_time
            movss tone.exposure, xmm0
        not_up:
        invoke key_down, VK_DOWN
        test eax, eax
        jz not_down
            movss xmm0, tone.exposure
            subss xmm0, delta_time
            movf xmm1, 0.01
            maxss xmm0, xmm1
            movss tone.exposure, xmm0
        not_down:

        ; 1. render scene into floating point framebuffer
        ; -----------------------------------------------
        call unbind_textures
        vcall context, ID3D11DeviceContext_OMSetRenderTargets, 1, ADDR hdr_target.rtv, hdr_depth
        vcall context, ID3D11DeviceContext_RSSetViewports, 1, ADDR viewport
        vcall context, ID3D11DeviceContext_ClearRenderTargetView, hdr_target.rtv, floats(0.0, 0.0, 0.0, 1.0)
        movf xmm3, 1.0                          ; the depth, a float: xmm3
        vcall context, ID3D11DeviceContext_ClearDepthStencilView, hdr_depth, D3D11_CLEAR_DEPTH, 0, 0
        vcall context, ID3D11DeviceContext_IASetPrimitiveTopology, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST
        invoke bind_constants, 0, transforms_buffer
        invoke transforms_from_camera, ADDR t, ADDR cam
        invoke shader_use, ADDR s
        invoke bind_constants, 1, lights_buffer
        invoke bind_texture, 0, wood
        invoke draw_vertices, transforms_buffer, ADDR t, cube_vb, 36, ADDR tunnel

        ; 2. render floating point colour buffer to the screen, tone mapped
        ; -----------------------------------------------------------------
        ; One triangle covering the screen, made by the vertex shader from SV_VertexID alone.
        vcall context, ID3D11DeviceContext_OMSetRenderTargets, 1, ADDR backbuffer_rtv, 0
        invoke update_buffer, tone_buffer, ADDR tone, sizeof tone_constants
        invoke shader_use, ADDR hdr_shader
        invoke bind_constants, 1, tone_buffer
        invoke bind_texture, 0, hdr_target.srv
        vcall context, ID3D11DeviceContext_Draw, 3, 0

        call window_present
        jmp render_loop
    render_loop_done:

    invoke ExitProcess, 0
main endp

end
Part of masm64-dx11, LearnOpenGL's lessons rewritten for Direct3D 11 in x64 assembly. Licensed CC BY-NC 4.0, after LearnOpenGL by Joey de Vries.