Skip to content

Commit a44157c

Browse files
authored
[example] Added textures_frame_buffer_rendering (#5468)
1 parent b00cbda commit a44157c

File tree

2 files changed

+208
-0
lines changed

2 files changed

+208
-0
lines changed
30.8 KB
Loading
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/*******************************************************************************************
2+
*
3+
* raylib [textures] example - framebuffer rendering
4+
*
5+
* Example complexity rating: [★★☆☆] 2/4
6+
*
7+
* Example originally created with raylib 5.6, last time updated with raylib 5.6
8+
*
9+
* Example contributed by Jack Boakes (@jackboakes) and reviewed by Ramon Santamaria (@raysan5)
10+
*
11+
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
12+
* BSD-like license that allows static linking with closed source software
13+
*
14+
* Copyright (c) 2026-2026 Jack Boakes (@jackboakes)
15+
*
16+
********************************************************************************************/
17+
18+
#include "raylib.h"
19+
#include "raymath.h"
20+
21+
//------------------------------------------------------------------------------------
22+
// Module Functions Declaration
23+
//------------------------------------------------------------------------------------
24+
static void DrawCameraPrism(Camera3D camera, float aspect, Color color);
25+
26+
//------------------------------------------------------------------------------------
27+
// Program main entry point
28+
//------------------------------------------------------------------------------------
29+
int main(void)
30+
{
31+
// Initialization
32+
//--------------------------------------------------------------------------------------
33+
const int screenWidth = 800;
34+
const int screenHeight = 450;
35+
const int splitWidth = screenWidth/2;
36+
37+
InitWindow(screenWidth, screenHeight, "raylib [textures] example - framebuffer rendering");
38+
39+
// Camera to look at the 3D world
40+
Camera3D subjectCamera = { 0 };
41+
subjectCamera.position = (Vector3){ 5.0f, 5.0f, 5.0f };
42+
subjectCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
43+
subjectCamera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
44+
subjectCamera.fovy = 45.0f;
45+
subjectCamera.projection = CAMERA_PERSPECTIVE;
46+
47+
// Camera to observe the subject camera and 3D world
48+
Camera3D observerCamera = { 0 };
49+
observerCamera.position = (Vector3){ 10.0f, 10.0f, 10.0f };
50+
observerCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
51+
observerCamera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
52+
observerCamera.fovy = 45.0f;
53+
observerCamera.projection = CAMERA_PERSPECTIVE;
54+
55+
// Set up render textures
56+
RenderTexture2D observerTarget = LoadRenderTexture(splitWidth, screenHeight);
57+
Rectangle observerSource = { 0.0f, 0.0f, (float)observerTarget.texture.width, -(float)observerTarget.texture.height };
58+
Rectangle observerDest = { 0.0f, 0.0f, (float)splitWidth, (float)screenHeight };
59+
60+
RenderTexture2D subjectTarget = LoadRenderTexture(splitWidth, screenHeight);
61+
Rectangle subjectSource = { 0.0f, 0.0f, (float)subjectTarget.texture.width, -(float)subjectTarget.texture.height };
62+
Rectangle subjectDest = { (float)splitWidth, 0.0f, (float)splitWidth, (float)screenHeight };
63+
const float textureAspectRatio = (float)subjectTarget.texture.width/(float)subjectTarget.texture.height;
64+
65+
// Rectangles for cropping render texture
66+
const float captureSize = 128.0f;
67+
Rectangle cropSource = { (subjectTarget.texture.width - captureSize)/2.0f, (subjectTarget.texture.height - captureSize)/2.0f, captureSize, -captureSize };
68+
Rectangle cropDest = { splitWidth + 20, 20, captureSize, captureSize};
69+
70+
SetTargetFPS(60);
71+
DisableCursor();
72+
//--------------------------------------------------------------------------------------
73+
74+
// Main game loop
75+
while (!WindowShouldClose()) // Detect window close button or ESC key
76+
{
77+
// Update
78+
//----------------------------------------------------------------------------------
79+
UpdateCamera(&observerCamera, CAMERA_FREE);
80+
UpdateCamera(&subjectCamera, CAMERA_ORBITAL);
81+
82+
if (IsKeyPressed(KEY_R)) observerCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
83+
84+
// Build LHS observer view texture
85+
BeginTextureMode(observerTarget);
86+
87+
ClearBackground(RAYWHITE);
88+
89+
BeginMode3D(observerCamera);
90+
91+
DrawGrid(10, 1.0f);
92+
DrawCube((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, GOLD);
93+
DrawCubeWires((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, PINK);
94+
DrawCameraPrism(subjectCamera, textureAspectRatio, GREEN);
95+
96+
EndMode3D();
97+
98+
DrawText("Observer View", 10, observerTarget.texture.height - 30, 20, BLACK);
99+
DrawText("WASD + Mouse to Move", 10, 10, 20, DARKGRAY);
100+
DrawText("Scroll to Zoom", 10, 30, 20, DARKGRAY);
101+
DrawText("R to Reset Observer Target", 10, 50, 20, DARKGRAY);
102+
103+
EndTextureMode();
104+
105+
// Build RHS subject view texture
106+
BeginTextureMode(subjectTarget);
107+
108+
ClearBackground(RAYWHITE);
109+
110+
BeginMode3D(subjectCamera);
111+
112+
DrawCube((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, GOLD);
113+
DrawCubeWires((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, PINK);
114+
DrawGrid(10, 1.0f);
115+
116+
EndMode3D();
117+
118+
DrawRectangleLines((subjectTarget.texture.width - captureSize)/2, (subjectTarget.texture.height - captureSize)/2, captureSize, captureSize, GREEN);
119+
DrawText("Subject View", 10, subjectTarget.texture.height - 30, 20, BLACK);
120+
121+
EndTextureMode();
122+
//----------------------------------------------------------------------------------
123+
124+
// Draw
125+
//----------------------------------------------------------------------------------
126+
BeginDrawing();
127+
128+
ClearBackground(BLACK);
129+
130+
// Draw observer texture LHS
131+
DrawTexturePro(observerTarget.texture, observerSource, observerDest, (Vector2){0.0f, 0.0f }, 0.0f, WHITE);
132+
133+
// Draw subject texture RHS
134+
DrawTexturePro(subjectTarget.texture, subjectSource, subjectDest, (Vector2){ 0.0f, 0.0f }, 0.0f, WHITE);
135+
136+
// Draw the small crop overlay on top
137+
DrawTexturePro(subjectTarget.texture, cropSource, cropDest, (Vector2){ 0.0f, 0.0f }, 0.0f, WHITE);
138+
DrawRectangleLinesEx(cropDest, 2, BLACK);
139+
140+
// Draw split screen divider line
141+
DrawLine(splitWidth, 0, splitWidth, screenHeight, BLACK);
142+
143+
EndDrawing();
144+
//----------------------------------------------------------------------------------
145+
}
146+
147+
// De-Initialization
148+
//--------------------------------------------------------------------------------------
149+
UnloadRenderTexture(observerTarget);
150+
UnloadRenderTexture(subjectTarget);
151+
CloseWindow(); // Close window and OpenGL context
152+
//--------------------------------------------------------------------------------------
153+
154+
return 0;
155+
}
156+
157+
//----------------------------------------------------------------------------------
158+
// Module Functions Definition
159+
//----------------------------------------------------------------------------------
160+
static void DrawCameraPrism(Camera3D camera, float aspect, Color color)
161+
{
162+
float length = Vector3Distance(camera.position, camera.target);
163+
// Define the 4 corners of the camera's prism plane sliced at the target in Normalized Device Coordinates
164+
Vector3 planeNDC[4] = {
165+
{ -1.0f, -1.0f, 1.0f }, // Bottom Left
166+
{ 1.0f, -1.0f, 1.0f }, // Bottom Right
167+
{ 1.0f, 1.0f, 1.0f }, // Top Right
168+
{ -1.0f, 1.0f, 1.0f } // Top Left
169+
};
170+
171+
// Build the matrices
172+
Matrix view = GetCameraMatrix(camera);
173+
Matrix proj = MatrixPerspective(camera.fovy * DEG2RAD, aspect, 0.05f, length);
174+
// Combine view and projection so we can reverse the full camera transform
175+
Matrix viewProj = MatrixMultiply(view, proj);
176+
// Invert the view-projection matrix to unproject points from NDC space back into world space
177+
Matrix inverseViewProj = MatrixInvert(viewProj);
178+
179+
// Transform the 4 plane corners from NDC into world space
180+
Vector3 corners[4];
181+
for (int i = 0; i < 4; i++)
182+
{
183+
float x = planeNDC[i].x;
184+
float y = planeNDC[i].y;
185+
float z = planeNDC[i].z;
186+
187+
// Multiply NDC position by the inverse view-projection matrix
188+
// This produces a homogeneous (x, y, z, w) position in world space
189+
float vx = inverseViewProj.m0*x + inverseViewProj.m4*y + inverseViewProj.m8*z + inverseViewProj.m12;
190+
float vy = inverseViewProj.m1*x + inverseViewProj.m5*y + inverseViewProj.m9*z + inverseViewProj.m13;
191+
float vz = inverseViewProj.m2*x + inverseViewProj.m6*y + inverseViewProj.m10*z + inverseViewProj.m14;
192+
float vw = inverseViewProj.m3*x + inverseViewProj.m7*y + inverseViewProj.m11*z + inverseViewProj.m15;
193+
194+
corners[i] = (Vector3){ vx/vw, vy/vw, vz/vw };
195+
}
196+
197+
// Draw the far plane sliced at the target
198+
DrawLine3D(corners[0], corners[1], color);
199+
DrawLine3D(corners[1], corners[2], color);
200+
DrawLine3D(corners[2], corners[3], color);
201+
DrawLine3D(corners[3], corners[0], color);
202+
203+
// Draw the prism lines from the far plane to the camera position
204+
for (int i = 0; i < 4; i++)
205+
{
206+
DrawLine3D(camera.position, corners[i], color);
207+
}
208+
}

0 commit comments

Comments
 (0)