Files
DarkflameServer/dUgcServer/UgcRender.h
Aaron Kimbrell abf1cc1d80 feat: UGC server that makes and serves player models' meshes and icons
A new server (dUgcServer, started by master with enable_ugc_server=1) that
takes unprocessed ugc and ugc_modular_build rows from the database and makes
what the client downloads with UGCUSE3DSERVICES: an optimized NIF (hidden
faces removed, ambient occlusion baked into vertex colors) and a 128px DDS
icon for player models, rendered by a software rasterizer from the client's
LDD brick primitives, and icons for cars and rockets assembled from their
modules per ModularBuildComponent/ModuleComponent. It serves them, with the
models' LXFML, over HTTP in the client's UGCC<dc>/3DOPTIMIZED and
IMAGE128DDS layout with .gz and .checksum files, and keeps its folder under
a size cap.

Processing state lives in ugc.is_optimized plus new processed_at,
process_attempts and process_error columns (and the same on
ugc_modular_build). ServiceType::UGC is appended. NifFile moves to dCommon
and records named node transforms for the modules' attach points.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:57 -05:00

57 lines
1.9 KiB
C++

#pragma once
#include <cstdint>
#include <vector>
#include <glm/glm.hpp>
#include "UgcModel.h"
/**
* A small software rasterizer (no GPU or display needed) for what the UGC server draws: the icons, and the renders
* from many directions that find the faces nobody can see and bake ambient occlusion into the vertex colors.
*/
namespace UgcRender {
// 8-bit RGBA, rows top to bottom, not premultiplied
struct Image {
int width{};
int height{};
std::vector<uint8_t> rgba;
};
struct IconOptions {
int size{ 128 };
int supersample{ 4 };
float yawDegrees{ 35.0f }; // camera around the model, from +Z towards +X
float pitchDegrees{ 25.0f }; // camera above the model
float fovDegrees{ 30.0f };
float margin{ 1.03f }; // 1 fills the icon, more leaves a border
glm::mat4 modelRotation{ 1.0f }; // applied to the model before the camera looks at it
};
// The model drawn from the icon's camera, framed to fit, on a transparent background
Image RenderIcon(const UgcModel::Model& model, const IconOptions& options);
struct OptimizeOptions {
int resolution{ 1024 }; // of each direction's render
bool removeHidden{ true };
bool bakeAo{ true };
float aoStrength{ 0.6f }; // 0 leaves the colors, 1 makes fully hidden corners black
};
struct OptimizeResult {
size_t trianglesBefore{};
size_t trianglesRemoved{};
};
/**
* Renders the opaque mesh from 42 directions around it: triangles that show in none of them are removed (with a
* conservative test, so small visible ones stay), and each vertex's share of the directions it can be seen from
* darkens its color (ambient occlusion). Transparent bricks hide nothing but are darkened too.
*/
OptimizeResult Optimize(UgcModel::Model& model, const OptimizeOptions& options);
// The 42 directions Optimize renders from (an icosahedron's corners and edge centres), unit length
std::vector<glm::vec3> SphereDirections();
}