Направленное затенение 3D-рендерера WebGPU отображается неравномерноJavascript

Форум по Javascript
Ответить
Anonymous
 Направленное затенение 3D-рендерера WebGPU отображается неравномерно

Сообщение Anonymous »

Привет, это мой первый пост о переполнении стека. Я вообще не хочу использовать ИИ в своем коде, я хочу изучать 3D-графику с реальными людьми. Если я что-то упускаю, дайте мне знать, так как я новичок в том, чтобы задавать вопросы здесь.
В любом случае, большая часть моего кода WebGPU взята с веб-сайта (https://shi-yan.github.io/webgpuunleashed/), я бы сказал, что это довольно хорошее подробное руководство, на котором я основывал свой код в своем проекте, хотя и не слишком подробно описывает шейдеры моего проекта.
Проблема для меня заключается в том, что плавная заливка выглядит разделенной на 4 стороны, кроме того, в этом проекте я в основном использую затенение Гуро/Вертекс, поэтому попиксельное затенение - это не то, что я хочу исправлять.
Я пытался проверить, как работают нормали в загрузчике obj, и похоже, что они не рассчитываются, в чем, вероятно, и есть проблема, я изменил значения, и это действительно изменило их равномерное распределение, хотя я не слишком уверен, как это работает.
Вот скриншот того, как это выглядит сейчас: Текущая заливка
Вот плавная штриховка, которую я хочу равномерно распределить по сетке: Предполагаемая заливка
Шейдер WGSL:
// Uniforms
@group(0) @binding(0)
var modelView: mat4x4;
@group(0) @binding(1)
var projection: mat4x4;
@group(0) @binding(2)
var normalMatrix: mat4x4;
@group(0) @binding(3)
var lightDirection: vec3;
@group(0) @binding(4)
var viewDirection: vec3;

// variables
const ambientColor:vec4 = vec4(0.0, 0.0, 0.0, 1.0);
const diffuseColor:vec4 = vec4(1.0, 1.0, 1.0, 1.0);
const specularColor:vec4 = vec4(1.0, 1.0, 1.0, 1.0);

const shininess:f32 = 20.0;

const ambientConstant:f32 = 1.0;
const diffuseConstant:f32 = 1.0;
const specularConstant:f32 = 1.0;

fn specular(lightDir:vec3, viewDir:vec3, normal:vec3, specularColor:vec3, shininess:f32) -> vec3 {
var reflectDir:vec3 = reflect(-lightDir, normal);
var specDot:f32 = max(dot(reflectDir, viewDir), 0.0);
return pow(specDot, shininess) * specularColor;
};

fn diffuse(lightDir:vec3, normal:vec3, diffuseColor:vec3) -> vec3 {
return max(dot(lightDir, normal), 0.0) * diffuseColor;
};

struct VertexOutput {
@builtin(position) clip_position: vec4,
@location(0) color: vec3
};

// vertex shader
@vertex
fn vs_main(
@location(0) inPos: vec3,
@location(1) inNormal: vec3
) -> VertexOutput {
var n:vec3 = normalize((normalMatrix * vec4(inNormal, 0.0)).xyz);
var viewDir:vec3 = normalize((normalMatrix * vec4(-viewDirection,0.0)).xyz);
var lightDir:vec3 = normalize((normalMatrix * vec4(-lightDirection,0.0)).xyz);

var radiance:vec3 = ambientColor.rgb * ambientConstant +
diffuse(lightDir, n, diffuseColor.rgb) * diffuseConstant +
specular(lightDir, viewDir, n, specularColor.rgb, shininess) * specularConstant;

var out: VertexOutput;
out.clip_position = projection * modelView * vec4(inPos, 1.0);
out.color = radiance;
return out;
}

// fragment shader
@fragment
fn fs_main(in: VertexOutput, @builtin(front_facing) face: bool) -> @location(0) vec4 {
return vec4(in.color,1.0);
};

функция загрузки объектов (В RBLCKUTILS):
loadOBJ: async function(self, device, path) {
const objResponse = await fetch(path);
const objBody = await objResponse.text();

let obj = await (async () => {
return new Promise((resolve, reject) => {
let obj = new OBJFile(objBody);
obj.parse();
resolve(obj);
})
})();

let positions = [];
let normals = [];

let minX = Number.MAX_VALUE;
let maxX = Number.MIN_VALUE;

let minY = Number.MAX_VALUE;
let maxY = Number.MIN_VALUE;

let minZ = Number.MAX_VALUE;
let maxZ = Number.MIN_VALUE;
for (let v of obj.result.models[0].vertices) {
positions.push(v.x);
positions.push(v.y);
positions.push(v.z);
normals.push(0.0);
normals.push(0.0);
normals.push(0.0);
}

positions = new Float32Array(positions);
normals = new Float32Array(normals);

let positionBuffer = self.createGPUBuffer(device, positions, GPUBufferUsage.VERTEX);
let indices = [];

//cs_start: normal_loading
for (let f of obj.result.models[0].faces) {
let points = [];
let facet_indices = [];
for (let v of f.vertices) {
const index = v.vertexIndex - 1;
indices.push(index);

const vertex = vec3.fromValues(positions[index * 3], positions[index * 3 + 1], positions[index * 3 + 2]);

minX = Math.min(positions[index * 3], minX);
maxX = Math.max(positions[index * 3], maxX);

minY = Math.min(positions[index * 3 + 1], minY);
maxY = Math.max(positions[index * 3 + 1], maxY);

minZ = Math.min(positions[index * 3 + 2], minZ);
maxZ = Math.max(positions[index * 3 + 2], maxZ);
points.push(vertex);
facet_indices.push(index);
}

const v1 = vec3.subtract(vec3.create(), points[1], points[0]);
const v2 = vec3.subtract(vec3.create(), points[2], points[0]);
const cross = vec3.cross(vec3.create(), v1, v2);
const normal = vec3.normalize(vec3.create(), cross);

for (let i of facet_indices) {
normals[i * 3] += normal[0];
normals[i * 3 + 1] += normal[1];
normals[i * 3 + 2] += normal[2];
}
}
let normalBuffer = self.createGPUBuffer(device, normals, GPUBufferUsage.VERTEX);
//cs_end: normal_loading

const indexSize = indices.length;

indices = new Uint16Array(indices);

let indexBuffer = self.createGPUBuffer(device, indices, GPUBufferUsage.INDEX);
return {
positionBuffer, normalBuffer, indexBuffer, indexSize, center: [(minX + maxX) * 0.5, (minY + maxY) * 0.5, (minZ + maxZ) * 0.5],
radius: Math.max(Math.max(maxX - minX, maxY - minY), maxZ - minZ) * 0.5
}
}

RBLCKRenderer (ФУНКЦИЯ SETUP3D):
setup3D: async function(self) {
if (self.canvas)
{
// create renderer
const renderer = rc.createRenderer(self.device, self.canvas, self.ctxt);
await renderer.init();

const { positionBuffer, normalBuffer, indexBuffer, indexSize } = await RBLCKUtils.loadOBJ(RBLCKUtils, self.device, '../Asset/OBJ/UtahTeapot.obj');

// camera main //
let modelViewMatrix = mat4.lookAt(mat4.create(),
vec3.fromValues(3, 3, 3), vec3.fromValues(0, 0, 0), vec3.fromValues(0.0, 0.0, 1.0));

let modelViewMatrixInverse = mat4.invert(mat4.create(), modelViewMatrix);
let normalMatrix = mat4.transpose(mat4.create(), modelViewMatrixInverse);

let transformationMatrix = mat4.lookAt(mat4.create(),
vec3.fromValues(3, -3, 1.5),
vec3.fromValues(0,0,0),
vec3.fromValues(0.0, 0.0, 1.0));

let projectionMatrix = mat4.perspective(mat4.create(),
1.4, self.canvas.width / self.canvas.height, 0.1, 1000.0);

let transformMatBuffer = RBLCKUtils.createGPUBuffer(self.device, transformationMatrix, GPUBufferUsage.UNIFORM);
let projectionMatBuffer = RBLCKUtils.createGPUBuffer(self.device, projectionMatrix, GPUBufferUsage.UNIFORM);

let normalMatBuffer = RBLCKUtils.createGPUBuffer(self.device, normalMatrix, GPUBufferUsage.UNIFORM);

let lightDirectionBuffer = new Float32Array([-1.0, -1.0, -1.0]);

const lightDirectionUniformBuffer = RBLCKUtils.createGPUBuffer(self.device, lightDirectionBuffer, GPUBufferUsage.UNIFORM);

const viewDirectionUniformBuffer = RBLCKUtils.createGPUBuffer(self.device, new Float32Array([-1.0, -1.0, -1.0]), GPUBufferUsage.UNIFORM);
// Uniform buffers test

// Forward the binding's resource
const uniformBindGroup = self.device.createBindGroup({
layout: renderer.gpu.bindGroupLayout,
entries: [
{
binding: 0,
resource: {
buffer: transformMatBuffer
}
},
{
binding: 1,
resource: {
buffer: projectionMatBuffer
}
},
{
binding: 2,
resource: {
buffer: normalMatBuffer
}
},
{
binding: 3,
resource: {
buffer: lightDirectionUniformBuffer
}
},
{
binding: 4,
resource: {
buffer: viewDirectionUniformBuffer
}
},
],
});

// Depth backing
const depthTextureDesc = {
size: [self.canvas.width, self.canvas.height, 1],
sampleCount: 4,
dimension: '2d',
format: 'depth24plus-stencil8',
usage: GPUTextureUsage.RENDER_ATTACHMENT
};

let depthTexture = self.device.createTexture(depthTextureDesc);
let depthTextureView = depthTexture.createView();

const depthAttachment = {
view: depthTextureView,
depthClearValue: 1,
depthLoadOp: 'clear',
depthStoreOp: 'store',
stencilClearValue: 0,
stencilLoadOp: 'clear',
stencilStoreOp: 'store'
};

// setup context
const Canvas_Config = {
device: self.device,
format: navigator.gpu.getPreferredCanvasFormat(),
usage: GPUTextureUsage.RENDER_ATTACHMENT,
alphaMode: 'opaque'
}

// configure
self.ctxt.configure(Canvas_Config);

// get the texture
self.currentTexture = self.ctxt.getCurrentTexture()
self.textureView = self.currentTexture.createView();

const msaaTexture = self.device.createTexture({
size: [self.canvas.width, self.canvas.height],
sampleCount: 4,
format: navigator.gpu.getPreferredCanvasFormat(),
usage: GPUTextureUsage.RENDER_ATTACHMENT,
});
const view = msaaTexture.createView();

// color attributes
self.ctxColorAtt = {
view: view,
resolveTarget: self.textureView,
clearValue: { r: 1, g: 1, b: 1, a: 1 },
loadOp: 'clear',
storeOp: 'store'
};

// color bulk here
self.renderPassDescriptor = {
colorAttachments: [self.ctxColorAtt],
depthStencilAttachment: depthAttachment
};

// encode
self.commandEncoder = self.device.createCommandEncoder();
self.passEncoder = self.commandEncoder.beginRenderPass(self.renderPassDescriptor);

self.passEncoder.setViewport(0, 0, self.canvas.width, self.canvas.height, 0, 1);
self.passEncoder.setPipeline(renderer.gpu.pipeline);
self.passEncoder.setBindGroup(0,uniformBindGroup);
self.passEncoder.setVertexBuffer(0,positionBuffer);
self.passEncoder.setVertexBuffer(1,normalBuffer);

self.passEncoder.setIndexBuffer(indexBuffer, 'uint16');
self.passEncoder.drawIndexed(indexSize);

self.passEncoder.end();

// Finalize
self.device.queue.submit([self.commandEncoder.finish()]);

window.addEventListener('resize',function() {
self.canvas.height = window.innerHeight;
self.canvas.width = window.innerWidth;
});

return renderer;
};
},


Подробнее здесь: https://stackoverflow.com/questions/798 ... ing-evenly
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»