WeatherEffectRenderer.java
net.minecraft.client.renderer.WeatherEffectRenderer
信息
- 全限定名:net.minecraft.client.renderer.WeatherEffectRenderer
- 类型:public class
- 包:net.minecraft.client.renderer
- 源码路径:src/main/java/net/minecraft/client/renderer/WeatherEffectRenderer.java
- 起始行号:L57
- 职责:
TODO
字段/常量
-
RAIN_PARTICLES_PER_BLOCK- 类型:
float - 修饰符:
private static final - 源码定位:
L58 - 说明:
TODO
- 类型:
-
RAIN_RADIUS- 类型:
int - 修饰符:
private static final - 源码定位:
L59 - 说明:
TODO
- 类型:
-
RAIN_LOCATION- 类型:
Identifier - 修饰符:
private static final - 源码定位:
L60 - 说明:
TODO
- 类型:
-
SNOW_LOCATION- 类型:
Identifier - 修饰符:
private static final - 源码定位:
L61 - 说明:
TODO
- 类型:
-
RAIN_TABLE_SIZE- 类型:
int - 修饰符:
private static final - 源码定位:
L62 - 说明:
TODO
- 类型:
-
HALF_RAIN_TABLE_SIZE- 类型:
int - 修饰符:
private static final - 源码定位:
L63 - 说明:
TODO
- 类型:
-
INDICES_PER_COLUMN- 类型:
int - 修饰符:
private static final - 源码定位:
L64 - 说明:
TODO
- 类型:
-
rainSoundTime- 类型:
int - 修饰符:
private - 源码定位:
L65 - 说明:
TODO
- 类型:
-
columnSizeX- 类型:
float[] - 修饰符:
private final - 源码定位:
L66 - 说明:
TODO
- 类型:
-
columnSizeZ- 类型:
float[] - 修饰符:
private final - 源码定位:
L67 - 说明:
TODO
- 类型:
内部类/嵌套类型
net.minecraft.client.renderer.WeatherEffectRenderer.ColumnInstance- 类型:
record - 修饰符:
public - 源码定位:
L290 - 说明:
TODO
- 类型:
构造器
public WeatherEffectRenderer() @ L69
- 构造器名:WeatherEffectRenderer
- 源码定位:L69
- 修饰符:public
参数:
- 无
说明:
TODO
方法
下面的方法块按源码顺序生成。
public void extractRenderState(Level level, int ticks, float partialTicks, Vec3 cameraPos, WeatherRenderState renderState) @ L81
- 方法名:extractRenderState
- 源码定位:L81
- 返回类型:void
- 修饰符:public
参数:
- level: Level
- ticks: int
- partialTicks: float
- cameraPos: Vec3
- renderState: WeatherRenderState
说明:
TODO
private void renderWeather(RenderPass renderPass, AbstractTexture texture, int startColumn, int columnCount) @ L115
- 方法名:renderWeather
- 源码定位:L115
- 返回类型:void
- 修饰符:private
参数:
- renderPass: RenderPass
- texture: AbstractTexture
- startColumn: int
- columnCount: int
说明:
TODO
public void render(Vec3 cameraPos, WeatherRenderState renderState) @ L120
- 方法名:render
- 源码定位:L120
- 返回类型:void
- 修饰符:public
参数:
- cameraPos: Vec3
- renderState: WeatherRenderState
说明:
TODO
private WeatherEffectRenderer.ColumnInstance createRainColumnInstance(RandomSource random, int ticks, int x, int bottomY, int topY, int z, int lightCoords, float partialTicks) @ L167
- 方法名:createRainColumnInstance
- 源码定位:L167
- 返回类型:WeatherEffectRenderer.ColumnInstance
- 修饰符:private
参数:
- random: RandomSource
- ticks: int
- x: int
- bottomY: int
- topY: int
- z: int
- lightCoords: int
- partialTicks: float
说明:
TODO
private WeatherEffectRenderer.ColumnInstance createSnowColumnInstance(RandomSource random, int ticks, int x, int bottomY, int topY, int z, int lightCoords, float partialTicks) @ L178
- 方法名:createSnowColumnInstance
- 源码定位:L178
- 返回类型:WeatherEffectRenderer.ColumnInstance
- 修饰符:private
参数:
- random: RandomSource
- ticks: int
- x: int
- bottomY: int
- topY: int
- z: int
- lightCoords: int
- partialTicks: float
说明:
TODO
private void renderInstances(VertexConsumer builder, List<WeatherEffectRenderer.ColumnInstance> columns, Vec3 cameraPos, float maxAlpha, int radius, float intensity) @ L189
- 方法名:renderInstances
- 源码定位:L189
- 返回类型:void
- 修饰符:private
参数:
- builder: VertexConsumer
- columns: List<WeatherEffectRenderer.ColumnInstance>
- cameraPos: Vec3
- maxAlpha: float
- radius: int
- intensity: float
说明:
TODO
public void tickRainParticles(ClientLevel level, Camera camera, int ticks, ParticleStatus particleStatus, int weatherRadius) @ L222
- 方法名:tickRainParticles
- 源码定位:L222
- 返回类型:void
- 修饰符:public
参数:
- level: ClientLevel
- camera: Camera
- ticks: int
- particleStatus: ParticleStatus
- weatherRadius: int
说明:
TODO
private Biome.Precipitation getPrecipitationAt(Level level, BlockPos pos) @ L280
- 方法名:getPrecipitationAt
- 源码定位:L280
- 返回类型:Biome.Precipitation
- 修饰符:private
参数:
- level: Level
- pos: BlockPos
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class WeatherEffectRenderer {
private static final float RAIN_PARTICLES_PER_BLOCK = 0.225F;
private static final int RAIN_RADIUS = 10;
private static final Identifier RAIN_LOCATION = Identifier.withDefaultNamespace("textures/environment/rain.png");
private static final Identifier SNOW_LOCATION = Identifier.withDefaultNamespace("textures/environment/snow.png");
private static final int RAIN_TABLE_SIZE = 32;
private static final int HALF_RAIN_TABLE_SIZE = 16;
private static final int INDICES_PER_COLUMN = 6;
private int rainSoundTime;
private final float[] columnSizeX = new float[1024];
private final float[] columnSizeZ = new float[1024];
public WeatherEffectRenderer() {
for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
float deltaX = x - 16;
float deltaZ = z - 16;
float distance = Mth.length(deltaX, deltaZ);
this.columnSizeX[z * 32 + x] = -deltaZ / distance;
this.columnSizeZ[z * 32 + x] = deltaX / distance;
}
}
}
public void extractRenderState(Level level, int ticks, float partialTicks, Vec3 cameraPos, WeatherRenderState renderState) {
renderState.intensity = level.getRainLevel(partialTicks);
if (!(renderState.intensity <= 0.0F)) {
renderState.radius = Minecraft.getInstance().options.weatherRadius().get();
int cameraBlockX = Mth.floor(cameraPos.x);
int cameraBlockY = Mth.floor(cameraPos.y);
int cameraBlockZ = Mth.floor(cameraPos.z);
BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
RandomSource random = RandomSource.createThreadLocalInstance();
for (int z = cameraBlockZ - renderState.radius; z <= cameraBlockZ + renderState.radius; z++) {
for (int x = cameraBlockX - renderState.radius; x <= cameraBlockX + renderState.radius; x++) {
int terrainHeight = level.getHeight(Heightmap.Types.MOTION_BLOCKING, x, z);
int y0 = Math.max(cameraBlockY - renderState.radius, terrainHeight);
int y1 = Math.max(cameraBlockY + renderState.radius, terrainHeight);
if (y1 - y0 != 0) {
Biome.Precipitation precipitation = this.getPrecipitationAt(level, mutablePos.set(x, cameraBlockY, z));
if (precipitation != Biome.Precipitation.NONE) {
int seed = x * x * 3121 + x * 45238971 ^ z * z * 418711 + z * 13761;
random.setSeed(seed);
int lightSampleY = Math.max(cameraBlockY, terrainHeight);
int lightCoords = LevelRenderer.getLightCoords(level, mutablePos.set(x, lightSampleY, z));
if (precipitation == Biome.Precipitation.RAIN) {
renderState.rainColumns.add(this.createRainColumnInstance(random, ticks, x, y0, y1, z, lightCoords, partialTicks));
} else if (precipitation == Biome.Precipitation.SNOW) {
renderState.snowColumns.add(this.createSnowColumnInstance(random, ticks, x, y0, y1, z, lightCoords, partialTicks));
}
}
}
}
}
}
}
private void renderWeather(RenderPass renderPass, AbstractTexture texture, int startColumn, int columnCount) {
renderPass.bindTexture("Sampler0", texture.getTextureView(), texture.getSampler());
renderPass.drawIndexed(0, startColumn * 6, columnCount * 6, 1);
}
public void render(Vec3 cameraPos, WeatherRenderState renderState) {
int columnCount = renderState.rainColumns.size() + renderState.snowColumns.size();
if (columnCount != 0) {
TextureManager textureManager = Minecraft.getInstance().getTextureManager();
AbstractTexture rainTexture = textureManager.getTexture(RAIN_LOCATION);
AbstractTexture snowTexture = textureManager.getTexture(SNOW_LOCATION);
RenderTarget weatherRenderTarget = OutputTarget.WEATHER_TARGET.getRenderTarget();
GpuTextureView colorTexture = weatherRenderTarget.getColorTextureView();
GpuTextureView depthTexture = weatherRenderTarget.getDepthTextureView();
RenderPipeline renderPipeline = Minecraft.useShaderTransparency() ? RenderPipelines.WEATHER_DEPTH_WRITE : RenderPipelines.WEATHER_NO_DEPTH_WRITE;
GpuBuffer vertexBuffer;
GpuBuffer indexBuffer;
VertexFormat.IndexType indexType;
try (ByteBufferBuilder builder = ByteBufferBuilder.exactlySized(columnCount * DefaultVertexFormat.PARTICLE.getVertexSize() * 4)) {
BufferBuilder bufferBuilder = new BufferBuilder(builder, VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE);
this.renderInstances(bufferBuilder, renderState.rainColumns, cameraPos, 1.0F, renderState.radius, renderState.intensity);
this.renderInstances(bufferBuilder, renderState.snowColumns, cameraPos, 0.8F, renderState.radius, renderState.intensity);
try (MeshData mesh = bufferBuilder.buildOrThrow()) {
vertexBuffer = renderPipeline.getVertexFormat().uploadImmediateVertexBuffer(mesh.vertexBuffer());
RenderSystem.AutoStorageIndexBuffer autoIndices = RenderSystem.getSequentialBuffer(mesh.drawState().mode());
indexBuffer = autoIndices.getBuffer(mesh.drawState().indexCount());
indexType = autoIndices.type();
}
}
GpuBufferSlice dynamicTransforms = RenderSystem.getDynamicUniforms()
.writeTransform(RenderSystem.getModelViewMatrix(), new Vector4f(1.0F, 1.0F, 1.0F, 1.0F), new Vector3f(), new Matrix4f());
try (RenderPass renderPass = RenderSystem.getDevice()
.createCommandEncoder()
.createRenderPass(() -> "Weather Effect", colorTexture, OptionalInt.empty(), depthTexture, OptionalDouble.empty())) {
renderPass.setPipeline(renderPipeline);
RenderSystem.bindDefaultUniforms(renderPass);
renderPass.setUniform("DynamicTransforms", dynamicTransforms);
renderPass.bindTexture(
"Sampler2", Minecraft.getInstance().gameRenderer.lightmap(), RenderSystem.getSamplerCache().getClampToEdge(FilterMode.LINEAR)
);
renderPass.setIndexBuffer(indexBuffer, indexType);
renderPass.setVertexBuffer(0, vertexBuffer);
this.renderWeather(renderPass, rainTexture, 0, renderState.rainColumns.size());
this.renderWeather(renderPass, snowTexture, renderState.rainColumns.size(), renderState.snowColumns.size());
}
}
}
private WeatherEffectRenderer.ColumnInstance createRainColumnInstance(
RandomSource random, int ticks, int x, int bottomY, int topY, int z, int lightCoords, float partialTicks
) {
int wrappedTicks = ticks & 131071;
int tickOffset = x * x * 3121 + x * 45238971 + z * z * 418711 + z * 13761 & 0xFF;
float blockPosRainSpeed = 3.0F + random.nextFloat();
float textureOffset = -(wrappedTicks + tickOffset + partialTicks) / 32.0F * blockPosRainSpeed;
float wrappedTextureOffset = textureOffset % 32.0F;
return new WeatherEffectRenderer.ColumnInstance(x, z, bottomY, topY, 0.0F, wrappedTextureOffset, lightCoords);
}
private WeatherEffectRenderer.ColumnInstance createSnowColumnInstance(
RandomSource random, int ticks, int x, int bottomY, int topY, int z, int lightCoords, float partialTicks
) {
float time = ticks + partialTicks;
float u = (float)(random.nextDouble() + time * 0.01F * (float)random.nextGaussian());
float v = (float)(random.nextDouble() + time * (float)random.nextGaussian() * 0.001F);
float vOffset = -((ticks & 511) + partialTicks) / 512.0F;
int brightenedLightCoords = LightCoordsUtil.pack((LightCoordsUtil.block(lightCoords) * 3 + 15) / 4, (LightCoordsUtil.sky(lightCoords) * 3 + 15) / 4);
return new WeatherEffectRenderer.ColumnInstance(x, z, bottomY, topY, u, vOffset + v, brightenedLightCoords);
}
private void renderInstances(
VertexConsumer builder, List<WeatherEffectRenderer.ColumnInstance> columns, Vec3 cameraPos, float maxAlpha, int radius, float intensity
) {
if (!columns.isEmpty()) {
float radiusSq = radius * radius;
for (WeatherEffectRenderer.ColumnInstance column : columns) {
float relativeX = (float)(column.x + 0.5 - cameraPos.x);
float relativeZ = (float)(column.z + 0.5 - cameraPos.z);
float distanceSq = (float)Mth.lengthSquared(relativeX, relativeZ);
float alpha = Mth.lerp(Math.min(distanceSq / radiusSq, 1.0F), maxAlpha, 0.5F) * intensity;
int color = ARGB.white(alpha);
int index = (column.z - Mth.floor(cameraPos.z) + 16) * 32 + column.x - Mth.floor(cameraPos.x) + 16;
float halfSizeX = this.columnSizeX[index] / 2.0F;
float halfSizeZ = this.columnSizeZ[index] / 2.0F;
float x0 = relativeX - halfSizeX;
float x1 = relativeX + halfSizeX;
float y1 = (float)(column.topY - cameraPos.y);
float y0 = (float)(column.bottomY - cameraPos.y);
float z0 = relativeZ - halfSizeZ;
float z1 = relativeZ + halfSizeZ;
float u0 = column.uOffset + 0.0F;
float u1 = column.uOffset + 1.0F;
float v0 = column.bottomY * 0.25F + column.vOffset;
float v1 = column.topY * 0.25F + column.vOffset;
builder.addVertex(x0, y1, z0).setUv(u0, v0).setColor(color).setLight(column.lightCoords);
builder.addVertex(x1, y1, z1).setUv(u1, v0).setColor(color).setLight(column.lightCoords);
builder.addVertex(x1, y0, z1).setUv(u1, v1).setColor(color).setLight(column.lightCoords);
builder.addVertex(x0, y0, z0).setUv(u0, v1).setColor(color).setLight(column.lightCoords);
}
}
}
public void tickRainParticles(ClientLevel level, Camera camera, int ticks, ParticleStatus particleStatus, int weatherRadius) {
float rainLevel = level.getRainLevel(1.0F);
if (!(rainLevel <= 0.0F)) {
RandomSource random = RandomSource.createThreadLocalInstance(ticks * 312987231L);
BlockPos cameraPosition = BlockPos.containing(camera.position());
BlockPos rainParticlePosition = null;
int weatherDiameter = 2 * weatherRadius + 1;
int weatherArea = weatherDiameter * weatherDiameter;
int rainParticles = (int)(0.225F * weatherArea * rainLevel * rainLevel) / (particleStatus == ParticleStatus.DECREASED ? 2 : 1);
for (int ii = 0; ii < rainParticles; ii++) {
int x = random.nextInt(weatherDiameter) - weatherRadius;
int z = random.nextInt(weatherDiameter) - weatherRadius;
BlockPos heightmapPosition = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, cameraPosition.offset(x, 0, z));
if (heightmapPosition.getY() > level.getMinY()
&& heightmapPosition.getY() <= cameraPosition.getY() + 10
&& heightmapPosition.getY() >= cameraPosition.getY() - 10
&& this.getPrecipitationAt(level, heightmapPosition) == Biome.Precipitation.RAIN) {
rainParticlePosition = heightmapPosition.below();
if (particleStatus == ParticleStatus.MINIMAL) {
break;
}
double blockX = random.nextDouble();
double blockZ = random.nextDouble();
BlockState block = level.getBlockState(rainParticlePosition);
FluidState fluid = level.getFluidState(rainParticlePosition);
VoxelShape blockShape = block.getCollisionShape(level, rainParticlePosition);
double blockTop = blockShape.max(Direction.Axis.Y, blockX, blockZ);
double fluidTop = fluid.getHeight(level, rainParticlePosition);
double particleY = Math.max(blockTop, fluidTop);
ParticleOptions particleType = !fluid.is(FluidTags.LAVA) && !block.is(Blocks.MAGMA_BLOCK) && !CampfireBlock.isLitCampfire(block)
? ParticleTypes.RAIN
: ParticleTypes.SMOKE;
level.addParticle(
particleType,
rainParticlePosition.getX() + blockX,
rainParticlePosition.getY() + particleY,
rainParticlePosition.getZ() + blockZ,
0.0,
0.0,
0.0
);
}
}
if (rainParticlePosition != null && random.nextInt(3) < this.rainSoundTime++) {
this.rainSoundTime = 0;
if (rainParticlePosition.getY() > cameraPosition.getY() + 1
&& level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, cameraPosition).getY() > Mth.floor((float)cameraPosition.getY())) {
level.playLocalSound(rainParticlePosition, SoundEvents.WEATHER_RAIN_ABOVE, SoundSource.WEATHER, 0.1F, 0.5F, false);
} else {
level.playLocalSound(rainParticlePosition, SoundEvents.WEATHER_RAIN, SoundSource.WEATHER, 0.2F, 1.0F, false);
}
}
}
}
private Biome.Precipitation getPrecipitationAt(Level level, BlockPos pos) {
if (!level.getChunkSource().hasChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()))) {
return Biome.Precipitation.NONE;
} else {
Biome biome = level.getBiome(pos).value();
return biome.getPrecipitationAt(pos, level.getSeaLevel());
}
}
@OnlyIn(Dist.CLIENT)
public record ColumnInstance(int x, int z, int bottomY, int topY, float uOffset, float vOffset, int lightCoords) {
}
}引用的其他类
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
RenderSystem.bindDefaultUniforms(), RenderSystem.getDevice(), RenderSystem.getDynamicUniforms(), RenderSystem.getModelViewMatrix(), RenderSystem.getSamplerCache(), RenderSystem.getSequentialBuffer()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
BufferBuilder()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
ByteBufferBuilder.exactlySized()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Minecraft.getInstance(), Minecraft.useShaderTransparency()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
LevelRenderer.getLightCoords()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/方法调用/构造调用 - 关联成员:
BlockPos.MutableBlockPos(), BlockPos.containing(), MutableBlockPos()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
SectionPos.blockToSectionCoord()
- 引用位置:
-
- 引用位置:
字段/方法调用 - 关联成员:
Identifier.withDefaultNamespace()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
ARGB.white()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
LightCoordsUtil.block(), LightCoordsUtil.pack(), LightCoordsUtil.sky()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Mth.floor(), Mth.length(), Mth.lengthSquared(), Mth.lerp()
- 引用位置:
-
- 引用位置:
参数/方法调用 - 关联成员:
RandomSource.createThreadLocalInstance()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
CampfireBlock.isLitCampfire()
- 引用位置:
-
- 引用位置:
参数
- 引用位置: