Skip to content
Snippets Groups Projects
Commit ce331b3a authored by Alexander Rose's avatar Alexander Rose
Browse files

basic text rendering: render-object, builder, shader

parent 1ed9f7d8
Branches
Tags
No related merge requests found
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ParamDefinition as PD } from 'mol-util/param-definition';
import { ValueCell } from 'mol-util/value-cell'
import { ChunkedArray } from 'mol-data/util';
import { Text } from './text';
import { getFontAtlas } from './font-atlas';
const quadIndices = new Uint16Array([
0, 1, 2,
1, 3, 2
])
export interface TextBuilder {
add(str: string, x: number, y: number, z: number, group: number): void
getText(): Text
}
export namespace TextBuilder {
export function create(props: Partial<PD.Values<Text.Params>> = {}, initialCount = 2048, chunkSize = 1024, text?: Text): TextBuilder {
const centers = ChunkedArray.create(Float32Array, 3, chunkSize, text ? text.centerBuffer.ref.value : initialCount);
const mappings = ChunkedArray.create(Float32Array, 2, chunkSize, text ? text.mappingBuffer.ref.value : initialCount);
const indices = ChunkedArray.create(Uint32Array, 3, chunkSize, text ? text.indexBuffer.ref.value : initialCount);
const groups = ChunkedArray.create(Float32Array, 1, chunkSize, text ? text.groupBuffer.ref.value : initialCount);
const tcoords = ChunkedArray.create(Float32Array, 2, chunkSize, text ? text.tcoordBuffer.ref.value : initialCount);
const p = { ...PD.getDefaultValues(Text.Params), ...props }
const { attachment, background, backgroundMargin } = p
const fontAtlas = getFontAtlas(p)
const { lineHeight } = fontAtlas
const margin = (lineHeight * backgroundMargin * 0.1) - 10
const outline = fontAtlas.buffer
console.log('margin', margin)
return {
add: (str: string, x: number, y: number, z: number, group: number) => {
let xadvance = 0
const nChar = str.length
// calculate width
for (let iChar = 0; iChar < nChar; ++iChar) {
const c = fontAtlas.get(str[iChar])
xadvance += c.w - 2 * outline
}
// attachment
let yShift: number, xShift: number
if (attachment.startsWith('top')) {
yShift = lineHeight / 1.25
} else if (attachment.startsWith('middle')) {
yShift = lineHeight / 2.5
} else {
yShift = 0 // "bottom"
}
if (attachment.endsWith('right')) {
xShift = xadvance
} else if (attachment.endsWith('center')) {
xShift = xadvance / 2
} else {
xShift = 0 // "left"
}
xShift += outline
yShift += outline
// background
if (background) {
ChunkedArray.add2(mappings, -lineHeight / 6 - xShift - margin, lineHeight - yShift + margin)
ChunkedArray.add2(mappings, -lineHeight / 6 - xShift - margin, 0 - yShift - margin)
ChunkedArray.add2(mappings, xadvance + lineHeight / 6 - xShift + 2 * outline + margin, lineHeight - yShift + margin)
ChunkedArray.add2(mappings, xadvance + lineHeight / 6 - xShift + 2 * outline + margin, 0 - yShift - margin)
const offset = centers.elementCount
for (let i = 0; i < 4; ++i) {
ChunkedArray.add2(tcoords, 0, 10)
ChunkedArray.add3(centers, x, y, z);
ChunkedArray.add(groups, group);
}
ChunkedArray.add3(indices, offset + quadIndices[0], offset + quadIndices[1], offset + quadIndices[2])
ChunkedArray.add3(indices, offset + quadIndices[3], offset + quadIndices[4], offset + quadIndices[5])
}
xadvance = 0
for (let iChar = 0; iChar < nChar; ++iChar) {
const c = fontAtlas.get(str[iChar])
ChunkedArray.add2(mappings, xadvance - xShift, c.h - yShift) // top left
ChunkedArray.add2(mappings, xadvance - xShift, 0 - yShift) // bottom left
ChunkedArray.add2(mappings, xadvance + c.w - xShift, c.h - yShift) // top right
ChunkedArray.add2(mappings, xadvance + c.w - xShift, 0 - yShift) // bottom right
const texWidth = fontAtlas.texture.width
const texHeight = fontAtlas.texture.height
ChunkedArray.add2(tcoords, c.x / texWidth, c.y / texHeight) // top left
ChunkedArray.add2(tcoords, c.x / texWidth, (c.y + c.h) / texHeight) // bottom left
ChunkedArray.add2(tcoords, (c.x + c.w) / texWidth, c.y / texHeight) // top right
ChunkedArray.add2(tcoords, (c.x + c.w) / texWidth, (c.y + c.h) / texHeight) // bottom right
xadvance += c.w - 2 * outline
const offset = centers.elementCount
for (let i = 0; i < 4; ++i) {
ChunkedArray.add3(centers, x, y, z);
ChunkedArray.add(groups, group);
}
ChunkedArray.add3(indices, offset + quadIndices[0], offset + quadIndices[1], offset + quadIndices[2])
ChunkedArray.add3(indices, offset + quadIndices[3], offset + quadIndices[4], offset + quadIndices[5])
}
},
getText: () => {
const cb = ChunkedArray.compact(centers, true) as Float32Array
const mb = ChunkedArray.compact(mappings, true) as Float32Array
const ib = ChunkedArray.compact(indices, true) as Uint32Array
const gb = ChunkedArray.compact(groups, true) as Float32Array
const tb = ChunkedArray.compact(tcoords, true) as Float32Array
return {
kind: 'text',
charCount: centers.elementCount / 4,
fontAtlas,
centerBuffer: text ? ValueCell.update(text.centerBuffer, cb) : ValueCell.create(cb),
mappingBuffer: text ? ValueCell.update(text.centerBuffer, mb) : ValueCell.create(mb),
indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib),
groupBuffer: text ? ValueCell.update(text.groupBuffer, gb) : ValueCell.create(gb),
tcoordBuffer: text ? ValueCell.update(text.tcoordBuffer, tb) : ValueCell.create(tb),
}
}
}
}
}
\ No newline at end of file
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ParamDefinition as PD } from 'mol-util/param-definition';
import { ValueCell } from 'mol-util';
import { Geometry } from '../geometry';
import { LocationIterator } from 'mol-geo/util/location-iterator';
import { TransformData, createIdentityTransform } from '../transform-data';
import { Theme } from 'mol-theme/theme';
import { createColors } from '../color-data';
import { createSizes, getMaxSize } from '../size-data';
import { createMarkers } from '../marker-data';
import { ColorNames } from 'mol-util/color/tables';
import { NullLocation } from 'mol-model/location';
import { UniformColorTheme } from 'mol-theme/color/uniform';
import { UniformSizeTheme } from 'mol-theme/size/uniform';
import { Sphere3D } from 'mol-math/geometry';
import { calculateBoundingSphere } from 'mol-gl/renderable/util';
import { TextValues } from 'mol-gl/renderable/text';
import { Color } from 'mol-util/color';
import { Vec3 } from 'mol-math/linear-algebra';
import { FontAtlas, getFontAtlas, FontAtlasParams } from './font-atlas';
import { RenderableState } from 'mol-gl/renderable';
import { clamp } from 'mol-math/interpolate';
type TextAttachment = 'bottom-left' | 'bottom-center' | 'bottom-right' | 'middle-left' | 'middle-center' | 'middle-right' | 'top-left' | 'top-center' | 'top-right'
/** Text */
export interface Text {
readonly kind: 'text',
/** Number of characters in the text */
readonly charCount: number,
/** Font Atlas */
readonly fontAtlas: FontAtlas,
/** Center buffer as array of xyz values wrapped in a value cell */
readonly centerBuffer: ValueCell<Float32Array>,
/** Mapping buffer as array of xy values wrapped in a value cell */
readonly mappingBuffer: ValueCell<Float32Array>,
/** Index buffer as array of center index triplets wrapped in a value cell */
readonly indexBuffer: ValueCell<Uint32Array>,
/** Group buffer as array of group ids for each vertex wrapped in a value cell */
readonly groupBuffer: ValueCell<Float32Array>,
/** Texture coordinates buffer as array of uv values wrapped in a value cell */
readonly tcoordBuffer: ValueCell<Float32Array>,
}
export namespace Text {
export function createEmpty(text?: Text): Text {
const cb = text ? text.centerBuffer.ref.value : new Float32Array(0)
const mb = text ? text.mappingBuffer.ref.value : new Float32Array(0)
const ib = text ? text.indexBuffer.ref.value : new Uint32Array(0)
const gb = text ? text.groupBuffer.ref.value : new Float32Array(0)
const tb = text ? text.tcoordBuffer.ref.value : new Float32Array(0)
return {
kind: 'text',
charCount: 0,
fontAtlas: getFontAtlas({}),
centerBuffer: text ? ValueCell.update(text.centerBuffer, cb) : ValueCell.create(cb),
mappingBuffer: text ? ValueCell.update(text.mappingBuffer, mb) : ValueCell.create(mb),
indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib),
groupBuffer: text ? ValueCell.update(text.groupBuffer, gb) : ValueCell.create(gb),
tcoordBuffer: text ? ValueCell.update(text.tcoordBuffer, tb) : ValueCell.create(tb)
}
}
export const Params = {
...Geometry.Params,
...FontAtlasParams,
sizeFactor: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }),
borderWidth: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }),
borderColor: PD.Color(ColorNames.grey),
offsetX: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }),
offsetY: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }),
offsetZ: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }),
background: PD.Boolean(false),
backgroundMargin: PD.Numeric(0.2, { min: 0, max: 10, step: 0.1 }),
backgroundColor: PD.Color(ColorNames.grey),
backgroundOpacity: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }),
attachment: PD.Select('normal', [['bottom-left', 'bottom-left'], ['bottom-center', 'bottom-center'], ['bottom-right', 'bottom-right'], ['middle-left', 'middle-left'], ['top-left', 'top-left'], ['top-center', 'top-center'], ['top-right', 'top-right']] as [TextAttachment, string][]),
}
export type Params = typeof Params
export function createValues(text: Text, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: PD.Values<Params>): TextValues {
const { instanceCount, groupCount } = locationIt
if (instanceCount !== transform.instanceCount.ref.value) {
throw new Error('instanceCount values in TransformData and LocationIterator differ')
}
const color = createColors(locationIt, theme.color)
const size = createSizes(locationIt, theme.size)
const marker = createMarkers(instanceCount * groupCount)
const counts = { drawCount: text.charCount * 2 * 3, groupCount, instanceCount }
const padding = getMaxSize(size)
const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
text.centerBuffer.ref.value, text.charCount * 4,
transform.aTransform.ref.value, instanceCount, padding
)
console.log(props.sizeFactor, text.fontAtlas.lineHeight, props.fontSize)
return {
aPosition: text.centerBuffer,
aMapping: text.mappingBuffer,
aGroup: text.groupBuffer,
elements: text.indexBuffer,
boundingSphere: ValueCell.create(boundingSphere),
invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
...color,
...size,
...marker,
...transform,
aTexCoord: text.tcoordBuffer,
tFont: ValueCell.create(text.fontAtlas.texture),
padding: ValueCell.create(padding),
...Geometry.createValues(props, counts),
uSizeFactor: ValueCell.create(props.sizeFactor / text.fontAtlas.lineHeight),
uBorderWidth: ValueCell.create(clamp(props.borderWidth / 2, 0, 0.5)),
uBorderColor: ValueCell.create(Color.toArrayNormalized(props.borderColor, Vec3.zero(), 0)),
uOffsetX: ValueCell.create(props.offsetX),
uOffsetY: ValueCell.create(props.offsetY),
uOffsetZ: ValueCell.create(props.offsetZ),
uBackgroundColor: ValueCell.create(Color.toArrayNormalized(props.backgroundColor, Vec3.zero(), 0)),
uBackgroundOpacity: ValueCell.create(props.backgroundOpacity),
}
}
export function createValuesSimple(text: Text, props: Partial<PD.Values<Params>>, colorValue = ColorNames.grey, sizeValue = 1, transform?: TransformData): TextValues {
if (!transform) transform = createIdentityTransform()
const locationIterator = LocationIterator(1, transform.instanceCount.ref.value, () => NullLocation, false, () => false)
const theme: Theme = {
color: UniformColorTheme({}, { value: colorValue}),
size: UniformSizeTheme({}, { value: sizeValue})
}
const p = { ...PD.getDefaultValues(Params), ...props }
return createValues(text, transform, locationIterator, theme, p)
}
export function updateValues(values: TextValues, props: PD.Values<Params>) {
Geometry.updateValues(values, props)
ValueCell.updateIfChanged(values.uSizeFactor, props.sizeFactor)
}
export function updateBoundingSphere(values: TextValues, text: Text) {
const padding = getMaxSize(values)
const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
values.aPosition.ref.value, text.charCount * 4,
values.aTransform.ref.value, values.instanceCount.ref.value, padding
)
if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
ValueCell.update(values.boundingSphere, boundingSphere)
}
if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere)
}
}
export function createRenderableState(props: PD.Values<Params>): RenderableState {
const state = Geometry.createRenderableState(props)
updateRenderableState(state, props)
return state
}
export function updateRenderableState(state: RenderableState, props: PD.Values<Params>) {
Geometry.updateRenderableState(state, props)
state.opaque = false
}
}
\ No newline at end of file
......@@ -14,6 +14,7 @@ import { MeshValues, MeshRenderable } from './renderable/mesh';
import { PointsValues, PointsRenderable } from './renderable/points';
import { LinesValues, LinesRenderable } from './renderable/lines';
import { SpheresValues, SpheresRenderable } from './renderable/spheres';
import { TextValues, TextRenderable } from './renderable/text';
const getNextId = idFactory(0, 0x7FFFFFFF)
......@@ -21,6 +22,7 @@ export interface BaseRenderObject { id: number, type: string, values: Renderable
export interface MeshRenderObject extends BaseRenderObject { type: 'mesh', values: MeshValues }
export interface PointsRenderObject extends BaseRenderObject { type: 'points', values: PointsValues }
export interface SpheresRenderObject extends BaseRenderObject { type: 'spheres', values: SpheresValues }
export interface TextRenderObject extends BaseRenderObject { type: 'text', values: TextValues }
export interface LinesRenderObject extends BaseRenderObject { type: 'lines', values: LinesValues }
export interface DirectVolumeRenderObject extends BaseRenderObject { type: 'direct-volume', values: DirectVolumeValues }
......@@ -28,7 +30,7 @@ export interface GaussianDensityRenderObject extends BaseRenderObject { type: 'g
//
export type GraphicsRenderObject = MeshRenderObject | PointsRenderObject | SpheresRenderObject | LinesRenderObject | DirectVolumeRenderObject
export type GraphicsRenderObject = MeshRenderObject | PointsRenderObject | SpheresRenderObject | TextRenderObject | LinesRenderObject | DirectVolumeRenderObject
export type ComputeRenderObject = GaussianDensityRenderObject
......@@ -45,6 +47,9 @@ export function createPointsRenderObject(values: PointsValues, state: Renderable
export function createSpheresRenderObject(values: SpheresValues, state: RenderableState): SpheresRenderObject {
return { id: getNextId(), type: 'spheres', values, state }
}
export function createTextRenderObject(values: TextValues, state: RenderableState): TextRenderObject {
return { id: getNextId(), type: 'text', values, state }
}
export function createLinesRenderObject(values: LinesValues, state: RenderableState): LinesRenderObject {
return { id: getNextId(), type: 'lines', values, state }
}
......@@ -61,6 +66,7 @@ export function createRenderable(ctx: WebGLContext, o: RenderObject): Renderable
case 'mesh': return MeshRenderable(ctx, o.id, o.values, o.state)
case 'points': return PointsRenderable(ctx, o.id, o.values, o.state)
case 'spheres': return SpheresRenderable(ctx, o.id, o.values, o.state)
case 'text': return TextRenderable(ctx, o.id, o.values, o.state)
case 'lines': return LinesRenderable(ctx, o.id, o.values, o.state)
case 'direct-volume': return DirectVolumeRenderable(ctx, o.id, o.values, o.state)
......
......@@ -148,6 +148,7 @@ export const GlobalUniformSchema = {
uViewportHeight: UniformSpec('f'),
uViewport: UniformSpec('v4'),
uCameraPosition: UniformSpec('v3'),
uFogNear: UniformSpec('f'),
uFogFar: UniformSpec('f'),
uFogColor: UniformSpec('v3'),
......
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Renderable, RenderableState, createRenderable } from '../renderable'
import { WebGLContext } from '../webgl/context';
import { createRenderItem } from '../webgl/render-item';
import { GlobalUniformSchema, BaseSchema, AttributeSpec, UniformSpec, Values, InternalSchema, SizeSchema, InternalValues, TextureSpec, ElementsSpec, ValueSpec } from './schema';
import { TextShaderCode } from '../shader-code';
import { ValueCell } from 'mol-util';
export const TextSchema = {
...BaseSchema,
...SizeSchema,
aPosition: AttributeSpec('float32', 3, 0),
aMapping: AttributeSpec('float32', 2, 0),
elements: ElementsSpec('uint32'),
aTexCoord: AttributeSpec('float32', 2, 0),
tFont: TextureSpec('image-uint8', 'alpha', 'ubyte', 'linear'),
padding: ValueSpec('number'),
uBorderWidth: UniformSpec('f'),
uBorderColor: UniformSpec('v3'),
uOffsetX: UniformSpec('f'),
uOffsetY: UniformSpec('f'),
uOffsetZ: UniformSpec('f'),
uBackgroundColor: UniformSpec('v3'),
uBackgroundOpacity: UniformSpec('f'),
}
export type TextSchema = typeof TextSchema
export type TextValues = Values<TextSchema>
export function TextRenderable(ctx: WebGLContext, id: number, values: TextValues, state: RenderableState): Renderable<TextValues> {
const schema = { ...GlobalUniformSchema, ...InternalSchema, ...TextSchema }
const internalValues: InternalValues = {
uObjectId: ValueCell.create(id),
uPickable: ValueCell.create(state.pickable ? 1 : 0)
}
const shaderCode = TextShaderCode
const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues })
return createRenderable(renderItem, values, state);
}
\ No newline at end of file
......@@ -99,6 +99,7 @@ namespace Renderer {
uLightColor: ValueCell.create(lightColor),
uLightAmbient: ValueCell.create(lightAmbient),
uCameraPosition: ValueCell.create(Vec3.clone(camera.state.position)),
uFogNear: ValueCell.create(camera.state.fogNear),
uFogFar: ValueCell.create(camera.state.fogFar),
uFogColor: ValueCell.create(fogColor),
......@@ -160,6 +161,7 @@ namespace Renderer {
ValueCell.update(globalUniforms.uModelViewProjection, Mat4.mul(modelViewProjection, modelView, camera.projection))
ValueCell.update(globalUniforms.uInvModelViewProjection, Mat4.invert(invModelViewProjection, modelViewProjection))
ValueCell.update(globalUniforms.uCameraPosition, camera.state.position)
ValueCell.update(globalUniforms.uFogFar, camera.state.fogFar)
ValueCell.update(globalUniforms.uFogNear, camera.state.fogNear)
......
......@@ -42,6 +42,12 @@ export const SpheresShaderCode = ShaderCode(
{ standardDerivatives: false, fragDepth: true }
)
export const TextShaderCode = ShaderCode(
require('mol-gl/shader/text.vert'),
require('mol-gl/shader/text.frag'),
{ standardDerivatives: true, fragDepth: false }
)
export const LinesShaderCode = ShaderCode(
require('mol-gl/shader/lines.vert'),
require('mol-gl/shader/lines.frag'),
......
uniform mat4 uProjection, uModel, uView;
uniform vec3 uCameraPosition;
uniform int uObjectId;
uniform int uInstanceCount;
......
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
precision highp float;
precision highp int;
#pragma glslify: import('./chunks/common-frag-params.glsl')
#pragma glslify: import('./chunks/color-frag-params.glsl')
uniform sampler2D tFont;
uniform vec3 uBorderColor;
uniform float uBorderWidth;
uniform vec3 uBackgroundColor;
uniform float uBackgroundOpacity;
varying vec2 vTexCoord;
const float smoothness = 32.0;
const float gamma = 2.2;
void main2(){
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
void main(){
#pragma glslify: import('./chunks/assign-material-color.glsl')
if (vTexCoord.x > 1.0) {
gl_FragColor = vec4(uBackgroundColor, uBackgroundOpacity);
} else {
// TODO nicer border
// retrieve signed distance
float sdf = texture2D(tFont, vTexCoord).a + uBorderWidth;
// perform adaptive anti-aliasing of the edges
float w = clamp(
smoothness * (abs(dFdx(vTexCoord.x)) + abs(dFdy(vTexCoord.y))),
0.0,
0.5
);
float a = smoothstep(0.5 - w, 0.5 + w, sdf);
// gamma correction for linear attenuation
a = pow(a, 1.0 / gamma);
if (a < 0.5) discard;
material.a *= a;
if (uBorderWidth > 0.0 && sdf < (0.5 + uBorderWidth)) {
material.xyz = uBorderColor;
}
gl_FragColor = material;
}
#if defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
if (uAlpha < uPickingAlphaThreshold)
discard; // ignore so the element below can be picked
#else
#pragma glslify: import('./chunks/apply-marker-color.glsl')
#pragma glslify: import('./chunks/apply-fog.glsl')
#endif
}
\ No newline at end of file
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
precision highp float;
precision highp int;
#pragma glslify: import('./chunks/common-vert-params.glsl')
#pragma glslify: import('./chunks/color-vert-params.glsl')
#pragma glslify: import('./chunks/size-vert-params.glsl')
uniform mat4 uModelView;
attribute vec3 aPosition;
attribute vec2 aMapping;
attribute vec2 aTexCoord;
attribute mat4 aTransform;
attribute float aInstance;
attribute float aGroup;
uniform float uOffsetX;
uniform float uOffsetY;
uniform float uOffsetZ;
// uniform bool ortho;
uniform float uPixelRatio;
uniform float uViewportHeight;
varying vec2 vTexCoord;
#pragma glslify: matrixScale = require(./utils/matrix-scale.glsl)
void main(void){
#pragma glslify: import('./chunks/assign-color-varying.glsl')
#pragma glslify: import('./chunks/assign-marker-varying.glsl')
#pragma glslify: import('./chunks/assign-size.glsl')
vTexCoord = aTexCoord;
float scale = matrixScale(uModelView);
float offsetX = uOffsetX * scale;
float offsetY = uOffsetY * scale;
float offsetZ = uOffsetZ * scale;
if (vTexCoord.x == 10.0) {
offsetZ -= 0.001;
}
vec4 mvPosition = uModelView * aTransform * vec4(aPosition, 1.0);
// #ifdef FIXED_SIZE
// if (ortho) {
// scale /= pixelRatio * ((uViewportHeight / 2.0) / -uCameraPosition.z) * 0.1;
// } else {
// scale /= pixelRatio * ((uViewportHeight / 2.0) / -mvPosition.z) * 0.1;
// }
// #endif
vec4 mvCorner = vec4(mvPosition.xyz, 1.0);
mvCorner.xy += aMapping * size * scale;
mvCorner.x += offsetX;
mvCorner.y += offsetY;
// if(ortho){
// mvCorner.xyz += normalize(-uCameraPosition) * offsetZ;
// } else {
// mvCorner.xyz += normalize(-mvCorner.xyz) * offsetZ;
// }
mvCorner.xyz += normalize(-mvCorner.xyz) * offsetZ;
gl_Position = uProjection * mvCorner;
vViewPosition = -mvCorner.xyz;
}
\ No newline at end of file
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import './index.html'
import { Canvas3D } from 'mol-canvas3d/canvas3d';
import { Geometry } from 'mol-geo/geometry/geometry';
import { TextBuilder } from 'mol-geo/geometry/text/text-builder';
import { Text } from 'mol-geo/geometry/text/text';
import { ParamDefinition as PD } from 'mol-util/param-definition';
import { Color } from 'mol-util/color';
import { createTextRenderObject, createSpheresRenderObject } from 'mol-gl/render-object';
import { Representation } from 'mol-repr/representation';
import { SpheresBuilder } from 'mol-geo/geometry/spheres/spheres-builder';
import { Spheres } from 'mol-geo/geometry/spheres/spheres';
const parent = document.getElementById('app')!
parent.style.width = '100%'
parent.style.height = '100%'
const canvas = document.createElement('canvas')
canvas.style.width = '100%'
canvas.style.height = '100%'
parent.appendChild(canvas)
const canvas3d = Canvas3D.create(canvas, parent)
canvas3d.animate()
function textRepr() {
const props: PD.Values<Text.Params> = {
...PD.getDefaultValues(Text.Params),
attachment: 'middle-center',
fontSize: 96,
fontWeight: 'bold',
}
const textBuilder = TextBuilder.create(props, 1, 1)
textBuilder.add('Hello world', 0, 0, 0, 0)
textBuilder.add('Добрый день', 0, 1, 0, 0)
textBuilder.add('美好的一天', 0, 2, 0, 0)
textBuilder.add('¿Cómo estás?', 0, -1, 0, 0)
textBuilder.add('αβγ Å', 0, -2, 0, 0)
const text = textBuilder.getText()
const values = Text.createValuesSimple(text, props, Color(0xFFDD00), 1)
const state = Text.createRenderableState(props)
const renderObject = createTextRenderObject(values, state)
console.log('text', renderObject)
const repr = Representation.fromRenderObject('text', renderObject)
return repr
}
function spheresRepr() {
const spheresBuilder = SpheresBuilder.create(2, 1)
spheresBuilder.add(5, 0, 0, 0)
spheresBuilder.add(-4, 1, 0, 0)
const spheres = spheresBuilder.getSpheres()
const values = Spheres.createValuesSimple(spheres, {}, Color(0xFF0000), 1)
const state = Geometry.createRenderableState()
const renderObject = createSpheresRenderObject(values, state)
console.log('spheres', renderObject)
const repr = Representation.fromRenderObject('spheres', renderObject)
return repr
}
canvas3d.add(textRepr())
canvas3d.add(spheresRepr())
canvas3d.resetCamera()
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment