From b9cfcde9c7f25ebd2f69ba270da6cc8b575fb239 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Wed, 28 Jan 2026 22:36:12 -0600 Subject: [PATCH] collada_scene: implement directional lighting --- .../curve_interpolation.max | Bin 299008 -> 335872 bytes src/collada_scene.cpp | 106 ++++++++++++++++-- src/effect/collada_scene.fx | 27 ++++- src/main.cpp | 5 +- .../curve_interpolation.cpp | 2 +- 5 files changed, 122 insertions(+), 18 deletions(-) diff --git a/scenes/curve_interpolation/curve_interpolation.max b/scenes/curve_interpolation/curve_interpolation.max index f660dd7b95bc5d204f01cb606ce281aa0a1dff12..1a8671c52e59d1751a2f30515b7f6830e2c49cb6 100755 GIT binary patch literal 335872 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 OYrw4mw+8-Z8u%ai%jC@f delta 3129 zcmcgudr(wW7(Xv|7X^0N0Lh9LSr)_B;wnM}yJDr-L&|0}%iQgOm7+sMgAuwYT9K>Z z8XpdBA`Of~8aR}<$w1PyoUF_qQxg@I&QxP&H8y2U_MLn2?lp)0YC3Zs-{bc^?m6E% zyTSgXV5_}5&PMaX@wWGq{yKmDyd2jOLJDw5I()|FjKTH%%$~x;0|||O=O)L}7*d*A z73!&Qm?_)r?Rg@7C8c+Ve;@OQDId+UCx*{uoHJdAq#VKdU@GB_zx@dgZf1e01_`qf_ zoiQ_kWMXzB$S9mCSq(Fs+&Oxa%$W4!@FkGTap9@K5EIUXN)REo=|;WOT&!;`h8;^-8k;o(=6HCT)q(i2y1!W1pT)Ca*<3aP z-oA$0=t$VTfnQDIv?X3H$*H4tyethm6qyjEaV)Q)GzqNP{5$i}OpDZlc^vo97$_LW zXPZmOa`F&armP>we`cJJRH&WEf1*S#L+5pD68DKuttI>9VOH|b@Z@f*VaZ^f!~=Z5 zTB37B+KH9r@NXD3!R#r#gj$r%Q+VE8)CTWviCEOKxp5Rb zWd3tVIax*?Qj**GQghhG5|rAV{3K^}LV2*8?_}%~3MoCjKHl@nsRB2X+k9+cp|Y!o z7f@I*L5!svlr4Ix`;}yZZHCEp5tO1p-WX zm42Bno=Iu)3pe{{9ZdF%ZDM?URR})zi_BHI(iKU=A*&~cOp`2`iR08-LgZtE2Z!|< zBzLN7ELQ&MVkF7e`aHwxAV*Mgr}if3D^{8+(JWJ?5ecGK`$%md3o8QRH)U|K$fv{2 z&=3$Cl*`J*)L|i-sRZ6{YG_}A9TL9~Y4F~lFhT86@rYD?3Jo8MV(2<7oD!c%Vf;J7 zDK!(IXdh}&ctV$Xp=FI|m)hfywp#Q{>Q?EYO81aYrO+jXyCrp#<_4)*mtbUoXqFZg z`CsxEK4r_Q{m*r1{aE{+e-K7i(_T93=0-wy)w{h*mm6taxPO%zUN?v;E~ND@5~J0j zNE;%J5~PnDJmigdyAO0v8n&$(R`dTTIEI1RfLNIN@JrjPo>{lNt+~d~kX1fdEM}>t zlac(u-WL%zZ}5-?L-y{EdZqatvgmqY>OqkuODi`{1E3Z$Q4g+Br_`oJ&@ie18kB6P;1eOo1+)HJ#AoM0PS6!E<>I*^Bd+Pi@O~SHkzYQW225rR7VUfN|`!plcsxTH0?wA*X&c(KLRc+mJfTB{D=Vw2stN{!hzUKb?q#~}qt+g2ZZh^@)uVE^-CE}8`%nA!NXypd=d|7y zX&FLzv=7FN>g^rdx3zBFf<3aO3F#q3zJ3uFsxPa|K4gEf!$}bf^(Td0QgLwm36X2B zUArQ@>p|>wp~qW#1M4HpWg+5k&INF?23~wZtklj<&R0@p<+ozBxyQzWbk7+vpXvXh T7X2(jiAL^sp`5bBB#rtTq6k>e diff --git a/src/collada_scene.cpp b/src/collada_scene.cpp index 41f5821..9297b8a 100644 --- a/src/collada_scene.cpp +++ b/src/collada_scene.cpp @@ -9,6 +9,7 @@ #include "new.hpp" extern ID3D10Device * g_pd3dDevice; +extern XMVECTOR g_Eye; extern XMMATRIX g_View; extern XMMATRIX g_Projection; @@ -22,6 +23,11 @@ namespace collada_scene { ID3D10EffectMatrixVariable * g_pViewVariable = NULL; ID3D10EffectMatrixVariable * g_pProjectionVariable = NULL; + ID3D10EffectVectorVariable * g_pViewEyeVariable = NULL; + ID3D10EffectVectorVariable * g_pLightPosVariable = NULL; + ID3D10EffectVectorVariable * g_pLightDirVariable = NULL; + ID3D10EffectVectorVariable * g_pLightColorVariable = NULL; + ID3D10EffectVectorVariable * g_pEmissionVariable = NULL; ID3D10EffectVectorVariable * g_pAmbientVariable = NULL; ID3D10EffectVectorVariable * g_pDiffuseVariable = NULL; @@ -67,8 +73,52 @@ namespace collada_scene { return S_OK; } + void scene_state::update_light_instance_vectors(light const& light, + node_instance const& node_instance, + int light_index) + { + const XMVECTOR position = XMVectorSet(0, 0, 0, 1); + const XMVECTOR direction = XMVectorSet(0, 0, -1, 0); + XMVECTOR light_position = XMVector3Transform(position, node_instance.world); + XMVECTOR light_direction = XMVector3TransformNormal(direction, node_instance.world); + XMVECTOR light_color = XMLoadFloat3((XMFLOAT3 *)&light.color); + + XMStoreFloat4(&m_lightPositions[light_index], light_position); + XMStoreFloat4(&m_lightDirections[light_index], light_direction); + XMStoreFloat4(&m_lightColors[light_index], light_color); + } + + void scene_state::update_light_instances() + { + int light_index = 0; + for (int i = 0; i < m_descriptor->nodes_count; i++) { + node const& node = *m_descriptor->nodes[i]; + node_instance const& node_instance = m_nodeInstances[i]; + for (int j = 0; j < node.instance_lights_count; j++) { + light const& light = *node.instance_lights[j].light; + update_light_instance_vectors(light, node_instance, light_index); + light_index += 1; + } + } + } + + void scene_state::allocate_light_instances() + { + // count light instances + int count = 0; + for (int i = 0; i < m_descriptor->nodes_count; i++) { + count += m_descriptor->nodes[i]->instance_lights_count; + } + + // allocate + m_lightInstancesCount = count; + m_lightPositions = New(m_lightInstancesCount); + m_lightDirections = New(m_lightInstancesCount); + m_lightColors = New(m_lightInstancesCount); + } + static void initialize_node_transforms(node const * const node, - node_instance * node_instance) + node_instance * const node_instance) { for (int i = 0; i < node->transforms_count; i++) { transform& transform = node_instance->transforms[i]; @@ -98,7 +148,7 @@ namespace collada_scene { } void scene_state::allocate_node_instance(node const * const node, - node_instance * node_instance) + node_instance * const node_instance) { node_instance->transforms = New(node->transforms_count); initialize_node_transforms(node, node_instance); @@ -133,6 +183,7 @@ namespace collada_scene { return E_FAIL; allocate_node_instances(); + allocate_light_instances(); return S_OK; } @@ -143,6 +194,7 @@ namespace collada_scene { D3D10_INPUT_ELEMENT_DESC layout[inputs.elements_count]; + assert(inputs.elements_count == 3); int byte_offset = 0; for (int i = 0; i < inputs.elements_count; i++) { layout[i].SemanticName = inputs.elements[i].semantic; @@ -200,6 +252,11 @@ namespace collada_scene { g_pViewVariable = g_pEffect->GetVariableByName("View")->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName("Projection")->AsMatrix(); + g_pViewEyeVariable = g_pEffect->GetVariableByName("ViewEye")->AsVector(); + g_pLightPosVariable = g_pEffect->GetVariableByName("LightPos")->AsVector(); + g_pLightDirVariable = g_pEffect->GetVariableByName("LightDir")->AsVector(); + g_pLightColorVariable = g_pEffect->GetVariableByName("LightColor")->AsVector(); + g_pEmissionVariable = g_pEffect->GetVariableByName("Emission")->AsVector(); g_pAmbientVariable = g_pEffect->GetVariableByName("Ambient")->AsVector(); g_pDiffuseVariable = g_pEffect->GetVariableByName("Diffuse")->AsVector(); @@ -559,28 +616,59 @@ namespace collada_scene { } } - void scene_state::render(float t) + void scene_state::update(float t) { - g_pViewVariable->SetMatrix((float *)&g_View); - g_pProjectionVariable->SetMatrix((float *)&g_Projection); - - g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - t = loop(t / 2.0f, 3.333333f); + // animate and update all world transforms for (int i = 0; i < m_descriptor->nodes_count; i++) { node const& node = *m_descriptor->nodes[i]; node_instance& node_instance = m_nodeInstances[i]; animate_node(node, node_instance, t); node_world_transform(node, node_instance); + } - g_pWorldVariable->SetMatrix((float *)&node_instance.world); + // update all lights (after world transforms are computed) + update_light_instances(); + } + + static int min(int a, int b) + { + return a < b ? a : b; + } + + void scene_state::render() + { + XMFLOAT4 eye; + XMFLOAT4X4 projection; + XMFLOAT4X4 view; + XMStoreFloat4(&eye, g_Eye); + XMStoreFloat4x4(&view, g_View); + XMStoreFloat4x4(&projection, g_Projection); + + g_pViewVariable->SetMatrix((float *)&view); + g_pProjectionVariable->SetMatrix((float *)&projection); + + g_pViewEyeVariable->SetFloatVector((float *)&eye); + + int lights = min(2, m_lightInstancesCount); + g_pLightPosVariable->SetFloatVectorArray((float *)m_lightPositions, 0, lights); + g_pLightDirVariable->SetFloatVectorArray((float *)m_lightDirections, 0, lights); + g_pLightColorVariable->SetFloatVectorArray((float *)m_lightColors, 0, lights); + + g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + for (int i = 0; i < m_descriptor->nodes_count; i++) { + node const& node = *m_descriptor->nodes[i]; + node_instance& node_instance = m_nodeInstances[i]; // joints aren't rendered if (node.type != node_type::NODE) continue; + g_pWorldVariable->SetMatrix((float *)&node_instance.world); + render_geometries(node.instance_geometries, node.instance_geometries_count); } } diff --git a/src/effect/collada_scene.fx b/src/effect/collada_scene.fx index c683dde..0c593b5 100644 --- a/src/effect/collada_scene.fx +++ b/src/effect/collada_scene.fx @@ -2,6 +2,12 @@ cbuffer cbEveryFrame { matrix View; matrix Projection; + + float4 ViewEye; + + float4 LightPos[2]; + float4 LightDir[2]; + float4 LightColor[2]; }; cbuffer cbMultiplePerFrame @@ -30,30 +36,39 @@ struct PS_INPUT float4 Pos : SV_POSITION; float3 Norm : NORMAL; float2 Tex : TEXCOORD0; + float4 WPos : POSITION; }; PS_INPUT VS(VS_INPUT input) { PS_INPUT output; - output.Pos = mul(float4(input.Pos, 1), World); - output.Pos = mul(output.Pos, View); + float4 world_pos = mul(float4(input.Pos, 1), World); + output.Pos = mul(world_pos, View); output.Pos = mul(output.Pos, Projection); output.Norm = mul(input.Norm, (float3x3)World); output.Tex = input.Tex; + output.WPos = world_pos; + return output; } float4 PS(PS_INPUT input) : SV_Target { - float4 color = Emission + Diffuse * 1.0 + Specular * 0.0; + float3 normal = normalize(input.Norm); + float3 view_dir = normalize(ViewEye.xyz - input.Pos.xyz); + + float3 color = Emission.xyz; + + for (int i = 0; i < 2; i++) { + float3 light_dir = normalize(-LightDir[i].xyz); + float diffuse_intensity = max(dot(normal, light_dir), 0.0); + color += Diffuse.xyz * diffuse_intensity * LightColor[i].xyz; + } return float4(color.xyz, 1); - - //return float4(input.Normal * 0.5 + 0.5, 1); - //return float4(input.Tex.xy, 0, 1); } BlendState DisableBlending diff --git a/src/main.cpp b/src/main.cpp index e6273c8..cc25f9e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,7 @@ #include "collada.hpp" #include "collada_scene.hpp" -#include "scenes/curve_interpolation.hpp" +#include "scenes/curve_interpolation/curve_interpolation.hpp" HINSTANCE g_hInstance = NULL; HWND g_hWnd = NULL; @@ -1843,7 +1843,8 @@ void Render(float t, float dt) //collada::Render(t); - g_SceneState.render(t); + g_SceneState.update(t); + g_SceneState.render(); RenderFont(dt); diff --git a/src/scenes/curve_interpolation/curve_interpolation.cpp b/src/scenes/curve_interpolation/curve_interpolation.cpp index b26354c..e47226c 100644 --- a/src/scenes/curve_interpolation/curve_interpolation.cpp +++ b/src/scenes/curve_interpolation/curve_interpolation.cpp @@ -1008,8 +1008,8 @@ instance_light const instance_lights_node_cube[] = { }; channel const * const node_channels_node_cube[] = { - &node_channel_node_cube_translation_x, &node_channel_node_cube_translation_y, + &node_channel_node_cube_translation_x, }; node const node_node_cube = {