添加关照、全局等高线、修改图层问题
This commit is contained in:
@ -0,0 +1,285 @@
|
||||
import { GPUTextureViewDimension, GPUIndexFormat, GPUFilterMode, GPUPrimitiveTopology, GPULoadOp, GPUStoreOp } from './WebGPUConstants.js';
|
||||
|
||||
class WebGPUTexturePassUtils {
|
||||
|
||||
constructor( device ) {
|
||||
|
||||
this.device = device;
|
||||
|
||||
const mipmapVertexSource = `
|
||||
struct VarysStruct {
|
||||
@builtin( position ) Position: vec4<f32>,
|
||||
@location( 0 ) vTex : vec2<f32>
|
||||
};
|
||||
|
||||
@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>;
|
||||
|
||||
@fragment
|
||||
fn main( @location( 0 ) vTex : vec2<f32> ) -> @location( 0 ) vec4<f32> {
|
||||
|
||||
return textureSample( img, imgSampler, vTex );
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
const flipYFragmentSource = `
|
||||
@group( 0 ) @binding( 0 )
|
||||
var imgSampler : sampler;
|
||||
|
||||
@group( 0 ) @binding( 1 )
|
||||
var img : texture_2d<f32>;
|
||||
|
||||
@fragment
|
||||
fn main( @location( 0 ) vTex : vec2<f32> ) -> @location( 0 ) vec4<f32> {
|
||||
|
||||
return textureSample( img, imgSampler, vec2( vTex.x, 1.0 - vTex.y ) );
|
||||
|
||||
}
|
||||
`;
|
||||
this.mipmapSampler = device.createSampler( { minFilter: GPUFilterMode.Linear } );
|
||||
this.flipYSampler = device.createSampler( { minFilter: GPUFilterMode.Nearest } ); //@TODO?: Consider using textureLoad()
|
||||
|
||||
// We'll need a new pipeline for every texture format used.
|
||||
this.transferPipelines = {};
|
||||
this.flipYPipelines = {};
|
||||
|
||||
this.mipmapVertexShaderModule = device.createShaderModule( {
|
||||
label: 'mipmapVertex',
|
||||
code: mipmapVertexSource
|
||||
} );
|
||||
|
||||
this.mipmapFragmentShaderModule = device.createShaderModule( {
|
||||
label: 'mipmapFragment',
|
||||
code: mipmapFragmentSource
|
||||
} );
|
||||
|
||||
this.flipYFragmentShaderModule = device.createShaderModule( {
|
||||
label: 'flipYFragment',
|
||||
code: flipYFragmentSource
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
getTransferPipeline( format ) {
|
||||
|
||||
let pipeline = this.transferPipelines[ 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
|
||||
},
|
||||
layout: 'auto'
|
||||
} );
|
||||
|
||||
this.transferPipelines[ format ] = pipeline;
|
||||
|
||||
}
|
||||
|
||||
return pipeline;
|
||||
|
||||
}
|
||||
|
||||
getFlipYPipeline( format ) {
|
||||
|
||||
let pipeline = this.flipYPipelines[ format ];
|
||||
|
||||
if ( pipeline === undefined ) {
|
||||
|
||||
pipeline = this.device.createRenderPipeline( {
|
||||
vertex: {
|
||||
module: this.mipmapVertexShaderModule,
|
||||
entryPoint: 'main'
|
||||
},
|
||||
fragment: {
|
||||
module: this.flipYFragmentShaderModule,
|
||||
entryPoint: 'main',
|
||||
targets: [ { format } ]
|
||||
},
|
||||
primitive: {
|
||||
topology: GPUPrimitiveTopology.TriangleStrip,
|
||||
stripIndexFormat: GPUIndexFormat.Uint32
|
||||
},
|
||||
layout: 'auto'
|
||||
} );
|
||||
|
||||
this.flipYPipelines[ format ] = pipeline;
|
||||
|
||||
}
|
||||
|
||||
return pipeline;
|
||||
|
||||
}
|
||||
|
||||
flipY( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) {
|
||||
|
||||
const format = textureGPUDescriptor.format;
|
||||
const { width, height } = textureGPUDescriptor.size;
|
||||
|
||||
const transferPipeline = this.getTransferPipeline( format );
|
||||
const flipYPipeline = this.getFlipYPipeline( format );
|
||||
|
||||
const tempTexture = this.device.createTexture( {
|
||||
size: { width, height, depthOrArrayLayers: 1 },
|
||||
format,
|
||||
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
|
||||
} );
|
||||
|
||||
const srcView = textureGPU.createView( {
|
||||
baseMipLevel: 0,
|
||||
mipLevelCount: 1,
|
||||
dimension: GPUTextureViewDimension.TwoD,
|
||||
baseArrayLayer
|
||||
} );
|
||||
|
||||
const dstView = tempTexture.createView( {
|
||||
baseMipLevel: 0,
|
||||
mipLevelCount: 1,
|
||||
dimension: GPUTextureViewDimension.TwoD,
|
||||
baseArrayLayer: 0
|
||||
} );
|
||||
|
||||
const commandEncoder = this.device.createCommandEncoder( {} );
|
||||
|
||||
const pass = ( pipeline, sourceView, destinationView ) => {
|
||||
|
||||
const bindGroupLayout = pipeline.getBindGroupLayout( 0 ); // @TODO: Consider making this static.
|
||||
|
||||
const bindGroup = this.device.createBindGroup( {
|
||||
layout: bindGroupLayout,
|
||||
entries: [ {
|
||||
binding: 0,
|
||||
resource: this.flipYSampler
|
||||
}, {
|
||||
binding: 1,
|
||||
resource: sourceView
|
||||
} ]
|
||||
} );
|
||||
|
||||
const passEncoder = commandEncoder.beginRenderPass( {
|
||||
colorAttachments: [ {
|
||||
view: destinationView,
|
||||
loadOp: GPULoadOp.Clear,
|
||||
storeOp: GPUStoreOp.Store,
|
||||
clearValue: [ 0, 0, 0, 0 ]
|
||||
} ]
|
||||
} );
|
||||
|
||||
passEncoder.setPipeline( pipeline );
|
||||
passEncoder.setBindGroup( 0, bindGroup );
|
||||
passEncoder.draw( 4, 1, 0, 0 );
|
||||
passEncoder.end();
|
||||
|
||||
};
|
||||
|
||||
pass( transferPipeline, srcView, dstView );
|
||||
pass( flipYPipeline, dstView, srcView );
|
||||
|
||||
this.device.queue.submit( [ commandEncoder.finish() ] );
|
||||
|
||||
tempTexture.destroy();
|
||||
|
||||
}
|
||||
|
||||
generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) {
|
||||
|
||||
const pipeline = this.getTransferPipeline( 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,
|
||||
dimension: GPUTextureViewDimension.TwoD,
|
||||
baseArrayLayer
|
||||
} );
|
||||
|
||||
for ( let i = 1; i < textureGPUDescriptor.mipLevelCount; i ++ ) {
|
||||
|
||||
const bindGroup = this.device.createBindGroup( {
|
||||
layout: bindGroupLayout,
|
||||
entries: [ {
|
||||
binding: 0,
|
||||
resource: this.mipmapSampler
|
||||
}, {
|
||||
binding: 1,
|
||||
resource: srcView
|
||||
} ]
|
||||
} );
|
||||
|
||||
const dstView = textureGPU.createView( {
|
||||
baseMipLevel: i,
|
||||
mipLevelCount: 1,
|
||||
dimension: GPUTextureViewDimension.TwoD,
|
||||
baseArrayLayer
|
||||
} );
|
||||
|
||||
const passEncoder = commandEncoder.beginRenderPass( {
|
||||
colorAttachments: [ {
|
||||
view: dstView,
|
||||
loadOp: GPULoadOp.Clear,
|
||||
storeOp: GPUStoreOp.Store,
|
||||
clearValue: [ 0, 0, 0, 0 ]
|
||||
} ]
|
||||
} );
|
||||
|
||||
passEncoder.setPipeline( pipeline );
|
||||
passEncoder.setBindGroup( 0, bindGroup );
|
||||
passEncoder.draw( 4, 1, 0, 0 );
|
||||
passEncoder.end();
|
||||
|
||||
srcView = dstView;
|
||||
|
||||
}
|
||||
|
||||
this.device.queue.submit( [ commandEncoder.finish() ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUTexturePassUtils;
|
Reference in New Issue
Block a user