Dies ist das Repository meines kleinen Portfolios.
Im Hintergrund läuft eine Planetensimulation, geschrieben in JavaScript und Three.js.
Die zu sehenden Texturen stammen von:
https://www.solarsystemscope.com/textures/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
4.4 KiB
178 lines
4.4 KiB
// Copyright 2020 Brandon Jones |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy |
|
// of this software and associated documentation files (the "Software"), to deal |
|
// in the Software without restriction, including without limitation the rights |
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
// copies of the Software, and to permit persons to whom the Software is |
|
// furnished to do so, subject to the following conditions: |
|
|
|
// The above copyright notice and this permission notice shall be included in |
|
// all copies or substantial portions of the Software. |
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
// SOFTWARE. |
|
|
|
import { GPUIndexFormat, GPUFilterMode, GPUPrimitiveTopology } from './constants.js'; |
|
|
|
// ported from https://github.com/toji/web-texture-tool/blob/master/src/webgpu-mipmap-generator.js |
|
|
|
class WebGPUTextureUtils { |
|
|
|
constructor( device ) { |
|
|
|
this.device = device; |
|
|
|
const mipmapVertexSource = ` |
|
struct VarysStruct { |
|
|
|
[[ builtin( position ) ]] Position: vec4<f32>; |
|
[[ location( 0 ) ]] vTex : vec2<f32>; |
|
|
|
}; |
|
|
|
[[ stage( vertex ) ]] |
|
fn main( [[ builtin( vertex_index ) ]] vertexIndex : u32 ) -> VarysStruct { |
|
|
|
var Varys: VarysStruct; |
|
|
|
var pos = array< vec2<f32>, 4 >( |
|
vec2<f32>( -1.0, 1.0 ), |
|
vec2<f32>( 1.0, 1.0 ), |
|
vec2<f32>( -1.0, -1.0 ), |
|
vec2<f32>( 1.0, -1.0 ) |
|
); |
|
|
|
var tex = array< vec2<f32>, 4 >( |
|
vec2<f32>( 0.0, 0.0 ), |
|
vec2<f32>( 1.0, 0.0 ), |
|
vec2<f32>( 0.0, 1.0 ), |
|
vec2<f32>( 1.0, 1.0 ) |
|
); |
|
|
|
Varys.vTex = tex[ vertexIndex ]; |
|
Varys.Position = vec4<f32>( pos[ vertexIndex ], 0.0, 1.0 ); |
|
|
|
return Varys; |
|
|
|
} |
|
`; |
|
|
|
const mipmapFragmentSource = ` |
|
[[ group( 0 ), binding( 0 ) ]] |
|
var imgSampler : sampler; |
|
|
|
[[ group( 0 ), binding( 1 ) ]] |
|
var img : texture_2d<f32>; |
|
|
|
[[ stage( fragment ) ]] |
|
fn main( [[ location( 0 ) ]] vTex : vec2<f32> ) -> [[ location( 0 ) ]] vec4<f32> { |
|
|
|
return textureSample( img, imgSampler, vTex ); |
|
|
|
} |
|
`; |
|
|
|
this.sampler = device.createSampler( { minFilter: GPUFilterMode.Linear } ); |
|
|
|
// We'll need a new pipeline for every texture format used. |
|
this.pipelines = {}; |
|
|
|
this.mipmapVertexShaderModule = device.createShaderModule( { |
|
code: mipmapVertexSource |
|
} ); |
|
|
|
this.mipmapFragmentShaderModule = device.createShaderModule( { |
|
code: mipmapFragmentSource |
|
} ); |
|
|
|
} |
|
|
|
getMipmapPipeline( format ) { |
|
|
|
let pipeline = this.pipelines[ format ]; |
|
|
|
if ( pipeline === undefined ) { |
|
|
|
pipeline = this.device.createRenderPipeline( { |
|
vertex: { |
|
module: this.mipmapVertexShaderModule, |
|
entryPoint: 'main', |
|
}, |
|
fragment: { |
|
module: this.mipmapFragmentShaderModule, |
|
entryPoint: 'main', |
|
targets: [ { format } ], |
|
}, |
|
primitive: { |
|
topology: GPUPrimitiveTopology.TriangleStrip, |
|
stripIndexFormat: GPUIndexFormat.Uint32 |
|
} |
|
} ); |
|
|
|
this.pipelines[ format ] = pipeline; |
|
|
|
} |
|
|
|
return pipeline; |
|
|
|
} |
|
|
|
generateMipmaps( textureGPU, textureGPUDescriptor ) { |
|
|
|
const pipeline = this.getMipmapPipeline( textureGPUDescriptor.format ); |
|
|
|
const commandEncoder = this.device.createCommandEncoder( {} ); |
|
const bindGroupLayout = pipeline.getBindGroupLayout( 0 ); // @TODO: Consider making this static. |
|
|
|
let srcView = textureGPU.createView( { |
|
baseMipLevel: 0, |
|
mipLevelCount: 1 |
|
} ); |
|
|
|
for ( let i = 1; i < textureGPUDescriptor.mipLevelCount; i ++ ) { |
|
|
|
const dstView = textureGPU.createView( { |
|
baseMipLevel: i, |
|
mipLevelCount: 1 |
|
} ); |
|
|
|
const passEncoder = commandEncoder.beginRenderPass( { |
|
colorAttachments: [ { |
|
view: dstView, |
|
loadValue: [ 0, 0, 0, 0 ] |
|
} ] |
|
} ); |
|
|
|
const bindGroup = this.device.createBindGroup( { |
|
layout: bindGroupLayout, |
|
entries: [ { |
|
binding: 0, |
|
resource: this.sampler |
|
}, { |
|
binding: 1, |
|
resource: srcView |
|
} ] |
|
} ); |
|
|
|
passEncoder.setPipeline( pipeline ); |
|
passEncoder.setBindGroup( 0, bindGroup ); |
|
passEncoder.draw( 4, 1, 0, 0 ); |
|
passEncoder.endPass(); |
|
|
|
srcView = dstView; |
|
|
|
} |
|
|
|
this.device.queue.submit( [ commandEncoder.finish() ] ); |
|
|
|
} |
|
|
|
} |
|
|
|
export default WebGPUTextureUtils;
|
|
|