lighting.asm

src/6.pbr/1.1.lighting/lighting.asm · 224 lines

;---------------------------------------------------------------------------------------------------
; 1.1 PBR lighting
;---------------------------------------------------------------------------------------------------
; Physically based rendering replaces Phong's hand-tuned terms with a model of how light actually
; reflects off a rough surface: Cook-Torrance. A material is no longer "diffuse colour, specular
; colour, shininess" but:
;
;   albedo     the base colour
;   metallic   0 for dielectrics (plastic, wood), 1 for metals
;   roughness  0 a mirror, 1 completely matte
;   ao         how much ambient light reaches it, baked in
;
; Energy is conserved: whatever a surface reflects as specular it cannot also scatter as diffuse.
; The lights are given as radiance in real units, far above 1, so the result is tone mapped
; (Reinhard) and gamma encoded on the way out.
;
; The grid runs metallic 0 -> 1 from bottom to top, roughness 0 -> 1 from left to right. Tab swaps
; in a textured material, where every one of those numbers comes from a map per texel: rusted iron
; (LearnOpenGL's 1.2 lighting_textured). The normal map is read without stored tangents: the
; tangent frame is rebuilt per pixel from screen-space derivatives.
;
;   Tab   uniform grid / textured spheres
;
; The sphere, the material loader and the sRGB backbuffer view are in includes/learn/pbr.asm,
; which the rest of the chapter shares.
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\pbr.asm

;---------------------------------------------------------------------------------------------------
.data
;---------------------------------------------------------------------------------------------------
; Mirror `cbuffer material` and `cbuffer lights` in pbr.hlsl.
material_constants struct
    albedo vec3 <>
    metallic real4 ?
    roughness real4 ?
    ao real4 ?
    textured dword ?
    pad real4 ?
material_constants ends

lights_constants struct
    positions vec4 4 dup(<>)
    colors vec4 4 dup(<>)
lights_constants ends

align 4
camera_start vec3 <0.0, 0.0, 22.0>
; four lights at the corners of a square in front of the grid, far brighter than 1
light_start vec4 <-10.0, 10.0, 10.0, 0.0>, <10.0, 10.0, 10.0, 0.0>, <-10.0, -10.0, 10.0, 0.0>, <10.0, -10.0, 10.0, 0.0>
light_color vec4 <300.0, 300.0, 300.0, 0.0>

align 16
t transforms <>
lights lights_constants <>
material material_constants <<0.5, 0.0, 0.0>, 0.0, 0.0, 1.0, 0, 0.0>
model_matrix mat4 <>
sphere_position vec3 <>
s shader <>
cam camera <>
ball sphere <>
align 8
transforms_buffer qword 0
material_buffer qword 0
lights_buffer qword 0
sampler qword 0
rusted_iron qword 5 dup(0)

; timing
current_frame real4 0.0
delta_time real4 0.0
last_frame real4 0.0

;---------------------------------------------------------------------------------------------------
.code
;---------------------------------------------------------------------------------------------------
align 16
main proc
    USING rbx, rsi
    SaveRegs
    invoke window_create, "LearnD3D11  (Tab: uniform grid / textured)"
    call window_create_depth
    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/6.pbr/1.1.lighting/pbr.hlsl", ADDR cube_layout, cube_layout_count

    ; set up vertex data and textures
    ; -------------------------------
    invoke create_sphere, ADDR ball, 64
    invoke create_constant_buffer, sizeof transforms
    mov transforms_buffer, rax
    invoke create_constant_buffer, sizeof material_constants
    mov material_buffer, rax
    invoke create_constant_buffer, sizeof lights_constants
    mov lights_buffer, rax
    invoke load_material, "resources/textures/pbr/rusted_iron/", ADDR rusted_iron

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

    ; lights
    ; ------
    invoke mem_copy, ADDR lights.positions, ADDR light_start, 4 * sizeof vec4
    movups xmm0, xmmword ptr light_color
    movups xmmword ptr lights.colors[0], xmm0
    movups xmmword ptr lights.colors[16], xmm0
    movups xmmword ptr lights.colors[32], xmm0
    movups xmmword ptr lights.colors[48], xmm0

    render_loop:
        call window_poll
        test eax, eax
        jz render_loop_done

        ; per-frame time logic
        call get_time
        movss current_frame, xmm0
        movss xmm1, xmm0
        subss xmm0, last_frame
        movss delta_time, xmm0
        movss last_frame, xmm1

        ; input
        invoke camera_process_input, ADDR cam, ADDR delta_time
        invoke window_mode, 2
        mov material.textured, eax

        ; render
        invoke window_begin, floats(0.1, 0.1, 0.1, 1.0)
        vcall context, ID3D11DeviceContext_IASetPrimitiveTopology, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST
        invoke bind_constants, 0, transforms_buffer
        invoke transforms_from_camera, ADDR t, ADDR cam

        ; the lights wander a little, so the highlights move across the spheres:
        ; x = -10 or 10, + 5 sin(t)
        movss xmm0, current_frame
        call sinf
        movf xmm1, 5.0
        mulss xmm0, xmm1
        lea rax, lights.positions
        lea rdx, light_start
        xor ecx, ecx
        wander:
            movss xmm1, real4 ptr [rdx]
            addss xmm1, xmm0
            movss real4 ptr [rax], xmm1
            add rax, sizeof vec4
            add rdx, sizeof vec4
            inc ecx
            cmp ecx, 4
            jb wander
        invoke update_buffer, lights_buffer, ADDR lights, sizeof lights_constants
        invoke shader_use, ADDR s
        invoke bind_constants, 1, material_buffer
        invoke bind_constants, 2, lights_buffer
        vcall context, ID3D11DeviceContext_PSSetShaderResources, 0, 5, ADDR rusted_iron

        ; render rows*column number of spheres with varying metallic/roughness values:
        ; metallic from bottom to top, roughness from left to right
        xor ebx, ebx                            ; row
        grid_rows:
            xor esi, esi                        ; column
            grid_columns:
                cvtsi2ss xmm0, ebx
                movf xmm1, 6.0
                divss xmm0, xmm1
                movss material.metallic, xmm0
                ; perfectly smooth reflects one point of light, which looks wrong for a point
                ; light: start just above zero
                cvtsi2ss xmm0, esi
                movf xmm1, 6.0
                divss xmm0, xmm1
                movf xmm1, 0.05
                movss xmm2, math_one
                call clampf
                movss material.roughness, xmm0
                invoke update_buffer, material_buffer, ADDR material, sizeof material_constants
                ; at ((column - 3) * 2.5, (row - 3) * 2.5, 0)
                movf xmm1, 2.5
                lea eax, [esi - 3]
                cvtsi2ss xmm0, eax
                mulss xmm0, xmm1
                movss sphere_position.x, xmm0
                lea eax, [ebx - 3]
                cvtsi2ss xmm0, eax
                mulss xmm0, xmm1
                movss sphere_position.y, xmm0
                mov dword ptr sphere_position.z, 0
                invoke m4_translate, ADDR model_matrix, ADDR sphere_position
                invoke draw_sphere, transforms_buffer, ADDR t, ADDR ball, ADDR model_matrix
                inc esi
                cmp esi, 7
                jb grid_columns
            inc ebx
            cmp ebx, 7
            jb grid_rows

        call window_present
        jmp render_loop
    render_loop_done:

    RestoreRegs
    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.