Rendering objects into both screen and separate resource
- akuvfx
- Topic Author
Less
More
1 year 2 months ago #1
by akuvfx
Rendering objects into both screen and separate resource was created by akuvfx
I’m trying to implement green screen or something like object id pass. Would it be possible to identify only objects I want to have included in draw/draw_indexed, and then add another draw call to draw it into resource i’ve created before? Then when new frame is being rendered, clear the resource with green color. I need it to be rendered at the same time as the game without modifying anything on back buffer. I managed to hook DX11 and replace shaders/return before calling original DrawIndexed and keep the models I need rendered for the green screen which works pretty well, but the issue is I need the game being rendered normally without that to have them both accessible at the same time.
Please Log in or Create an account to join the conversation.
- crosire
Less
More
1 year 2 months ago #2
by crosire
Replied by crosire on topic Rendering objects into both screen and separate resource
struct __declspec(uuid(...)) rtv_state {
std::vector<reshade::api::resource_view> rtvs;
reshade::api::resource_view dsv;
};
static void on_init_command_list(reshade::api::command_list *cmd_list) {
cmd_list->create_private_data<rtv_state>();
}
static void on_destroy_command_list(reshade::api::command_list *cmd_list) {
cmd_list->destroy_private_data<rtv_state>();
}
static void on_bind_render_targets_and_depth_stencil(reshade::api::command_list *cmd_list, uint32_t count, const reshade::api::resource_view *rtvs, reshade::api::resource_view dsv)
{
// Keep track of current render target state
auto ¤t_state = cmd_list->get_private_data<rtv_state>();
current_state.rtvs.assign(rtvs, rtvs + count);
current_state.dsv = dsv;
}
reshade::api::resource green_screen = ...;
reshade::api::resource_view green_screen_rtv = ...; // device->create_resource_view(green_screen, reshade::api::resource_usage::render_target, ...);
static bool on_draw(reshade::api::command_list *cmd_list, uint32_t vertices, uint32_t instances, uint32_t first_vertex, uint32_t first_instance)
{
cmd_list->bind_render_targets_and_depth_stencil(1, &green_screen_rtv);
cmd_list->draw(vertices, instances, first_vertex, first_instance); // Duplicate draw call, but rendering to custom render target
// Retrieve render target state and restore it again
const auto ¤t_state = cmd_list->get_private_data<rtv_state>();
cmd_list->bind_render_targets_and_depth_stencil(current_state.rtvs.size(), current_state.rtvs.data(), current_state.dsv);
return false; // Return false so that original draw call is executed again afterwards, now that original render targets were restored
}
Please Log in or Create an account to join the conversation.
1 year 2 months ago #3
by akuvfx
Replied by akuvfx on topic Rendering objects into both screen and separate resource
Thank you so much for your help. I tried doing this and checking which models I want to render to custom render target and while I can prevent the original draw calls for models I need (with different stride and byte width values, I found ones I need), I have the problem where with this draw call, without it the resource ends up green with hud only, and with it even if I don't draw other models into that resource all of them end up in there (if I don't draw other ones, it doesn't draw the hud there but it draws everything else that I want to keep in the original render and have only a few models in green screen). Any ideas what I could do about it?
The game I'm doing this for is Rocket League if it helps It's supposed to record both original game and green screen for the same frame so that they perfectly line up (depth map, normals and camera data too, but I've figured it out already). In the worst case I can render green screen every second frame and save them separately, it'd be 1 frame off always though, and it'd drop framerate twice and recording other passes drops fps enough. Maybe you have any other ideas how I could possibly implement green screen?
Here's the code I tried (this one renders green background with hud elements, but if you change the ! in if statement it will render the entire game for whatever reason):
(Stride == 32 || vedesc.ByteWidth == 4194304 && pscdesc.ByteWidth == 4096 && indesc.ByteWidth == 4194304)
The game I'm doing this for is Rocket League if it helps It's supposed to record both original game and green screen for the same frame so that they perfectly line up (depth map, normals and camera data too, but I've figured it out already). In the worst case I can render green screen every second frame and save them separately, it'd be 1 frame off always though, and it'd drop framerate twice and recording other passes drops fps enough. Maybe you have any other ideas how I could possibly implement green screen?
Here's the code I tried (this one renders green background with hud elements, but if you change the ! in if statement it will render the entire game for whatever reason):
static bool on_draw_indexed(reshade::api::command_list* cmd_list, uint32_t index_count, uint32_t instance_count, uint32_t first_index, int32_t vertex_offset, uint32_t first_instance) {
ID3D11DeviceContext* context = reinterpret_cast<ID3D11DeviceContext*>(cmd_list->get_native());
context->IAGetVertexBuffers(0, 1, &veBuffer, &Stride, &veBufferOffset);
if (veBuffer) veBuffer->GetDesc(&vedesc);
if (veBuffer != NULL) { veBuffer->Release(); veBuffer = NULL; }
context->IAGetIndexBuffer(&inBuffer, &inFormat, &inOffset);
if (inBuffer) inBuffer->GetDesc(&indesc);
if (inBuffer != NULL) { inBuffer->Release(); inBuffer = NULL; }
context->PSGetConstantBuffers(pscStartSlot, 1, &pscBuffer);
if (pscBuffer != NULL) pscBuffer->GetDesc(&pscdesc);
if (pscBuffer != NULL) { pscBuffer->Release(); pscBuffer = NULL; }
if (!(Stride == 32 && vedesc.ByteWidth == 4194304 && pscdesc.ByteWidth == 4096 && indesc.ByteWidth == 4194304)) {
// Duplicate draw call, but rendering to custom render target
cmd_list->bind_render_targets_and_depth_stencil(1, &data.green_screen_rtv);
cmd_list->draw_indexed(index_count, instance_count, first_index, vertex_offset, first_instance);
// Retrieve render target state and restore it again
// const auto& current_state = cmd_list->get_private_data<rtv_state>();
cmd_list->bind_render_targets_and_depth_stencil(current_state.rtvs.size(), current_state.rtvs.data(), current_state.dsv);
}
// Return false so that original draw call is executed again afterwards, now that original render targets were restored
return false;
}
Please Log in or Create an account to join the conversation.
- crosire
Less
More
1 year 2 months ago #4
by crosire
Replied by crosire on topic Rendering objects into both screen and separate resource
If the HUD is in your green screen resource, then there has to be more to it than the snippets shown, since something rendered that in there already. So it's difficult to reason on things without knowing what else is happening in the add-on.
Btw., if you are locked into D3D11, can simplify the render target tracking a lot (D3D11 is nice enough to provide a method to query the curren render targets, so can avoid keeping track of it yourself):
Btw., if you are locked into D3D11, can simplify the render target tracking a lot (D3D11 is nice enough to provide a method to query the curren render targets, so can avoid keeping track of it yourself):
ID3D11RenderTargetView *prev_rtvs[8] = {};
ID3D11DepthStencilView *prev_dsv = nullptr;
context->OMGetRenderTargets(8, prev_rtvs, &prev_dsv);
cmd_list->bind_render_targets_and_depth_stencil(1, &data.green_screen_rtv);
cmd_list->draw_indexed(index_count, instance_count, first_index, vertex_offset, first_instance);
context->OMSetRenderTargets(8, prev_rtvs, prev_dsv);
// Or alternatively: cmd_list->bind_render_targets_and_depth_stencil(8, reinterpret_cast<const resource_view *>(prev_rtvs), *reinterpret_cast<resource_view *>(&prev_dsv));
for (UINT i = 0; i < 8; ++i)
if (prev_rtvs[i]) prev_rtvs[i]->Release();
if (prev_dsv) prev_dsv->Release();
Please Log in or Create an account to join the conversation.
1 year 2 months ago #5
by akuvfx
Replied by akuvfx on topic Rendering objects into both screen and separate resource
Thank you, I will change render target tracking later since RL uses D3D11. The reason why the hud ends up in green screen resource is because I’m skipping that single draw call I mentioned, which apparently draws the entire game and then draws the hud on top. At least I think that’s what the game is doing, so without that draw call it ends up being HUD only. But if I keep the draw call, the entire game will be in the resource and it only needs that single draw call, even without other ones. I can prevent other ones from being called and then I can remove objects from the game and then it ends up in the resource just fine, but it also prevents the draw calls from actual screen. So I can’t have both and I don’t understand why. The addon only records the screen like in the video-capture example just with extra resource for normal maps but it doesn’t affect green screen resource in any way. The only thing that happens to the resource is clearing it when the game clears its screen and whatever happens in the draw_indexed hook. When I prevent the draw call I mentioned earlier completely, then the game doesn’t render anything either so I think the game somehow does this to put it together with the hud, I just don’t get why I can’t render it to my resource without that draw call, it just ends up empty without it (only hud which seems to be separate thing) and none of the draw calls for models in game do anything to the resource. I could organize the code a bit more and maybe then it’d be easier for you to see.
Please Log in or Create an account to join the conversation.