mirror of
https://github.com/raysan5/raylib.git
synced 2026-01-09 21:18:44 +01:00
[example] Added textures_frame_buffer_rendering (#5468)
This commit is contained in:
BIN
examples/textures/textures_frame_buffer_rendering.png
Normal file
BIN
examples/textures/textures_frame_buffer_rendering.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
208
examples/textures/textures_framebuffer_rendering.c
Normal file
208
examples/textures/textures_framebuffer_rendering.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [textures] example - framebuffer rendering
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.6, last time updated with raylib 5.6
|
||||
*
|
||||
* Example contributed by Jack Boakes (@jackboakes) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2026-2026 Jack Boakes (@jackboakes)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//------------------------------------------------------------------------------------
|
||||
static void DrawCameraPrism(Camera3D camera, float aspect, Color color);
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
const int splitWidth = screenWidth/2;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [textures] example - framebuffer rendering");
|
||||
|
||||
// Camera to look at the 3D world
|
||||
Camera3D subjectCamera = { 0 };
|
||||
subjectCamera.position = (Vector3){ 5.0f, 5.0f, 5.0f };
|
||||
subjectCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
|
||||
subjectCamera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
|
||||
subjectCamera.fovy = 45.0f;
|
||||
subjectCamera.projection = CAMERA_PERSPECTIVE;
|
||||
|
||||
// Camera to observe the subject camera and 3D world
|
||||
Camera3D observerCamera = { 0 };
|
||||
observerCamera.position = (Vector3){ 10.0f, 10.0f, 10.0f };
|
||||
observerCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
|
||||
observerCamera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
|
||||
observerCamera.fovy = 45.0f;
|
||||
observerCamera.projection = CAMERA_PERSPECTIVE;
|
||||
|
||||
// Set up render textures
|
||||
RenderTexture2D observerTarget = LoadRenderTexture(splitWidth, screenHeight);
|
||||
Rectangle observerSource = { 0.0f, 0.0f, (float)observerTarget.texture.width, -(float)observerTarget.texture.height };
|
||||
Rectangle observerDest = { 0.0f, 0.0f, (float)splitWidth, (float)screenHeight };
|
||||
|
||||
RenderTexture2D subjectTarget = LoadRenderTexture(splitWidth, screenHeight);
|
||||
Rectangle subjectSource = { 0.0f, 0.0f, (float)subjectTarget.texture.width, -(float)subjectTarget.texture.height };
|
||||
Rectangle subjectDest = { (float)splitWidth, 0.0f, (float)splitWidth, (float)screenHeight };
|
||||
const float textureAspectRatio = (float)subjectTarget.texture.width/(float)subjectTarget.texture.height;
|
||||
|
||||
// Rectangles for cropping render texture
|
||||
const float captureSize = 128.0f;
|
||||
Rectangle cropSource = { (subjectTarget.texture.width - captureSize)/2.0f, (subjectTarget.texture.height - captureSize)/2.0f, captureSize, -captureSize };
|
||||
Rectangle cropDest = { splitWidth + 20, 20, captureSize, captureSize};
|
||||
|
||||
SetTargetFPS(60);
|
||||
DisableCursor();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(&observerCamera, CAMERA_FREE);
|
||||
UpdateCamera(&subjectCamera, CAMERA_ORBITAL);
|
||||
|
||||
if (IsKeyPressed(KEY_R)) observerCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
|
||||
|
||||
// Build LHS observer view texture
|
||||
BeginTextureMode(observerTarget);
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
BeginMode3D(observerCamera);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
DrawCube((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, GOLD);
|
||||
DrawCubeWires((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, PINK);
|
||||
DrawCameraPrism(subjectCamera, textureAspectRatio, GREEN);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Observer View", 10, observerTarget.texture.height - 30, 20, BLACK);
|
||||
DrawText("WASD + Mouse to Move", 10, 10, 20, DARKGRAY);
|
||||
DrawText("Scroll to Zoom", 10, 30, 20, DARKGRAY);
|
||||
DrawText("R to Reset Observer Target", 10, 50, 20, DARKGRAY);
|
||||
|
||||
EndTextureMode();
|
||||
|
||||
// Build RHS subject view texture
|
||||
BeginTextureMode(subjectTarget);
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
BeginMode3D(subjectCamera);
|
||||
|
||||
DrawCube((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, GOLD);
|
||||
DrawCubeWires((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, PINK);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawRectangleLines((subjectTarget.texture.width - captureSize)/2, (subjectTarget.texture.height - captureSize)/2, captureSize, captureSize, GREEN);
|
||||
DrawText("Subject View", 10, subjectTarget.texture.height - 30, 20, BLACK);
|
||||
|
||||
EndTextureMode();
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(BLACK);
|
||||
|
||||
// Draw observer texture LHS
|
||||
DrawTexturePro(observerTarget.texture, observerSource, observerDest, (Vector2){0.0f, 0.0f }, 0.0f, WHITE);
|
||||
|
||||
// Draw subject texture RHS
|
||||
DrawTexturePro(subjectTarget.texture, subjectSource, subjectDest, (Vector2){ 0.0f, 0.0f }, 0.0f, WHITE);
|
||||
|
||||
// Draw the small crop overlay on top
|
||||
DrawTexturePro(subjectTarget.texture, cropSource, cropDest, (Vector2){ 0.0f, 0.0f }, 0.0f, WHITE);
|
||||
DrawRectangleLinesEx(cropDest, 2, BLACK);
|
||||
|
||||
// Draw split screen divider line
|
||||
DrawLine(splitWidth, 0, splitWidth, screenHeight, BLACK);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadRenderTexture(observerTarget);
|
||||
UnloadRenderTexture(subjectTarget);
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
static void DrawCameraPrism(Camera3D camera, float aspect, Color color)
|
||||
{
|
||||
float length = Vector3Distance(camera.position, camera.target);
|
||||
// Define the 4 corners of the camera's prism plane sliced at the target in Normalized Device Coordinates
|
||||
Vector3 planeNDC[4] = {
|
||||
{ -1.0f, -1.0f, 1.0f }, // Bottom Left
|
||||
{ 1.0f, -1.0f, 1.0f }, // Bottom Right
|
||||
{ 1.0f, 1.0f, 1.0f }, // Top Right
|
||||
{ -1.0f, 1.0f, 1.0f } // Top Left
|
||||
};
|
||||
|
||||
// Build the matrices
|
||||
Matrix view = GetCameraMatrix(camera);
|
||||
Matrix proj = MatrixPerspective(camera.fovy * DEG2RAD, aspect, 0.05f, length);
|
||||
// Combine view and projection so we can reverse the full camera transform
|
||||
Matrix viewProj = MatrixMultiply(view, proj);
|
||||
// Invert the view-projection matrix to unproject points from NDC space back into world space
|
||||
Matrix inverseViewProj = MatrixInvert(viewProj);
|
||||
|
||||
// Transform the 4 plane corners from NDC into world space
|
||||
Vector3 corners[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
float x = planeNDC[i].x;
|
||||
float y = planeNDC[i].y;
|
||||
float z = planeNDC[i].z;
|
||||
|
||||
// Multiply NDC position by the inverse view-projection matrix
|
||||
// This produces a homogeneous (x, y, z, w) position in world space
|
||||
float vx = inverseViewProj.m0*x + inverseViewProj.m4*y + inverseViewProj.m8*z + inverseViewProj.m12;
|
||||
float vy = inverseViewProj.m1*x + inverseViewProj.m5*y + inverseViewProj.m9*z + inverseViewProj.m13;
|
||||
float vz = inverseViewProj.m2*x + inverseViewProj.m6*y + inverseViewProj.m10*z + inverseViewProj.m14;
|
||||
float vw = inverseViewProj.m3*x + inverseViewProj.m7*y + inverseViewProj.m11*z + inverseViewProj.m15;
|
||||
|
||||
corners[i] = (Vector3){ vx/vw, vy/vw, vz/vw };
|
||||
}
|
||||
|
||||
// Draw the far plane sliced at the target
|
||||
DrawLine3D(corners[0], corners[1], color);
|
||||
DrawLine3D(corners[1], corners[2], color);
|
||||
DrawLine3D(corners[2], corners[3], color);
|
||||
DrawLine3D(corners[3], corners[0], color);
|
||||
|
||||
// Draw the prism lines from the far plane to the camera position
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
DrawLine3D(camera.position, corners[i], color);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user