// raw3d_test.c - 用 draw_quad 画 3D 方块,验证场景图变换 #include "../Engine/Core/engine.h" #include "../Engine/Window/window.h" #include "../Engine/Rendering/graphics_device.h" #include "../Engine/Rendering/shader.h" #include "../Engine/Scene/scene_graph.h" #include "../Engine/include/engine_api.h" #include "../Engine/ASM/math_c_fallback.h" static GraphicsDevice* g_dev = NULL; static Shader* g_shader = NULL; static Scene g_scene; static float g_time = 0; typedef struct { float p[3],n[3],uv[2],c[4]; } V; static void draw_quad_3d(ID3D11DeviceContext* ctx, float x, float y, float w, float h, float r, float g, float b, float a) { V v[4] = {{{x,y,0},{0,0,-1},{0,0},{r,g,b,a}},{{x+w,y,0},{0,0,-1},{1,0},{r,g,b,a}},{{x+w,y+h,0},{0,0,-1},{1,1},{r,g,b,a}},{{x,y+h,0},{0,0,-1},{0,1},{r,g,b,a}}}; uint32_t idx[6] = {0,1,2,0,2,3}; ID3D11Buffer *vb=NULL,*ib=NULL; D3D11_BUFFER_DESC bd={}; D3D11_SUBRESOURCE_DATA sd={}; bd.ByteWidth=sizeof(V)*4; bd.Usage=D3D11_USAGE_DEFAULT; bd.BindFlags=D3D11_BIND_VERTEX_BUFFER; sd.pSysMem=v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&vb); bd.ByteWidth=sizeof(uint32_t)*6; bd.BindFlags=D3D11_BIND_INDEX_BUFFER; sd.pSysMem=idx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&ib); UINT stride=sizeof(V),off=0; ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&vb,&stride,&off); ctx->lpVtbl->IASetIndexBuffer(ctx,ib,DXGI_FORMAT_R32_UINT,0); ctx->lpVtbl->DrawIndexed(ctx,6,0,0); ib->lpVtbl->Release(ib); vb->lpVtbl->Release(vb); } static void on_render(Engine* engine) { if (!g_dev) return; ID3D11DeviceContext* ctx = g_dev->context; scene_update(&g_scene); g_time += (float)engine->delta_time; float sw=(float)g_dev->width, sh=(float)g_dev->height; float fov=1.0f/tanf(0.4f), asp=sw/sh; // VP矩阵: 摄像机在(8,5,10)看原点 float ex=8,ey=5,ez=10; float fx=-ex,fy=-ey,fz=-ez, fl=sqrtf(fx*fx+fy*fy+fz*fz); fx/=fl;fy/=fl;fz/=fl; float rx=fy*0-fz*1,ry=fz*0-fx*0,rz=fx*1-fy*0; float rl=sqrtf(rx*rx+ry*ry+rz*rz);rx/=rl;ry/=rl;rz/=rl; float ux=ry*fz-rz*fy,uy=rz*fx-rx*fz,uz=rx*fy-ry*fx; float mvp[16]; mvp[0]=rx*fov/asp;mvp[1]=ry*fov/asp;mvp[2]=rz*fov/asp;mvp[3]=0; mvp[4]=ux*fov;mvp[5]=uy*fov;mvp[6]=uz*fov;mvp[7]=0; mvp[8]=fx;mvp[9]=fy;mvp[10]=fz;mvp[11]=0; mvp[12]=-(rx*ex+ry*ey+rz*ez)*fov/asp; mvp[13]=-(ux*ex+uy*ey+uz*ez)*fov; mvp[14]=-(fx*ex+fy*ey+fz*ez);mvp[15]=1; graphics_device_clear(g_dev, 0.15f, 0.18f, 0.25f, 1.0f); D3D11_VIEWPORT vp={};vp.Width=sw;vp.Height=sh;vp.MaxDepth=1; ctx->lpVtbl->RSSetViewports(ctx,1,&vp); D3D11_RASTERIZER_DESC rd={};rd.FillMode=D3D11_FILL_SOLID;rd.CullMode=D3D11_CULL_NONE; ID3D11RasterizerState* rs=NULL; g_dev->device->lpVtbl->CreateRasterizerState(g_dev->device,&rd,&rs); ctx->lpVtbl->RSSetState(ctx,rs); D3D11_DEPTH_STENCIL_DESC dsd={};dsd.DepthEnable=FALSE; ID3D11DepthStencilState* dss=NULL; g_dev->device->lpVtbl->CreateDepthStencilState(g_dev->device,&dsd,&dss); ctx->lpVtbl->OMSetDepthStencilState(ctx,dss,0); ctx->lpVtbl->IASetPrimitiveTopology(ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); shader_bind(g_shader, ctx); // 地面 shader_set_matrix(g_shader, ctx, mvp); draw_quad_3d(ctx, -5, 0, 10, 10, 0.3f, 0.35f, 0.4f, 1); // 场景节点 for (int i=0;ivisible||n->id==0||n->user_type!=1) continue; // 用世界矩阵变换4个角点 float corners[4][3] = {{-0.5f,-0.5f,0},{0.5f,-0.5f,0},{0.5f,0.5f,0},{-0.5f,0.5f,0}}; V v[4]; uint32_t idx[6]={0,1,2,0,2,3}; float colors[][3]={{1,0.2f,0.2f},{0.2f,1,0.2f},{0.2f,0.2f,1},{1,1,0.2f},{0.5f,0.2f,0.8f},{0.2f,0.8f,0.8f},{0.8f,0.5f,0.2f},{0.5f,0.5f,0.5f}}; int ci=(i-1)%8; for(int c=0;c<4;c++){ float px=0,py=0,pz=0; for(int r=0;r<4;r++) {float wc=n->world_matrix.m[0][r]*corners[c][0]+n->world_matrix.m[1][r]*corners[c][1]+n->world_matrix.m[2][r]*corners[c][2]+n->world_matrix.m[3][r]; px+=wc*mvp[r*4+0]; py+=wc*mvp[r*4+1]; pz+=wc*mvp[r*4+2];} // 简化: 直接用世界坐标+投影 float wx=n->world_matrix.m[3][0]+corners[c][0]; float wy=n->world_matrix.m[3][1]+corners[c][1]; float wz=n->world_matrix.m[3][2]+corners[c][2]; v[c].p[0]=wx; v[c].p[1]=wy; v[c].p[2]=wz; v[c].n[0]=0; v[c].n[1]=0; v[c].n[2]=1; v[c].c[0]=colors[ci][0]; v[c].c[1]=colors[ci][1]; v[c].c[2]=colors[ci][2]; v[c].c[3]=1; } ID3D11Buffer* vb=NULL,*ib2=NULL; D3D11_BUFFER_DESC bd2={}; D3D11_SUBRESOURCE_DATA sd2={}; bd2.ByteWidth=sizeof(V)*4; bd2.Usage=D3D11_USAGE_DEFAULT; bd2.BindFlags=D3D11_BIND_VERTEX_BUFFER; sd2.pSysMem=v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd2,&sd2,&vb); bd2.ByteWidth=sizeof(uint32_t)*6; bd2.BindFlags=D3D11_BIND_INDEX_BUFFER; sd2.pSysMem=idx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd2,&sd2,&ib2); UINT s2=sizeof(V),o2=0; ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&vb,&s2,&o2); ctx->lpVtbl->IASetIndexBuffer(ctx,ib2,DXGI_FORMAT_R32_UINT,0); ctx->lpVtbl->DrawIndexed(ctx,6,0,0); ib2->lpVtbl->Release(ib2); vb->lpVtbl->Release(vb); } if(rs) rs->lpVtbl->Release(rs); if(dss) dss->lpVtbl->Release(dss); graphics_device_present(g_dev); } static void on_key(Engine* engine, int key) { if (key==VK_ESCAPE) engine_request_quit(engine); } int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int) { EngineConfig cfg=engine_default_config(); cfg.app_name="lity3d Raw3D"; Engine* e=engine_create(); if(!engine_init(e,&cfg))return -1; g_dev=graphics_device_create(); if(!graphics_device_init(g_dev,window_get_handle(e->window),cfg.window_width,cfg.window_height,1))return -1; g_shader=shader_create(); shader_compile(g_shader,g_dev->device,NULL,NULL,0,0); scene_init(&g_scene); SceneNode* c1=scene_create_node(&g_scene,"Cube1"); scene_set_position(c1,0,0.5f,0); c1->user_type=1; SceneNode* c2=scene_create_node(&g_scene,"Cube2"); scene_set_position(c2,-3,0.5f,2); c2->user_type=1; SceneNode* c3=scene_create_node(&g_scene,"Cube3"); scene_set_position(c3,3,0.5f,-2); scene_set_scale(c3,0.5f,0.5f,0.5f); c3->user_type=1; SceneNode* ch=scene_create_node(&g_scene,"Child"); scene_set_position(ch,2,0,0); ch->user_type=1; scene_set_parent(ch,c1); engine_set_render_callback(e,on_render); engine_set_key_callback(e,on_key); engine_run(e); shader_destroy(g_shader); graphics_device_destroy(g_dev); engine_shutdown(e); return 0; }