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

use mesh-builder for spacefill repr

parent 881d22f8
No related branches found
No related tags found
No related merge requests found
Showing
with 193 additions and 172 deletions
......@@ -32,7 +32,7 @@ async function getPdb(pdb: string) {
}
import mcubes from './mcubes'
import Cylinder from 'mol-geo/primitive/cylinder';
// import Cylinder from 'mol-geo/primitive/cylinder';
export default class State {
async initRenderer (container: HTMLDivElement) {
......@@ -41,8 +41,8 @@ export default class State {
const p1 = Vec3.create(0, 4, 0)
const p2 = Vec3.create(-3, 0, 0)
const position = ValueCell.create(new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0]))
const normal = ValueCell.create(new Float32Array([0, 0, 0, 0, 0, 0, 0, 0, 0]))
// const position = ValueCell.create(new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0]))
// const normal = ValueCell.create(new Float32Array([0, 0, 0, 0, 0, 0, 0, 0, 0]))
const transformArray1 = ValueCell.create(new Float32Array(16))
const transformArray2 = ValueCell.create(new Float32Array(16 * 3))
......@@ -61,41 +61,41 @@ export default class State {
255, 0, 0
])
const points = createRenderObject('point', {
position,
transform: transformArray1
})
renderer.add(points)
const mesh = createRenderObject('mesh', {
position,
normal,
color,
transform: transformArray2
})
renderer.add(mesh)
const cylinder = Cylinder({ height: 3, radiusBottom: 0.5, radiusTop: 0.5 })
console.log(cylinder)
const cylinderMesh = createRenderObject('mesh', {
position: ValueCell.create(cylinder.vertices),
normal: ValueCell.create(cylinder.normals),
color,
transform: transformArray2
}, cylinder.indices)
renderer.add(cylinderMesh)
const sphere = Icosahedron()
console.log(sphere)
const box = Box()
console.log(box)
const points2 = createRenderObject('point', {
position: ValueCell.create(new Float32Array(box.vertices)),
transform: transformArray1
})
renderer.add(points2)
// const points = createRenderObject('point', {
// position,
// transform: transformArray1
// })
// // renderer.add(points)
// const mesh = createRenderObject('mesh', {
// position,
// normal,
// color,
// transform: transformArray2
// })
// renderer.add(mesh)
// const cylinder = Cylinder({ height: 3, radiusBottom: 0.5, radiusTop: 0.5 })
// console.log(cylinder)
// const cylinderMesh = createRenderObject('mesh', {
// position: ValueCell.create(cylinder.vertices),
// normal: ValueCell.create(cylinder.normals),
// color,
// transform: transformArray2
// }, cylinder.indices)
// renderer.add(cylinderMesh)
// const sphere = Icosahedron()
// console.log(sphere)
// const box = Box()
// console.log(box)
// const points2 = createRenderObject('point', {
// position: ValueCell.create(new Float32Array(box.vertices)),
// transform: transformArray1
// })
// renderer.add(points2)
let rr = 0.7;
function cubesF(x: number, y: number, z: number) {
......@@ -107,8 +107,13 @@ export default class State {
position: cubes.surface.vertexBuffer,
normal: cubes.surface.normalBuffer,
color,
transform: transformArray1,
}, cubes.surface.indexBuffer.ref.value);
transform: transformArray2,
elements: cubes.surface.indexBuffer,
instanceCount: transformArray2.ref.value.length / 16,
elementCount: cubes.surface.triangleCount,
positionCount: cubes.surface.vertexCount
}, {});
const mesh2 = makeCubesMesh();
renderer.add(mesh2)
......@@ -120,18 +125,11 @@ export default class State {
async function createSpacefills (structure: Structure) {
const spacefills: RenderObject[] = []
const { elements, units } = structure;
const unitIds = ElementSet.unitIds(elements);
for (let i = 0, _i = unitIds.length; i < _i; i++) {
const unitId = unitIds[i];
const unit = units[unitId];
const atomGroup = ElementSet.unitGetByIndex(elements, i);
const spacefill = Spacefill()
spacefills.push(...await Run(spacefill.create(unit, atomGroup), log, 1))
}
const spacefill = Spacefill()
spacefills.push(...await Run(spacefill.create(units, elements), log, 100))
return spacefills
}
const structures = await getPdb('1crn')
const structures = await getPdb('3pqr')
const spacefills = await createSpacefills(structures[0])
spacefills.forEach(renderer.add)
......
......@@ -16,9 +16,9 @@ export const DefaultBoxProps = {
heightSegments: 1,
depthSegments: 1
}
export type BoxProps = typeof DefaultBoxProps
export type BoxProps = Partial<typeof DefaultBoxProps>
export default function Box(props?: Partial<BoxProps>) {
export default function Box(props?: BoxProps) {
const { width, height, depth, widthSegments, heightSegments, depthSegments } = { ...DefaultBoxProps, ...props }
// buffers
......
......@@ -18,9 +18,9 @@ export const DefaultCylinderProps = {
thetaStart: 0.0,
thetaLength: Math.PI * 2
}
export type CylinderProps = typeof DefaultCylinderProps
export type CylinderProps = Partial<typeof DefaultCylinderProps>
export default function Cylinder(props?: Partial<CylinderProps>) {
export default function Cylinder(props?: CylinderProps) {
const { radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength } = { ...DefaultCylinderProps, ...props };
// buffers
......
......@@ -27,8 +27,8 @@ export const DefaultIcosahedronProps = {
radius: 1,
detail: 0
}
export type IcosahedronProps = typeof DefaultIcosahedronProps
export type IcosahedronProps = Partial<typeof DefaultIcosahedronProps>
export default function Icosahedron(props?: Partial<IcosahedronProps>) {
export default function Icosahedron(props?: IcosahedronProps) {
return Polyhedron(vertices, indices, { ...DefaultIcosahedronProps, ...props })
}
\ No newline at end of file
......@@ -13,9 +13,9 @@ export const DefaultPolyhedronProps = {
radius: 1,
detail: 0
}
export type PolyhedronProps = typeof DefaultPolyhedronProps
export type PolyhedronProps = Partial<typeof DefaultPolyhedronProps>
export default function Polyhedron(_vertices: Helpers.NumberArray, _indices: Helpers.NumberArray, props?: Partial<PolyhedronProps>) {
export default function Polyhedron(_vertices: Helpers.NumberArray, _indices: Helpers.NumberArray, props?: PolyhedronProps) {
const { radius, detail } = { ...DefaultPolyhedronProps, ...props }
const vertices: number[] = [];
......@@ -95,6 +95,8 @@ export default function Polyhedron(_vertices: Helpers.NumberArray, _indices: Hel
} else {
vertices.push(...v[i][k + 1], ...v[i + 1][k + 1], ...v[i + 1][k])
}
const l = vertices.length / 3
indices.push(l - 3, l - 2, l - 1)
}
}
}
......
......@@ -15,7 +15,7 @@ export interface RepresentationProps {
}
export interface UnitRepresentation {
create: (unit: Unit, elementGroup: ElementGroup, props?: Partial<RepresentationProps>) => Task<RenderObject[]>,
create: (units: ReadonlyArray<Unit>, elements: ElementSet, props?: Partial<RepresentationProps>) => Task<RenderObject[]>,
update: (props: RepresentationProps) => boolean,
}
......@@ -42,7 +42,7 @@ export class StructureRepresentation {
}
const u = this.repr.create(units[0], 0 as any, 0 as any);
const u = this.repr.create(units, 0 as any, 0 as any);
await ctx.update('Building units...');
await ctx.runChild(u);
......
......@@ -8,78 +8,75 @@ import { ValueCell } from 'mol-util/value-cell'
import { createRenderObject, RenderObject } from 'mol-gl/renderer'
import { createColorTexture } from 'mol-gl/util';
import Icosahedron from 'mol-geo/primitive/icosahedron'
import { Vec3, Mat4 } from 'mol-math/linear-algebra'
import { OrderedSet } from 'mol-data/int'
import { Element, ElementGroup, Unit } from 'mol-model/structure';
import { Element, Unit, ElementSet } from 'mol-model/structure';
import P from 'mol-model/structure/query/properties';
import { RepresentationProps, UnitRepresentation } from './index';
import { Task } from 'mol-task'
import { MeshBuilder } from '../../shape/mesh-builder';
export default function Spacefill(): UnitRepresentation {
let vertices: Float32Array
let normals: Float32Array
const renderObjects: RenderObject[] = []
// unit: Unit, atomGroup: AtomGroup
return {
create: (unit: Unit, elementGroup: ElementGroup, props: Partial<RepresentationProps> = {}) => Task.create('Spacefill', async ctx => {
const elementCount = OrderedSet.size(elementGroup.elements)
create: (units: ReadonlyArray<Unit>, elements: ElementSet, props: Partial<RepresentationProps> = {}) => Task.create('Spacefill', async ctx => {
const l = Element.Location();
l.unit = unit;
const meshBuilder = MeshBuilder.create()
const sphere = Icosahedron({ radius: 1, detail: 0 })
const vertexCount = sphere.vertices.length / 3
const unitIds = ElementSet.unitIds(elements);
for (let i = 0, _i = unitIds.length; i < _i; i++) {
const unitId = unitIds[i];
const unit = units[unitId];
const elementGroup = ElementSet.unitGetByIndex(elements, i);
vertices = new Float32Array(elementCount * vertexCount * 3)
normals = new Float32Array(elementCount * vertexCount * 3)
const elementCount = OrderedSet.size(elementGroup.elements)
const v = Vec3.zero()
const m = Mat4.identity()
l.unit = unit;
for (let i = 0; i < elementCount; i++) {
l.element = OrderedSet.getAt(elementGroup.elements, i)
const v = Vec3.zero()
const m = Mat4.identity()
v[0] = P.atom.x(l)
v[1] = P.atom.y(l)
v[2] = P.atom.z(l)
Mat4.setTranslation(m, v)
for (let i = 0; i < elementCount; i++) {
l.element = OrderedSet.getAt(elementGroup.elements, i)
for (let j = 0; j < vertexCount; ++j) {
Vec3.fromArray(v, sphere.vertices, j * 3)
Vec3.transformMat4(v, v, m)
Vec3.toArray(v, vertices, i * vertexCount * 3 + j * 3)
}
v[0] = P.atom.x(l)
v[1] = P.atom.y(l)
v[2] = P.atom.z(l)
Mat4.setTranslation(m, v)
normals.set(sphere.normals, i * vertexCount * 3);
meshBuilder.addIcosahedron(m, { radius: P.atom.vdw(l), detail: 1 })
}
if (i % 100 === 0 && ctx.shouldUpdate) {
await ctx.update({ message: 'Spacefill', current: i, max: elementCount });
if (i % 10 === 0 && ctx.shouldUpdate) {
await ctx.update({ message: 'Spacefill', current: i, max: _i });
}
}
const transformArray = new Float32Array(16)
const transformArray = new Float32Array(32)
const m4 = Mat4.identity()
Mat4.toArray(m4, transformArray, 0)
const color = ValueCell.create(createColorTexture(1))
color.ref.value.set([ 0, 0, 255 ])
const spheres = createRenderObject(
'mesh',
{
position: ValueCell.create(new Float32Array(vertices)),
normal: ValueCell.create(new Float32Array(normals)),
color,
transform: ValueCell.create(transformArray)
}
)
const mesh = meshBuilder.getMesh()
// console.log(mesh)
// console.log({ vertices, normals, vertexCount, atomCount })
const spheres = createRenderObject('mesh', {
position: mesh.vertexBuffer,
normal: mesh.normalBuffer,
color,
transform: ValueCell.create(transformArray),
elements: mesh.indexBuffer,
instanceCount: transformArray.length / 16,
elementCount: mesh.triangleCount,
positionCount: mesh.vertexCount
}, {})
renderObjects.push(spheres)
return renderObjects
......
......@@ -9,18 +9,22 @@ import { Vec3, Mat4 } from 'mol-math/linear-algebra';
import { ChunkedArray } from 'mol-data/util';
import Box, { BoxProps } from '../primitive/box';
import Icosahedron, { IcosahedronProps } from '../primitive/icosahedron';
import { Mesh } from './mesh';
type ElementId = { id: number }
type ElementId = { id?: number }
export interface MeshBuilder {
add(t: Mat4, _vertices: Float32Array, _normals: Float32Array, _indices?: Uint32Array): number
addBox(t: Mat4, props?: BoxProps & ElementId): number
addIcosahedron(t: Mat4, props?: IcosahedronProps & ElementId): number
getMesh(): Mesh
}
const tmpV = Vec3.zero()
// TODO cache primitives based on props
export namespace MeshBuilder {
export function create(initialCount = 2048, chunkSize = 1024): MeshBuilder {
const vertices = ChunkedArray.create(Float32Array, 3, chunkSize, initialCount);
......@@ -32,16 +36,22 @@ export namespace MeshBuilder {
ChunkedArray.compact(indices, true)
const add = (t: Mat4, _vertices: Float32Array, _normals: Float32Array, _indices?: Uint32Array) => {
const offset = vertices.elementCount * vertices.elementSize
const add = (t: Mat4, _vertices: Float32Array, _normals: Float32Array, _indices: Uint32Array) => {
const { elementCount, elementSize } = vertices
for (let i = 0, il = _vertices.length; i < il; i += 3) {
// position
Vec3.fromArray(tmpV, _vertices, i)
Vec3.transformMat4(tmpV, tmpV, t)
// Vec3.transformDirection(tmpV, tmpV, n) // TODO
ChunkedArray.add3(vertices, tmpV[0], tmpV[1], tmpV[2]);
// normal
Vec3.fromArray(tmpV, _normals, i)
// Vec3.transformDirection(tmpV, tmpV, n) // TODO
ChunkedArray.add3(normals, tmpV[0], tmpV[1], tmpV[2]);
}
// ChunkedArray.add(vertices, _vertices[i])
return offset
for (let i = 0, il = _indices.length; i < il; i += 3) {
ChunkedArray.add3(indices, _indices[i] + elementCount, _indices[i + 1] + elementCount, _indices[i + 2] + elementCount);
}
return elementCount * elementSize
}
return {
......@@ -50,6 +60,10 @@ export namespace MeshBuilder {
const box = Box(props)
return add(t, box.vertices, box.normals, box.indices)
},
addIcosahedron: (t: Mat4, props?: IcosahedronProps & ElementId) => {
const icosahedron = Icosahedron(props)
return add(t, icosahedron.vertices, icosahedron.normals, icosahedron.indices)
},
getMesh: () => {
return {
vertexCount: vertices.elementCount,
......
......@@ -63,13 +63,26 @@ namespace Attribute {
export type ArrayCell<T> = { array: ReferenceCell<T> }
export type ReferenceCell<T> = { readonly version: number, readonly value: T }
export function create<T extends Helpers.TypedArray>(regl: REGL.Regl, array: ValueCell<T>, props: AttributeProps): Attribute<T> {
export function create<T extends Float32Array>(regl: REGL.Regl, array: ValueCell<T>, count: number, props: AttributeProps): Attribute<T> {
const itemSize = props.size
let _array = array.ref.value
let _count = _array.length / itemSize
if (props.stride) _count = _array.length / (props.stride / _array.BYTES_PER_ELEMENT)
console.log(_array.length, props.stride)
const buffer = regl.buffer(_array)
let _count = count
// if (props.stride) _count = _array.length / (props.stride / _array.BYTES_PER_ELEMENT)
// console.log(_array.length, props.stride)
// console.log('buffer', {
// data: _array,
// length: count * itemSize,
// usage: 'dynamic',
// type: 'float32'
// })
const buffer = regl.buffer({
data: _array,
// length: count * itemSize * _array.BYTES_PER_ELEMENT,
usage: 'dynamic',
type: 'float32',
dimension: itemSize
} as any)
// console.log(buffer)
const attribute: REGL.AttributeConfig = { ...props, buffer }
const growIfNeeded = function(count: number) {
if (count * itemSize > _array.length) {
......
......@@ -14,7 +14,7 @@ export type AttributesData = { [k: string]: Helpers.TypedArray }
export type Attributes<T extends AttributesData> = { [K in keyof T]: Attribute<T[K]> }
export type AttributesBuffers<T extends AttributesData> = { [K in keyof T]: REGL.AttributeConfig }
export interface Renderable<T extends AttributesData> {
export interface Renderable {
draw(): void
// isPicking: () => boolean
// isVisible: () => boolean
......
......@@ -18,52 +18,49 @@ type Mesh = 'mesh'
type Uniforms = { [k: string]: REGL.Uniform | REGL.Texture }
namespace Mesh {
export type DataType = {
position: { type: Float32Array, itemSize: 3 }
normal: { type: Float32Array, itemSize: 3 }
transform: { type: Float32Array, itemSize: 16 }
color: { type: ColorTexture, itemSize: 16 }
export type Data = {
position: ValueCell<Float32Array>
normal: ValueCell<Float32Array>
transform: ValueCell<Float32Array>
color: ValueCell<ColorTexture>
elements: ValueCell<Uint32Array>
instanceCount: number
elementCount: number
positionCount: number
}
export type Data = { [K in keyof DataType]: DataType[K]['type'] }
export type BoxedData = { [K in keyof Data]: ValueCell<Data[K]> }
export function create(regl: REGL.Regl, data: BoxedData, uniforms: Uniforms, elements?: Helpers.UintArray): Renderable<Data> {
// console.log('mesh', {
// count: attributes.position.getCount(),
// instances: attributes.transformColumn0.getCount(),
// attributes,
// uniforms
// })
const instanceCount = data.transform.ref.value.length / 16
const instanceId = ValueCell.create(fillSerial(new Float32Array(instanceCount)))
// console.log(instanceId)
export function create(regl: REGL.Regl, data: Data, uniforms: Uniforms): Renderable {
console.log(data)
const instanceId = ValueCell.create(fillSerial(new Float32Array(data.instanceCount)))
const command = regl({
...MeshShaders,
uniforms: {
objectId: uniforms.objectId || 0,
instanceCount,
instanceCount: data.instanceCount,
...createColorUniforms(regl, data.color),
...uniforms
},
attributes: getBuffers({
instanceId: Attribute.create(regl, instanceId, { size: 1, divisor: 1 }),
position: Attribute.create(regl, data.position, { size: 3 }),
normal: Attribute.create(regl, data.normal, { size: 3 }),
...createTransformAttributes(regl, data.transform)
instanceId: Attribute.create(regl, instanceId, data.instanceCount, { size: 1, divisor: 1 }),
position: Attribute.create(regl, data.position, data.positionCount, { size: 3 }),
normal: Attribute.create(regl, data.normal, data.positionCount, { size: 3 }),
...createTransformAttributes(regl, data.transform, data.instanceCount)
}),
elements: elements && regl.elements({
data: new Uint16Array(elements),
elements: regl.elements({
data: data.elements.ref.value,
primitive: 'triangles',
// type: 'uint16',
// count: elements.length / 3,
// length: elements.length * 2
type: 'uint32',
count: data.elementCount * 3,
// length: count * 3 * 2
}),
count: elements ? elements.length : data.position.ref.value.length / 3,
instances: instanceCount,
primitive: 'triangles'
instances: data.instanceCount,
})
return {
draw: () => command(),
draw: () => {
command()
console.log(command.stats)
}
}
}
}
......
......@@ -15,25 +15,25 @@ import { PointShaders } from '../shaders'
type Point = 'point'
namespace Point {
export type DataType = {
position: { type: Float32Array, itemSize: 3 }
transform: { type: Float32Array, itemSize: 16 }
export type Data = {
position: ValueCell<Float32Array>
transform: ValueCell<Float32Array>
instanceCount: number
positionCount: number
}
export type Data = { [K in keyof DataType]: DataType[K]['type'] }
export type BoxedData = { [K in keyof Data]: ValueCell<Data[K]> }
export function create(regl: REGL.Regl, data: BoxedData): Renderable<Data> {
const instanceCount = data.transform.ref.value.length / 16
const instanceId = ValueCell.create(fillSerial(new Float32Array(instanceCount)))
export function create(regl: REGL.Regl, data: Data): Renderable {
const instanceId = ValueCell.create(fillSerial(new Float32Array(data.instanceCount)))
const command = regl({
...PointShaders,
attributes: getBuffers({
instanceId: Attribute.create(regl, instanceId, { size: 1, divisor: 1 }),
position: Attribute.create(regl, data.position, { size: 3 }),
...createTransformAttributes(regl, data.transform)
instanceId: Attribute.create(regl, instanceId, data.instanceCount, { size: 1, divisor: 1 }),
position: Attribute.create(regl, data.position, data.positionCount, { size: 3 }),
...createTransformAttributes(regl, data.transform, data.positionCount)
}),
count: data.position.ref.value.length / 3,
instances: instanceCount,
count: data.positionCount,
instances: data.instanceCount,
primitive: 'points'
})
return {
......
......@@ -11,16 +11,16 @@ import { ColorTexture } from '../util';
import { Attributes, AttributesData, AttributesBuffers } from '../renderable'
import Attribute from '../attribute'
export function createTransformAttributes (regl: REGL.Regl, transform: ValueCell<Float32Array>) {
export function createTransformAttributes (regl: REGL.Regl, transform: ValueCell<Float32Array>, count: number) {
const size = 4
const divisor = 1
const bpe = transform.ref.value.BYTES_PER_ELEMENT
const stride = 16 * bpe
return {
transformColumn0: Attribute.create(regl, transform, { size, divisor, offset: 0, stride }),
transformColumn1: Attribute.create(regl, transform, { size, divisor, offset: 4 * bpe, stride }),
transformColumn2: Attribute.create(regl, transform, { size, divisor, offset: 8 * bpe, stride }),
transformColumn3: Attribute.create(regl, transform, { size, divisor, offset: 12 * bpe, stride })
transformColumn0: Attribute.create(regl, transform, count, { size, divisor, offset: 0, stride }),
transformColumn1: Attribute.create(regl, transform, count, { size, divisor, offset: 4 * bpe, stride }),
transformColumn2: Attribute.create(regl, transform, count, { size, divisor, offset: 8 * bpe, stride }),
transformColumn3: Attribute.create(regl, transform, count, { size, divisor, offset: 12 * bpe, stride })
}
}
......
......@@ -28,13 +28,12 @@ export type RenderData = { [k: string]: ValueCell<Helpers.TypedArray> }
export interface RenderObject {
id: number
type: 'mesh' | 'point'
data: any
elements: any
uniforms: any
data: PointRenderable.Data | MeshRenderable.Data
uniforms: { [k: string]: REGL.Uniform }
}
export function createRenderObject(type: 'mesh' | 'point', data: any, elements?: any, uniforms?: any) {
return { id: getNextId(), type, data, elements, uniforms }
export function createRenderObject(type: 'mesh' | 'point', data: PointRenderable.Data | MeshRenderable.Data, uniforms: { [k: string]: REGL.Uniform }) {
return { id: getNextId(), type, data, uniforms }
}
export interface Renderer {
......@@ -46,14 +45,14 @@ export interface Renderer {
export function createRenderable(regl: REGL.Regl, o: RenderObject) {
switch (o.type) {
case 'mesh': return MeshRenderable.create(regl, o.data, o.uniforms || {}, o.elements)
case 'point': return PointRenderable.create(regl, o.data)
case 'mesh': return MeshRenderable.create(regl, o.data as MeshRenderable.Data, o.uniforms || {})
case 'point': return PointRenderable.create(regl, o.data as PointRenderable.Data)
}
}
export function createRenderer(container: HTMLDivElement): Renderer {
const renderableList: Renderable<any>[] = []
const objectIdRenderableMap: { [k: number]: Renderable<any> } = {}
const renderableList: Renderable[] = []
const objectIdRenderableMap: { [k: number]: Renderable } = {}
const regl = glContext.create({
container,
......@@ -65,7 +64,7 @@ export function createRenderer(container: HTMLDivElement): Renderer {
'EXT_blend_minmax',
'ANGLE_instanced_arrays'
],
// profile: true
profile: true
})
const camera = Camera.create(regl, container, {
......
......@@ -71,5 +71,6 @@ void main() {
vec3 color = vColor * (diffuse + ambient) + specular;
gl_FragColor.rgb = N;
// gl_FragColor.rgb = vec3(1.0, 0.0, 0.0);
gl_FragColor.a = 1.0;
}
\ No newline at end of file
......@@ -21,6 +21,6 @@ attribute vec4 transformColumn0, transformColumn1, transformColumn2, transformCo
void main(){
mat4 transform = mat4(transformColumn0, transformColumn1, transformColumn2, transformColumn3);
// vColor = color;
gl_PointSize = 20.0;
gl_PointSize = 5.0;
gl_Position = projection * view * model * transform * vec4(position, 1.0);
}
\ 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