No failing webGPU version found
This commit is contained in:
@@ -10,7 +10,7 @@ import {UrlConstants} from '../../../constants/UrlConstants';
|
|||||||
import {FormsModule} from '@angular/forms';
|
import {FormsModule} from '@angular/forms';
|
||||||
import {BabylonCanvas, RenderCallback, RenderConfig} from '../../../shared/rendering/canvas/babylon-canvas.component';
|
import {BabylonCanvas, RenderCallback, RenderConfig} from '../../../shared/rendering/canvas/babylon-canvas.component';
|
||||||
import {FRACTAL2D_FRAGMENT, FRACTAL2D_VERTEX} from './fractal.shader';
|
import {FRACTAL2D_FRAGMENT, FRACTAL2D_VERTEX} from './fractal.shader';
|
||||||
import {PointerEventTypes, PointerInfo, Scene, ShaderMaterial, Vector2} from '@babylonjs/core';
|
import {PointerEventTypes, PointerInfo, Scene, ShaderMaterial, Vector2, WebGPUEngine} from '@babylonjs/core';
|
||||||
import {MatButton} from '@angular/material/button';
|
import {MatButton} from '@angular/material/button';
|
||||||
import {MatIcon} from '@angular/material/icon';
|
import {MatIcon} from '@angular/material/icon';
|
||||||
import {NgxSliderModule, Options} from '@angular-slider/ngx-slider';
|
import {NgxSliderModule, Options} from '@angular-slider/ngx-slider';
|
||||||
@@ -74,6 +74,7 @@ export class FractalComponent implements OnInit {
|
|||||||
|
|
||||||
renderConfig: RenderConfig = {
|
renderConfig: RenderConfig = {
|
||||||
mode: '2D',
|
mode: '2D',
|
||||||
|
pipeline: 'Material',
|
||||||
initialViewSize: 100,
|
initialViewSize: 100,
|
||||||
vertexShader: FRACTAL2D_VERTEX,
|
vertexShader: FRACTAL2D_VERTEX,
|
||||||
fragmentShader: FRACTAL2D_FRAGMENT,
|
fragmentShader: FRACTAL2D_FRAGMENT,
|
||||||
@@ -155,8 +156,8 @@ export class FractalComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onSceneReady(scene: Scene): void {
|
onSceneReady(options: {scene: Scene, engine: WebGPUEngine}): void {
|
||||||
scene.onPointerObservable.add((pointerInfo) => {
|
options.scene.onPointerObservable.add((pointerInfo) => {
|
||||||
switch (pointerInfo.type) {
|
switch (pointerInfo.type) {
|
||||||
|
|
||||||
case PointerEventTypes.POINTERDOWN:
|
case PointerEventTypes.POINTERDOWN:
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export class Fractal3dComponent {
|
|||||||
|
|
||||||
fractalConfig: RenderConfig = {
|
fractalConfig: RenderConfig = {
|
||||||
mode: '3D',
|
mode: '3D',
|
||||||
|
pipeline: 'Material',
|
||||||
initialViewSize: 4,
|
initialViewSize: 4,
|
||||||
vertexShader: MANDELBULB_VERTEX,
|
vertexShader: MANDELBULB_VERTEX,
|
||||||
fragmentShader: MANDELBULB_FRAGMENT,
|
fragmentShader: MANDELBULB_FRAGMENT,
|
||||||
|
|||||||
137
src/app/pages/algorithms/path-tracing/path-tracing-shader.ts
Normal file
137
src/app/pages/algorithms/path-tracing/path-tracing-shader.ts
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
export const PATH_TRACING_SHADER = `
|
||||||
|
struct Camera {
|
||||||
|
position: vec4<f32>,
|
||||||
|
forward: vec4<f32>,
|
||||||
|
right: vec4<f32>,
|
||||||
|
up: vec4<f32>
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceneParams {
|
||||||
|
values: vec4<f32>
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sphere {
|
||||||
|
center: vec3<f32>,
|
||||||
|
radius: f32,
|
||||||
|
color: vec3<f32>,
|
||||||
|
emission: vec3<f32>
|
||||||
|
};
|
||||||
|
|
||||||
|
@group(0) @binding(0) var outputTex : texture_storage_2d<rgba8unorm, write>;
|
||||||
|
// Uniform -> Storage (read)
|
||||||
|
@group(0) @binding(1) var<storage, read> cam : Camera;
|
||||||
|
// Uniform -> Storage (read)
|
||||||
|
@group(0) @binding(2) var<storage, read> params : SceneParams;
|
||||||
|
|
||||||
|
fn getSceneSphere(i: i32) -> Sphere {
|
||||||
|
var s: Sphere;
|
||||||
|
s.emission = vec3<f32>(0.0);
|
||||||
|
|
||||||
|
if (i == 0) { s.center = vec3<f32>(-100.5, 0.0, 0.0); s.radius = 100.0; s.color = vec3<f32>(0.8, 0.1, 0.1); }
|
||||||
|
else if (i == 1) { s.center = vec3<f32>( 100.5, 0.0, 0.0); s.radius = 100.0; s.color = vec3<f32>(0.1, 0.8, 0.1); }
|
||||||
|
else if (i == 2) { s.center = vec3<f32>(0.0, 100.5, 0.0); s.radius = 100.0; s.color = vec3<f32>(0.8, 0.8, 0.8); }
|
||||||
|
else if (i == 3) { s.center = vec3<f32>(0.0, -100.5, 0.0); s.radius = 100.0; s.color = vec3<f32>(0.8, 0.8, 0.8); }
|
||||||
|
else if (i == 4) { s.center = vec3<f32>(0.0, 0.0, 100.5); s.radius = 100.0; s.color = vec3<f32>(0.8, 0.8, 0.8); }
|
||||||
|
else if (i == 5) { s.center = vec3<f32>(0.0, 1.5, 0.0); s.radius = 0.3; s.color = vec3<f32>(1.0); s.emission = vec3<f32>(15.0); }
|
||||||
|
else if (i == 6) { s.center = vec3<f32>(-0.3, -0.3, -0.3); s.radius = 0.25; s.color = vec3<f32>(0.9, 0.9, 0.1); }
|
||||||
|
else { s.center = vec3<f32>(0.3, -0.3, 0.2); s.radius = 0.25; s.color = vec3<f32>(0.2, 0.2, 0.9); }
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hitSphere(ro: vec3<f32>, rd: vec3<f32>, s: Sphere) -> f32 {
|
||||||
|
let oc = ro - s.center;
|
||||||
|
let b = dot(oc, rd);
|
||||||
|
let c = dot(oc, oc) - s.radius * s.radius;
|
||||||
|
let h = b*b - c;
|
||||||
|
if (h < 0.0) { return -1.0; }
|
||||||
|
return -b - sqrt(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rand(seed: ptr<function, u32>) -> f32 {
|
||||||
|
*seed = *seed * 747796405u + 2891336453u;
|
||||||
|
let word = ((*seed >> ((*seed >> 28u) + 4u)) ^ *seed) * 277803737u;
|
||||||
|
return f32((word >> 22u) ^ word) / 4294967296.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn randomHemisphereDir(normal: vec3<f32>, seed: ptr<function, u32>) -> vec3<f32> {
|
||||||
|
let r1 = rand(seed);
|
||||||
|
let r2 = rand(seed);
|
||||||
|
let theta = 6.283185 * r1;
|
||||||
|
let phi = acos(2.0 * r2 - 1.0);
|
||||||
|
let x = sin(phi) * cos(theta);
|
||||||
|
let y = sin(phi) * sin(theta);
|
||||||
|
let z = cos(phi);
|
||||||
|
let v = normalize(vec3<f32>(x, y, z));
|
||||||
|
if (dot(v, normal) < 0.0) { return -v; }
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@compute @workgroup_size(8, 8, 1)
|
||||||
|
fn main(@builtin(global_invocation_id) global_id : vec3<u32>) {
|
||||||
|
let dims = textureDimensions(outputTex);
|
||||||
|
let coord = vec2<i32>(global_id.xy);
|
||||||
|
|
||||||
|
if (coord.x >= i32(dims.x) || coord.y >= i32(dims.y)) { return; }
|
||||||
|
|
||||||
|
let uv = (vec2<f32>(coord) / vec2<f32>(dims)) * 2.0 - 1.0;
|
||||||
|
let aspect = f32(dims.x) / f32(dims.y);
|
||||||
|
let screenPos = vec2<f32>(uv.x * aspect, -uv.y);
|
||||||
|
|
||||||
|
var ro = cam.position.xyz;
|
||||||
|
var rd = normalize(cam.forward.xyz + cam.right.xyz * screenPos.x + cam.up.xyz * screenPos.y);
|
||||||
|
|
||||||
|
var col = vec3<f32>(0.0);
|
||||||
|
var throughput = vec3<f32>(1.0);
|
||||||
|
// Zugriff auf params.values statt params.x
|
||||||
|
var seed = u32(global_id.x + global_id.y * dims.x) + u32(params.values.x) * 719393u;
|
||||||
|
|
||||||
|
for (var i = 0; i < 4; i++) {
|
||||||
|
var tMin = 10000.0;
|
||||||
|
var hitIndex = -1;
|
||||||
|
|
||||||
|
for (var j = 0; j < 8; j++) {
|
||||||
|
let s = getSceneSphere(j);
|
||||||
|
let t = hitSphere(ro, rd, s);
|
||||||
|
if (t > 0.001 && t < tMin) {
|
||||||
|
tMin = t;
|
||||||
|
hitIndex = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hitIndex == -1) {
|
||||||
|
col = col + throughput * vec3<f32>(0.1, 0.1, 0.15);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hitSphere = getSceneSphere(hitIndex);
|
||||||
|
let hitPos = ro + rd * tMin;
|
||||||
|
let normal = normalize(hitPos - hitSphere.center);
|
||||||
|
|
||||||
|
if (length(hitSphere.emission) > 0.0) {
|
||||||
|
col = col + throughput * hitSphere.emission;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
throughput = throughput * hitSphere.color;
|
||||||
|
ro = hitPos;
|
||||||
|
rd = randomHemisphereDir(normal, &seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug: Falls Bild immer noch schwarz, entkommentieren:
|
||||||
|
// textureStore(outputTex, coord, vec4<f32>(1.0, 0.0, 0.0, 1.0));
|
||||||
|
|
||||||
|
textureStore(outputTex, coord, vec4<f32>(col, 1.0));
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
export const RED_SHADER = `
|
||||||
|
@group(0) @binding(0) var outputTex : texture_storage_2d<rgba8unorm, write>;
|
||||||
|
|
||||||
|
@compute @workgroup_size(1, 1, 1)
|
||||||
|
fn main(@builtin(global_invocation_id) global_id : vec3<u32>) {
|
||||||
|
// Schreibe Rot (R=1, G=0, B=0, A=1) an die Pixel-Position
|
||||||
|
textureStore(outputTex, global_id.xy, vec4<f32>(1.0, 0.0, 0.0, 1.0));
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
<app-information [algorithmInformation]="algoInformation"/>
|
<app-information [algorithmInformation]="algoInformation"/>
|
||||||
<app-babylon-canvas
|
<app-babylon-canvas
|
||||||
[config]="fractalConfig"
|
[config]="fractalConfig"
|
||||||
[renderCallback]="onRender"
|
(sceneReady)="onSceneReady($event)"
|
||||||
/>
|
/>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import {BabylonCanvas, RenderCallback, RenderConfig} from '../../../shared/rendering/canvas/babylon-canvas.component';
|
import { BabylonCanvas, RenderConfig } from '../../../shared/rendering/canvas/babylon-canvas.component';
|
||||||
import {Information} from '../information/information';
|
import { Information } from '../information/information';
|
||||||
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card';
|
import { MatCard, MatCardContent, MatCardHeader, MatCardTitle } from '@angular/material/card';
|
||||||
import {TranslatePipe} from '@ngx-translate/core';
|
import { TranslatePipe } from '@ngx-translate/core';
|
||||||
import {AlgorithmInformation} from '../information/information.models';
|
import { AlgorithmInformation } from '../information/information.models';
|
||||||
import {PATH_TRACING_VERTEX_SHADER} from './path-tracing.shader';
|
import {
|
||||||
|
ComputeShader,
|
||||||
|
Layer,
|
||||||
|
RawTexture,
|
||||||
|
Scene,
|
||||||
|
WebGPUEngine,
|
||||||
|
Constants
|
||||||
|
} from '@babylonjs/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-path-tracing',
|
selector: 'app-path-tracing',
|
||||||
@@ -23,26 +30,73 @@ import {PATH_TRACING_VERTEX_SHADER} from './path-tracing.shader';
|
|||||||
export class PathTracingComponent {
|
export class PathTracingComponent {
|
||||||
|
|
||||||
algoInformation: AlgorithmInformation = {
|
algoInformation: AlgorithmInformation = {
|
||||||
title: '',
|
title: 'WebGPU Debug',
|
||||||
entries: [
|
entries: [],
|
||||||
],
|
|
||||||
disclaimer: '',
|
disclaimer: '',
|
||||||
disclaimerBottom: '',
|
disclaimerBottom: '',
|
||||||
disclaimerListEntry: ['']
|
disclaimerListEntry: []
|
||||||
};
|
};
|
||||||
|
|
||||||
fractalConfig: RenderConfig = {
|
fractalConfig: RenderConfig = {
|
||||||
mode: '3D',
|
mode: '3D',
|
||||||
|
pipeline: 'Compute',
|
||||||
initialViewSize: 4,
|
initialViewSize: 4,
|
||||||
vertexShader: PATH_TRACING_VERTEX_SHADER,
|
|
||||||
fragmentShader: '',
|
|
||||||
uniformNames: ["time", "power", "fractalType"]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private time = 0;
|
private cs!: ComputeShader;
|
||||||
|
private texture!: RawTexture;
|
||||||
|
|
||||||
onRender: RenderCallback = () => {
|
onSceneReady(payload: { scene: Scene, engine: WebGPUEngine }) {
|
||||||
this.time += 0.005;
|
const { scene, engine } = payload;
|
||||||
};
|
const canvas = engine.getRenderingCanvas()!;
|
||||||
|
const width = 512;
|
||||||
|
const height = 512;
|
||||||
|
|
||||||
|
// 1. Textur erstellen (Storage)
|
||||||
|
this.texture = new RawTexture(
|
||||||
|
new Uint8Array(width * height * 4),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
Constants.TEXTUREFORMAT_RGBA,
|
||||||
|
scene,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
Constants.TEXTURE_NEAREST_SAMPLINGMODE,
|
||||||
|
Constants.TEXTURETYPE_UNSIGNED_BYTE,
|
||||||
|
Constants.TEXTURE_CREATIONFLAG_STORAGE
|
||||||
|
);
|
||||||
|
|
||||||
|
// 2. Minimal-Shader
|
||||||
|
const shaderCode = `
|
||||||
|
@group(0) @binding(0) var outputTex : texture_storage_2d<rgba8unorm, write>;
|
||||||
|
@compute @workgroup_size(8, 8, 1)
|
||||||
|
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
|
||||||
|
textureStore(outputTex, gid.xy, vec4<f32>(0.0, 1.0, 0.0, 1.0));
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 3. Shader erstellen
|
||||||
|
this.cs = new ComputeShader(
|
||||||
|
"simple",
|
||||||
|
engine,
|
||||||
|
{ computeSource: shaderCode },
|
||||||
|
{
|
||||||
|
bindingsMapping: { "outputTex": { group: 0, binding: 0 } },
|
||||||
|
entryPoint: "main"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.cs.setTexture("outputTex", this.texture);
|
||||||
|
|
||||||
|
// 4. Layer
|
||||||
|
const layer = new Layer("viewLayer", null, scene);
|
||||||
|
layer.texture = this.texture;
|
||||||
|
|
||||||
|
// 5. Der Trick: Einmaliger Dispatch nach einer kurzen Pause
|
||||||
|
// Das umgeht alle "isReady" oder Binding-Timing Probleme
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log("Forcing Compute Dispatch...");
|
||||||
|
this.cs.dispatch(width / 8, height / 8, 1);
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
export const PATH_TRACING_VERTEX_SHADER = /* glsl */`
|
|
||||||
attribute vec3 position;
|
|
||||||
attribute vec2 uv;
|
|
||||||
varying vec2 vUV;
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
gl_Position = vec4(position, 1.0);
|
|
||||||
vUV = uv;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
import {AfterViewInit, Component, ElementRef, EventEmitter, inject, Input, NgZone, OnDestroy, Output, ViewChild} from '@angular/core';
|
import {AfterViewInit, Component, ElementRef, EventEmitter, Input, OnDestroy, Output, ViewChild} from '@angular/core';
|
||||||
import {ArcRotateCamera, Camera, Engine, MeshBuilder, Scene, ShaderMaterial, Vector2, Vector3} from '@babylonjs/core';
|
import {ArcRotateCamera, Camera, MeshBuilder, Scene, ShaderMaterial, Vector2, Vector3, WebGPUEngine} from '@babylonjs/core';
|
||||||
|
|
||||||
export interface RenderConfig {
|
export interface RenderConfig {
|
||||||
mode: '2D' | '3D';
|
mode: '2D' | '3D';
|
||||||
|
pipeline: 'Material' | 'Compute';
|
||||||
initialViewSize: number;
|
initialViewSize: number;
|
||||||
vertexShader: string;
|
vertexShader?: string;
|
||||||
fragmentShader: string;
|
fragmentShader?: string;
|
||||||
uniformNames: string[];
|
uniformNames?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RenderCallback = (material: ShaderMaterial, camera: Camera, canvas: HTMLCanvasElement, scene: Scene) => void;
|
export type RenderCallback = (material: ShaderMaterial, camera: Camera, canvas: HTMLCanvasElement, scene: Scene) => void;
|
||||||
@@ -18,24 +19,21 @@ export type RenderCallback = (material: ShaderMaterial, camera: Camera, canvas:
|
|||||||
styleUrl: './babylon-canvas.component.scss',
|
styleUrl: './babylon-canvas.component.scss',
|
||||||
})
|
})
|
||||||
export class BabylonCanvas implements AfterViewInit, OnDestroy {
|
export class BabylonCanvas implements AfterViewInit, OnDestroy {
|
||||||
readonly ngZone = inject(NgZone);
|
|
||||||
|
|
||||||
@ViewChild('renderCanvas', { static: true }) canvasRef!: ElementRef<HTMLCanvasElement>;
|
@ViewChild('renderCanvas', { static: true }) canvasRef!: ElementRef<HTMLCanvasElement>;
|
||||||
|
|
||||||
@Input({ required: true }) config!: RenderConfig;
|
@Input({ required: true }) config!: RenderConfig;
|
||||||
@Input() renderCallback?: RenderCallback;
|
@Input() renderCallback?: RenderCallback;
|
||||||
|
|
||||||
@Output() sceneReady = new EventEmitter<Scene>();
|
@Output() sceneReady = new EventEmitter<{scene: Scene, engine: WebGPUEngine}>();
|
||||||
|
|
||||||
private engine!: Engine;
|
private engine!: WebGPUEngine;
|
||||||
private scene!: Scene;
|
private scene!: Scene;
|
||||||
private shaderMaterial!: ShaderMaterial;
|
private shaderMaterial!: ShaderMaterial;
|
||||||
private camera!: Camera;
|
private camera!: Camera;
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
this.ngZone.runOutsideAngular(() => {
|
this.initBabylon().then(r => console.log("Rendering engine initialized."));
|
||||||
this.initBabylon();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*ngOnChanges(changes: SimpleChanges): void {
|
/*ngOnChanges(changes: SimpleChanges): void {
|
||||||
@@ -52,15 +50,27 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initBabylon(): void {
|
async initBabylon(): Promise<void> {
|
||||||
|
if (!navigator.gpu) {
|
||||||
|
alert("Your browser does not support webgpu, maybe you have activate the hardware acceleration.!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const canvas = this.canvasRef.nativeElement;
|
const canvas = this.canvasRef.nativeElement;
|
||||||
this.engine = new Engine(canvas, true);
|
this.engine = new WebGPUEngine(canvas, {
|
||||||
|
antialias: true
|
||||||
|
});
|
||||||
|
await this.engine.initAsync();
|
||||||
|
|
||||||
|
|
||||||
this.scene = new Scene(this.engine);
|
this.scene = new Scene(this.engine);
|
||||||
this.setupCamera(canvas);
|
this.setupCamera(canvas);
|
||||||
canvas.addEventListener('wheel', (evt: WheelEvent) => evt.preventDefault(), { passive: false });
|
canvas.addEventListener('wheel', (evt: WheelEvent) => evt.preventDefault(), { passive: false });
|
||||||
this.createShaderMaterial();
|
if (this.config.pipeline !== 'Compute') {
|
||||||
this.createFullScreenRect();
|
this.createShaderMaterial();
|
||||||
this.sceneReady.emit(this.scene);
|
this.createFullScreenRect();
|
||||||
|
}
|
||||||
|
this.sceneReady.emit({ scene: this.scene, engine: this.engine });
|
||||||
this.addRenderLoop(canvas);
|
this.addRenderLoop(canvas);
|
||||||
this.addResizeHandler();
|
this.addResizeHandler();
|
||||||
}
|
}
|
||||||
@@ -102,6 +112,8 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private createFullScreenRect() {
|
private createFullScreenRect() {
|
||||||
|
if (!this.shaderMaterial) return;
|
||||||
|
|
||||||
const plane = MeshBuilder.CreatePlane("plane", {size: 110}, this.scene);
|
const plane = MeshBuilder.CreatePlane("plane", {size: 110}, this.scene);
|
||||||
|
|
||||||
if (this.config.mode === '3D') {
|
if (this.config.mode === '3D') {
|
||||||
@@ -116,6 +128,13 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private createShaderMaterial() {
|
private createShaderMaterial() {
|
||||||
|
|
||||||
|
if (!this.config.vertexShader || !this.config.fragmentShader || !this.config.uniformNames)
|
||||||
|
{
|
||||||
|
console.warn("Bablyon canvas needs a vertex shader, a fragment shader and a uniforms array.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.shaderMaterial = new ShaderMaterial(
|
this.shaderMaterial = new ShaderMaterial(
|
||||||
"shaderMaterial",
|
"shaderMaterial",
|
||||||
this.scene,
|
this.scene,
|
||||||
@@ -135,14 +154,16 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
|
|||||||
private addRenderLoop(canvas: HTMLCanvasElement) {
|
private addRenderLoop(canvas: HTMLCanvasElement) {
|
||||||
this.engine.runRenderLoop(() => {
|
this.engine.runRenderLoop(() => {
|
||||||
|
|
||||||
// callback call to call specific uniforms
|
|
||||||
if (this.renderCallback) {
|
if (this.renderCallback) {
|
||||||
|
// callback call to call specific uniforms
|
||||||
this.renderCallback(this.shaderMaterial, this.camera, canvas, this.scene);
|
this.renderCallback(this.shaderMaterial, this.camera, canvas, this.scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
// default uniforms which maybe each scene has
|
if (this.shaderMaterial) {
|
||||||
this.shaderMaterial.setVector2("resolution", new Vector2(canvas.width, canvas.height));
|
// default uniforms which maybe each material scene has
|
||||||
this.shaderMaterial.setVector3("cameraPosition", this.camera.position);
|
this.shaderMaterial.setVector2("resolution", new Vector2(canvas.width, canvas.height));
|
||||||
|
this.shaderMaterial.setVector3("cameraPosition", this.camera.position);
|
||||||
|
}
|
||||||
|
|
||||||
this.scene.render();
|
this.scene.render();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user