Files
ReplayModCinematic/src/main/java/com/replaymod/render/capturer/RealLensOpenGlFrameCapturer.java
2026-07-07 05:04:16 +04:00

118 lines
4.1 KiB
Java

package com.replaymod.render.capturer;
import com.replaymod.render.frame.OpenGlFrame;
import com.replaymod.render.frame.RealLensOpenGlFrame;
import com.replaymod.render.rendering.Channel;
import com.replaymod.replaystudio.pathing.path.Path;
import com.replaymod.simplepathing.ReplayModSimplePathing;
import com.replaymod.pathing.properties.LensProperties;
import org.apache.commons.lang3.tuple.Triple;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
public class RealLensOpenGlFrameCapturer
extends OpenGlFrameCapturer<RealLensOpenGlFrame, RealLensOpenGlFrameCapturer.Data> {
public static class Data implements CaptureData {
public float dx, dy, dz;
public float yaw, pitch;
public Data(float dx, float dy, float dz,
float yaw, float pitch) {
this.dx = dx;
this.dy = dy;
this.dz = dz;
this.yaw = yaw;
this.pitch = pitch;
}
}
private static Data[] golden_disk(int n, float r) {
Data[] points = new Data[n];
final float GOLDEN_ANGLE = (float) (Math.PI * (3.0 - Math.sqrt(5.0)));
float random_offset = (float) Math.sqrt(r*r/n) * 0.5f;
for (int i = 0; i < n; i++) {
float rr = r * (float) Math.sqrt((float) i / n);
float t = i * GOLDEN_ANGLE;
points[i] = new Data(
rr * (float) Math.cos(t) + (ThreadLocalRandom.current().nextFloat() * 2f - 1f) * random_offset,
rr * (float) Math.sin(t) + (ThreadLocalRandom.current().nextFloat() * 2f - 1f) * random_offset,
0f, 0f, 0f
);
}
return points;
}
private static final float FOCAL_DISTANCE = 5.0f;
private static final float APERTURE_RADIUS = 0.05f;
private static final int SAMPLES = 64;
private static Data[] calculateCameras(float focal_distance, float aperture_radius, int samples) {
Data[] cameras = golden_disk(samples, aperture_radius);
for (Data cam : cameras) {
// Направление от смещённой камеры к фокальной точке (0, 0, FOCAL_DISTANCE)
float dirX = 0 - cam.dx;
float dirY = 0 - cam.dy;
float dirZ = focal_distance - cam.dz;
// Вычисляем yaw и pitch из направления
cam.yaw = (float) -Math.toDegrees(Math.atan2(dirX, dirZ));
cam.pitch = (float) Math.toDegrees(Math.atan2(dirY, Math.sqrt(dirX*dirX + dirZ*dirZ)));
}
return cameras;
}
private final Path positionPath;
public RealLensOpenGlFrameCapturer(
WorldRenderer worldRenderer,
RenderInfo renderInfo
) {
super(worldRenderer, renderInfo);
this.positionPath = ReplayModSimplePathing.instance.getCurrentTimeline().getPositionPath();
}
@Override
public Map<Channel, RealLensOpenGlFrame> process() {
float partialTicks = renderInfo.updateForNextFrame();
int frameId = framesDone++;
int fps = renderInfo.getRenderSettings().getFramesPerSecond();
long keyframeTime = (long) frameId * 1000 / fps;
float focalDistance = positionPath.getValue(LensProperties.FOCAL_DISTANCE, keyframeTime).map(Triple::getLeft).orElse(5.0f);
float apertureRadius = positionPath.getValue(LensProperties.APERTURE_RADIUS, keyframeTime).map(Triple::getLeft).orElse(0.05f);
int samples = renderInfo.getRenderSettings().getLensBlurSamples();
if (positionPath == null) {
System.err.println("positionPath is null!");
focalDistance = Float.MAX_VALUE;
apertureRadius = 0.01f;
}
Data[] cameras = calculateCameras(focalDistance, apertureRadius, samples);
OpenGlFrame[] frames = new OpenGlFrame[cameras.length];
for (int i = 0; i < cameras.length; i++) {
frames[i] = renderFrame(frameId, partialTicks, cameras[i]);
}
return Collections.singletonMap(Channel.BRGA, new RealLensOpenGlFrame(frames));
}
}