跳转至

Player / Free / Fixed Camera

通用数据位于 lib.kasuga.rendering.output.camera,Minecraft 接入位于 lib.kasuga.rendering.output.mc。原理见 多机位与输出。 所有创建、控制和关闭操作在渲染线程执行。

类型与创建

CameraType 姿态与配置来源 控制方式
PLAYER 原生玩家摄像机、第一/第三人称、当前 FOV/roll、资源和着色器 原生玩家控制;句柄管理输出生命周期
FREE 独立世界位置、旋转、FOV、尺寸和 CameraRenderSettings 直接控制、供应器或动画轨道
FIXED 目标插值位置/朝向与偏移;独立投影和 CameraRenderSettings 跟随目标、偏移、朝向模式和投影控制

FIXED 表示绑定目标的跟随相机。静止机位可用固定姿态的 FREE。 type() 与 CameraState 的 READY / PAUSED / FAILED / CLOSED 生命周期独立。

CameraHandle player = MinecraftCameras.createPlayer(frame -> consume(frame));
CameraHandle free = MinecraftCameras.createFree("example:free",
        new WorldCameraView(0, 80, 0, 90, 20, 0, 60, 1280, 720),
        CameraRenderSettings.defaults(), frame -> consume(frame));
CameraHandle fixed = MinecraftCameras.createFixed("example:follow", entity,
        new CameraProjection(60, 1280, 720),
        CameraRenderSettings.defaults(), frame -> consume(frame));

createFree 接受 WorldCameraView 或 Supplier<WorldCameraView>,各有省略 settings 的默认重载。 原有 MinecraftCameras.create(...) 保留为 Free Camera 的兼容入口。

createFixed 的签名如下,均返回 CameraHandle:

createFixed(String viewId, Entity entity, CameraProjection projection,
            CameraRenderSettings settings, Consumer<OutputFrame<FrameTexture>> consumer)
createFixed(String viewId, Supplier<? extends Entity> entity, CameraProjection projection,
            CameraRenderSettings settings, Consumer<OutputFrame<FrameTexture>> consumer)
createFixed(String viewId, CameraTarget target, CameraProjection projection,
            CameraRenderSettings settings, Consumer<OutputFrame<FrameTexture>> consumer)
createFixed(String viewId, CameraTarget target, CameraProjection projection,
            CameraFollowSettings follow, CameraRenderSettings settings,
            Consumer<OutputFrame<FrameTexture>> consumer)

Free/Fixed 的 view ID 必须非空、唯一,且不能为 minecraft:main。Player 使用 minecraft:main, 只允许一个拥有生命周期的 Player 句柄;多个消费者通过 MinecraftFrameOutputs.open(MIRROR, ...) 共享主画面。 Player 输出包含原生世界、手部、后处理、HUD/GUI,不额外渲染世界。暂停/关闭仅取消这个句柄的订阅, 玩家主窗口和其他主画面消费者继续运行。Free/Fixed 输出世界画面。

跟随数据与实体接入

CameraTarget target = MinecraftCameraTargets.entity(() -> Minecraft.getInstance().player);
fixed.follow(target); // 切换目标,保留投影和偏移
fixed.updateFollowSettings(new CameraFollowSettings(
        0, 2, 4,       // 世界坐标偏移,不随实体朝向旋转
        0, 10, 0,      // yaw / pitch / roll,单位为度
        true));        // 跟随朝向,角度字段作为附加偏移
fixed.setVerticalFov(55);
fixed.zoom(2);
fixed.setProjection(new CameraProjection(50, 1920, 1080));

CameraTarget 是通用函数接口 CameraTarget.Pose sample(float partialTick); Pose(double x, double y, double z, float yaw, float pitch, float roll) 不含 Entity 或模型格式类型。 自定义宿主可以绑定任意对象。Minecraft adapter 默认使用实体插值后的眼睛位置和视线朝向。 传入实体对象会持续绑定该对象;传入 supplier 可以在 respawn/维度切换后取得新对象。

默认 CameraFollowSettings.defaults() 所有偏移为 0,followRotation=true。 设为 false 时仍跟随位置,yaw/pitch/roll 作为世界中的绝对朝向。 FOV、zoom、projection 和渲染配置更新均保留目标绑定。此接口没有自动避墙或碰撞推离逻辑。

目标返回 null 表示暂时不可用。实体为 null、已移除或不属于当前源世界时,Minecraft adapter 跳过该视图、暂停其区块订阅并保留句柄和输出,目标可用后自动恢复。 等待期间 CameraState 仍为 READY,该视图帧号不增加;pose() 抛出 IllegalStateException, 不会使句柄失败。首次目标出现前也能设置 FOV/投影。目标抛出的运行时异常则使相机失败并释放资源。

followTarget() 返回 Optional<CameraTarget>;followSettings() 返回当前不可变配置。 对 Player/Free 调用跟随写入或 followSettings() 抛出 UnsupportedOperationException。 Fixed 不接受 updatePose / moveTo / moveBy / rotateTo / rotateBy / animation();通过跟随配置控制它。

Free 控制与渲染配置

Free 位置、旋转和动画接口见 摄像机动画。Player 不接受独立姿态、投影、 跟随、动画和渲染配置写入,对应操作抛出 UnsupportedOperationException。

free.setProjection(new CameraProjection(65, 1280, 720));
CameraRenderSettings settings = free.renderSettings().orElseThrow();
free.updateRenderSettings(new CameraRenderSettings(12,
        CameraRenderSettings.Quality.FANCY,
        CameraRenderSettings.Shader.pack(shaderPack)));

renderSettings() 对 Player 返回 empty,对 Minecraft Free/Fixed 返回当前配置。 updateRenderSettings 在下一次目标可用的渲染帧重建该机位的 renderer/assets/Iris session,保留 pose/follow、动画、view ID 和输出订阅。当前帧和回调继续使用原 session 配置,回调中可安全请求更新。 相同配置不重建;渲染暂停时延迟生效。shader pack 需要 Iris,初始化失败遵循相机失败/释放契约。 字段与资源包规则见 多机位配置。

CameraProjection 要求垂直 FOV 在 (0, 180) 度内,宽高为正整数,提供 from(view)、 withVerticalFov、zoom 和 apply(view)。Free 修改投影会停止自身动画;更新渲染配置不会停止动画。 窗口拥有的 Free Camera 以实际 framebuffer/DPI 尺寸为准。

宿主扩展与生命周期

纯 Java 宿主使用 CameraSource.Player(ViewProvider)、CameraSource.Free(Supplier<WorldCameraView>) 或 CameraSource.Fixed(CameraTarget, CameraProjection, CameraFollowSettings) 创建通用数据,交给 OwnedCamera(String viewId, CameraSource source, Producer producer, Output output, Runnable checkThread, Runnable onClosed)。 原有接受姿态 supplier 的构造器仍创建 Free Camera。 Player ViewProvider.sample(float partialTick) 提供原生摄像机快照;实际输出 producer 由宿主实现。

sampleAvailablePose(partialTick) 返回 Optional,供宿主在固定目标不可用时跳过渲染; samplePose(partialTick) 要求本帧有姿态。只对 Free 推进动画 tick,目标采样不推进模拟时间。 Producer.renderSettings/updateRenderSettings 是宿主配置扩展点。暂停、故障、关闭与资源所有权 遵循 多机位生命周期。

验证入口

./gradlew :modules:modelling:modelUnitTest
./gradlew :modules:modelling:runClientHeadless -PkasugaClientDirectory=/absolute/path/to/isolated-client -PkasugaQuickPlayWorld=camera-types -PkasugaTestCameraTypes=true

在隔离目录预备测试世界副本。客户端成功标识为 CAMERA_TYPES_SMOKE_PASS,报告在 debug/camera-types.json,覆盖原生主输出共享和暂停、Free 投影、实体插值、目标恢复、 回调修改配置后的 session 重建、实际世界纹理和 GL 错误检查。JVM 测试覆盖类型控制边界、 double 精度、偏移/朝向、投影保留目标以及失败释放。