Skip to content

Commit

Permalink
Start of Cylinder working
Browse files Browse the repository at this point in the history
  • Loading branch information
seflless committed Sep 24, 2023
1 parent a193daf commit bede444
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 54 deletions.
18 changes: 18 additions & 0 deletions src/math/Vector3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ export interface Vector3 {
y: number;
z: number;
set(vec: Vector3): Vector3;
setX(x: number): Vector3;
setY(y: number): Vector3;
setZ(z: number): Vector3;
add(vec: Vector3): Vector3;
subtract(vec: Vector3): Vector3;
multiply(scalar: number): Vector3;
Expand All @@ -26,6 +29,21 @@ const Vector3Proto = {
return this;
},

setX(this: Vector3, x: number): Vector3 {
this.x = x;
return this;
},

setY(this: Vector3, y: number): Vector3 {
this.y = y;
return this;
},

setZ(this: Vector3, z: number): Vector3 {
this.z = z;
return this;
},

/**
* Adds a vector to this vector, mutating it in place. It
* returns this vector, so that API chaining is possible (ie: `v.add(v2).add(v3)`)
Expand Down
190 changes: 138 additions & 52 deletions src/renderer/renderCylinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ enum CylinderEnds {
}

export function renderCylinder(
_scene: Scene,
scene: Scene,
svg: SVGElement,
_defs: SVGDefsElement,
cylinder: CylinderShape,
Expand Down Expand Up @@ -53,34 +53,6 @@ export function renderCylinder(
const yAxisCameraSpace = yAxisWorldSpace.clone();
inverseCameraMatrix.applyToVector3(yAxisCameraSpace);

const addCylinderEnd = (
{ x, y }: Vector3,
radius: number,
dotProduct: number,
fill: Color
) => {
const dotProductAbsolute = Math.abs(dotProduct);
// Create a 'circle' element
const circle = document.createElementNS(
"http://www.w3.org/2000/svg",
"ellipse"
);

circle.id = "sphere";
circle.setAttribute("cx", x.toString());
circle.setAttribute("cy", y.toString());

// TODO: Factor in camera projection matrix, this currectly
// ignores all zoom factors. Can we even handle skew with sphere?!
// I don't think we can.
circle.setAttribute("rx", radius.toString());
circle.setAttribute("ry", (radius * dotProductAbsolute).toString());

circle.setAttribute("fill", ColorToCSS(fill));

svg.appendChild(circle);
};

const cylinderScale = worldTransform.getScale().x;
const cylinderScaleFactor = cylinderScale * cameraZoom;
const Radius = cylinder.radius * cylinderScaleFactor;
Expand All @@ -91,6 +63,10 @@ export function renderCylinder(
const dotProduct = yAxisWorldSpace.dotProduct(
cameraDirection.clone().multiply(-1)
);
const dotProductAbsolute = Math.abs(dotProduct);

const ShortRadius = Radius * dotProductAbsolute;

console.log(
`dotProduct: ${dotProduct.toFixed(3)}
yAxisCameraSpace: ${yAxisCameraSpace.x.toFixed(
Expand All @@ -99,12 +75,90 @@ export function renderCylinder(
);
const isTopVisible = dotProduct > 0;

addCylinderEnd(
isTopVisible ? points[CylinderEnds.Top] : points[CylinderEnds.Bottom],
cylinder.radius,
dotProduct,
isTopVisible ? Color(255, 0, 0) : Color(0, 0, 255)
const yAxisScreenSpace = Vector3(yAxisCameraSpace.x, -yAxisCameraSpace.y, 0)
.normalize()
.multiply(isTopVisible ? 1 : -1);

const capCenter = isTopVisible
? points[CylinderEnds.Top]
: points[CylinderEnds.Bottom];

const tailCenter = isTopVisible
? points[CylinderEnds.Bottom]
: points[CylinderEnds.Top];

// addCylinderEnd(
// capCenter,
// cylinder.radius,
// dotProduct,
// isTopVisible ? Color(255, 0, 0) : Color(0, 0, 255),
// svg
// );

const leftNormal = Vector3(-yAxisScreenSpace.y, yAxisScreenSpace.x, 0);
const rightNormal = Vector3(yAxisScreenSpace.y, -yAxisScreenSpace.x, 0);
const topLeftPoint = leftNormal.clone().multiply(Radius).add(capCenter);
const topRightPoint = rightNormal.clone().multiply(Radius).add(capCenter);
const bottomLeftPoint = leftNormal.clone().multiply(Radius).add(tailCenter);
const bottomRightPoint = rightNormal.clone().multiply(Radius).add(tailCenter);

const xAxisRotation = normalToXAxisDegrees(rightNormal.x, rightNormal.y);
const largeArcFlag = 0;
const sweepFlag = 0;

const reversedLightDirection = scene.directionalLight.direction
.clone()
.multiply(-1);

const capPath = document.createElementNS(
"http://www.w3.org/2000/svg",
"path"
);
capPath.setAttribute("id", "cylinder-top");
capPath.setAttribute(
"fill",
applyLighting(
scene.directionalLight.color,
cylinder.fill,
scene.ambientLightColor,
isTopVisible
? reversedLightDirection.dotProduct(yAxisWorldSpace)
: reversedLightDirection.dotProduct(
yAxisWorldSpace.clone().multiply(-1)
)
)
);
capPath.setAttribute(
"d",
`
M ${topLeftPoint.x} ${
topLeftPoint.y
} A ${Radius} ${ShortRadius} ${xAxisRotation} ${largeArcFlag} ${sweepFlag} ${
topRightPoint.x
} ${topRightPoint.y}
A ${Radius} ${ShortRadius} ${xAxisRotation} ${1} ${sweepFlag} ${
topLeftPoint.x
} ${topLeftPoint.y}`
);

svg.appendChild(capPath);

const tubePath = document.createElementNS(
"http://www.w3.org/2000/svg",
"path"
);
tubePath.setAttribute("id", "cylinder-tube");
tubePath.setAttribute("fill", "purple");
tubePath.setAttribute(
"d",
`
M ${topLeftPoint.x} ${topLeftPoint.y}
A ${Radius} ${ShortRadius} ${xAxisRotation} 0 1 ${topRightPoint.x} ${topRightPoint.y}
L ${bottomRightPoint.x} ${bottomRightPoint.y}
A ${Radius} ${ShortRadius} ${xAxisRotation} 0 0 ${bottomLeftPoint.x} ${bottomLeftPoint.y}
`
);
svg.appendChild(tubePath);

// Scenarios we can view the cylinder from:
// 1. From the top/bottom (can't see the tube)
Expand All @@ -113,30 +167,62 @@ export function renderCylinder(

// Are we viewing the cylinder from the top or bottom?

points.forEach(({ x, y }, index) => {
const circle = document.createElementNS(
"http://www.w3.org/2000/svg",
"circle"
);
// points.forEach(({ x, y }, index) => {
// const circle = document.createElementNS(
// "http://www.w3.org/2000/svg",
// "circle"
// );

circle.id = "sphere";
circle.setAttribute("cx", x.toString());
circle.setAttribute("cy", y.toString());
// circle.id = "sphere";
// circle.setAttribute("cx", x.toString());
// circle.setAttribute("cy", y.toString());

// TODO: Factor in camera projection matrix, this currectly
// ignores all zoom factors. Can we even handle skew with sphere?!
// I don't think we can.
circle.setAttribute("r", (5).toString());
// // TODO: Factor in camera projection matrix, this currectly
// // ignores all zoom factors. Can we even handle skew with sphere?!
// // I don't think we can.
// circle.setAttribute("r", (5).toString());

circle.setAttribute(
"fill",
index === CylinderEnds.Top ? "rgb(128,0,0)" : "rgb(0,0,128)"
);
// circle.setAttribute(
// "fill",
// index === CylinderEnds.Top ? "rgb(128,0,0)" : "rgb(0,0,128)"
// );

svg.appendChild(circle);
});
// svg.appendChild(circle);
// });

// Get the center of the cylinder's top face

// Get the center of the cylinder's bottom face
}

function addCylinderEnd(

Check failure on line 198 in src/renderer/renderCylinder.ts

View workflow job for this annotation

GitHub Actions / build (16.x)

'addCylinderEnd' is declared but its value is never read.
{ x, y }: Vector3,
radius: number,
dotProductAbsolute: number,
fill: Color,
svg: SVGElement
) {
// Create a 'circle' element
const circle = document.createElementNS(
"http://www.w3.org/2000/svg",
"ellipse"
);

circle.id = "sphere";
circle.setAttribute("cx", x.toString());
circle.setAttribute("cy", y.toString());

// TODO: Factor in camera projection matrix, this currectly
// ignores all zoom factors. Can we even handle skew with sphere?!
// I don't think we can.
circle.setAttribute("rx", radius.toString());
circle.setAttribute("ry", (radius * dotProductAbsolute).toString());

circle.setAttribute("fill", ColorToCSS(fill));

svg.appendChild(circle);
}

function normalToXAxisDegrees(x: number, y: number) {
return (Math.atan2(y, x) / Math.PI) * 180;
}
6 changes: 4 additions & 2 deletions workbench/scenes/SingleCylinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,10 @@ export default function () {
// updateCamera(45, 20);

// cylinder.rotation.x = now * 90;
cylinder.rotation.x = 0;
cylinder.rotation.z = 0;
cylinder.rotation.x = 45;
cylinder.rotation.y = now * 90;

// cylinder.rotation.x = now * 90;

// lightSphere.position.x =
// Math.sin(now * Math.PI * 2 * lightSpeed) * lightDistance;
Expand Down

0 comments on commit bede444

Please sign in to comment.