draw 3d cubes
This commit is contained in:
parent
d55ec71edc
commit
2dd13ddd5a
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.wasm
|
||||
*.pyc
|
||||
__pycache__
|
||||
29
build.sh
Normal file
29
build.sh
Normal file
@ -0,0 +1,29 @@
|
||||
clang++ \
|
||||
-v \
|
||||
--target=wasm32 \
|
||||
-O3 \
|
||||
-flto \
|
||||
-nostdlib \
|
||||
-Wl,--no-entry \
|
||||
-Wl,--export=rotate \
|
||||
-Wl,--lto-O3 \
|
||||
-Wl,--print-map \
|
||||
-Wl,--import-memory \
|
||||
-D_XM_NO_INTRINSICS_ \
|
||||
-I. \
|
||||
-o rotate.wasm \
|
||||
rotate.c
|
||||
|
||||
|
||||
# clang \
|
||||
# -O1 \
|
||||
# --target=wasm32 \
|
||||
# -emit-llvm \
|
||||
# -c \
|
||||
# -S \
|
||||
# test.c
|
||||
|
||||
# llc \
|
||||
# -march=wasm32 \
|
||||
# -filetype=obj \
|
||||
# test.ll
|
||||
@ -1,6 +1,7 @@
|
||||
struct Configuration {
|
||||
gridSize: vec2f,
|
||||
aspect: vec2f
|
||||
aspect: vec2f,
|
||||
matrix: mat4x4f
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<uniform> config: Configuration;
|
||||
|
||||
2247
directxmath/directxmath.h
Normal file
2247
directxmath/directxmath.h
Normal file
File diff suppressed because it is too large
Load Diff
2187
directxmath/directxmathconvert.inl
Normal file
2187
directxmath/directxmathconvert.inl
Normal file
File diff suppressed because it is too large
Load Diff
3413
directxmath/directxmathmatrix.inl
Normal file
3413
directxmath/directxmathmatrix.inl
Normal file
File diff suppressed because it is too large
Load Diff
2425
directxmath/directxmathmisc.inl
Normal file
2425
directxmath/directxmathmisc.inl
Normal file
File diff suppressed because it is too large
Load Diff
14689
directxmath/directxmathvector.inl
Normal file
14689
directxmath/directxmathvector.inl
Normal file
File diff suppressed because it is too large
Load Diff
121
index.js
121
index.js
@ -15,7 +15,6 @@ canvas.height = canvas.clientHeight
|
||||
|
||||
const context = canvas.getContext("webgpu");
|
||||
const canvasFormat = navigator.gpu.getPreferredCanvasFormat();
|
||||
//console.log(canvasFormat);
|
||||
context.configure({
|
||||
device: device,
|
||||
format: canvasFormat,
|
||||
@ -36,30 +35,48 @@ renderPass.end();
|
||||
const commandBuffer = encoder.finish();
|
||||
device.queue.submit([commandBuffer]);
|
||||
|
||||
const vertices = new Float32Array([
|
||||
// X, Y,
|
||||
-0.8, -0.8, // Triangle 1 (Blue)
|
||||
0.8, -0.8,
|
||||
0.8, 0.8,
|
||||
|
||||
-0.8, -0.8, // Triangle 2 (Red)
|
||||
0.8, 0.8,
|
||||
-0.8, 0.8,
|
||||
]);
|
||||
const cubeResponse = await fetch("obj/cube.bin");
|
||||
const cubeObj = await cubeResponse.arrayBuffer();
|
||||
|
||||
const vertexBuffer = device.createBuffer({
|
||||
const cubeView = new DataView(cubeObj);
|
||||
const indexCount = cubeView.getUint32(0, true);
|
||||
const indexBufferOffset = cubeView.getUint32(4, true);
|
||||
const indexBufferSize = cubeView.getUint32(8, true);
|
||||
const vertexBufferOffset = cubeView.getUint32(12, true);
|
||||
const vertexBufferSize = cubeView.getUint32(16, true);
|
||||
console.log(`indexBufferOffset ${indexBufferOffset} indexBufferSize ${indexBufferSize}`);
|
||||
console.log(`vertexBufferOffset ${vertexBufferOffset} vertexBufferSize ${vertexBufferSize}`);
|
||||
const cubeIndexCount = indexBufferSize / 2;
|
||||
|
||||
const cubeVerticesStride = 36;
|
||||
|
||||
const indexVertexBuffer = device.createBuffer({
|
||||
label: "cell vertices",
|
||||
size: vertices.byteLength,
|
||||
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
|
||||
size: indexBufferSize + vertexBufferSize,
|
||||
usage: GPUBufferUsage.INDEX | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
|
||||
});
|
||||
device.queue.writeBuffer(vertexBuffer, 0, vertices);
|
||||
device.queue.writeBuffer(indexVertexBuffer, 0, cubeObj, indexBufferOffset, indexBufferSize);
|
||||
device.queue.writeBuffer(indexVertexBuffer, indexBufferSize, cubeObj, vertexBufferOffset, vertexBufferSize);
|
||||
|
||||
const vertexBufferLayout = {
|
||||
arrayStride: 8,
|
||||
arrayStride: cubeVerticesStride,
|
||||
attributes: [{
|
||||
format: "float32x2",
|
||||
format: "float32x3",
|
||||
offset: 0,
|
||||
shaderLocation: 0,
|
||||
}, {
|
||||
format: "float32x2",
|
||||
offset: 12,
|
||||
shaderLocation: 1,
|
||||
}, {
|
||||
format: "float16x4",
|
||||
offset: 20,
|
||||
shaderLocation: 2,
|
||||
}, {
|
||||
format: "float16x4",
|
||||
offset: 28,
|
||||
shaderLocation: 3,
|
||||
}],
|
||||
stepMode: "vertex",
|
||||
};
|
||||
@ -115,7 +132,15 @@ const cellPipeline = device.createRenderPipeline({
|
||||
targets: [{
|
||||
format: canvasFormat,
|
||||
}]
|
||||
}
|
||||
},
|
||||
primitive: {
|
||||
topology: 'triangle-list',
|
||||
},
|
||||
depthStencil: {
|
||||
depthWriteEnabled: true,
|
||||
depthCompare: 'less',
|
||||
format: 'depth24plus',
|
||||
},
|
||||
});
|
||||
|
||||
const computeShaderModule = device.createShaderModule({
|
||||
@ -135,13 +160,24 @@ const computePipeline = device.createComputePipeline({
|
||||
const gridSize = 32;
|
||||
const workGroupSize = 16;
|
||||
|
||||
const uniformArray = new Float32Array([gridSize, gridSize, 1, 1]);
|
||||
//const uniformArray2 = new Float32Array([gridSize, gridSize, 1, 1]);
|
||||
const memory = new WebAssembly.Memory({ initial: 1 });
|
||||
const uniformArray = new Float32Array(memory.buffer);
|
||||
uniformArray[0] = gridSize;
|
||||
uniformArray[1] = gridSize;
|
||||
uniformArray[2] = 1;
|
||||
uniformArray[3] = 1;
|
||||
const uniformArraySize = 4 * 4 + 4 * 4 * 4;
|
||||
const rotate = await WebAssembly.instantiateStreaming(fetch("rotate.wasm"), {
|
||||
env: { memory: memory }
|
||||
});
|
||||
|
||||
const uniformBuffer = device.createBuffer({
|
||||
label: "grid uniform",
|
||||
size: uniformArray.byteLength,
|
||||
size: uniformArraySize,
|
||||
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
||||
});
|
||||
device.queue.writeBuffer(uniformBuffer, 0, uniformArray);
|
||||
device.queue.writeBuffer(uniformBuffer, 0, uniformArray, 0, uniformArraySize / 4);
|
||||
|
||||
const cellStateArray = new Uint32Array(gridSize * gridSize);
|
||||
|
||||
@ -198,8 +234,28 @@ const bindGroups = [
|
||||
let tick = 0;
|
||||
let which = 0;
|
||||
|
||||
function createDepthTexture() {
|
||||
return device.createTexture({
|
||||
size: [canvas.width, canvas.height],
|
||||
format: 'depth24plus',
|
||||
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
||||
});
|
||||
}
|
||||
|
||||
var depthTexture = undefined;
|
||||
|
||||
function render()
|
||||
{
|
||||
if (canvas.clientWidth !== canvas.width || canvas.clientWidth !== canvas.height) {
|
||||
canvas.width = canvas.clientWidth;
|
||||
canvas.height = canvas.clientHeight;
|
||||
|
||||
if (depthTexture !== undefined) {
|
||||
depthTexture.destroy();
|
||||
}
|
||||
depthTexture = createDepthTexture();
|
||||
}
|
||||
|
||||
const encoder = device.createCommandEncoder();
|
||||
|
||||
const computePass = encoder.beginComputePass();
|
||||
@ -209,15 +265,14 @@ function render()
|
||||
computePass.dispatchWorkgroups(workgroupCount);
|
||||
computePass.end();
|
||||
|
||||
const aspect = canvas.width / canvas.height;
|
||||
rotate.instance.exports.rotate(tick * 0.01, aspect, 4 * 4);
|
||||
|
||||
tick += 1;
|
||||
if ((tick % 5) == 0) {
|
||||
which ^= 1;
|
||||
}
|
||||
|
||||
canvas.width = canvas.clientWidth
|
||||
canvas.height = canvas.clientHeight
|
||||
|
||||
const aspect = canvas.height / canvas.width;
|
||||
if (canvas.width > canvas.height) {
|
||||
uniformArray[2] = aspect;
|
||||
uniformArray[3] = 1;
|
||||
@ -225,7 +280,7 @@ function render()
|
||||
uniformArray[2] = 1;
|
||||
uniformArray[3] = 1 / aspect;
|
||||
}
|
||||
device.queue.writeBuffer(uniformBuffer, 0, uniformArray, 0);
|
||||
device.queue.writeBuffer(uniformBuffer, 0, uniformArray, 0, uniformArraySize / 4);
|
||||
|
||||
const renderPass = encoder.beginRenderPass({
|
||||
colorAttachments: [{
|
||||
@ -233,13 +288,23 @@ function render()
|
||||
loadOp: "clear",
|
||||
clearValue: { r: 0.2, g: 0.2, b: 0.4, a: 1 },
|
||||
storeOp: "store",
|
||||
}]
|
||||
}],
|
||||
depthStencilAttachment: {
|
||||
view: depthTexture.createView(),
|
||||
depthClearValue: 1.0,
|
||||
depthLoadOp: 'clear',
|
||||
depthStoreOp: 'store',
|
||||
},
|
||||
});
|
||||
|
||||
renderPass.setPipeline(cellPipeline);
|
||||
renderPass.setVertexBuffer(0, vertexBuffer);
|
||||
const vertexOffset = indexBufferSize;
|
||||
renderPass.setVertexBuffer(0, indexVertexBuffer, vertexOffset, vertexBufferSize);
|
||||
renderPass.setIndexBuffer(indexVertexBuffer, "uint16", 0, indexBufferSize);
|
||||
renderPass.setBindGroup(0, bindGroups[which]);
|
||||
renderPass.draw(vertices.length / 2, gridSize * gridSize);
|
||||
//renderPass.draw(cubeVerticesCount, gridSize * gridSize);
|
||||
renderPass.drawIndexed(cubeIndexCount, gridSize * gridSize);
|
||||
//renderPass.drawIndexed(cubeIndexCount);
|
||||
|
||||
renderPass.end();
|
||||
|
||||
|
||||
21
index.wgsl
21
index.wgsl
@ -1,23 +1,29 @@
|
||||
struct Configuration {
|
||||
gridSize: vec2f,
|
||||
aspect: vec2f
|
||||
aspect: vec2f,
|
||||
matrix: mat4x4f
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<uniform> config: Configuration;
|
||||
@group(0) @binding(1) var<storage> state: array<u32>;
|
||||
|
||||
struct VertexInput {
|
||||
@location(0) position: vec2f,
|
||||
@location(0) position: vec3f,
|
||||
@location(1) texture: vec2f,
|
||||
@location(2) normal: vec3f,
|
||||
@location(3) tangent: vec4f,
|
||||
@builtin(instance_index) instance: u32,
|
||||
};
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) position: vec4f,
|
||||
@location(0) cell: vec2f,
|
||||
@location(1) normal: vec3f,
|
||||
};
|
||||
|
||||
struct FragmentInput {
|
||||
@location(0) cell: vec2f,
|
||||
@location(1) normal: vec3f,
|
||||
};
|
||||
|
||||
@vertex
|
||||
@ -28,16 +34,21 @@ fn vertexMain(input: VertexInput) -> VertexOutput
|
||||
|
||||
let state = f32(state[input.instance]);
|
||||
let cell = vec2f(instance % config.gridSize.x, floor(instance / config.gridSize.y));
|
||||
let grid = (position * state + cell) / config.gridSize;
|
||||
let grid = (position * state + vec3f(cell, 0)) / config.gridSize.xxx;
|
||||
|
||||
var output: VertexOutput;
|
||||
output.position = vec4f((grid * 2 - 1) * config.aspect, 0, 1);
|
||||
//output.position = (config.matrix * vec4f((grid * 2 - 1), 1)) * vec4f(config.aspect, 1, 1);
|
||||
output.position = config.matrix * vec4f((grid * 2 - 1), 1);
|
||||
|
||||
//output.position = config.matrix * vec4f(input.position, 1);
|
||||
|
||||
output.cell = cell / config.gridSize;
|
||||
output.normal = input.normal;
|
||||
return output;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fragmentMain(input: FragmentInput) -> @location(0) vec4f
|
||||
{
|
||||
return vec4f(input.cell, 0, 1);
|
||||
return vec4f(input.normal * 0.5 + 0.5, 1);
|
||||
}
|
||||
|
||||
BIN
obj/cube.bin
Normal file
BIN
obj/cube.bin
Normal file
Binary file not shown.
36
obj/cube.obj
Normal file
36
obj/cube.obj
Normal file
@ -0,0 +1,36 @@
|
||||
# Blender 5.2.0 LTS
|
||||
# www.blender.org
|
||||
mtllib Untitled.mtl
|
||||
o Cube
|
||||
v 1.000000 1.000000 -1.000000
|
||||
v 1.000000 -1.000000 -1.000000
|
||||
v 1.000000 1.000000 1.000000
|
||||
v 1.000000 -1.000000 1.000000
|
||||
v -1.000000 1.000000 -1.000000
|
||||
v -1.000000 -1.000000 -1.000000
|
||||
v -1.000000 1.000000 1.000000
|
||||
v -1.000000 -1.000000 1.000000
|
||||
vn -0.0000 1.0000 -0.0000
|
||||
vn -0.0000 -0.0000 1.0000
|
||||
vn -1.0000 -0.0000 -0.0000
|
||||
vn -0.0000 -1.0000 -0.0000
|
||||
vn 1.0000 -0.0000 -0.0000
|
||||
vn -0.0000 -0.0000 -1.0000
|
||||
vt 0.000000 1.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.000000 0.000000
|
||||
s 0
|
||||
usemtl Material
|
||||
f 5/1/1 3/2/1 1/3/1
|
||||
f 3/3/2 8/4/2 4/2/2
|
||||
f 7/1/3 6/2/3 8/4/3
|
||||
f 2/3/4 8/4/4 6/1/4
|
||||
f 1/3/5 4/4/5 2/2/5
|
||||
f 5/1/6 2/2/6 6/4/6
|
||||
f 5/1/1 7/4/1 3/2/1
|
||||
f 3/3/2 7/1/2 8/4/2
|
||||
f 7/1/3 5/3/3 6/2/3
|
||||
f 2/3/4 4/2/4 8/4/4
|
||||
f 1/3/5 3/1/5 4/4/5
|
||||
f 5/1/6 1/3/6 2/2/6
|
||||
25
rotate.c
Normal file
25
rotate.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include "directxmath/directxmath.h"
|
||||
|
||||
extern "C" void rotate(float angle, float aspect, float * buffer);
|
||||
|
||||
void rotate(float angle, float aspect, float * buffer)
|
||||
{
|
||||
//XMMATRIX mat = XMMatrixRotationZ(angle);
|
||||
//XMMATRIX mat2 = XMMatrixRotationX(angle);
|
||||
//XMMATRIX mat2 = XMMatrixTranslation(0, 0, 1);
|
||||
//XMStoreFloat4x4((XMFLOAT4X4*)buffer, mat * mat2);
|
||||
|
||||
|
||||
XMVECTOR eye = XMVectorSet(3, 3, 3, 0);
|
||||
XMVECTOR at = XMVectorSet(0, 0, 0, 0);
|
||||
XMVECTOR up = XMVectorSet(0, 1, 0, 0);
|
||||
XMMATRIX view = XMMatrixLookAtRH(eye, at, up);
|
||||
|
||||
float fov_angle_y = XMConvertToRadians(45);
|
||||
float near_z = 0.01;
|
||||
float far_z = 1000.0;
|
||||
XMMATRIX projection = XMMatrixPerspectiveFovRH(fov_angle_y, aspect, near_z, far_z);
|
||||
|
||||
XMMATRIX rot = XMMatrixRotationY(angle);
|
||||
XMStoreFloat4x4((XMFLOAT4X4*)buffer, rot * view * projection);
|
||||
}
|
||||
128
tools/obj/obj.py
Normal file
128
tools/obj/obj.py
Normal file
@ -0,0 +1,128 @@
|
||||
import sys
|
||||
import struct
|
||||
from itertools import chain
|
||||
from dataclasses import dataclass
|
||||
|
||||
from obj import tangent
|
||||
|
||||
with open(sys.argv[1], 'r') as f:
|
||||
lines = f.read().split('\n')
|
||||
|
||||
position = []
|
||||
texture = []
|
||||
normal = []
|
||||
faces = []
|
||||
|
||||
def parse_vertex(prefix, s):
|
||||
return s.removeprefix(prefix).strip().split()
|
||||
|
||||
def float_vector(l, n):
|
||||
v = list(map(float, l))
|
||||
assert len(v) == n
|
||||
return v
|
||||
|
||||
vertex_types = [
|
||||
("v ", position, 3),
|
||||
("vn ", normal, 3),
|
||||
("vt ", texture, 2),
|
||||
]
|
||||
|
||||
ignore_prefixes = ["#", "mtllib ", "usemtl ", "o ", "s "]
|
||||
|
||||
def parse_line(line):
|
||||
if not line.strip():
|
||||
return
|
||||
|
||||
for prefix in ignore_prefixes:
|
||||
if line.startswith(prefix):
|
||||
return
|
||||
|
||||
for prefix, out, n in vertex_types:
|
||||
if line.startswith(prefix):
|
||||
out.append(float_vector(parse_vertex(prefix, line), n))
|
||||
return
|
||||
|
||||
if line.startswith("f "):
|
||||
vertices = [
|
||||
tuple(int(i)-1 for i in vertex.split("/"))
|
||||
for vertex in parse_vertex("f ", line)
|
||||
]
|
||||
assert len(vertices) == 3, vertices # is not triangle
|
||||
faces.append(vertices)
|
||||
return
|
||||
|
||||
assert False, repr(line) # unhandled line prefix
|
||||
|
||||
for line in lines:
|
||||
parse_line(line)
|
||||
|
||||
vertex_buffer_keys = dict()
|
||||
vertex_buffer = []
|
||||
index_buffer = []
|
||||
|
||||
for face in faces:
|
||||
for vertex in face:
|
||||
if vertex not in vertex_buffer_keys:
|
||||
vertex_buffer_keys[vertex] = len(vertex_buffer)
|
||||
vertex_buffer.append(tuple(chain(
|
||||
position[vertex[0]],
|
||||
texture[vertex[1]],
|
||||
normal[vertex[2]],
|
||||
)))
|
||||
|
||||
index_buffer.append(vertex_buffer_keys[vertex])
|
||||
|
||||
def render_vertex(f, vertex, tangent):
|
||||
# extra padding zero for normal R16G16B16A16
|
||||
# position texture normal tangent
|
||||
stride = struct.pack("<" + "fff" + "ff" + "eeee" + "eeee", *vertex, 0, *tangent)
|
||||
print(vertex, tangent)
|
||||
#print(len(stride))
|
||||
f.write(stride)
|
||||
|
||||
minv = [0, 0, 0]
|
||||
maxv = [0, 0, 0]
|
||||
for v in vertex_buffer:
|
||||
for i in range(3):
|
||||
if v[i] > maxv[i]:
|
||||
maxv[i] = v[i]
|
||||
if v[i] < minv[i]:
|
||||
minv[i] = v[i]
|
||||
|
||||
with open(sys.argv[2], 'wb') as f:
|
||||
|
||||
header_size = 4 * 5 + 4 * 6
|
||||
|
||||
index_size = 2 * 1
|
||||
index_buffer_size = index_size * len(index_buffer)
|
||||
|
||||
vertex_size = (4 * 3) + (4 * 2) + (2 * 4) + (2 * 4)
|
||||
vertex_buffer_size = vertex_size * len(vertex_buffer)
|
||||
|
||||
index_count = len(index_buffer)
|
||||
index_buffer_offset = header_size
|
||||
vertex_buffer_offset = header_size + index_buffer_size
|
||||
|
||||
tangents = tangent.generate_tangents(vertex_buffer, index_buffer)
|
||||
|
||||
header = struct.pack("<IIIIIffffff",
|
||||
index_count,
|
||||
index_buffer_offset,
|
||||
index_buffer_size,
|
||||
vertex_buffer_offset,
|
||||
vertex_buffer_size,
|
||||
*minv,
|
||||
*maxv)
|
||||
f.write(header)
|
||||
|
||||
assert f.tell() == index_buffer_offset
|
||||
for index in index_buffer:
|
||||
print(index, vertex_buffer[index])
|
||||
f.write(struct.pack("<H", index))
|
||||
|
||||
assert f.tell() == vertex_buffer_offset
|
||||
|
||||
for vertex, tangent in zip(vertex_buffer, tangents):
|
||||
render_vertex(f, vertex, tangent)
|
||||
|
||||
assert f.tell() == vertex_buffer_offset + vertex_buffer_size
|
||||
81
tools/obj/tangent.py
Normal file
81
tools/obj/tangent.py
Normal file
@ -0,0 +1,81 @@
|
||||
import numpy as np
|
||||
|
||||
PNT = list[tuple[float, float, float, # position
|
||||
float, float, # texture
|
||||
float, float, float, float]] # normal
|
||||
|
||||
def get_position(vertex_buffer: list[PNT], index):
|
||||
return vertex_buffer[index][0:3]
|
||||
|
||||
def get_texture(vertex_buffer: list[PNT], index):
|
||||
return vertex_buffer[index][3:5]
|
||||
|
||||
def get_normal(vertex_buffer: list[PNT], index):
|
||||
return vertex_buffer[index][5:8]
|
||||
|
||||
def normalize(v):
|
||||
return v / np.linalg.norm(v)
|
||||
|
||||
def generate_tangents(vertex_buffer: list[PNT],
|
||||
index_buffer: list[int]):
|
||||
vertex_count = len(vertex_buffer)
|
||||
|
||||
triangle_count = len(index_buffer) // 3
|
||||
|
||||
tan_s = np.zeros((vertex_count, 3,))
|
||||
tan_t = np.zeros((vertex_count, 3,))
|
||||
|
||||
for t in range(triangle_count):
|
||||
i0 = index_buffer[t * 3 + 0]
|
||||
i1 = index_buffer[t * 3 + 1]
|
||||
i2 = index_buffer[t * 3 + 2]
|
||||
|
||||
p0 = get_position(vertex_buffer, i0)
|
||||
p1 = get_position(vertex_buffer, i1)
|
||||
p2 = get_position(vertex_buffer, i2)
|
||||
|
||||
uv0 = get_texture(vertex_buffer, i0)
|
||||
uv1 = get_texture(vertex_buffer, i1)
|
||||
uv2 = get_texture(vertex_buffer, i2)
|
||||
|
||||
x1 = p1[0] - p0[0]
|
||||
x2 = p2[0] - p0[0]
|
||||
y1 = p1[1] - p0[1]
|
||||
y2 = p2[1] - p0[1]
|
||||
z1 = p1[2] - p0[2]
|
||||
z2 = p2[2] - p0[2]
|
||||
|
||||
s1 = uv1[0] - uv0[0]
|
||||
s2 = uv2[0] - uv0[0]
|
||||
|
||||
t1 = uv1[1] - uv0[1]
|
||||
t2 = uv2[1] - uv0[1]
|
||||
|
||||
d = (s1 * t2 - s2 * t1)
|
||||
r = 1.0 / d if d != 0 else 0
|
||||
|
||||
sdir = np.array([(t2 * x1 - t1 * x2) * r,
|
||||
(t2 * y1 - t1 * y2) * r,
|
||||
(t2 * z1 - t1 * z2) * r])
|
||||
|
||||
tdir = np.array([(s1 * x2 - s2 * x1) * r,
|
||||
(s1 * y2 - s2 * y1) * r,
|
||||
(s1 * z2 - s2 * z1) * r])
|
||||
|
||||
tan_s += sdir
|
||||
tan_t += tdir
|
||||
|
||||
tangents = []
|
||||
for v in range(vertex_count):
|
||||
n = np.array(get_normal(vertex_buffer, v))
|
||||
s = tan_s[v]
|
||||
|
||||
# orthagonalize
|
||||
tangent = normalize(s - n * np.dot(n, s))
|
||||
h = np.dot(np.cross(n, s), tan_t[v])
|
||||
w = -1.0 if h < 0.0 else 1.0
|
||||
tangent_w = (tangent[0], tangent[1], tangent[2], w)
|
||||
#print(tangent_w)
|
||||
tangents.append(tangent_w)
|
||||
|
||||
return tangents
|
||||
Loading…
x
Reference in New Issue
Block a user