Pipeline creation, work on shader code
This commit is contained in:
		
							
								
								
									
										112
									
								
								src/_BinaryWriter.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/_BinaryWriter.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | |||||||
|  | import { Matrix4x4Object, Vector2Object, Vector3Object, Vector4Object } from "./data"; | ||||||
|  |  | ||||||
|  | export class _BinaryWriter { | ||||||
|  |  | ||||||
|  | 	static readonly DEFAULT_CAPACITY = 16; | ||||||
|  |  | ||||||
|  | 	_buffer: ArrayBuffer; | ||||||
|  | 	_dataView: DataView; | ||||||
|  | 	_typedArray: Uint8Array; | ||||||
|  | 	_length: number; | ||||||
|  |  | ||||||
|  | 	get subarray(): Uint8Array { return new Uint8Array(this._buffer, 0, this._length); } | ||||||
|  |  | ||||||
|  | 	constructor(capacity = _BinaryWriter.DEFAULT_CAPACITY) { | ||||||
|  | 		capacity = Math.max(capacity, 1); | ||||||
|  | 		this._buffer = new ArrayBuffer(capacity); | ||||||
|  | 		this._dataView = new DataView(this._buffer); | ||||||
|  | 		this._typedArray = new Uint8Array(this._buffer); | ||||||
|  | 		this._length = 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	clear(): _BinaryWriter { | ||||||
|  | 		this._length = 0; | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ensureCapacity(desiredCapacity: number): _BinaryWriter { | ||||||
|  | 		if (this._buffer.byteLength >= desiredCapacity) { | ||||||
|  | 			return this; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		let newCapacity = this._buffer.byteLength * 2; | ||||||
|  | 		while (newCapacity < desiredCapacity) { | ||||||
|  | 			newCapacity *= 2; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		const newBuffer = new ArrayBuffer(newCapacity); | ||||||
|  | 		const newDataView = new DataView(newBuffer); | ||||||
|  | 		const newTypedArray = new Uint8Array(newBuffer); | ||||||
|  |  | ||||||
|  | 		newTypedArray.set(this.subarray); | ||||||
|  |  | ||||||
|  | 		this._buffer = newBuffer; | ||||||
|  | 		this._dataView = newDataView; | ||||||
|  | 		this._typedArray = newTypedArray; | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ensureUnusedCapacity(desiredUnusedCapacity: number): _BinaryWriter { | ||||||
|  | 		return this.ensureCapacity(this._buffer.byteLength + desiredUnusedCapacity); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	writeU32(value: number): _BinaryWriter { | ||||||
|  | 		this.ensureUnusedCapacity(4); | ||||||
|  | 		this._dataView.setUint32(this._length, value, true); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	writeF32(value: number): _BinaryWriter { | ||||||
|  | 		this.ensureUnusedCapacity(4); | ||||||
|  | 		this._dataView.setFloat32(this._length, value, true); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	writeVector2(value: Vector2Object): _BinaryWriter { | ||||||
|  | 		this.writeF32(value.x); | ||||||
|  | 		this.writeF32(value.y); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	writeVector3(value: Vector3Object): _BinaryWriter { | ||||||
|  | 		this.writeF32(value.x); | ||||||
|  | 		this.writeF32(value.y); | ||||||
|  | 		this.writeF32(value.z); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	writeVector4(value: Vector4Object): _BinaryWriter { | ||||||
|  | 		this.writeF32(value.x); | ||||||
|  | 		this.writeF32(value.y); | ||||||
|  | 		this.writeF32(value.z); | ||||||
|  | 		this.writeF32(value.w); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	writeMatrix4x4(value: Matrix4x4Object): _BinaryWriter { | ||||||
|  | 		this.writeF32(value.ix); | ||||||
|  | 		this.writeF32(value.iy); | ||||||
|  | 		this.writeF32(value.iz); | ||||||
|  | 		this.writeF32(value.iw); | ||||||
|  | 		this.writeF32(value.jx); | ||||||
|  | 		this.writeF32(value.jy); | ||||||
|  | 		this.writeF32(value.jz); | ||||||
|  | 		this.writeF32(value.jw); | ||||||
|  | 		this.writeF32(value.kx); | ||||||
|  | 		this.writeF32(value.ky); | ||||||
|  | 		this.writeF32(value.kz); | ||||||
|  | 		this.writeF32(value.kw); | ||||||
|  | 		this.writeF32(value.tx); | ||||||
|  | 		this.writeF32(value.ty); | ||||||
|  | 		this.writeF32(value.tz); | ||||||
|  | 		this.writeF32(value.tw); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	alloc(byteLength: number): DataView { | ||||||
|  | 		this.ensureUnusedCapacity(byteLength); | ||||||
|  | 		const dataView = new DataView(this._buffer, this._length, byteLength); | ||||||
|  | 		this._length += byteLength; | ||||||
|  | 		return dataView; | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										154
									
								
								src/oktaeder.ts
									
									
									
									
									
								
							
							
						
						
									
										154
									
								
								src/oktaeder.ts
									
									
									
									
									
								
							| @@ -4,8 +4,13 @@ | |||||||
|  * obtain one at http://mozilla.org/MPL/2.0/. |  * obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | export * from "./_BinaryWriter"; | ||||||
|  | export * from "./shader"; | ||||||
|  |  | ||||||
|  | import { _BinaryWriter as BinaryWriter } from "./_BinaryWriter"; | ||||||
| import { Camera, Scene } from "./data"; | import { Camera, Scene } from "./data"; | ||||||
| import { IndexBuffer, IndexBufferProps, Material, MaterialProps, Texture2D, Texture2DProps, VertexBuffer, VertexBufferProps } from "./resources"; | import { IndexBuffer, IndexBufferProps, Material, MaterialProps, Texture2D, Texture2DProps, VertexBuffer, VertexBufferProps } from "./resources"; | ||||||
|  | import { ShaderFlagKey, ShaderFlags, createPipeline, shaderFlagsKey } from "./shader"; | ||||||
|  |  | ||||||
| export class Renderer { | export class Renderer { | ||||||
|  |  | ||||||
| @@ -23,11 +28,20 @@ export class Renderer { | |||||||
|  |  | ||||||
| 	_depthBuffer: Texture2D; | 	_depthBuffer: Texture2D; | ||||||
|  |  | ||||||
|  | 	_globalBindGroupLayout: GPUBindGroupLayout; | ||||||
|  | 	_materialBindGroupLayout: GPUBindGroupLayout; | ||||||
|  | 	_objectBindGroupLayout: GPUBindGroupLayout; | ||||||
|  | 	_pipelineLayout: GPUPipelineLayout; | ||||||
|  |  | ||||||
|  | 	_pipelineCache: Map<ShaderFlagKey, GPURenderPipeline>; | ||||||
|  |  | ||||||
|  | 	_uniformWriter: BinaryWriter; | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * This constructor is intended primarily for internal use. Consider using | 	 * This constructor is intended primarily for internal use. Consider using | ||||||
| 	 * `Renderer.createIndexBuffer` instead. | 	 * `Renderer.createIndexBuffer` instead. | ||||||
| 	 */ | 	 */ | ||||||
| 	private constructor ( | 	private constructor( | ||||||
| 		adapter: GPUAdapter, | 		adapter: GPUAdapter, | ||||||
| 		device: GPUDevice, | 		device: GPUDevice, | ||||||
| 		context: GPUCanvasContext, | 		context: GPUCanvasContext, | ||||||
| @@ -69,9 +83,130 @@ export class Renderer { | |||||||
| 			height: framebufferTexture.height, | 			height: framebufferTexture.height, | ||||||
| 			format: "depth", | 			format: "depth", | ||||||
| 		}); | 		}); | ||||||
|  |  | ||||||
|  | 		this._globalBindGroupLayout = device.createBindGroupLayout({ | ||||||
|  | 			entries: [ | ||||||
|  | 				{ | ||||||
|  | 					binding: 0, | ||||||
|  | 					visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, | ||||||
|  | 					buffer: { | ||||||
|  | 						hasDynamicOffset: true, | ||||||
|  | 						type: "uniform", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				{ | ||||||
|  | 					binding: 1, | ||||||
|  | 					visibility: GPUShaderStage.FRAGMENT, | ||||||
|  | 					buffer: { | ||||||
|  | 						hasDynamicOffset: true, | ||||||
|  | 						type: "read-only-storage", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				{ | ||||||
|  | 					binding: 2, | ||||||
|  | 					visibility: GPUShaderStage.FRAGMENT, | ||||||
|  | 					buffer: { | ||||||
|  | 						hasDynamicOffset: true, | ||||||
|  | 						type: "read-only-storage", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			], | ||||||
|  | 			label: "Global", | ||||||
|  | 		}); | ||||||
|  | 		this._materialBindGroupLayout = device.createBindGroupLayout({ | ||||||
|  | 			entries: [ | ||||||
|  | 				{ | ||||||
|  | 					binding: 0, | ||||||
|  | 					visibility: GPUShaderStage.FRAGMENT, | ||||||
|  | 					buffer: { | ||||||
|  | 						hasDynamicOffset: true, | ||||||
|  | 						type: "uniform", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				{ | ||||||
|  | 					binding: 1, | ||||||
|  | 					visibility: GPUShaderStage.FRAGMENT, | ||||||
|  | 					sampler: { type: "filtering" }, | ||||||
|  | 				}, | ||||||
|  | 				{ | ||||||
|  | 					binding: 2, | ||||||
|  | 					visibility: GPUShaderStage.FRAGMENT, | ||||||
|  | 					texture: { | ||||||
|  | 						sampleType: "float", | ||||||
|  | 						viewDimension: "2d", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				{ | ||||||
|  | 					binding: 3, | ||||||
|  | 					visibility: GPUShaderStage.FRAGMENT, | ||||||
|  | 					texture: { | ||||||
|  | 						sampleType: "float", | ||||||
|  | 						viewDimension: "2d", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				{ | ||||||
|  | 					binding: 4, | ||||||
|  | 					visibility: GPUShaderStage.FRAGMENT, | ||||||
|  | 					texture: { | ||||||
|  | 						sampleType: "float", | ||||||
|  | 						viewDimension: "2d", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				{ | ||||||
|  | 					binding: 5, | ||||||
|  | 					visibility: GPUShaderStage.FRAGMENT, | ||||||
|  | 					texture: { | ||||||
|  | 						sampleType: "float", | ||||||
|  | 						viewDimension: "2d", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				{ | ||||||
|  | 					binding: 6, | ||||||
|  | 					visibility: GPUShaderStage.FRAGMENT, | ||||||
|  | 					texture: { | ||||||
|  | 						sampleType: "float", | ||||||
|  | 						viewDimension: "2d", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				{ | ||||||
|  | 					binding: 7, | ||||||
|  | 					visibility: GPUShaderStage.FRAGMENT, | ||||||
|  | 					texture: { | ||||||
|  | 						sampleType: "float", | ||||||
|  | 						viewDimension: "2d", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			], | ||||||
|  | 			label: "Material", | ||||||
|  | 		}); | ||||||
|  | 		this._objectBindGroupLayout = device.createBindGroupLayout({ | ||||||
|  | 			entries: [ | ||||||
|  | 				{ | ||||||
|  | 					binding: 0, | ||||||
|  | 					visibility: GPUShaderStage.VERTEX, | ||||||
|  | 					buffer: { | ||||||
|  | 						hasDynamicOffset: true, | ||||||
|  | 						type: "uniform", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			], | ||||||
|  | 			label: "Object", | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		this._pipelineLayout = device.createPipelineLayout({ | ||||||
|  | 			bindGroupLayouts: [ | ||||||
|  | 				this._globalBindGroupLayout, | ||||||
|  | 				this._materialBindGroupLayout, | ||||||
|  | 				this._objectBindGroupLayout, | ||||||
|  | 			], | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		this._pipelineCache = new Map(); | ||||||
|  |  | ||||||
|  | 		this._uniformWriter = new BinaryWriter(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	static async init(canvas: HTMLCanvasElement) { | 	static async init(canvas: HTMLCanvasElement): Promise<Renderer> { | ||||||
| 		if (!navigator.gpu) { | 		if (!navigator.gpu) { | ||||||
| 			throw new Error("WebGPU is not supported"); | 			throw new Error("WebGPU is not supported"); | ||||||
| 		} | 		} | ||||||
| @@ -92,6 +227,8 @@ export class Renderer { | |||||||
|  |  | ||||||
| 		const format = navigator.gpu.getPreferredCanvasFormat(); | 		const format = navigator.gpu.getPreferredCanvasFormat(); | ||||||
| 		context.configure({ device, format }); | 		context.configure({ device, format }); | ||||||
|  |  | ||||||
|  | 		return new Renderer(adapter, device, context, format); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -124,6 +261,19 @@ export class Renderer { | |||||||
| 		return new VertexBuffer(this, props); | 		return new VertexBuffer(this, props); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	_getOrCreatePipeline(flags: ShaderFlags): GPURenderPipeline { | ||||||
|  | 		const key = shaderFlagsKey(flags); | ||||||
|  |  | ||||||
|  | 		let pipeline = this._pipelineCache.get(key); | ||||||
|  | 		if (pipeline !== undefined) { | ||||||
|  | 			return pipeline; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		pipeline = createPipeline(this, flags); | ||||||
|  | 		this._pipelineCache.set(key, pipeline); | ||||||
|  | 		return pipeline; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	render(scene: Scene, camera: Camera): Renderer { | 	render(scene: Scene, camera: Camera): Renderer { | ||||||
| 		const { width, height } = this._context.getCurrentTexture(); | 		const { width, height } = this._context.getCurrentTexture(); | ||||||
| 		if (this._depthBuffer.width !== width || this._depthBuffer.height !== height) { | 		if (this._depthBuffer.width !== width || this._depthBuffer.height !== height) { | ||||||
|   | |||||||
							
								
								
									
										164
									
								
								src/shader.ts
									
									
									
									
									
								
							
							
						
						
									
										164
									
								
								src/shader.ts
									
									
									
									
									
								
							| @@ -1,8 +1,127 @@ | |||||||
|  | import { Renderer } from "./oktaeder"; | ||||||
|  |  | ||||||
|  | export type ShaderFlagKey = number; | ||||||
|  |  | ||||||
| export interface ShaderFlags { | export interface ShaderFlags { | ||||||
| 	texCoord: boolean; | 	readonly texCoord: boolean; | ||||||
| 	lightTexCoord: boolean; | 	readonly lightTexCoord: boolean; | ||||||
| 	normal: boolean; | 	readonly normal: boolean; | ||||||
| 	tangent: boolean; | 	readonly tangent: boolean; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function shaderFlagsKey({ | ||||||
|  | 	texCoord, | ||||||
|  | 	lightTexCoord, | ||||||
|  | 	normal, | ||||||
|  | 	tangent, | ||||||
|  | }: ShaderFlags): ShaderFlagKey { | ||||||
|  | 	let key = 0; | ||||||
|  | 	key |= Number(texCoord) << 0; | ||||||
|  | 	key |= Number(lightTexCoord) << 1; | ||||||
|  | 	key |= Number(normal) << 2; | ||||||
|  | 	key |= Number(tangent) << 3; | ||||||
|  | 	return key; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function createPipeline(renderer: Renderer, { | ||||||
|  | 	texCoord, | ||||||
|  | 	lightTexCoord, | ||||||
|  | 	normal, | ||||||
|  | 	tangent, | ||||||
|  | }: ShaderFlags): GPURenderPipeline { | ||||||
|  | 	const shaderCode = createShaderCode({ texCoord, lightTexCoord, normal, tangent }); | ||||||
|  |  | ||||||
|  | 	const shaderModule = renderer._device.createShaderModule({ | ||||||
|  | 		code: shaderCode, | ||||||
|  | 		hints: { | ||||||
|  | 			"vert": { layout: renderer._pipelineLayout }, | ||||||
|  | 			"frag": { layout: renderer._pipelineLayout }, | ||||||
|  | 		}, | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	let vertexLocation = 0; | ||||||
|  |  | ||||||
|  | 	const pipeline = renderer._device.createRenderPipeline({ | ||||||
|  | 		layout: renderer._pipelineLayout, | ||||||
|  | 		vertex: { | ||||||
|  | 			entryPoint: "vert", | ||||||
|  | 			module: shaderModule, | ||||||
|  | 			buffers: [ | ||||||
|  | 				{ | ||||||
|  | 					arrayStride: 12, | ||||||
|  | 					attributes: [{ | ||||||
|  | 						shaderLocation: vertexLocation++, | ||||||
|  | 						format: "float32x3", | ||||||
|  | 						offset: 0, | ||||||
|  | 					}], | ||||||
|  | 				}, | ||||||
|  | 				...(texCoord ? [{ | ||||||
|  | 					arrayStride: 8, | ||||||
|  | 					attributes: [{ | ||||||
|  | 						shaderLocation: vertexLocation++, | ||||||
|  | 						format: "float32x2", | ||||||
|  | 						offset: 0, | ||||||
|  | 					}], | ||||||
|  | 				} satisfies GPUVertexBufferLayout] : []), | ||||||
|  | 				...(lightTexCoord ? [{ | ||||||
|  | 					arrayStride: 8, | ||||||
|  | 					attributes: [{ | ||||||
|  | 						shaderLocation: vertexLocation++, | ||||||
|  | 						format: "float32x2", | ||||||
|  | 						offset: 0, | ||||||
|  | 					}], | ||||||
|  | 				} satisfies GPUVertexBufferLayout] : []), | ||||||
|  | 				...(normal ? [{ | ||||||
|  | 					arrayStride: 12, | ||||||
|  | 					attributes: [{ | ||||||
|  | 						shaderLocation: vertexLocation++, | ||||||
|  | 						format: "float32x3", | ||||||
|  | 						offset: 0, | ||||||
|  | 					}], | ||||||
|  | 				} satisfies GPUVertexBufferLayout] : []), | ||||||
|  | 				...(tangent ? [{ | ||||||
|  | 					arrayStride: 16, | ||||||
|  | 					attributes: [{ | ||||||
|  | 						shaderLocation: vertexLocation++, | ||||||
|  | 						format: "float32x4", | ||||||
|  | 						offset: 0, | ||||||
|  | 					}], | ||||||
|  | 				} satisfies GPUVertexBufferLayout] : []), | ||||||
|  | 			], | ||||||
|  | 		}, | ||||||
|  | 		fragment: { | ||||||
|  | 			entryPoint: "frag", | ||||||
|  | 			module: shaderModule, | ||||||
|  | 			targets: [{ | ||||||
|  | 				format: renderer._format, | ||||||
|  | 				blend: { | ||||||
|  | 					color: { | ||||||
|  | 						operation: "add", | ||||||
|  | 						srcFactor: "one", | ||||||
|  | 						dstFactor: "one-minus-src-alpha", | ||||||
|  | 					}, | ||||||
|  | 					alpha: { | ||||||
|  | 						operation: "add", | ||||||
|  | 						srcFactor: "one", | ||||||
|  | 						dstFactor: "one-minus-src-alpha", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				writeMask: GPUColorWrite.ALL, | ||||||
|  | 			}], | ||||||
|  | 		}, | ||||||
|  | 		depthStencil: { | ||||||
|  | 			depthCompare: "greater", | ||||||
|  | 			depthWriteEnabled: true, | ||||||
|  | 			format: "depth32float", | ||||||
|  | 		}, | ||||||
|  | 		primitive: { | ||||||
|  | 			cullMode: "back", | ||||||
|  | 			frontFace: "ccw", | ||||||
|  | 			topology: "triangle-list", | ||||||
|  | 		}, | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	return pipeline; | ||||||
| } | } | ||||||
|  |  | ||||||
| export function createShaderCode({ | export function createShaderCode({ | ||||||
| @@ -84,6 +203,24 @@ struct ObjectUniforms { | |||||||
| @group(1) @binding(6) var _EmissiveTexture: texture_2d<f32>; | @group(1) @binding(6) var _EmissiveTexture: texture_2d<f32>; | ||||||
| @group(1) @binding(7) var _TransmissionCollimationTexture: texture_2d<f32>; | @group(1) @binding(7) var _TransmissionCollimationTexture: texture_2d<f32>; | ||||||
|  |  | ||||||
|  | fn screenSpaceMatrixTStoVS(positionVS: vec3<f32>, normalVS: vec3<f32>, texCoord: vec2<f32>) -> mat3x3<f32> { | ||||||
|  | 	let q0 = dpdx(positionVS); | ||||||
|  | 	let q1 = dpdy(positionVS); | ||||||
|  | 	let uv0 = dpdx(texCoord); | ||||||
|  | 	let uv1 = dpdy(texCoord); | ||||||
|  |  | ||||||
|  | 	let q1perp = cross(q1, normalVS); | ||||||
|  | 	let q0perp = cross(normalVS, q0); | ||||||
|  |  | ||||||
|  | 	let tangentVS = q1perp * uv0.x + q0perp * uv1.x; | ||||||
|  | 	let bitangentVS = q1perp * uv0.y + q0perp * uv1.y; | ||||||
|  |  | ||||||
|  | 	let det = max(dot(tangentVS, tangentVS), dot(bitangentVS, bitangentVS)); | ||||||
|  | 	let scale = (det == 0.0) ? 0.0 : inserseSqrt(det); | ||||||
|  |  | ||||||
|  | 	return mat3x3(tangentVS * scale, bitangentVS * scale, normalVS); | ||||||
|  | } | ||||||
|  |  | ||||||
| @vertex | @vertex | ||||||
| fn vert(vertex: Vertex) -> Varyings { | fn vert(vertex: Vertex) -> Varyings { | ||||||
| 	var output: Varyings; | 	var output: Varyings; | ||||||
| @@ -122,7 +259,7 @@ fn frag(fragment: Varyings) -> @location(0) vec2<f32> { | |||||||
| 		let baseColorPartialCoverageTexel = texture(_BaseColorPartialCoverageTexture, _Sampler, fragment.texCoord); | 		let baseColorPartialCoverageTexel = texture(_BaseColorPartialCoverageTexture, _Sampler, fragment.texCoord); | ||||||
| 		baseColor *= baseColorPartialCoverageTexel.rgb; | 		baseColor *= baseColorPartialCoverageTexel.rgb; | ||||||
| 		partialCoverage *= baseColorPartialCoverageTexel.a; | 		partialCoverage *= baseColorPartialCoverageTexel.a; | ||||||
| 		let roughnessMetallicTexel = texture(_RoughnessMetallic, _Sampler, fragment.texCoord); | 		let roughnessMetallicTexel = texture(_RoughnessMetallicTexture, _Sampler, fragment.texCoord); | ||||||
| 		roughness *= roughnessMetallicTexel.g; | 		roughness *= roughnessMetallicTexel.g; | ||||||
| 		metallic *= roughnessMetallicTexel.b; | 		metallic *= roughnessMetallicTexel.b; | ||||||
| 		let emissiveTexel = texture(_EmissiveTexture, _Sampler, fragment.texCoord); | 		let emissiveTexel = texture(_EmissiveTexture, _Sampler, fragment.texCoord); | ||||||
| @@ -140,14 +277,19 @@ fn frag(fragment: Varyings) -> @location(0) vec2<f32> { | |||||||
| 		let dPositionVSdx = dpdx(positionVS); | 		let dPositionVSdx = dpdx(positionVS); | ||||||
| 		let dPositionVSdy = dpdy(positionVS); | 		let dPositionVSdy = dpdy(positionVS); | ||||||
| 		let geometricNormalVS = normalize(cross(dPositionVSdx, dPositionVSdy)); | 		let geometricNormalVS = normalize(cross(dPositionVSdx, dPositionVSdy)); | ||||||
| 		let actualNormalVS = geometricNormalVS; |  | ||||||
| 	`} | 	`} | ||||||
| 	${texCoord ? ` | 	${texCoord ? ` | ||||||
| 	` : ` | 		${tangent ? ` | ||||||
| 		let actualNormalVS = geometricNormalVS; | 			let tangentVS = normalize(fragment.tangentVS); | ||||||
| 	`} | 			let bitangentVS = normalize(fragment.bitangentVS); | ||||||
| 	${tangent ? ` | 			let matrixTStoVS = mat3x3(tangentVS, bitangentVS, geometricNormalVS); | ||||||
| 		let tangentVS = | 		` : ` | ||||||
|  | 			let matrixTStoVS = screenSpaceMatrixTStoVS(positionVS, geometricNormalVS, fragment.texCoord); | ||||||
|  | 		`} | ||||||
|  | 		let normalTextureTexel = texture(_NormalTexture, _Sampler, fragment.texCoord); | ||||||
|  | 		var normalTS = normalTextureTexel.xyz * 2.0 - 1.0; | ||||||
|  | 		normalTS.xy *= _Material.normalScale; | ||||||
|  | 		let actualNormalVS = normalize(matrixTStoVS * geometricNormalVS); | ||||||
| 	` : ` | 	` : ` | ||||||
| 		let actualNormalVS = geometricNormalVS; | 		let actualNormalVS = geometricNormalVS; | ||||||
| 	`} | 	`} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Szymon Nowakowski
					Szymon Nowakowski