first commit
This commit is contained in:
770
pipelines/OceanPipeline.js
Normal file
770
pipelines/OceanPipeline.js
Normal file
@@ -0,0 +1,770 @@
|
||||
import { RenderPipeline } from "/framework/RenderPipeline.js";
|
||||
|
||||
import { Block } from "/framework/Block.js";
|
||||
|
||||
import Camera from "/framework/Camera.js";
|
||||
|
||||
import EventManager from "/framework/eventManager.js";
|
||||
|
||||
import { SpectrumPass } from "../passes/SpectrumPass.js";
|
||||
|
||||
import { RowFFTPass } from "../passes/RowFFTPass.js";
|
||||
|
||||
import { ColFFTPass } from "../passes/ColFFTPass.js";
|
||||
|
||||
import { OceanRenderPass } from "../passes/OceanRenderPass.js";
|
||||
|
||||
import { OceanSolidRenderPass } from "../passes/OceanSolidRenderPass.js";
|
||||
|
||||
import { SkySpherePass } from "../passes/SkySpherePass.js";
|
||||
|
||||
|
||||
export class OceanPipeline extends RenderPipeline {
|
||||
|
||||
constructor( engine, canvas ) {
|
||||
|
||||
super( engine );
|
||||
|
||||
this.canvas = canvas;
|
||||
this.canvasConfigured = false;
|
||||
|
||||
this.gridSize = 64;
|
||||
this.meshResolution = 64;
|
||||
|
||||
this.offsetX = 0;
|
||||
this.offsetZ = 0;
|
||||
|
||||
this.wavelengthScale = 1.0;
|
||||
|
||||
this.tiling = 1;
|
||||
|
||||
this.handleInput = true;
|
||||
|
||||
this.renderMode = "solid";
|
||||
this.shadingMode = "lighting";
|
||||
|
||||
this.isPaused = false;
|
||||
this.elapsedTime = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
async create( ) {
|
||||
|
||||
this.patchSize = 80;
|
||||
this.heightScale = 54.0;
|
||||
this.timeScale = 0.35;
|
||||
|
||||
this.startTime = performance.now();
|
||||
|
||||
const simSize = this.gridSize;
|
||||
|
||||
this.memory.set( "h0Real", new Float32Array( simSize * simSize ) );
|
||||
|
||||
this.memory.set( "h0Imag", new Float32Array( simSize * simSize ) );
|
||||
|
||||
this.memory.set( "spectrumReal", new Float32Array( simSize * simSize ) );
|
||||
|
||||
this.memory.set( "spectrumImag", new Float32Array( simSize * simSize ) );
|
||||
|
||||
this.memory.set( "rowReal", new Float32Array( simSize * simSize ) );
|
||||
|
||||
this.memory.set( "rowImag", new Float32Array( simSize * simSize ) );
|
||||
|
||||
this.memory.set( "colReal", new Float32Array( simSize * simSize ) );
|
||||
|
||||
this.memory.set( "colImag", new Float32Array( simSize * simSize ) );
|
||||
|
||||
this.memory.set( "heightField", new Float32Array( simSize * simSize ) );
|
||||
|
||||
this.memory.set( "computeParams", new Float32Array( 4 ) );
|
||||
|
||||
this.memory.set( "renderParams", new Float32Array( [ simSize, this.patchSize, this.heightScale, 0, this.meshResolution, this.tiling, this.wavelengthScale ] ) );
|
||||
|
||||
this._seedSpectrum();
|
||||
|
||||
const geometry = this._buildGridGeometry( this.meshResolution, this.patchSize );
|
||||
|
||||
this.memory.set( "positions", geometry.positions );
|
||||
|
||||
this.memory.set( "uvs", geometry.uvs );
|
||||
|
||||
this.memory.set( "indices", geometry.indices );
|
||||
|
||||
this.memory.set( "lineIndices", geometry.lineIndices );
|
||||
|
||||
const skySphere = this._buildSkySphereGeometry( 220, 32, 64 );
|
||||
|
||||
this.memory.set( "skyPositions", skySphere.positions );
|
||||
|
||||
this.memory.set( "skyNormals", skySphere.normals );
|
||||
|
||||
this.memory.set( "skyIndices", skySphere.indices );
|
||||
|
||||
const cubeGeometry = this._buildCubeGeometry();
|
||||
|
||||
this.memory.set( "cubePositions", cubeGeometry.positions );
|
||||
|
||||
this.memory.set( "cubeColors", cubeGeometry.colors );
|
||||
|
||||
this.memory.set( "cubeIndices", cubeGeometry.indices );
|
||||
|
||||
|
||||
const block = new Block( "ocean", this );
|
||||
|
||||
const spectrumPass = new SpectrumPass( );
|
||||
|
||||
const rowFFTPass = new RowFFTPass( );
|
||||
|
||||
const colFFTPass = new ColFFTPass( );
|
||||
|
||||
const renderWirePass = new OceanRenderPass( );
|
||||
|
||||
const renderSolidPass = new OceanSolidRenderPass( );
|
||||
|
||||
const skySpherePass = new SkySpherePass( );
|
||||
|
||||
block.addPass( "Spectrum", spectrumPass );
|
||||
|
||||
block.addPass( "RowFFT", rowFFTPass );
|
||||
|
||||
block.addPass( "ColFFT", colFFTPass );
|
||||
|
||||
block.addPass( "RenderWire", renderWirePass );
|
||||
|
||||
block.addPass( "RenderSolid", renderSolidPass );
|
||||
|
||||
block.addPass( "SkySphere", skySpherePass );
|
||||
|
||||
this.addBlock( block );
|
||||
|
||||
this.camera = new Camera( [ 0, 90, 120 ], [ 0, 0, 0 ], [ 0, 1, 0 ] );
|
||||
|
||||
this.camera.far = 6000.0;
|
||||
|
||||
this.camera.pitch = Math.PI / 3;
|
||||
|
||||
this.camera.update();
|
||||
|
||||
this.eventManager = new EventManager( );
|
||||
|
||||
if ( this.canvas && this.handleInput ) {
|
||||
|
||||
this.eventManager.setup( this.canvas, this.camera );
|
||||
|
||||
this.eventManager.registerEventListeners();
|
||||
|
||||
}
|
||||
|
||||
await super.create();
|
||||
|
||||
}
|
||||
|
||||
|
||||
setHeightScale( value ) {
|
||||
|
||||
this.heightScale = value;
|
||||
|
||||
this.memory.computeParams[ 2 ] = value;
|
||||
this.memory.renderParams[ 2 ] = value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
setWavelengthScale( value ) {
|
||||
|
||||
if ( value <= 0 ) {
|
||||
|
||||
value = 0.25;
|
||||
|
||||
}
|
||||
|
||||
this.wavelengthScale = value;
|
||||
|
||||
if ( this.memory && this.memory.renderParams ) {
|
||||
|
||||
this.memory.renderParams[ 6 ] = this.wavelengthScale;
|
||||
|
||||
}
|
||||
|
||||
this._seedSpectrum( );
|
||||
|
||||
const block = this.getBlockByName( "ocean" );
|
||||
|
||||
if ( block ) {
|
||||
|
||||
const spectrumPass = block.getPass( "Spectrum" );
|
||||
|
||||
if ( spectrumPass && spectrumPass.shader ) {
|
||||
|
||||
spectrumPass.shader.setVariable( "h0Real", this.memory.h0Real );
|
||||
|
||||
spectrumPass.shader.setVariable( "h0Imag", this.memory.h0Imag );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
setRenderMode( mode ) {
|
||||
|
||||
if ( mode !== "wireframe" && mode !== "solid" ) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
this.renderMode = mode;
|
||||
|
||||
}
|
||||
|
||||
|
||||
setShadingMode( mode ) {
|
||||
|
||||
let code = 0;
|
||||
|
||||
if ( mode === "normals" ) {
|
||||
|
||||
code = 1;
|
||||
|
||||
} else if ( mode === "solid" ) {
|
||||
|
||||
code = 2;
|
||||
|
||||
} else if ( mode === "height" ) {
|
||||
|
||||
code = 3;
|
||||
|
||||
} else if ( mode === "realistic" ) {
|
||||
|
||||
code = 4;
|
||||
|
||||
} else {
|
||||
|
||||
mode = "lighting";
|
||||
code = 0;
|
||||
|
||||
}
|
||||
|
||||
this.shadingMode = mode;
|
||||
this.memory.renderParams[ 3 ] = code;
|
||||
|
||||
}
|
||||
|
||||
|
||||
setTiling( value ) {
|
||||
|
||||
if ( value < 1 ) {
|
||||
|
||||
value = 1;
|
||||
|
||||
}
|
||||
|
||||
this.tiling = value;
|
||||
this.memory.renderParams[ 5 ] = value;
|
||||
|
||||
}
|
||||
|
||||
setOffset( x, z ) {
|
||||
|
||||
this.offsetX = x;
|
||||
this.offsetZ = z;
|
||||
|
||||
// Offsets are now handled in the vertex shader via instancing.
|
||||
|
||||
}
|
||||
|
||||
|
||||
setPaused( paused ) {
|
||||
|
||||
if ( paused === this.isPaused ) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
this.isPaused = paused;
|
||||
|
||||
if ( !paused ) {
|
||||
|
||||
this.startTime = performance.now() - this.elapsedTime * 1000.0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
async stepOnce( stepSeconds = 1 / 60 ) {
|
||||
|
||||
if ( !this.isPaused ) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
this.elapsedTime += stepSeconds;
|
||||
|
||||
this.memory.computeParams[ 0 ] = this.elapsedTime * this.timeScale;
|
||||
this.memory.computeParams[ 1 ] = this.gridSize;
|
||||
|
||||
await this.bindBuffers( );
|
||||
await this.execute( );
|
||||
|
||||
}
|
||||
|
||||
|
||||
async bindBuffers( ) {
|
||||
|
||||
const nowSeconds = ( performance.now() - this.startTime ) / 1000;
|
||||
|
||||
if ( !this.isPaused ) {
|
||||
|
||||
this.elapsedTime = nowSeconds;
|
||||
|
||||
}
|
||||
|
||||
this.memory.computeParams[ 0 ] = this.elapsedTime * this.timeScale;
|
||||
this.memory.computeParams[ 1 ] = this.gridSize;
|
||||
|
||||
|
||||
const block = this.getBlockByName( "ocean" );
|
||||
|
||||
const spectrumPass = block.getPass( "Spectrum" );
|
||||
|
||||
const rowFFTPass = block.getPass( "RowFFT" );
|
||||
|
||||
const colFFTPass = block.getPass( "ColFFT" );
|
||||
|
||||
const renderWirePass = block.getPass( "RenderWire" );
|
||||
|
||||
const renderSolidPass = block.getPass( "RenderSolid" );
|
||||
|
||||
const skyPass = block.getPass( "SkySphere" );
|
||||
|
||||
|
||||
await spectrumPass.bindBuffers( );
|
||||
|
||||
await rowFFTPass.bindBuffers( );
|
||||
|
||||
await colFFTPass.bindBuffers( );
|
||||
|
||||
|
||||
if ( this.renderMode === "solid" ) {
|
||||
|
||||
await renderSolidPass.bindBuffers( );
|
||||
|
||||
} else {
|
||||
|
||||
await renderWirePass.bindBuffers( );
|
||||
|
||||
}
|
||||
|
||||
if ( skyPass ) {
|
||||
|
||||
await skyPass.bindBuffers( );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
async execute( ) {
|
||||
|
||||
const block = this.getBlockByName( "ocean" );
|
||||
|
||||
const spectrumPass = block.getPass( "Spectrum" );
|
||||
|
||||
const rowFFTPass = block.getPass( "RowFFT" );
|
||||
|
||||
const colFFTPass = block.getPass( "ColFFT" );
|
||||
|
||||
|
||||
await spectrumPass.execute( );
|
||||
|
||||
await rowFFTPass.execute( );
|
||||
|
||||
await colFFTPass.execute( );
|
||||
|
||||
}
|
||||
|
||||
|
||||
_seedSpectrum( ) {
|
||||
|
||||
const size = this.gridSize;
|
||||
|
||||
const phillipsA = 0.0006;
|
||||
|
||||
const windSpeed = 24.0;
|
||||
|
||||
const windDir = { x: 0.8, y: 0.6 };
|
||||
|
||||
const baseL = windSpeed * windSpeed / 9.81;
|
||||
|
||||
let wlScale = this.wavelengthScale;
|
||||
|
||||
if ( wlScale <= 0 ) {
|
||||
|
||||
wlScale = 0.25;
|
||||
|
||||
}
|
||||
|
||||
const L = baseL;
|
||||
|
||||
for ( let y = 0; y < size; y++ ) {
|
||||
|
||||
for ( let x = 0; x < size; x++ ) {
|
||||
|
||||
const kx = ( x - size / 2 ) * ( Math.PI * 2 / this.patchSize );
|
||||
|
||||
const ky = ( y - size / 2 ) * ( Math.PI * 2 / this.patchSize );
|
||||
|
||||
const kLength = Math.sqrt( kx * kx + ky * ky );
|
||||
|
||||
if ( kLength === 0 ) {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
const kxNorm = kx / kLength;
|
||||
|
||||
const kyNorm = ky / kLength;
|
||||
|
||||
const windDotK = kxNorm * windDir.x + kyNorm * windDir.y;
|
||||
|
||||
const kScaled = kLength / wlScale;
|
||||
|
||||
const phillips = phillipsA * Math.exp( -1 / ( kScaled * kScaled * L * L ) ) / Math.pow( kScaled, 4 ) * ( windDotK * windDotK );
|
||||
|
||||
const gaussianR = this._gaussianRandom();
|
||||
|
||||
const gaussianI = this._gaussianRandom();
|
||||
|
||||
const amplitude = Math.sqrt( phillips ) * Math.SQRT1_2;
|
||||
|
||||
const idx = y * size + x;
|
||||
|
||||
this.memory.h0Real[ idx ] = gaussianR * amplitude;
|
||||
|
||||
this.memory.h0Imag[ idx ] = gaussianI * amplitude;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// enforce conjugate symmetry: h0(-k) = conj( h0(k) ) for a real height field
|
||||
for ( let y = 0; y < size; y++ ) {
|
||||
|
||||
for ( let x = 0; x < size; x++ ) {
|
||||
|
||||
const idx = y * size + x;
|
||||
|
||||
const mx = ( size - x ) % size;
|
||||
|
||||
const my = ( size - y ) % size;
|
||||
|
||||
const mirrorIdx = my * size + mx;
|
||||
|
||||
this.memory.h0Real[ mirrorIdx ] = this.memory.h0Real[ idx ];
|
||||
|
||||
this.memory.h0Imag[ mirrorIdx ] = -this.memory.h0Imag[ idx ];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
this.memory.computeParams[ 0 ] = 0;
|
||||
this.memory.computeParams[ 1 ] = this.gridSize;
|
||||
this.memory.computeParams[ 2 ] = this.heightScale;
|
||||
this.memory.computeParams[ 3 ] = this.patchSize;
|
||||
this.memory.renderParams[ 2 ] = this.heightScale;
|
||||
|
||||
}
|
||||
|
||||
|
||||
_gaussianRandom( ) {
|
||||
|
||||
let u = 0, v = 0;
|
||||
|
||||
while ( u === 0 ) u = Math.random();
|
||||
|
||||
while ( v === 0 ) v = Math.random();
|
||||
|
||||
return Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );
|
||||
|
||||
}
|
||||
|
||||
|
||||
_buildGridGeometry( size, span ) {
|
||||
|
||||
const vertexCount = size * size;
|
||||
|
||||
const positions = new Float32Array( vertexCount * 3 );
|
||||
|
||||
const uvs = new Float32Array( vertexCount * 2 );
|
||||
|
||||
const quadCount = ( size - 1 ) * ( size - 1 );
|
||||
|
||||
const indices = new Uint32Array( quadCount * 6 );
|
||||
|
||||
const horizontalLines = size * ( size - 1 );
|
||||
|
||||
const verticalLines = ( size - 1 ) * size;
|
||||
|
||||
const lineIndices = new Uint32Array( ( horizontalLines + verticalLines ) * 2 );
|
||||
|
||||
let pi = 0;
|
||||
let ui = 0;
|
||||
|
||||
for ( let y = 0; y < size; y++ ) {
|
||||
|
||||
for ( let x = 0; x < size; x++ ) {
|
||||
|
||||
const fx = x / ( size - 1 );
|
||||
|
||||
const fy = y / ( size - 1 );
|
||||
|
||||
const worldX = ( fx - 0.5 ) * span;
|
||||
|
||||
const worldZ = ( fy - 0.5 ) * span;
|
||||
|
||||
positions[ pi++ ] = worldX;
|
||||
positions[ pi++ ] = 0;
|
||||
positions[ pi++ ] = worldZ;
|
||||
|
||||
uvs[ ui++ ] = x;
|
||||
uvs[ ui++ ] = y;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let ii = 0;
|
||||
|
||||
let li = 0;
|
||||
|
||||
for ( let y = 0; y < size - 1; y++ ) {
|
||||
|
||||
for ( let x = 0; x < size - 1; x++ ) {
|
||||
|
||||
const topLeft = y * size + x;
|
||||
|
||||
const topRight = topLeft + 1;
|
||||
|
||||
const bottomLeft = topLeft + size;
|
||||
|
||||
const bottomRight = bottomLeft + 1;
|
||||
|
||||
indices[ ii++ ] = topLeft;
|
||||
indices[ ii++ ] = bottomLeft;
|
||||
indices[ ii++ ] = topRight;
|
||||
|
||||
indices[ ii++ ] = topRight;
|
||||
indices[ ii++ ] = bottomLeft;
|
||||
indices[ ii++ ] = bottomRight;
|
||||
|
||||
}
|
||||
|
||||
// horizontal line for row y at each segment
|
||||
for ( let x = 0; x < size - 1; x++ ) {
|
||||
|
||||
const a = y * size + x;
|
||||
|
||||
const b = a + 1;
|
||||
|
||||
lineIndices[ li++ ] = a;
|
||||
lineIndices[ li++ ] = b;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// vertical lines
|
||||
for ( let x = 0; x < size; x++ ) {
|
||||
|
||||
for ( let y = 0; y < size - 1; y++ ) {
|
||||
|
||||
const a = y * size + x;
|
||||
|
||||
const b = a + size;
|
||||
|
||||
lineIndices[ li++ ] = a;
|
||||
lineIndices[ li++ ] = b;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
positions,
|
||||
uvs,
|
||||
indices,
|
||||
lineIndices
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
_buildSkySphereGeometry( radius, latSegments, lonSegments ) {
|
||||
|
||||
const latCount = latSegments;
|
||||
|
||||
const lonCount = lonSegments;
|
||||
|
||||
const vertexCount = ( latCount + 1 ) * ( lonCount + 1 );
|
||||
|
||||
const positions = new Float32Array( vertexCount * 3 );
|
||||
|
||||
const normals = new Float32Array( vertexCount * 3 );
|
||||
|
||||
const uvs = new Float32Array( vertexCount * 2 );
|
||||
|
||||
const indices = new Uint32Array( latCount * lonCount * 6 );
|
||||
|
||||
let pi = 0;
|
||||
|
||||
let ni = 0;
|
||||
|
||||
let ui = 0;
|
||||
|
||||
for ( let lat = 0; lat <= latCount; lat++ ) {
|
||||
|
||||
const theta = lat * Math.PI / latCount;
|
||||
|
||||
const sinTheta = Math.sin( theta );
|
||||
|
||||
const cosTheta = Math.cos( theta );
|
||||
|
||||
for ( let lon = 0; lon <= lonCount; lon++ ) {
|
||||
|
||||
const phi = lon * Math.PI * 2.0 / lonCount;
|
||||
|
||||
const sinPhi = Math.sin( phi );
|
||||
|
||||
const cosPhi = Math.cos( phi );
|
||||
|
||||
const x = sinTheta * cosPhi;
|
||||
|
||||
const y = cosTheta;
|
||||
|
||||
const z = sinTheta * sinPhi;
|
||||
|
||||
positions[ pi++ ] = x * radius;
|
||||
|
||||
positions[ pi++ ] = y * radius;
|
||||
|
||||
positions[ pi++ ] = z * radius;
|
||||
|
||||
const nx = -x;
|
||||
|
||||
const ny = -y;
|
||||
|
||||
const nz = -z;
|
||||
|
||||
normals[ ni++ ] = nx;
|
||||
|
||||
normals[ ni++ ] = ny;
|
||||
|
||||
normals[ ni++ ] = nz;
|
||||
|
||||
uvs[ ui++ ] = lon / lonCount;
|
||||
|
||||
uvs[ ui++ ] = lat / latCount;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let ii = 0;
|
||||
|
||||
for ( let y = 0; y < latCount; y++ ) {
|
||||
|
||||
for ( let x = 0; x < lonCount; x++ ) {
|
||||
|
||||
const i0 = y * ( lonCount + 1 ) + x;
|
||||
|
||||
const i1 = i0 + 1;
|
||||
|
||||
const i2 = ( y + 1 ) * ( lonCount + 1 ) + x;
|
||||
|
||||
const i3 = i2 + 1;
|
||||
|
||||
indices[ ii++ ] = i0;
|
||||
|
||||
indices[ ii++ ] = i2;
|
||||
|
||||
indices[ ii++ ] = i1;
|
||||
|
||||
indices[ ii++ ] = i1;
|
||||
|
||||
indices[ ii++ ] = i2;
|
||||
|
||||
indices[ ii++ ] = i3;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
positions,
|
||||
|
||||
normals,
|
||||
|
||||
uvs,
|
||||
|
||||
indices
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
_buildCubeGeometry( ) {
|
||||
|
||||
const positions = new Float32Array( [
|
||||
// Front
|
||||
-1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1,
|
||||
// Back
|
||||
-1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1,
|
||||
// Top
|
||||
-1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1,
|
||||
// Bottom
|
||||
-1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1,
|
||||
// Right
|
||||
1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1,
|
||||
// Left
|
||||
-1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1
|
||||
] );
|
||||
|
||||
const colors = new Float32Array( [
|
||||
// Front
|
||||
0.1, 0.6, 1.0, 0.1, 0.6, 1.0, 0.1, 0.6, 1.0, 0.1, 0.6, 1.0,
|
||||
// Back
|
||||
0.1, 0.2, 0.8, 0.1, 0.2, 0.8, 0.1, 0.2, 0.8, 0.1, 0.2, 0.8,
|
||||
// Top
|
||||
0.2, 0.8, 0.5, 0.2, 0.8, 0.5, 0.2, 0.8, 0.5, 0.2, 0.8, 0.5,
|
||||
// Bottom
|
||||
0.9, 0.7, 0.2, 0.9, 0.7, 0.2, 0.9, 0.7, 0.2, 0.9, 0.7, 0.2,
|
||||
// Right
|
||||
0.8, 0.3, 0.4, 0.8, 0.3, 0.4, 0.8, 0.3, 0.4, 0.8, 0.3, 0.4,
|
||||
// Left
|
||||
0.4, 0.9, 0.7, 0.4, 0.9, 0.7, 0.4, 0.9, 0.7, 0.4, 0.9, 0.7
|
||||
] );
|
||||
|
||||
const indices = new Uint32Array( [
|
||||
0, 1, 2, 0, 2, 3, // Front
|
||||
4, 5, 6, 4, 6, 7, // Back
|
||||
8, 9, 10, 8, 10, 11, // Top
|
||||
12, 13, 14, 12, 14, 15, // Bottom
|
||||
16, 17, 18, 16, 18, 19, // Right
|
||||
20, 21, 22, 20, 22, 23 // Left
|
||||
] );
|
||||
|
||||
return {
|
||||
positions,
|
||||
colors,
|
||||
indices
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user