point rendering
There is no browser build of this example yet.
Is it the same as C?
- Desktop:verified The Zig version renders a final frame that is byte-identical to the C example.
- Browser:not checked yet The browser comparison does not cover this example yet.
//! raylib [models] example - point rendering
//!
//! Zig-API translation of examples/models/models_point_rendering.c (raylib 6.2).
//! Example contributed by Reese Gallagher (@satchelfrost) and reviewed by Ramon Santamaria (@raysan5)
//! Example licensed under an unmodified zlib/libpng license.
//! Copyright (c) 2024-2025 Reese Gallagher (@satchelfrost)
const std = @import("std");
const rl = @import("raylib");
const max_points = 10000000; // 10 million
const min_points = 1000; // 1 thousand
// libc PRNG, as in the C example (rand(), RAND_MAX on glibc)
extern "c" fn rand() c_int;
const rand_max: f32 = 2147483648.0; // (float)RAND_MAX: 2147483647 rounds to 2^31
pub fn main() !void {
// Initialization
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [models] example - point rendering");
defer rl.closeWindow();
var camera: rl.Camera = .{
.position = .{ .x = 3.0, .y = 3.0, .z = 3.0 },
.target = .{ .x = 0.0, .y = 0.0, .z = 0.0 },
.up = .{ .x = 0.0, .y = 1.0, .z = 0.0 },
.fovy = 45.0,
.projection = .perspective,
};
const position: rl.Vector3 = .{ .x = 0.0, .y = 0.0, .z = 0.0 };
var use_draw_model_points = true;
var num_points_changed = false;
var num_points: i32 = 1000;
var mesh = try genMeshPoints(num_points);
var model = try rl.loadModelFromMesh(mesh);
defer rl.unloadModel(model);
rl.setTargetFPS(60);
// Main game loop
while (!rl.windowShouldClose()) {
// Update
rl.updateCamera(&camera, .orbital);
if (rl.isKeyPressed(.space)) use_draw_model_points = !use_draw_model_points;
if (rl.isKeyPressed(.up)) {
num_points = @min(num_points * 10, max_points);
num_points_changed = true;
}
if (rl.isKeyPressed(.down)) {
num_points = @max(@divTrunc(num_points, 10), min_points);
num_points_changed = true;
}
// Upload a different point cloud size
if (num_points_changed) {
rl.unloadModel(model);
mesh = try genMeshPoints(num_points);
model = try rl.loadModelFromMesh(mesh);
num_points_changed = false;
}
// Draw
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.black);
{
rl.beginMode3D(camera);
defer rl.endMode3D();
// The new method only uploads the points once to the GPU
if (use_draw_model_points) {
drawModelPoints(model, position, 1.0, .white);
} else {
// The old method must continually draw the "points" (lines)
const count: usize = @intCast(num_points);
const vertices = mesh.vertices.?[0 .. count * 3];
const colors = mesh.colors.?[0 .. count * 4];
for (0..count) |i| {
const v = vertices[i * 3 ..][0..3];
const c = colors[i * 4 ..][0..4];
rl.drawPoint3D(.{ .x = v[0], .y = v[1], .z = v[2] }, .{ .r = c[0], .g = c[1], .b = c[2], .a = c[3] });
}
}
// Draw a unit sphere for reference
rl.drawSphereWires(position, 1.0, 10, 10, .yellow);
}
// Draw UI text
rl.drawText(rl.textFormat("Point Count: {d}", .{num_points}), 10, screen_height - 50, 40, .white);
rl.drawText("UP - Increase points", 10, 40, 20, .white);
rl.drawText("DOWN - Decrease points", 10, 70, 20, .white);
rl.drawText("SPACE - Drawing function", 10, 100, 20, .white);
if (use_draw_model_points) {
rl.drawText("Using: DrawModelPoints()", 10, 130, 20, .green);
} else {
rl.drawText("Using: DrawPoint3D()", 10, 130, 20, .red);
}
rl.drawFPS(10, 10);
}
}
/// Generate a spherical point cloud
fn genMeshPoints(num_points: i32) !rl.Mesh {
const count: usize = @intCast(num_points);
const vertices: [*]f32 = @ptrCast(@alignCast(rl.memAlloc(@intCast(count * 3 * @sizeOf(f32))) orelse return error.OutOfMemory));
const colors: [*]u8 = @ptrCast(rl.memAlloc(@intCast(count * 4)) orelse return error.OutOfMemory);
var mesh = std.mem.zeroes(rl.Mesh);
mesh.triangleCount = 1;
mesh.vertexCount = num_points;
mesh.vertices = vertices;
mesh.colors = colors;
// REF: https://en.wikipedia.org/wiki/Spherical_coordinate_system
for (0..count) |i| {
const theta = (rl.pi * randFloat()) / rand_max;
const phi = (2.0 * rl.pi * randFloat()) / rand_max;
const r = (10.0 * randFloat()) / rand_max;
vertices[i * 3 ..][0..3].* = .{
r * @sin(theta) * @cos(phi),
r * @sin(theta) * @sin(phi),
r * @cos(theta),
};
const color = rl.colorFromHSV(r * 360.0, 1.0, 1.0);
colors[i * 4 ..][0..4].* = .{ color.r, color.g, color.b, color.a };
}
// Upload mesh data from CPU (RAM) to GPU (VRAM) memory
rl.uploadMesh(&mesh, false);
return mesh;
}
fn randFloat() f32 {
return @floatFromInt(rand());
}
/// Draw a model as points
/// WARNING: OpenGL ES 2.0 does not support point mode drawing
fn drawModelPoints(model: rl.Model, position: rl.Vector3, scale: f32, tint: rl.Color) void {
rl.gl.enablePointMode();
rl.gl.disableBackfaceCulling();
rl.drawModel(model, position, scale, tint);
rl.gl.enableBackfaceCulling();
rl.gl.disablePointMode();
}
/// Draw a model as points with extended parameters
/// WARNING: OpenGL ES 2.0 does not support point mode drawing
fn drawModelPointsEx(model: rl.Model, position: rl.Vector3, rotation_axis: rl.Vector3, rotation_angle: f32, scale: rl.Vector3, tint: rl.Color) void {
rl.gl.enablePointMode();
rl.gl.disableBackfaceCulling();
rl.drawModelEx(model, position, rotation_axis, rotation_angle, scale, tint);
rl.gl.enableBackfaceCulling();
rl.gl.disablePointMode();
}/*******************************************************************************************
*
* raylib [models] example - point rendering
*
* Example complexity rating: [★★★☆] 3/4
*
* Example originally created with raylib 5.0, last time updated with raylib 5.0
*
* Example contributed by Reese Gallagher (@satchelfrost) 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) 2024-2025 Reese Gallagher (@satchelfrost)
*
********************************************************************************************/
#include "raylib.h"
#include "rlgl.h"
#include <stdlib.h> // Required for: rand()
#include <math.h> // Required for: cosf(), sinf()
#define MAX_POINTS 10000000 // 10 million
#define MIN_POINTS 1000 // 1 thousand
//------------------------------------------------------------------------------------
// Module Functions Declaration
//------------------------------------------------------------------------------------
static Mesh GenMeshPoints(int numPoints); // Generate mesh using points
void DrawModelPoints(Model model, Vector3 position, float scale, Color tint); // Draw a model as points
void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model as points with extended parameters
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [models] example - point rendering");
Camera camera = {
.position = { 3.0f, 3.0f, 3.0f },
.target = { 0.0f, 0.0f, 0.0f },
.up = { 0.0f, 1.0f, 0.0f },
.fovy = 45.0f,
.projection = CAMERA_PERSPECTIVE
};
Vector3 position = { 0.0f, 0.0f, 0.0f };
bool useDrawModelPoints = true;
bool numPointsChanged = false;
int numPoints = 1000;
Mesh mesh = GenMeshPoints(numPoints);
Model model = LoadModelFromMesh(mesh);
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose())
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(&camera, CAMERA_ORBITAL);
if (IsKeyPressed(KEY_SPACE)) useDrawModelPoints = !useDrawModelPoints;
if (IsKeyPressed(KEY_UP))
{
numPoints = (numPoints*10 > MAX_POINTS)? MAX_POINTS : numPoints*10;
numPointsChanged = true;
}
if (IsKeyPressed(KEY_DOWN))
{
numPoints = (numPoints/10 < MIN_POINTS)? MIN_POINTS : numPoints/10;
numPointsChanged = true;
}
// Upload a different point cloud size
if (numPointsChanged)
{
UnloadModel(model);
mesh = GenMeshPoints(numPoints);
model = LoadModelFromMesh(mesh);
numPointsChanged = false;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(BLACK);
BeginMode3D(camera);
// The new method only uploads the points once to the GPU
if (useDrawModelPoints) DrawModelPoints(model, position, 1.0f, WHITE);
else
{
// The old method must continually draw the "points" (lines)
for (int i = 0; i < numPoints; i++)
{
Vector3 pos = {
.x = mesh.vertices[i*3 + 0],
.y = mesh.vertices[i*3 + 1],
.z = mesh.vertices[i*3 + 2],
};
Color color = {
.r = mesh.colors[i*4 + 0],
.g = mesh.colors[i*4 + 1],
.b = mesh.colors[i*4 + 2],
.a = mesh.colors[i*4 + 3],
};
DrawPoint3D(pos, color);
}
}
// Draw a unit sphere for reference
DrawSphereWires(position, 1.0f, 10, 10, YELLOW);
EndMode3D();
// Draw UI text
DrawText(TextFormat("Point Count: %d", numPoints), 10, screenHeight - 50, 40, WHITE);
DrawText("UP - Increase points", 10, 40, 20, WHITE);
DrawText("DOWN - Decrease points", 10, 70, 20, WHITE);
DrawText("SPACE - Drawing function", 10, 100, 20, WHITE);
if (useDrawModelPoints) DrawText("Using: DrawModelPoints()", 10, 130, 20, GREEN);
else DrawText("Using: DrawPoint3D()", 10, 130, 20, RED);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadModel(model);
CloseWindow();
//--------------------------------------------------------------------------------------
return 0;
}
//------------------------------------------------------------------------------------
// Module Functions Definition
//------------------------------------------------------------------------------------
// Generate a spherical point cloud
static Mesh GenMeshPoints(int numPoints)
{
Mesh mesh = {
.triangleCount = 1,
.vertexCount = numPoints,
.vertices = (float *)MemAlloc(numPoints*3*sizeof(float)),
.colors = (unsigned char*)MemAlloc(numPoints*4*sizeof(unsigned char)),
};
// REF: https://en.wikipedia.org/wiki/Spherical_coordinate_system
for (int i = 0; i < numPoints; i++)
{
float theta = ((float)PI*rand())/((float)RAND_MAX);
float phi = (2.0f*PI*rand())/((float)RAND_MAX);
float r = (10.0f*rand())/((float)RAND_MAX);
mesh.vertices[i*3 + 0] = r*sinf(theta)*cosf(phi);
mesh.vertices[i*3 + 1] = r*sinf(theta)*sinf(phi);
mesh.vertices[i*3 + 2] = r*cosf(theta);
Color color = ColorFromHSV(r*360.0f, 1.0f, 1.0f);
mesh.colors[i*4 + 0] = color.r;
mesh.colors[i*4 + 1] = color.g;
mesh.colors[i*4 + 2] = color.b;
mesh.colors[i*4 + 3] = color.a;
}
// Upload mesh data from CPU (RAM) to GPU (VRAM) memory
UploadMesh(&mesh, false);
return mesh;
}
// Draw a model points
// WARNING: OpenGL ES 2.0 does not support point mode drawing
void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)
{
rlEnablePointMode();
rlDisableBackfaceCulling();
DrawModel(model, position, scale, tint);
rlEnableBackfaceCulling();
rlDisablePointMode();
}
// Draw a model points
// WARNING: OpenGL ES 2.0 does not support point mode drawing
void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
{
rlEnablePointMode();
rlDisableBackfaceCulling();
DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
rlEnableBackfaceCulling();
rlDisablePointMode();
}From raylib 6.2. The original on GitHub.