118 lines
4.1 KiB
Java
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));
|
|
}
|
|
} |