EntityRenderer.java

net.minecraft.client.renderer.entity.EntityRenderer

信息

  • 全限定名:net.minecraft.client.renderer.entity.EntityRenderer
  • 类型:public abstract class
  • 包:net.minecraft.client.renderer.entity
  • 源码路径:src/main/java/net/minecraft/client/renderer/entity/EntityRenderer.java
  • 起始行号:L37
  • 职责:

    TODO

字段/常量

  • SHADOW_POWER_FALLOFF_Y

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L38
    • 说明:

      TODO

  • MAX_SHADOW_RADIUS

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L39
    • 说明:

      TODO

  • NAMETAG_SCALE

    • 类型: float
    • 修饰符: public static final
    • 源码定位: L40
    • 说明:

      TODO

  • entityRenderDispatcher

    • 类型: EntityRenderDispatcher
    • 修饰符: protected final
    • 源码定位: L41
    • 说明:

      TODO

  • font

    • 类型: Font
    • 修饰符: private final
    • 源码定位: L42
    • 说明:

      TODO

  • shadowRadius

    • 类型: float
    • 修饰符: protected
    • 源码定位: L43
    • 说明:

      TODO

  • shadowStrength

    • 类型: float
    • 修饰符: protected
    • 源码定位: L44
    • 说明:

      TODO

内部类/嵌套类型

构造器

protected EntityRenderer(EntityRendererProvider.Context context) @ L46

  • 构造器名:EntityRenderer
  • 源码定位:L46
  • 修饰符:protected

参数:

  • context: EntityRendererProvider.Context

说明:

TODO

方法

下面的方法块按源码顺序生成。

public final int getPackedLightCoords(T entity, float partialTickTime) @ L51

  • 方法名:getPackedLightCoords
  • 源码定位:L51
  • 返回类型:int
  • 修饰符:public final

参数:

  • entity: T
  • partialTickTime: float

说明:

TODO

protected int getSkyLightLevel(T entity, BlockPos blockPos) @ L56

  • 方法名:getSkyLightLevel
  • 源码定位:L56
  • 返回类型:int
  • 修饰符:protected

参数:

  • entity: T
  • blockPos: BlockPos

说明:

TODO

protected int getBlockLightLevel(T entity, BlockPos blockPos) @ L60

  • 方法名:getBlockLightLevel
  • 源码定位:L60
  • 返回类型:int
  • 修饰符:protected

参数:

  • entity: T
  • blockPos: BlockPos

说明:

TODO

public boolean shouldRender(T entity, Frustum culler, double camX, double camY, double camZ) @ L64

  • 方法名:shouldRender
  • 源码定位:L64
  • 返回类型:boolean
  • 修饰符:public

参数:

  • entity: T
  • culler: Frustum
  • camX: double
  • camY: double
  • camZ: double

说明:

TODO

protected AABB getBoundingBoxForCulling(T entity) @ L93

  • 方法名:getBoundingBoxForCulling
  • 源码定位:L93
  • 返回类型:AABB
  • 修饰符:protected

参数:

  • entity: T

说明:

TODO

protected boolean affectedByCulling(T entity) @ L97

  • 方法名:affectedByCulling
  • 源码定位:L97
  • 返回类型:boolean
  • 修饰符:protected

参数:

  • entity: T

说明:

TODO

public Vec3 getRenderOffset(S state) @ L101

  • 方法名:getRenderOffset
  • 源码定位:L101
  • 返回类型:Vec3
  • 修饰符:public

参数:

  • state: S

说明:

TODO

public void submit(S state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState camera) @ L105

  • 方法名:submit
  • 源码定位:L105
  • 返回类型:void
  • 修饰符:public

参数:

  • state: S
  • poseStack: PoseStack
  • submitNodeCollector: SubmitNodeCollector
  • camera: CameraRenderState

说明:

TODO

protected boolean shouldShowName(T entity, double distanceToCameraSq) @ L115

  • 方法名:shouldShowName
  • 源码定位:L115
  • 返回类型:boolean
  • 修饰符:protected

参数:

  • entity: T
  • distanceToCameraSq: double

说明:

TODO

public Font getFont() @ L119

  • 方法名:getFont
  • 源码定位:L119
  • 返回类型:Font
  • 修饰符:public

参数:

说明:

TODO

protected void submitNameDisplay(S state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState camera) @ L123

  • 方法名:submitNameDisplay
  • 源码定位:L123
  • 返回类型:void
  • 修饰符:protected

参数:

  • state: S
  • poseStack: PoseStack
  • submitNodeCollector: SubmitNodeCollector
  • camera: CameraRenderState

说明:

TODO

protected final <S extends EntityRenderState> void submitNameDisplay(S state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState camera, int offset) @ L127

  • 方法名:submitNameDisplay
  • 源码定位:L127
  • 返回类型: void
  • 修饰符:protected final

参数:

  • state: S
  • poseStack: PoseStack
  • submitNodeCollector: SubmitNodeCollector
  • camera: CameraRenderState
  • offset: int

说明:

TODO

protected Component getNameTag(T entity) @ L147

  • 方法名:getNameTag
  • 源码定位:L147
  • 返回类型:Component
  • 修饰符:protected

参数:

  • entity: T

说明:

TODO

protected float getShadowRadius(S state) @ L151

  • 方法名:getShadowRadius
  • 源码定位:L151
  • 返回类型:float
  • 修饰符:protected

参数:

  • state: S

说明:

TODO

protected float getShadowStrength(S state) @ L155

  • 方法名:getShadowStrength
  • 源码定位:L155
  • 返回类型:float
  • 修饰符:protected

参数:

  • state: S

说明:

TODO

public abstract S createRenderState() @ L159

  • 方法名:createRenderState
  • 源码定位:L159
  • 返回类型:S
  • 修饰符:public abstract

参数:

说明:

TODO

public final S createRenderState(T entity, float partialTicks) @ L161

  • 方法名:createRenderState
  • 源码定位:L161
  • 返回类型:S
  • 修饰符:public final

参数:

  • entity: T
  • partialTicks: float

说明:

TODO

public void extractRenderState(T entity, S state, float partialTicks) @ L168

  • 方法名:extractRenderState
  • 源码定位:L168
  • 返回类型:void
  • 修饰符:public

参数:

  • entity: T
  • state: S
  • partialTicks: float

说明:

TODO

protected void finalizeRenderState(T entity, S state) @ L279

  • 方法名:finalizeRenderState
  • 源码定位:L279
  • 返回类型:void
  • 修饰符:protected

参数:

  • entity: T
  • state: S

说明:

TODO

private void extractShadow(S state, Minecraft minecraft, Level level) @ L285

  • 方法名:extractShadow
  • 源码定位:L285
  • 返回类型:void
  • 修饰符:private

参数:

  • state: S
  • minecraft: Minecraft
  • level: Level

说明:

TODO

private void extractShadowPiece(S state, Level level, float pow, BlockPos.MutableBlockPos pos, ChunkAccess chunk) @ L321

  • 方法名:extractShadowPiece
  • 源码定位:L321
  • 返回类型:void
  • 修饰符:private

参数:

  • state: S
  • level: Level
  • pow: float
  • pos: BlockPos.MutableBlockPos
  • chunk: ChunkAccess

说明:

TODO

private static Entity getServerSideEntity(Entity entity) @ L342

  • 方法名:getServerSideEntity
  • 源码定位:L342
  • 返回类型:Entity
  • 修饰符:private static

参数:

  • entity: Entity

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public abstract class EntityRenderer<T extends Entity, S extends EntityRenderState> {
    private static final float SHADOW_POWER_FALLOFF_Y = 0.5F;
    private static final float MAX_SHADOW_RADIUS = 32.0F;
    public static final float NAMETAG_SCALE = 0.025F;
    protected final EntityRenderDispatcher entityRenderDispatcher;
    private final Font font;
    protected float shadowRadius;
    protected float shadowStrength = 1.0F;
 
    protected EntityRenderer(EntityRendererProvider.Context context) {
        this.entityRenderDispatcher = context.getEntityRenderDispatcher();
        this.font = context.getFont();
    }
 
    public final int getPackedLightCoords(T entity, float partialTickTime) {
        BlockPos blockPos = BlockPos.containing(entity.getLightProbePosition(partialTickTime));
        return LightCoordsUtil.pack(this.getBlockLightLevel(entity, blockPos), this.getSkyLightLevel(entity, blockPos));
    }
 
    protected int getSkyLightLevel(T entity, BlockPos blockPos) {
        return entity.level().getBrightness(LightLayer.SKY, blockPos);
    }
 
    protected int getBlockLightLevel(T entity, BlockPos blockPos) {
        return entity.isOnFire() ? 15 : entity.level().getBrightness(LightLayer.BLOCK, blockPos);
    }
 
    public boolean shouldRender(T entity, Frustum culler, double camX, double camY, double camZ) {
        if (!entity.shouldRender(camX, camY, camZ)) {
            return false;
        } else if (!this.affectedByCulling(entity)) {
            return true;
        } else {
            AABB boundingBox = this.getBoundingBoxForCulling(entity).inflate(0.5);
            if (boundingBox.hasNaN() || boundingBox.getSize() == 0.0) {
                boundingBox = new AABB(
                    entity.getX() - 2.0, entity.getY() - 2.0, entity.getZ() - 2.0, entity.getX() + 2.0, entity.getY() + 2.0, entity.getZ() + 2.0
                );
            }
 
            if (culler.isVisible(boundingBox)) {
                return true;
            } else {
                if (entity instanceof Leashable leashable) {
                    Entity leashHolder = leashable.getLeashHolder();
                    if (leashHolder != null) {
                        AABB leasherBox = this.entityRenderDispatcher.getRenderer(leashHolder).getBoundingBoxForCulling(leashHolder);
                        return culler.isVisible(leasherBox) || culler.isVisible(boundingBox.minmax(leasherBox));
                    }
                }
 
                return false;
            }
        }
    }
 
    protected AABB getBoundingBoxForCulling(T entity) {
        return entity.getBoundingBox();
    }
 
    protected boolean affectedByCulling(T entity) {
        return true;
    }
 
    public Vec3 getRenderOffset(S state) {
        return state.passengerOffset != null ? state.passengerOffset : Vec3.ZERO;
    }
 
    public void submit(S state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState camera) {
        if (state.leashStates != null) {
            for (EntityRenderState.LeashState leashState : state.leashStates) {
                submitNodeCollector.submitLeash(poseStack, leashState);
            }
        }
 
        this.submitNameDisplay(state, poseStack, submitNodeCollector, camera);
    }
 
    protected boolean shouldShowName(T entity, double distanceToCameraSq) {
        return entity.shouldShowName() || entity.hasCustomName() && entity == this.entityRenderDispatcher.crosshairPickEntity;
    }
 
    public Font getFont() {
        return this.font;
    }
 
    protected void submitNameDisplay(S state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState camera) {
        this.submitNameDisplay(state, poseStack, submitNodeCollector, camera, 0);
    }
 
    protected final <S extends EntityRenderState> void submitNameDisplay(
        S state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState camera, int offset
    ) {
        poseStack.pushPose();
        if (state.scoreText != null) {
            submitNodeCollector.submitNameTag(
                poseStack, state.nameTagAttachment, offset, state.scoreText, !state.isDiscrete, state.lightCoords, state.distanceToCameraSq, camera
            );
            poseStack.translate(0.0F, 9.0F * 1.15F * 0.025F, 0.0F);
        }
 
        if (state.nameTag != null) {
            submitNodeCollector.submitNameTag(
                poseStack, state.nameTagAttachment, offset, state.nameTag, !state.isDiscrete, state.lightCoords, state.distanceToCameraSq, camera
            );
        }
 
        poseStack.popPose();
    }
 
    protected @Nullable Component getNameTag(T entity) {
        return entity.getDisplayName();
    }
 
    protected float getShadowRadius(S state) {
        return this.shadowRadius;
    }
 
    protected float getShadowStrength(S state) {
        return this.shadowStrength;
    }
 
    public abstract S createRenderState();
 
    public final S createRenderState(T entity, float partialTicks) {
        S state = this.createRenderState();
        this.extractRenderState(entity, state, partialTicks);
        this.finalizeRenderState(entity, state);
        return state;
    }
 
    public void extractRenderState(T entity, S state, float partialTicks) {
        state.entityType = entity.getType();
        state.x = Mth.lerp((double)partialTicks, entity.xOld, entity.getX());
        state.y = Mth.lerp((double)partialTicks, entity.yOld, entity.getY());
        state.z = Mth.lerp((double)partialTicks, entity.zOld, entity.getZ());
        state.isInvisible = entity.isInvisible();
        state.ageInTicks = entity.tickCount + partialTicks;
        state.boundingBoxWidth = entity.getBbWidth();
        state.boundingBoxHeight = entity.getBbHeight();
        state.eyeHeight = entity.getEyeHeight();
        if (entity.isPassenger()
            && entity.getVehicle() instanceof AbstractMinecart minecart
            && minecart.getBehavior() instanceof NewMinecartBehavior behavior
            && behavior.cartHasPosRotLerp()) {
            double cartLerpX = Mth.lerp((double)partialTicks, minecart.xOld, minecart.getX());
            double cartLerpY = Mth.lerp((double)partialTicks, minecart.yOld, minecart.getY());
            double cartLerpZ = Mth.lerp((double)partialTicks, minecart.zOld, minecart.getZ());
            state.passengerOffset = behavior.getCartLerpPosition(partialTicks).subtract(new Vec3(cartLerpX, cartLerpY, cartLerpZ));
        } else {
            state.passengerOffset = null;
        }
 
        if (this.entityRenderDispatcher.camera != null) {
            state.distanceToCameraSq = this.entityRenderDispatcher.distanceToSqr(entity);
            boolean shouldShowName = state.distanceToCameraSq < 4096.0 && this.shouldShowName(entity, state.distanceToCameraSq);
            if (shouldShowName) {
                state.nameTag = this.getNameTag(entity);
                state.nameTagAttachment = entity.getAttachments().getNullable(EntityAttachment.NAME_TAG, 0, entity.getYRot(partialTicks));
            } else {
                state.nameTag = null;
            }
 
            if (state.distanceToCameraSq < 100.0) {
                state.scoreText = entity.belowNameDisplay();
            } else {
                state.scoreText = null;
            }
        }
 
        label77: {
            state.isDiscrete = entity.isDiscrete();
            Level level = entity.level();
            if (entity instanceof Leashable leashable) {
                Entity entityYRot = leashable.getLeashHolder();
                if (entityYRot instanceof Entity) {
                    float entityYRotx = entity.getPreciseBodyRotation(partialTicks) * (float) (Math.PI / 180.0);
                    Vec3 attachOffset = leashable.getLeashOffset(partialTicks);
                    BlockPos entityEyePos = BlockPos.containing(entity.getEyePosition(partialTicks));
                    BlockPos roperEyePos = BlockPos.containing(entityYRot.getEyePosition(partialTicks));
                    int startBlockLight = this.getBlockLightLevel(entity, entityEyePos);
                    int endBlockLight = this.entityRenderDispatcher.getRenderer(entityYRot).getBlockLightLevel(entityYRot, roperEyePos);
                    int startSkyLight = level.getBrightness(LightLayer.SKY, entityEyePos);
                    int endSkyLight = level.getBrightness(LightLayer.SKY, roperEyePos);
                    boolean quadConnection = entityYRot.supportQuadLeashAsHolder() && leashable.supportQuadLeash();
                    int leashCount = quadConnection ? 4 : 1;
                    if (state.leashStates == null || state.leashStates.size() != leashCount) {
                        state.leashStates = new ArrayList<>(leashCount);
 
                        for (int i = 0; i < leashCount; i++) {
                            state.leashStates.add(new EntityRenderState.LeashState());
                        }
                    }
 
                    if (quadConnection) {
                        float roperYRot = entityYRot.getPreciseBodyRotation(partialTicks) * (float) (Math.PI / 180.0);
                        Vec3 holderPos = entityYRot.getPosition(partialTicks);
                        Vec3[] leashableAttachmentPoints = leashable.getQuadLeashOffsets();
                        Vec3[] roperAttachmentPoints = entityYRot.getQuadLeashHolderOffsets();
                        int i = 0;
 
                        while (true) {
                            if (i >= leashCount) {
                                break label77;
                            }
 
                            EntityRenderState.LeashState leashState = state.leashStates.get(i);
                            leashState.offset = leashableAttachmentPoints[i].yRot(-entityYRotx);
                            leashState.start = entity.getPosition(partialTicks).add(leashState.offset);
                            leashState.end = holderPos.add(roperAttachmentPoints[i].yRot(-roperYRot));
                            leashState.startBlockLight = startBlockLight;
                            leashState.endBlockLight = endBlockLight;
                            leashState.startSkyLight = startSkyLight;
                            leashState.endSkyLight = endSkyLight;
                            leashState.slack = false;
                            i++;
                        }
                    } else {
                        Vec3 rotatedAttachOffset = attachOffset.yRot(-entityYRotx);
                        EntityRenderState.LeashState leashState = state.leashStates.getFirst();
                        leashState.offset = rotatedAttachOffset;
                        leashState.start = entity.getPosition(partialTicks).add(rotatedAttachOffset);
                        leashState.end = entityYRot.getRopeHoldPosition(partialTicks);
                        leashState.startBlockLight = startBlockLight;
                        leashState.endBlockLight = endBlockLight;
                        leashState.startSkyLight = startSkyLight;
                        leashState.endSkyLight = endSkyLight;
                        break label77;
                    }
                }
            }
 
            state.leashStates = null;
        }
 
        state.displayFireAnimation = entity.displayFireAnimation();
        Minecraft minecraft = Minecraft.getInstance();
        boolean appearsGlowing = minecraft.shouldEntityAppearGlowing(entity);
        state.outlineColor = appearsGlowing ? ARGB.opaque(entity.getTeamColor()) : 0;
        state.lightCoords = this.getPackedLightCoords(entity, partialTicks);
    }
 
    protected void finalizeRenderState(T entity, S state) {
        Minecraft minecraft = Minecraft.getInstance();
        Level level = entity.level();
        this.extractShadow(state, minecraft, level);
    }
 
    private void extractShadow(S state, Minecraft minecraft, Level level) {
        state.shadowPieces.clear();
        if (minecraft.options.entityShadows().get() && !state.isInvisible) {
            float shadowRadius = Math.min(this.getShadowRadius(state), 32.0F);
            state.shadowRadius = shadowRadius;
            if (shadowRadius > 0.0F) {
                double distSq = state.distanceToCameraSq;
                float pow = (float)((1.0 - distSq / 256.0) * this.getShadowStrength(state));
                if (pow > 0.0F) {
                    int x0 = Mth.floor(state.x - shadowRadius);
                    int x1 = Mth.floor(state.x + shadowRadius);
                    int z0 = Mth.floor(state.z - shadowRadius);
                    int z1 = Mth.floor(state.z + shadowRadius);
                    float depth = Math.min(pow / 0.5F - 1.0F, shadowRadius);
                    int y0 = Mth.floor(state.y - depth);
                    int y1 = Mth.floor(state.y);
                    BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
 
                    for (int z = z0; z <= z1; z++) {
                        for (int x = x0; x <= x1; x++) {
                            pos.set(x, 0, z);
                            ChunkAccess chunk = level.getChunk(pos);
 
                            for (int y = y0; y <= y1; y++) {
                                pos.setY(y);
                                this.extractShadowPiece(state, level, pow, pos, chunk);
                            }
                        }
                    }
                }
            }
        } else {
            state.shadowRadius = 0.0F;
        }
    }
 
    private void extractShadowPiece(S state, Level level, float pow, BlockPos.MutableBlockPos pos, ChunkAccess chunk) {
        float powerAtDepth = pow - (float)(state.y - pos.getY()) * 0.5F;
        BlockPos belowPos = pos.below();
        BlockState belowState = chunk.getBlockState(belowPos);
        if (belowState.getRenderShape() != RenderShape.INVISIBLE) {
            int brightness = level.getMaxLocalRawBrightness(pos);
            if (brightness > 3) {
                if (belowState.isCollisionShapeFullBlock(chunk, belowPos)) {
                    VoxelShape belowShape = belowState.getShape(chunk, belowPos);
                    if (!belowShape.isEmpty()) {
                        float alpha = Mth.clamp(powerAtDepth * 0.5F * Lightmap.getBrightness(level.dimensionType(), brightness), 0.0F, 1.0F);
                        float relativeX = (float)(pos.getX() - state.x);
                        float relativeY = (float)(pos.getY() - state.y);
                        float relativeZ = (float)(pos.getZ() - state.z);
                        state.shadowPieces.add(new EntityRenderState.ShadowPiece(relativeX, relativeY, relativeZ, belowShape, alpha));
                    }
                }
            }
        }
    }
 
    private static @Nullable Entity getServerSideEntity(Entity entity) {
        IntegratedServer server = Minecraft.getInstance().getSingleplayerServer();
        if (server != null) {
            ServerLevel level = server.getLevel(entity.level().dimension());
            if (level != null) {
                return level.getEntity(entity.getId());
            }
        }
 
        return null;
    }
}

引用的其他类

  • PoseStack

    • 引用位置: 参数
  • Minecraft

    • 引用位置: 参数/方法调用
    • 关联成员: Minecraft.getInstance()
  • Font

    • 引用位置: 字段/返回值
  • Lightmap

    • 引用位置: 方法调用
    • 关联成员: Lightmap.getBrightness()
  • SubmitNodeCollector

    • 引用位置: 参数
  • Frustum

    • 引用位置: 参数
  • EntityRenderDispatcher

    • 引用位置: 字段
  • EntityRendererProvider

    • 引用位置: 参数
  • EntityRenderState

    • 引用位置: 方法调用/构造调用/返回值
    • 关联成员: EntityRenderState.LeashState(), EntityRenderState.ShadowPiece(), LeashState(), ShadowPiece()
  • CameraRenderState

    • 引用位置: 参数
  • BlockPos

    • 引用位置: 参数/方法调用/构造调用
    • 关联成员: BlockPos.MutableBlockPos(), BlockPos.containing(), MutableBlockPos()
  • Component

    • 引用位置: 返回值
  • ARGB

    • 引用位置: 方法调用
    • 关联成员: ARGB.opaque()
  • LightCoordsUtil

    • 引用位置: 方法调用
    • 关联成员: LightCoordsUtil.pack()
  • Mth

    • 引用位置: 方法调用
    • 关联成员: Mth.clamp(), Mth.floor(), Mth.lerp()
  • Entity

    • 引用位置: 参数/返回值
  • Level

    • 引用位置: 参数
  • ChunkAccess

    • 引用位置: 参数
  • AABB

    • 引用位置: 构造调用/返回值
    • 关联成员: AABB()
  • Vec3

    • 引用位置: 构造调用/返回值
    • 关联成员: Vec3()