diff --git a/src/mol-io/reader/kin/ngl-based-parser.ts b/src/mol-io/reader/kin/ngl-based-parser.ts index 59b861878..36aeef138 100644 --- a/src/mol-io/reader/kin/ngl-based-parser.ts +++ b/src/mol-io/reader/kin/ngl-based-parser.ts @@ -254,7 +254,8 @@ function convertKinTriangleArrays (ribbonObject: RibbonObject) { labelArray: convertedLabels, positionArray: convertedPositions, breakArray: convertedBreaks, - colorArray: convertedColors + colorArray: convertedColors, + pairTriangleNormals: ribbonObject.pairTriangleNormals } } @@ -308,7 +309,8 @@ function removePointBreaksTriangleArrays (convertedRibbonObject: RibbonObject) { labelArray: editedLabels, positionArray: editedPositions, breakArray: editedBreaks, - colorArray: editedColors + colorArray: editedColors, + pairTriangleNormals: convertedRibbonObject.pairTriangleNormals } } @@ -371,6 +373,7 @@ class KinParser { let ballLabel: string[], ballPosition: number[], ballColor: number[] let isRibbonList = false + let ribbonIsTriangles = false let prevRibbonPointLabel = '' let ribbonListDefaultColor: number[] = localColorDict['white'] @@ -533,6 +536,7 @@ class KinParser { }) } isRibbonList = true + ribbonIsTriangles = line.startsWith('@triangle') /* triangle or trianglelist */ prevRibbonPointLabel = '' ribbonPointLabelArray = [] ribbonPointPositionArray = [] @@ -553,7 +557,8 @@ class KinParser { labelArray: ribbonPointLabelArray, positionArray: ribbonPointPositionArray, breakArray: ribbonPointBreakArray, - colorArray: ribbonPointColorArray + colorArray: ribbonPointColorArray, + pairTriangleNormals: !ribbonIsTriangles }) } else if (line.startsWith('@text')) { isText = true diff --git a/src/mol-io/reader/kin/schema.ts b/src/mol-io/reader/kin/schema.ts index 32d24e5d6..977e165cc 100644 --- a/src/mol-io/reader/kin/schema.ts +++ b/src/mol-io/reader/kin/schema.ts @@ -47,7 +47,8 @@ export interface RibbonObject { labelArray: string[], ///< Array of labels per element positionArray: number[], ///< Catenation of x, y, z for each element, 9x as many as triangles (3 vertices per triangle) colorArray: number[], ///< Catenation of r, g, b for each element, 9x as many as triangles (3 colors per triangle) - breakArray: boolean[] ///< A single boolean per element indicating if there is a break there + breakArray: boolean[], ///< A single boolean per element indicating if there is a break there + pairTriangleNormals: boolean ///< Whether to pair every other triangle normal for lighting (true for ribbons, false for triangles) } export interface VectorList { diff --git a/src/mol-model-formats/shape/kin.ts b/src/mol-model-formats/shape/kin.ts index 786ae9b2c..ff6468b68 100644 --- a/src/mol-model-formats/shape/kin.ts +++ b/src/mol-model-formats/shape/kin.ts @@ -175,6 +175,7 @@ async function getMesh(ctx: RuntimeContext, ribbonObjects: RibbonObject[]) { // There are three vertices per triangle. /// @todo Ribbon lighting is to be set up to make each pair of triangles look like a quad with the same normal. const numTriangles = coords.length / 9; + let prevTriangleNormal: Vec3 | undefined = undefined; for (let i = 0; i < numTriangles; i++) { const vertexList: Vec3[] = []; @@ -215,14 +216,21 @@ async function getMesh(ctx: RuntimeContext, ribbonObjects: RibbonObject[]) { b = c; c = temp; } - const n = Vec3.zero(); // Put both orientations of the triangle. Add a small amount along the normal to make them // not be exactly on top of each other so that we only see the front face of each. + let n = Vec3.zero(); Vec3.triangleNormal(n, a, b, c); + if (i % 2 === 1) { + // For ribbons, every other triangle is meant to be paired with the previous one to make a quad with the same normal. + // So use the same normal for every other triangle. + n = prevTriangleNormal || n; + } + prevTriangleNormal = n; addOffsetTriangle(builderState, a, b, c, n, 0.01); - Vec3.triangleNormal(n, a, c, b); + // Invert the normal for the back face. + Vec3.negate(n, n); addOffsetTriangle(builderState, a, c, b, n, 0.01); } }