CloudRenderer.java
net.minecraft.client.renderer.CloudRenderer
信息
- 全限定名:net.minecraft.client.renderer.CloudRenderer
- 类型:public class
- 包:net.minecraft.client.renderer
- 源码路径:src/main/java/net/minecraft/client/renderer/CloudRenderer.java
- 起始行号:L40
- 继承:SimplePreparableReloadListener<Optional<CloudRenderer.TextureData>>
- 实现:AutoCloseable
- 职责:
TODO
字段/常量
-
FLAG_INSIDE_FACE- 类型:
int - 修饰符:
private static final - 源码定位:
L41 - 说明:
TODO
- 类型:
-
FLAG_USE_TOP_COLOR- 类型:
int - 修饰符:
private static final - 源码定位:
L42 - 说明:
TODO
- 类型:
-
CELL_SIZE_IN_BLOCKS- 类型:
float - 修饰符:
private static final - 源码定位:
L43 - 说明:
TODO
- 类型:
-
TICKS_PER_CELL- 类型:
int - 修饰符:
private static final - 源码定位:
L44 - 说明:
TODO
- 类型:
-
BLOCKS_PER_SECOND- 类型:
float - 修饰符:
private static final - 源码定位:
L45 - 说明:
TODO
- 类型:
-
UBO_SIZE- 类型:
int - 修饰符:
private static final - 源码定位:
L46 - 说明:
TODO
- 类型:
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L47 - 说明:
TODO
- 类型:
-
TEXTURE_LOCATION- 类型:
Identifier - 修饰符:
private static final - 源码定位:
L48 - 说明:
TODO
- 类型:
-
EMPTY_CELL- 类型:
long - 修饰符:
private static final - 源码定位:
L49 - 说明:
TODO
- 类型:
-
COLOR_OFFSET- 类型:
int - 修饰符:
private static final - 源码定位:
L50 - 说明:
TODO
- 类型:
-
NORTH_OFFSET- 类型:
int - 修饰符:
private static final - 源码定位:
L51 - 说明:
TODO
- 类型:
-
EAST_OFFSET- 类型:
int - 修饰符:
private static final - 源码定位:
L52 - 说明:
TODO
- 类型:
-
SOUTH_OFFSET- 类型:
int - 修饰符:
private static final - 源码定位:
L53 - 说明:
TODO
- 类型:
-
WEST_OFFSET- 类型:
int - 修饰符:
private static final - 源码定位:
L54 - 说明:
TODO
- 类型:
-
needsRebuild- 类型:
boolean - 修饰符:
private - 源码定位:
L55 - 说明:
TODO
- 类型:
-
prevCellX- 类型:
int - 修饰符:
private - 源码定位:
L56 - 说明:
TODO
- 类型:
-
prevCellZ- 类型:
int - 修饰符:
private - 源码定位:
L57 - 说明:
TODO
- 类型:
-
prevRelativeCameraPos- 类型:
CloudRenderer.RelativeCameraPos - 修饰符:
private - 源码定位:
L58 - 说明:
TODO
- 类型:
-
prevCloudStatus- 类型:
CloudStatus - 修饰符:
private - 源码定位:
L59 - 说明:
TODO
- 类型:
-
texture- 类型:
CloudRenderer.TextureData - 修饰符:
private - 源码定位:
L60 - 说明:
TODO
- 类型:
-
quadCount- 类型:
int - 修饰符:
private - 源码定位:
L61 - 说明:
TODO
- 类型:
-
ubo- 类型:
MappableRingBuffer - 修饰符:
private final - 源码定位:
L62 - 说明:
TODO
- 类型:
-
utb- 类型:
MappableRingBuffer - 修饰符:
private - 源码定位:
L63 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.client.renderer.CloudRenderer.RelativeCameraPos- 类型:
enum - 修饰符:
private static - 源码定位:
L345 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.CloudRenderer.TextureData- 类型:
record - 修饰符:
public - 源码定位:
L352 - 说明:
TODO
- 类型:
构造器
- 无
方法
下面的方法块按源码顺序生成。
protected Optional<CloudRenderer.TextureData> prepare(ResourceManager manager, ProfilerFiller profiler) @ L65
- 方法名:prepare
- 源码定位:L65
- 返回类型:Optional<CloudRenderer.TextureData>
- 修饰符:protected
参数:
- manager: ResourceManager
- profiler: ProfilerFiller
说明:
TODO
private static int getSizeForCloudDistance(int radiusCells) @ L101
- 方法名:getSizeForCloudDistance
- 源码定位:L101
- 返回类型:int
- 修饰符:private static
参数:
- radiusCells: int
说明:
TODO
protected void apply(Optional<CloudRenderer.TextureData> preparations, ResourceManager manager, ProfilerFiller profiler) @ L108
- 方法名:apply
- 源码定位:L108
- 返回类型:void
- 修饰符:protected
参数:
- preparations: Optional<CloudRenderer.TextureData>
- manager: ResourceManager
- profiler: ProfilerFiller
说明:
TODO
private static boolean isCellEmpty(int color) @ L113
- 方法名:isCellEmpty
- 源码定位:L113
- 返回类型:boolean
- 修饰符:private static
参数:
- color: int
说明:
TODO
private static long packCellData(int color, boolean north, boolean east, boolean south, boolean west) @ L117
- 方法名:packCellData
- 源码定位:L117
- 返回类型:long
- 修饰符:private static
参数:
- color: int
- north: boolean
- east: boolean
- south: boolean
- west: boolean
说明:
TODO
private static boolean isNorthEmpty(long cellData) @ L121
- 方法名:isNorthEmpty
- 源码定位:L121
- 返回类型:boolean
- 修饰符:private static
参数:
- cellData: long
说明:
TODO
private static boolean isEastEmpty(long cellData) @ L125
- 方法名:isEastEmpty
- 源码定位:L125
- 返回类型:boolean
- 修饰符:private static
参数:
- cellData: long
说明:
TODO
private static boolean isSouthEmpty(long cellData) @ L129
- 方法名:isSouthEmpty
- 源码定位:L129
- 返回类型:boolean
- 修饰符:private static
参数:
- cellData: long
说明:
TODO
private static boolean isWestEmpty(long cellData) @ L133
- 方法名:isWestEmpty
- 源码定位:L133
- 返回类型:boolean
- 修饰符:private static
参数:
- cellData: long
说明:
TODO
public void render(int color, CloudStatus cloudStatus, float bottomY, int range, Vec3 cameraPosition, long gameTime, float partialTicks) @ L137
- 方法名:render
- 源码定位:L137
- 返回类型:void
- 修饰符:public
参数:
- color: int
- cloudStatus: CloudStatus
- bottomY: float
- range: int
- cameraPosition: Vec3
- gameTime: long
- partialTicks: float
说明:
TODO
private void buildMesh(CloudRenderer.RelativeCameraPos relativePos, ByteBuffer faceBuffer, int centerCellX, int centerCellZ, boolean extrude, int radiusCells) @ L231
- 方法名:buildMesh
- 源码定位:L231
- 返回类型:void
- 修饰符:private
参数:
- relativePos: CloudRenderer.RelativeCameraPos
- faceBuffer: ByteBuffer
- centerCellX: int
- centerCellZ: int
- extrude: boolean
- radiusCells: int
说明:
TODO
private void tryBuildCell(CloudRenderer.RelativeCameraPos relativePos, ByteBuffer faceBuffer, int cellX, int cellZ, boolean extrude, int relativeCellX, int textureWidth, int relativeCellZ, int textureHeight, long[] cells) @ L260
- 方法名:tryBuildCell
- 源码定位:L260
- 返回类型:void
- 修饰符:private
参数:
- relativePos: CloudRenderer.RelativeCameraPos
- faceBuffer: ByteBuffer
- cellX: int
- cellZ: int
- extrude: boolean
- relativeCellX: int
- textureWidth: int
- relativeCellZ: int
- textureHeight: int
- cells: long[]
说明:
TODO
private void buildFlatCell(ByteBuffer faceBuffer, int x, int z) @ L284
- 方法名:buildFlatCell
- 源码定位:L284
- 返回类型:void
- 修饰符:private
参数:
- faceBuffer: ByteBuffer
- x: int
- z: int
说明:
TODO
private void encodeFace(ByteBuffer faceBuffer, int x, int z, Direction direction, int flags) @ L288
- 方法名:encodeFace
- 源码定位:L288
- 返回类型:void
- 修饰符:private
参数:
- faceBuffer: ByteBuffer
- x: int
- z: int
- direction: Direction
- flags: int
说明:
TODO
private void buildExtrudedCell(CloudRenderer.RelativeCameraPos relativePos, ByteBuffer faceBuffer, int x, int z, long cellData) @ L295
- 方法名:buildExtrudedCell
- 源码定位:L295
- 返回类型:void
- 修饰符:private
参数:
- relativePos: CloudRenderer.RelativeCameraPos
- faceBuffer: ByteBuffer
- x: int
- z: int
- cellData: long
说明:
TODO
public void markForRebuild() @ L328
- 方法名:markForRebuild
- 源码定位:L328
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void endFrame() @ L332
- 方法名:endFrame
- 源码定位:L332
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void close() @ L336
- 方法名:close
- 源码定位:L336
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class CloudRenderer extends SimplePreparableReloadListener<Optional<CloudRenderer.TextureData>> implements AutoCloseable {
private static final int FLAG_INSIDE_FACE = 16;
private static final int FLAG_USE_TOP_COLOR = 32;
private static final float CELL_SIZE_IN_BLOCKS = 12.0F;
private static final int TICKS_PER_CELL = 400;
private static final float BLOCKS_PER_SECOND = 0.6F;
private static final int UBO_SIZE = new Std140SizeCalculator().putVec4().putVec3().putVec3().get();
private static final Logger LOGGER = LogUtils.getLogger();
private static final Identifier TEXTURE_LOCATION = Identifier.withDefaultNamespace("textures/environment/clouds.png");
private static final long EMPTY_CELL = 0L;
private static final int COLOR_OFFSET = 4;
private static final int NORTH_OFFSET = 3;
private static final int EAST_OFFSET = 2;
private static final int SOUTH_OFFSET = 1;
private static final int WEST_OFFSET = 0;
private boolean needsRebuild = true;
private int prevCellX = Integer.MIN_VALUE;
private int prevCellZ = Integer.MIN_VALUE;
private CloudRenderer.RelativeCameraPos prevRelativeCameraPos = CloudRenderer.RelativeCameraPos.INSIDE_CLOUDS;
private @Nullable CloudStatus prevCloudStatus;
private CloudRenderer.@Nullable TextureData texture;
private int quadCount = 0;
private final MappableRingBuffer ubo = new MappableRingBuffer(() -> "Cloud UBO", 130, UBO_SIZE);
private @Nullable MappableRingBuffer utb;
protected Optional<CloudRenderer.TextureData> prepare(ResourceManager manager, ProfilerFiller profiler) {
try {
Optional var20;
try (
InputStream input = manager.open(TEXTURE_LOCATION);
NativeImage texture = NativeImage.read(input);
) {
int width = texture.getWidth();
int height = texture.getHeight();
long[] cells = new long[width * height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int color = texture.getPixel(x, y);
if (isCellEmpty(color)) {
cells[x + y * width] = 0L;
} else {
boolean north = isCellEmpty(texture.getPixel(x, Math.floorMod(y - 1, height)));
boolean east = isCellEmpty(texture.getPixel(Math.floorMod(x + 1, height), y));
boolean south = isCellEmpty(texture.getPixel(x, Math.floorMod(y + 1, height)));
boolean west = isCellEmpty(texture.getPixel(Math.floorMod(x - 1, height), y));
cells[x + y * width] = packCellData(color, north, east, south, west);
}
}
}
var20 = Optional.of(new CloudRenderer.TextureData(cells, width, height));
}
return var20;
} catch (IOException var19) {
LOGGER.error("Failed to load cloud texture", (Throwable)var19);
return Optional.empty();
}
}
private static int getSizeForCloudDistance(int radiusCells) {
int maxFacesPerCell = 4;
int maxCells = (radiusCells + 1) * 2 * (radiusCells + 1) * 2 / 2;
int maxFaces = maxCells * 4 + 54;
return maxFaces * 3;
}
protected void apply(Optional<CloudRenderer.TextureData> preparations, ResourceManager manager, ProfilerFiller profiler) {
this.texture = preparations.orElse(null);
this.needsRebuild = true;
}
private static boolean isCellEmpty(int color) {
return ARGB.alpha(color) < 10;
}
private static long packCellData(int color, boolean north, boolean east, boolean south, boolean west) {
return (long)color << 4 | (north ? 1 : 0) << 3 | (east ? 1 : 0) << 2 | (south ? 1 : 0) << 1 | (west ? 1 : 0) << 0;
}
private static boolean isNorthEmpty(long cellData) {
return (cellData >> 3 & 1L) != 0L;
}
private static boolean isEastEmpty(long cellData) {
return (cellData >> 2 & 1L) != 0L;
}
private static boolean isSouthEmpty(long cellData) {
return (cellData >> 1 & 1L) != 0L;
}
private static boolean isWestEmpty(long cellData) {
return (cellData >> 0 & 1L) != 0L;
}
public void render(int color, CloudStatus cloudStatus, float bottomY, int range, Vec3 cameraPosition, long gameTime, float partialTicks) {
if (this.texture != null) {
int radiusBlocks = range * 16;
int radiusCells = Mth.ceil(radiusBlocks / 12.0F);
int utbSize = getSizeForCloudDistance(radiusCells);
if (this.utb == null || this.utb.currentBuffer().size() != utbSize) {
if (this.utb != null) {
this.utb.close();
}
this.utb = new MappableRingBuffer(() -> "Cloud UTB", 258, utbSize);
}
float relativeBottomY = (float)(bottomY - cameraPosition.y);
float relativeTopY = relativeBottomY + 4.0F;
CloudRenderer.RelativeCameraPos relativeCameraPos;
if (relativeTopY < 0.0F) {
relativeCameraPos = CloudRenderer.RelativeCameraPos.ABOVE_CLOUDS;
} else if (relativeBottomY > 0.0F) {
relativeCameraPos = CloudRenderer.RelativeCameraPos.BELOW_CLOUDS;
} else {
relativeCameraPos = CloudRenderer.RelativeCameraPos.INSIDE_CLOUDS;
}
float cloudOffset = (float)(gameTime % (this.texture.width * 400L)) + partialTicks;
double cloudX = cameraPosition.x + cloudOffset * 0.030000001F;
double cloudZ = cameraPosition.z + 3.96F;
double textureWidthBlocks = this.texture.width * 12.0;
double textureHeightBlocks = this.texture.height * 12.0;
cloudX -= Mth.floor(cloudX / textureWidthBlocks) * textureWidthBlocks;
cloudZ -= Mth.floor(cloudZ / textureHeightBlocks) * textureHeightBlocks;
int cellX = Mth.floor(cloudX / 12.0);
int cellZ = Mth.floor(cloudZ / 12.0);
float xInCell = (float)(cloudX - cellX * 12.0F);
float zInCell = (float)(cloudZ - cellZ * 12.0F);
boolean fancyClouds = cloudStatus == CloudStatus.FANCY;
RenderPipeline renderPipeline = fancyClouds ? RenderPipelines.CLOUDS : RenderPipelines.FLAT_CLOUDS;
if (this.needsRebuild
|| cellX != this.prevCellX
|| cellZ != this.prevCellZ
|| relativeCameraPos != this.prevRelativeCameraPos
|| cloudStatus != this.prevCloudStatus) {
this.needsRebuild = false;
this.prevCellX = cellX;
this.prevCellZ = cellZ;
this.prevRelativeCameraPos = relativeCameraPos;
this.prevCloudStatus = cloudStatus;
this.utb.rotate();
try (GpuBuffer.MappedView view = RenderSystem.getDevice().createCommandEncoder().mapBuffer(this.utb.currentBuffer(), false, true)) {
this.buildMesh(relativeCameraPos, view.data(), cellX, cellZ, fancyClouds, radiusCells);
this.quadCount = view.data().position() / 3;
}
}
if (this.quadCount != 0) {
try (GpuBuffer.MappedView view = RenderSystem.getDevice().createCommandEncoder().mapBuffer(this.ubo.currentBuffer(), false, true)) {
Std140Builder.intoBuffer(view.data())
.putVec4(ARGB.vector4fFromARGB32(color))
.putVec3(-xInCell, relativeBottomY, -zInCell)
.putVec3(12.0F, 4.0F, 12.0F);
}
GpuBufferSlice dynamicTransforms = RenderSystem.getDynamicUniforms()
.writeTransform(RenderSystem.getModelViewMatrix(), new Vector4f(1.0F, 1.0F, 1.0F, 1.0F), new Vector3f(), new Matrix4f());
RenderTarget mainRenderTarget = Minecraft.getInstance().getMainRenderTarget();
RenderTarget cloudTarget = Minecraft.getInstance().levelRenderer.getCloudsTarget();
RenderSystem.AutoStorageIndexBuffer indices = RenderSystem.getSequentialBuffer(VertexFormat.Mode.QUADS);
GpuBuffer indexBuffer = indices.getBuffer(6 * this.quadCount);
GpuTextureView colorTexture;
GpuTextureView depthTexture;
if (cloudTarget != null) {
colorTexture = cloudTarget.getColorTextureView();
depthTexture = cloudTarget.getDepthTextureView();
} else {
colorTexture = mainRenderTarget.getColorTextureView();
depthTexture = mainRenderTarget.getDepthTextureView();
}
try (RenderPass renderPass = RenderSystem.getDevice()
.createCommandEncoder()
.createRenderPass(() -> "Clouds", colorTexture, OptionalInt.empty(), depthTexture, OptionalDouble.empty())) {
renderPass.setPipeline(renderPipeline);
RenderSystem.bindDefaultUniforms(renderPass);
renderPass.setUniform("DynamicTransforms", dynamicTransforms);
renderPass.setIndexBuffer(indexBuffer, indices.type());
renderPass.setUniform("CloudInfo", this.ubo.currentBuffer());
renderPass.setUniform("CloudFaces", this.utb.currentBuffer());
renderPass.drawIndexed(0, 0, 6 * this.quadCount, 1);
}
}
}
}
private void buildMesh(
CloudRenderer.RelativeCameraPos relativePos, ByteBuffer faceBuffer, int centerCellX, int centerCellZ, boolean extrude, int radiusCells
) {
if (this.texture != null) {
long[] cells = this.texture.cells;
int textureWidth = this.texture.width;
int textureHeight = this.texture.height;
for (int ring = 0; ring <= 2 * radiusCells; ring++) {
for (int relativeCellX = -ring; relativeCellX <= ring; relativeCellX++) {
int relativeCellZ = ring - Math.abs(relativeCellX);
if (relativeCellZ >= 0
&& relativeCellZ <= radiusCells
&& relativeCellX * relativeCellX + relativeCellZ * relativeCellZ <= radiusCells * radiusCells) {
if (relativeCellZ != 0) {
this.tryBuildCell(
relativePos, faceBuffer, centerCellX, centerCellZ, extrude, relativeCellX, textureWidth, -relativeCellZ, textureHeight, cells
);
}
this.tryBuildCell(
relativePos, faceBuffer, centerCellX, centerCellZ, extrude, relativeCellX, textureWidth, relativeCellZ, textureHeight, cells
);
}
}
}
}
}
private void tryBuildCell(
CloudRenderer.RelativeCameraPos relativePos,
ByteBuffer faceBuffer,
int cellX,
int cellZ,
boolean extrude,
int relativeCellX,
int textureWidth,
int relativeCellZ,
int textureHeight,
long[] cells
) {
int indexX = Math.floorMod(cellX + relativeCellX, textureWidth);
int indexY = Math.floorMod(cellZ + relativeCellZ, textureHeight);
long cellData = cells[indexX + indexY * textureWidth];
if (cellData != 0L) {
if (extrude) {
this.buildExtrudedCell(relativePos, faceBuffer, relativeCellX, relativeCellZ, cellData);
} else {
this.buildFlatCell(faceBuffer, relativeCellX, relativeCellZ);
}
}
}
private void buildFlatCell(ByteBuffer faceBuffer, int x, int z) {
this.encodeFace(faceBuffer, x, z, Direction.DOWN, 32);
}
private void encodeFace(ByteBuffer faceBuffer, int x, int z, Direction direction, int flags) {
int dirAndFlags = direction.get3DDataValue() | flags;
dirAndFlags |= (x & 1) << 7;
dirAndFlags |= (z & 1) << 6;
faceBuffer.put((byte)(x >> 1)).put((byte)(z >> 1)).put((byte)dirAndFlags);
}
private void buildExtrudedCell(CloudRenderer.RelativeCameraPos relativePos, ByteBuffer faceBuffer, int x, int z, long cellData) {
if (relativePos != CloudRenderer.RelativeCameraPos.BELOW_CLOUDS) {
this.encodeFace(faceBuffer, x, z, Direction.UP, 0);
}
if (relativePos != CloudRenderer.RelativeCameraPos.ABOVE_CLOUDS) {
this.encodeFace(faceBuffer, x, z, Direction.DOWN, 0);
}
if (isNorthEmpty(cellData) && z > 0) {
this.encodeFace(faceBuffer, x, z, Direction.NORTH, 0);
}
if (isSouthEmpty(cellData) && z < 0) {
this.encodeFace(faceBuffer, x, z, Direction.SOUTH, 0);
}
if (isWestEmpty(cellData) && x > 0) {
this.encodeFace(faceBuffer, x, z, Direction.WEST, 0);
}
if (isEastEmpty(cellData) && x < 0) {
this.encodeFace(faceBuffer, x, z, Direction.EAST, 0);
}
boolean addInteriorFaces = Math.abs(x) <= 1 && Math.abs(z) <= 1;
if (addInteriorFaces) {
for (Direction direction : Direction.values()) {
this.encodeFace(faceBuffer, x, z, direction, 16);
}
}
}
public void markForRebuild() {
this.needsRebuild = true;
}
public void endFrame() {
this.ubo.rotate();
}
@Override
public void close() {
this.ubo.close();
if (this.utb != null) {
this.utb.close();
}
}
@OnlyIn(Dist.CLIENT)
private static enum RelativeCameraPos {
ABOVE_CLOUDS,
INSIDE_CLOUDS,
BELOW_CLOUDS;
}
@OnlyIn(Dist.CLIENT)
public record TextureData(long[] cells, int width, int height) {
}
}引用的其他类
-
- 引用位置:
方法调用 - 关联成员:
Std140Builder.intoBuffer()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
Std140SizeCalculator()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
NativeImage.read()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
RenderSystem.bindDefaultUniforms(), RenderSystem.getDevice(), RenderSystem.getDynamicUniforms(), RenderSystem.getModelViewMatrix(), RenderSystem.getSequentialBuffer()
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Minecraft.getInstance()
- 引用位置:
-
- 引用位置:
字段/构造调用 - 关联成员:
MappableRingBuffer()
- 引用位置:
-
- 引用位置:
参数/方法调用 - 关联成员:
Direction.values()
- 引用位置:
-
- 引用位置:
字段/方法调用 - 关联成员:
Identifier.withDefaultNamespace()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
SimplePreparableReloadListener
- 引用位置:
继承
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
ARGB.alpha(), ARGB.vector4fFromARGB32()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Mth.ceil(), Mth.floor()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置: