Pipeline creation, work on shader code
This commit is contained in:
parent
89576c33bd
commit
7fef3c90d8
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;
|
||||||
`}
|
`}
|
||||||
|
Loading…
Reference in New Issue
Block a user