Octree.java
net.minecraft.client.renderer.Octree
信息
- 全限定名:net.minecraft.client.renderer.Octree
- 类型:public class
- 包:net.minecraft.client.renderer
- 源码路径:src/main/java/net/minecraft/client/renderer/Octree.java
- 起始行号:L16
- 职责:
TODO
字段/常量
-
root- 类型:
Octree.Branch - 修饰符:
private final - 源码定位:
L17 - 说明:
TODO
- 类型:
-
cameraSectionCenter- 类型:
BlockPos - 修饰符:
private final - 源码定位:
L18 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.client.renderer.Octree.AxisSorting- 类型:
enum - 修饰符:
private static - 源码定位:
L56 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.Octree.Branch- 类型:
class - 修饰符:
private - 源码定位:
L86 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.Octree.Leaf- 类型:
class - 修饰符:
private final - 源码定位:
L242 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.Octree.Node- 类型:
interface - 修饰符:
public - 源码定位:
L275 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.Octree.OctreeVisitor- 类型:
interface - 修饰符:
public - 源码定位:
L285 - 说明:
TODO
- 类型:
构造器
public Octree(SectionPos cameraSection, int renderDistance, int sectionsPerChunk, int minBlockY) @ L20
- 构造器名:Octree
- 源码定位:L20
- 修饰符:public
参数:
- cameraSection: SectionPos
- renderDistance: int
- sectionsPerChunk: int
- minBlockY: int
说明:
TODO
方法
下面的方法块按源码顺序生成。
public boolean add(SectionRenderDispatcher.RenderSection section) @ L35
- 方法名:add
- 源码定位:L35
- 返回类型:boolean
- 修饰符:public
参数:
- section: SectionRenderDispatcher.RenderSection
说明:
TODO
public void visitNodes(Octree.OctreeVisitor visitor, Frustum frustum, int closeDistance) @ L39
- 方法名:visitNodes
- 源码定位:L39
- 返回类型:void
- 修饰符:public
参数:
- visitor: Octree.OctreeVisitor
- frustum: Frustum
- closeDistance: int
说明:
TODO
private boolean isClose(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, int closeDistance) @ L43
- 方法名:isClose
- 源码定位:L43
- 返回类型:boolean
- 修饰符:private
参数:
- minX: double
- minY: double
- minZ: double
- maxX: double
- maxY: double
- maxZ: double
- closeDistance: int
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class Octree {
private final Octree.Branch root;
private final BlockPos cameraSectionCenter;
public Octree(SectionPos cameraSection, int renderDistance, int sectionsPerChunk, int minBlockY) {
int visibleAreaDiameterInSections = renderDistance * 2 + 1;
int boundingBoxSizeInSections = Mth.smallestEncompassingPowerOfTwo(visibleAreaDiameterInSections);
int distanceToBBEdgeInBlocks = renderDistance * 16;
BlockPos cameraSectionOrigin = cameraSection.origin();
this.cameraSectionCenter = cameraSection.center();
int minX = cameraSectionOrigin.getX() - distanceToBBEdgeInBlocks;
int maxX = minX + boundingBoxSizeInSections * 16 - 1;
int minY = boundingBoxSizeInSections >= sectionsPerChunk ? minBlockY : cameraSectionOrigin.getY() - distanceToBBEdgeInBlocks;
int maxY = minY + boundingBoxSizeInSections * 16 - 1;
int minZ = cameraSectionOrigin.getZ() - distanceToBBEdgeInBlocks;
int maxZ = minZ + boundingBoxSizeInSections * 16 - 1;
this.root = new Octree.Branch(new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ));
}
public boolean add(SectionRenderDispatcher.RenderSection section) {
return this.root.add(section);
}
public void visitNodes(Octree.OctreeVisitor visitor, Frustum frustum, int closeDistance) {
this.root.visitNodes(visitor, false, frustum, 0, closeDistance, true);
}
private boolean isClose(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, int closeDistance) {
int cameraX = this.cameraSectionCenter.getX();
int cameraY = this.cameraSectionCenter.getY();
int cameraZ = this.cameraSectionCenter.getZ();
return cameraX > minX - closeDistance
&& cameraX < maxX + closeDistance
&& cameraY > minY - closeDistance
&& cameraY < maxY + closeDistance
&& cameraZ > minZ - closeDistance
&& cameraZ < maxZ + closeDistance;
}
@OnlyIn(Dist.CLIENT)
private static enum AxisSorting {
XYZ(4, 2, 1),
XZY(4, 1, 2),
YXZ(2, 4, 1),
YZX(1, 4, 2),
ZXY(2, 1, 4),
ZYX(1, 2, 4);
private final int xShift;
private final int yShift;
private final int zShift;
private AxisSorting(int xShift, int yShift, int zShift) {
this.xShift = xShift;
this.yShift = yShift;
this.zShift = zShift;
}
public static Octree.AxisSorting getAxisSorting(int absXDiff, int absYDiff, int absZDiff) {
if (absXDiff > absYDiff && absXDiff > absZDiff) {
return absYDiff > absZDiff ? XYZ : XZY;
} else if (absYDiff > absXDiff && absYDiff > absZDiff) {
return absXDiff > absZDiff ? YXZ : YZX;
} else {
return absXDiff > absYDiff ? ZXY : ZYX;
}
}
}
@OnlyIn(Dist.CLIENT)
private class Branch implements Octree.Node {
private final Octree.@Nullable Node[] nodes;
private final BoundingBox boundingBox;
private final int bbCenterX;
private final int bbCenterY;
private final int bbCenterZ;
private final Octree.AxisSorting sorting;
private final boolean cameraXDiffNegative;
private final boolean cameraYDiffNegative;
private final boolean cameraZDiffNegative;
public Branch(BoundingBox boundingBox) {
Objects.requireNonNull(Octree.this);
super();
this.nodes = new Octree.Node[8];
this.boundingBox = boundingBox;
this.bbCenterX = this.boundingBox.minX() + this.boundingBox.getXSpan() / 2;
this.bbCenterY = this.boundingBox.minY() + this.boundingBox.getYSpan() / 2;
this.bbCenterZ = this.boundingBox.minZ() + this.boundingBox.getZSpan() / 2;
int cameraXDiff = Octree.this.cameraSectionCenter.getX() - this.bbCenterX;
int cameraYDiff = Octree.this.cameraSectionCenter.getY() - this.bbCenterY;
int cameraZDiff = Octree.this.cameraSectionCenter.getZ() - this.bbCenterZ;
this.sorting = Octree.AxisSorting.getAxisSorting(Math.abs(cameraXDiff), Math.abs(cameraYDiff), Math.abs(cameraZDiff));
this.cameraXDiffNegative = cameraXDiff < 0;
this.cameraYDiffNegative = cameraYDiff < 0;
this.cameraZDiffNegative = cameraZDiff < 0;
}
public boolean add(SectionRenderDispatcher.RenderSection section) {
long sectionNode = section.getSectionNode();
boolean sectionXDiffNegative = SectionPos.sectionToBlockCoord(SectionPos.x(sectionNode)) - this.bbCenterX < 0;
boolean sectionYDiffNegative = SectionPos.sectionToBlockCoord(SectionPos.y(sectionNode)) - this.bbCenterY < 0;
boolean sectionZDiffNegative = SectionPos.sectionToBlockCoord(SectionPos.z(sectionNode)) - this.bbCenterZ < 0;
boolean xDiffsOppositeSides = sectionXDiffNegative != this.cameraXDiffNegative;
boolean yDiffsOppositeSides = sectionYDiffNegative != this.cameraYDiffNegative;
boolean zDiffsOppositeSides = sectionZDiffNegative != this.cameraZDiffNegative;
int nodeIndex = getNodeIndex(this.sorting, xDiffsOppositeSides, yDiffsOppositeSides, zDiffsOppositeSides);
if (this.areChildrenLeaves()) {
boolean alreadyExisted = this.nodes[nodeIndex] != null;
this.nodes[nodeIndex] = Octree.this.new Leaf(section);
return !alreadyExisted;
} else if (this.nodes[nodeIndex] != null) {
Octree.Branch branch = (Octree.Branch)this.nodes[nodeIndex];
return branch.add(section);
} else {
BoundingBox childBoundingBox = this.createChildBoundingBox(sectionXDiffNegative, sectionYDiffNegative, sectionZDiffNegative);
Octree.Branch branch = Octree.this.new Branch(childBoundingBox);
this.nodes[nodeIndex] = branch;
return branch.add(section);
}
}
private static int getNodeIndex(Octree.AxisSorting sorting, boolean xDiffsOppositeSides, boolean yDiffsOppositeSides, boolean zDiffsOppositeSides) {
int index = 0;
if (xDiffsOppositeSides) {
index += sorting.xShift;
}
if (yDiffsOppositeSides) {
index += sorting.yShift;
}
if (zDiffsOppositeSides) {
index += sorting.zShift;
}
return index;
}
private boolean areChildrenLeaves() {
return this.boundingBox.getXSpan() == 32;
}
private BoundingBox createChildBoundingBox(boolean sectionXDiffNegative, boolean sectionYDiffNegative, boolean sectionZDiffNegative) {
int minX;
int maxX;
if (sectionXDiffNegative) {
minX = this.boundingBox.minX();
maxX = this.bbCenterX - 1;
} else {
minX = this.bbCenterX;
maxX = this.boundingBox.maxX();
}
int minY;
int maxY;
if (sectionYDiffNegative) {
minY = this.boundingBox.minY();
maxY = this.bbCenterY - 1;
} else {
minY = this.bbCenterY;
maxY = this.boundingBox.maxY();
}
int minZ;
int maxZ;
if (sectionZDiffNegative) {
minZ = this.boundingBox.minZ();
maxZ = this.bbCenterZ - 1;
} else {
minZ = this.bbCenterZ;
maxZ = this.boundingBox.maxZ();
}
return new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
}
@Override
public void visitNodes(Octree.OctreeVisitor visitor, boolean skipFrustumCheck, Frustum frustum, int depth, int closeDistance, boolean isClose) {
boolean isVisible = skipFrustumCheck;
if (!skipFrustumCheck) {
int checkResult = frustum.cubeInFrustum(this.boundingBox);
skipFrustumCheck = checkResult == -2;
isVisible = checkResult == -2 || checkResult == -1;
}
if (isVisible) {
isClose = isClose
&& Octree.this.isClose(
(double)this.boundingBox.minX(),
(double)this.boundingBox.minY(),
(double)this.boundingBox.minZ(),
(double)this.boundingBox.maxX(),
(double)this.boundingBox.maxY(),
(double)this.boundingBox.maxZ(),
closeDistance
);
visitor.visit(this, skipFrustumCheck, depth, isClose);
for (Octree.Node node : this.nodes) {
if (node != null) {
node.visitNodes(visitor, skipFrustumCheck, frustum, depth + 1, closeDistance, isClose);
}
}
}
}
@Override
public SectionRenderDispatcher.@Nullable RenderSection getSection() {
return null;
}
@Override
public AABB getAABB() {
return new AABB(
this.boundingBox.minX(),
this.boundingBox.minY(),
this.boundingBox.minZ(),
this.boundingBox.maxX() + 1,
this.boundingBox.maxY() + 1,
this.boundingBox.maxZ() + 1
);
}
}
@OnlyIn(Dist.CLIENT)
private final class Leaf implements Octree.Node {
private final SectionRenderDispatcher.RenderSection section;
private Leaf(SectionRenderDispatcher.RenderSection section) {
Objects.requireNonNull(Octree.this);
super();
this.section = section;
}
@Override
public void visitNodes(Octree.OctreeVisitor visitor, boolean skipFrustumCheck, Frustum frustum, int depth, int closeDistance, boolean isClose) {
AABB boundingBox = this.section.getBoundingBox();
if (skipFrustumCheck || frustum.isVisible(this.getSection().getBoundingBox())) {
isClose = isClose
&& Octree.this.isClose(
boundingBox.minX, boundingBox.minY, boundingBox.minZ, boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ, closeDistance
);
visitor.visit(this, skipFrustumCheck, depth, isClose);
}
}
@Override
public SectionRenderDispatcher.RenderSection getSection() {
return this.section;
}
@Override
public AABB getAABB() {
return this.section.getBoundingBox();
}
}
@OnlyIn(Dist.CLIENT)
public interface Node {
void visitNodes(Octree.OctreeVisitor visitor, boolean skipFrustumCheck, Frustum frustum, int depth, final int closeDistance, boolean isClose);
SectionRenderDispatcher.@Nullable RenderSection getSection();
AABB getAABB();
}
@FunctionalInterface
@OnlyIn(Dist.CLIENT)
public interface OctreeVisitor {
void visit(final Octree.Node node, final boolean fullyVisible, int depth, boolean isClose);
}
}引用的其他类
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
字段
- 引用位置:
-
- 引用位置:
参数/方法调用 - 关联成员:
SectionPos.sectionToBlockCoord(), SectionPos.x(), SectionPos.y(), SectionPos.z()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Mth.smallestEncompassingPowerOfTwo()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
BoundingBox()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
AABB()
- 引用位置: