Camera Obscura

Camera Obscura

将你的世界或服务器作为地图物品拍照,无需客户端模组!

装饰

此模组将不再在 Modrinth 上更新!

最新版本请见 https://www.curseforge.com/minecraft/mc-mods/camera-obscura-serverside-rendering

暗箱相机(Camera Obscura)

动画渲染

暗箱相机是一个服务端软件光栅化器,直接在服务端渲染任意实体(玩家、生物等)所看到的世界,并以照片或视频的形式生成 Minecraft 地图。 它与自定义物品(Nexo、ItemsAdder)深度集成,并拥有自定义预设系统。


功能特性

  • 拍摄照片:生成一个地图物品,显示目标实体所看到的内容。
  • 录制视频:将你的世界录制成视频,并可在物品展示框上播放。
  • 完全可配置:分辨率、颜色模式、抖动算法、渲染距离等均可调整。
  • 自定义物品支持:可通过 NexoItemsAdder 创建任意外观的相机/摄像机。
  • 异步渲染:绝不阻塞服务器主线程。
  • 无需客户端模组:所有功能均在服务端实现;地图/录像可在原版客户端上正常工作。

PNG 渲染


安装

Fabric 服务端

  1. 安装 Fabric APIPolymer(用于虚拟物品)。
  2. camera-obscura-fabric.jar 放入你的 mods/ 文件夹中。
  3. 配置文件将在启动时自动生成。

配置

配置文件位于 config/cameraobscura/config.json

{
  "renderDistance": 32,
  "showSystemMessages": false,
  "renderEntities": true,
  "fullbright": false,
  "fov": 70,
  "biomeBlend": 1,
  "ssaa": 2,
  "maxChunkRebuildsPerTick": 5,
  "debug": false,
  "cameraConsumesItem": true,
  "cameraConsumeItem": "map",
  "commandPermissionLevel": 2
}
选项 描述
renderDistance 视距(以方块为单位)(数值越高,渲染时间越长)。
showSystemMessages 是否在聊天中显示“正在拍照…”/“完成!”消息。
renderEntities 是否渲染画面中的实体(玩家、生物、物品展示框)。
fullbright 忽略光照(所有内容以全亮度显示)。
fov 视野角度(以度为单位,默认为 70)。
biomeBlend 方块颜色混合半径(生物群系色调)。0 = 不进行混合。
ssaa 超采样抗锯齿系数(1 = 关闭,2 = 2 倍超采样,3 = 3 倍)。
maxChunkRebuildsPerTick 每个视频录像及实时地图每帧重建的最大区块数(用于限制 CPU 峰值)。
debug 在输出图像上打印帧时间并显示 FPS 叠加层。
cameraConsumesItem 拍照是否消耗物品(例如地图)。
cameraConsumeItem 所需物品的材料(例如 mappaper)。
commandPermissionLevel 命令的基本权限等级。

命令与权限

基础权限cameraobscura.command

所有命令都使用根命令 /camera-obscura

1. 从你的视角拍摄地图

/camera-obscura [scale]
  • scale:地图分辨率倍数(1 = 128×128,2 = 256×256,最高 3)。
  • 给予你一张已填充地图,显示当前所看到的画面。

2. 从其他实体的视角拍摄地图

/camera-obscura <entity> <player> [scale]
  • <entity>:任意活体实体(玩家、生物等)
  • <player>:接收地图物品的玩家。

3. 保存为 PNG 图像

/camera-obscura save [entity] [scale]
  • 将渲染的图像保存为 .png 文件于 config/cameraobscura/renders/ 目录。

4. 重新加载配置

/camera-obscura reload

重新加载配置文件。

5. 清除资源/模型缓存

/camera-obscura clear-cache

6. 给予相机物品

/camera-obscura give <preset> [player]
  • <preset>presets.json 中定义的预设名称(例如 cameracamcorderinstantpolaroidpro_camerahandycamcctv)。
  • [player]:可选的玩家名称;若省略,则将物品给予命令发送者。

示例:

  • /camera-obscura give camera -> 给予自己默认相机。
  • /camera-obscura give camcorder Pinnit -> 给予玩家 Pinnit 一台摄像机。
  • /camera-obscura give my-preset -> 给予自己一个来自预设的物品。

📷 使用相机物品

基础相机

  • 将相机持于主手
  • 右键点击 -> 倒计时结束后,照片地图物品将出现在你的物品栏中(若已满则会掉落在地面上)。
  • 该地图显示那一刻的视角所见世界。

摄像机

  • 操作方式相同,但会开始录制而非单张照片。
  • 动作栏文本会提示当前录制状态。
  • 松开按键停止录制,视频将被保存为地图物品,可在物品展示框上播放。
  • 录制期间,相机周围会出现粒子效果(帧效果)。
  • 视频以 APNG 格式存储于 config/cameraobscura/camera_videos/<id>.apng

数据组件

该模组使用数据组件在物品堆叠上存储相机设置。

这使得你可以通过标准命令、配方或战利品表来创建具有不同分辨率、颜色模式和视频参数的相机。

可用组件

组件 ID 类型 描述
camera-obscura:color string (ColorMode) "COLOR""MONOCHROME""GRAYSCALE""SEPIA"
camera-obscura:resolution {width:int, height:int} 像素分辨率(例如 {width:256, height:256}
camera-obscura:dither string (DitherMode) "NONE""BAYER_2X2""FLOYD_STEINBERG" 等(详见下方完整列表)
camera-obscura:video {frame_rate:int, max_frames:int, loop_playback:bool} 视频录制参数
camera-obscura:map unit 将物品标记为实时地图(内部使用)
camera-obscura:camera_entity entity_reference 存储拍摄照片的实体(内部使用)
camera-obscura:data {id:uuid, video_params:...} 内部视频数据

DitherMode 值NONEBAYER_2X2BAYER_4X4BAYER_8X8FLOYD_STEINBERGATKINSONJARVIS_JUDICE_NINKESTUCKISIERRABURKES


在命令中使用组件

/give

/give @p camera-obscura:camera[camera-obscura:color="SEPIA",camera-obscura:resolution={width:512,height:512},camera-obscura:dither="FLOYD_STEINBERG"]

/item modify

创建一个包含物品修改器的数据包:

{
  "function": "set_components",
  "components": {
    "camera-obscura:color": "GRAYSCALE",
    "camera-obscura:resolution": { "width": 192, "height": 192 },
    "camera-obscura:dither": "BAYER_8X8"
  }
}

然后运行:/item modify entity @s weapon.mainhand my_pack:camera_settings


在配方中使用组件

在合成配方中:

{
  "type": "minecraft:crafting_shaped",
  "pattern": ["###", "#P#", "###"],
  "key": {
    "#": "minecraft:iron_ingot",
    "P": "minecraft:ender_pearl"
  },
  "result": {
    "id": "camera-obscura:camera",
    "components": {
      "camera-obscura:color": "SEPIA",
      "camera-obscura:resolution": { "width": 128, "height": 128 },
      "camera-obscura:dither": "NONE"
    }
  }
}

对于摄像机(视频模式),请包含 video

"components": {
  "camera-obscura:color": "COLOR",
  "camera-obscura:resolution": { "width": 256, "height": 256 },
  "camera-obscura:video": { "frame_rate": 15, "max_frames": 300 }
}

给予具有默认视频设置的摄像机

基础摄像机物品(无组件)使用全局配置默认值。若要显式设置视频参数:

/give @s camera-obscura:camcorder[camera-obscura:video={frame_rate:10,max_frames:200,loop_playback:true}]

内置物品

在 Fabric 上,暗箱相机添加了一些内置相机和摄像机物品,具有预先配置好的设置(颜色模式、分辨率、视频参数)。

相机物品(照片模式)

物品 ID 颜色模式 分辨率 抖动算法
camera-obscura:camera COLOR 128×128 NONE
camera-obscura:grayscale_camera GRAYSCALE 128×128 NONE
camera-obscura:primitive_camera MONOCHROME 128×128 NONE
camera-obscura:retro_camera SEPIA 128×128 NONE

摄像机物品(视频模式)

以预设帧率和最大帧数录制视频。

物品 ID 颜色模式 分辨率 抖动算法 视频(帧率 / 最大帧数)
camera-obscura:camcorder COLOR 128×128 NONE 10 FPS / 400 帧
camera-obscura:grayscale_camcorder GRAYSCALE 128×128 NONE 20 FPS / 400 帧
camera-obscura:primitive_camcorder MONOCHROME 128×128 NONE 20 FPS / 400 帧
camera-obscura:retro_camcorder SEPIA 128×128 NONE 20 FPS / 400 帧

使用示例:

/give @s camera-obscura:grayscale_camera

视频播放

要播放视频地图:

  • 将地图放入物品展示框中。
  • 右键点击物品展示框,视频将在地图上开始播放。
  • 再次右键点击即可停止播放。

预设

你可以添加自己的预设,即具有自定义材料、显示名称和相机设置(分辨率、颜色模式、抖动模式、视频参数)的预配置相机物品。

预设存储于 presets.json 中,可通过 /camera-obscura give <preset> <player> 命令给予玩家。


预设配置格式

presets.json 文件包含一个 JSON 对象,其中每个键为一个预设名称,对应的值是一个包含以下字段的对象:

字段 描述
material 物品 ID(例如 "paper""clock"
camera 相机特定选项(详见下文)
components 可选的额外原版数据组件,应用于物品堆叠(需要 1.20.5+)

相机选项

所有字段均为可选

字段 类型 描述
resolution { width, height } 输出像素分辨率(例如 { "width": 256, "height": 256 }
color_mode string "COLOR""MONOCHROME""GRAYSCALE""SEPIA"
dither_mode string "NONE""BAYER_2X2""FLOYD_STEINBERG"
video_params { frame_rate, max_frames } 视频录制参数

默认预设

该模组自带几个可直接使用的预设。你可以按需修改或删除它们。

{
  "camera": {
    "material": "paper",
    "camera": {
      "resolution": { "width": 128, "height": 128 },
      "color_mode": "COLOR",
      "dither_mode": "NONE",
      "video": { "frame_rate": 0, "max_frames": 1 }
    },
    "components": {
      "minecraft:item_name": { "text": "相机", "color": "gold" },
      "minecraft:max_stack_size": 1
    }
  },
  "camcorder": {
    "material": "paper",
    "camera": {
      "resolution": { "width": 128, "height": 128 },
      "color_mode": "COLOR",
      "dither_mode": "NONE",
      "video": { "frame_rate": 20, "max_frames": 200 }
    }
  },
  "instant": {
    "material": "paper",
    "camera": {
      "resolution": { "width": 256, "height": 256 },
      "color_mode": "SEPIA",
      "dither_mode": "BAYER_4X4"
    },
    "components": {
      "minecraft:item_name": { "text": "即时相机", "italic": false }
    }
  },
  "polaroid": {
    "material": "paper",
    "camera": {
      "resolution": { "width": 512, "height": 512 },
      "color_mode": "GRAYSCALE",
      "dither_mode": "FLOYD_STEINBERG"
    },
    "components": {
      "minecraft:item_name": { "text": "宝丽来", "color": "white" },
      "minecraft:custom_model_data": 1
    }
  },
  "pro_camera": {
    "material": "ender_eye",
    "camera": {
      "resolution": { "width": 128, "height": 128 },
      "color_mode": "COLOR",
      "dither_mode": "NONE",
      "video": { "frame_rate": 30, "max_frames": 600 }
    },
    "components": {
      "minecraft:item_name": { "text": "专业相机", "color": "light_purple", "bold": true },
      "minecraft:max_stack_size": 1,
      "minecraft:custom_model_data": 2
    }
  },
  "handycam": {
    "material": "clock",
    "camera": {
      "resolution": { "width": 256, "height": 256 },
      "color_mode": "COLOR",
      "dither_mode": "BAYER_2X2",
      "video": { "frame_rate": 15, "max_frames": 450 }
    },
    "components": {
      "minecraft:item_name": { "text": "手持摄像机", "color": "aqua" },
      "minecraft:max_stack_size": 1
    }
  },
  "cctv": {
    "material": "observer",
    "camera": {
      "resolution": { "width": 192, "height": 192 },
      "color_mode": "MONOCHROME",
      "dither_mode": "SIERRA",
      "video": { "frame_rate": 5, "max_frames": 30000 }
    },
    "components": {
      "minecraft:item_name": { "text": "闭路电视摄像头", "color": "dark_gray" },
      "minecraft:max_stack_size": 1
    }
  }
}

在命令中使用预设

/camera-obscura give camera
/camera-obscura give camcorder
/camera-obscura give instant
/camera-obscura give handycam Notch

Tab 补全会提示可用的预设名称。

重新加载预设

在服务器运行期间编辑 presets.json 后,运行:

/camera-obscura reload

此命令无需重启服务器即可重新加载主配置及所有预设。


工作原理(技术概述)

暗箱相机完全在服务端运行,并使用软件光栅化器逐像素绘制场景。

  • 渲染器会请求目标周围的区块和实体。
  • 方块模型被转换为三角形并存储于缓存中(按区块)。
  • 光照、环境光遮蔽和雾效均根据真实的世界状态计算。
  • 渲染在单独的线程池上异步进行,不会造成主游戏卡顿。
  • 渲染完成后,图像被转换为一张或多张 Minecraft 地图(或保存为 PNG)。
  • 视频录制会按配置的帧率捕捉画面。

性能考量

  • 更高的分辨率和 SSAA 会大幅增加 CPU 使用率。
  • 如果区块未加载,超过 128 的渲染距离可能导致问题。
  • 视频录制会占用大量 CPU。如需高质量录制,请考虑降低帧率!

故障排查

问题 检查方法
照片未出现在物品栏中 确认 cameraConsumesItem 设置为 false,或你拥有所需物品(例如地图)。
出现“缺少所需物品”消息 你的物品栏中需要有配置的 cameraConsumeItem 材料。
渲染时间过长(超过 5 秒) 减少 renderDistancessaaresolution。启用 debug 可查看每帧耗时。
服务器崩溃并出现内存溢出(OOM)错误 增加服务器内存(-Xmx2G 或更高)。降低 renderDistancessaa
自定义 Nexo/ItemsAdder 物品被忽略 确保 camera 部分缩进正确,且机制名称必须完全拼写为 camera