gpt4 book ai didi

matrix - 在顶点着色器中将 GLSL mat4 分解为原始 RTS 值以计算 View UV 偏移

转载 作者:行者123 更新时间:2023-12-05 04:32:46 26 4
gpt4 key购买 nike

我需要获取模型和相机之间的旋转差异,将值转换为弧度/度,并将其传递给片段着色器。

为此,我需要分解模型旋转矩阵,也许还需要分解相机 View 矩阵。我似乎无法找到一种方法来分解适用于着色器的机制。

旋转细节进入片段着色器计算 uv 偏移。

original_rotation + viewing_angles 用于计算以下纹理的最终类 Sprite 偏移并显示为广告牌。

最终 UV 应该向下偏移(例如:H3 到 A3),从上面看向上(例如:A3 到 H3),从左到右看,反之亦然(例如:D1 到 D8,反之亦然)。

texture to offset

    const vertex_shader = `
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
attribute vec3 position;
attribute vec2 uv;
attribute mat4 instanceMatrix;
attribute float index;
attribute float texture_index;
uniform vec2 rows_cols;
uniform vec3 camera_location;

varying float vTexIndex;
varying vec2 vUv;
varying vec4 transformed_normal;


float normal_to_orbit(vec3 rotation_vector, vec3 view_vector){

rotation_vector = normalize(rotation_vector);
view_vector = normalize(view_vector);
vec3 x_direction = vec3(1.0,0,0);
vec3 y_direction = vec3(0,1.0,0);
vec3 z_direction = vec3(0,0,1.0);

float rotation_x_length = dot(rotation_vector, x_direction);
float rotation_y_length = dot(rotation_vector, y_direction);
float rotation_z_length = dot(rotation_vector, z_direction);

float view_x_length = dot(view_vector, x_direction);
float view_y_length = dot(view_vector, y_direction);
float view_z_length = dot(view_vector, z_direction);

//TOP
float top_rotation = degrees(atan(rotation_x_length, rotation_z_length));
float top_view = degrees(atan(view_x_length, view_z_length));
float top_final = top_view-top_rotation;
float top_idx = floor(top_final/(360.0/rows_cols.x));
//FRONT
float front_rotation = degrees(atan(rotation_x_length, rotation_z_length));
float front_view = degrees(atan(view_x_length, view_z_length));
float front_final = front_view-front_rotation;
float front_idx = floor(front_final/(360.0/rows_cols.y));

return abs((front_idx*rows_cols.x)+top_idx);
}

vec3 extractEulerAngleXYZ(mat4 mat) {
vec3 rotangles = vec3(0,0,0);
rotangles.x = atan(mat[2].z, -mat[1].z);
float cosYangle = sqrt(pow(mat[0].x, 2.0) + pow(mat[0].y, 2.0));
rotangles.y = atan(cosYangle, mat[0].z);
float sinXangle = sin(rotangles.x);
float cosXangle = cos(rotangles.x);
rotangles.z = atan(cosXangle * mat[1].y + sinXangle * mat[2].y, cosXangle * mat[1].x + sinXangle * mat[2].x);
return rotangles;
}

float view_index(vec3 position, mat4 mv_matrix, mat4 rot_matrix){
vec4 posInView = mv_matrix * vec4(0.0, 0.0, 0.0, 1.0);
// posInView /= posInView[3];
vec3 VinView = normalize(-posInView.xyz); // (0, 0, 0) - posInView
// vec4 NinView = normalize(rot_matrix * vec4(0.0, 0.0, 1.0, 1.0));
// float NdotV = dot(NinView, VinView);
vec4 view_normal = rot_matrix * vec4(VinView.xyz, 1.0);
float view_x_length = dot(view_normal.xyz, vec3(1.0,0,0));
float view_y_length = dot(view_normal.xyz, vec3(0,1.0,0));
float view_z_length = dot(view_normal.xyz, vec3(0,0,1.0));
// float radians = atan(-view_x_length, -view_z_length);
float radians = atan(view_x_length, view_z_length);
// float angle = radians/PI*180.0 + 180.0;
float angle = degrees(radians);
if (radians < 0.0) { angle += 360.0; }
if (0.0<=angle && angle<=360.0){
return floor(angle/(360.0/rows_cols.x));
}
return 0.0;

}

void main(){
vec4 original_normal = vec4(0.0, 0.0, 1.0, 1.0);
// transformed_normal = modelViewMatrix * instanceMatrix * original_normal;
vec3 rotangles = extractEulerAngleXYZ(modelViewMatrix * instanceMatrix);
// transformed_normal = vec4(rotangles.xyz, 1.0);
transformed_normal = vec4(camera_location.xyz, 1.0);


vec4 v = (modelViewMatrix* instanceMatrix* vec4(0.0, 0.0, 0.0, 1.0)) + vec4(position.x, position.y, 0.0, 0.0) * vec4(1.0, 1.0, 1.0, 1.0);
vec4 model_center = (modelViewMatrix* instanceMatrix* vec4(0.0, 0.0, 0.0, 1.0));
vec4 model_normal = (modelViewMatrix* instanceMatrix* vec4(0.0, 0.0, 1.0, 1.0));
vec4 cam_loc = vec4(camera_location.xyz, 1.0);
vec4 view_vector = normalize((cam_loc-model_center));
//float findex = normal_to_orbit(model_normal.xyz, view_vector.xyz);
float findex = view_index(position, base_matrix, combined_rot);

vTexIndex = texture_index;
vUv = vec2(mod(findex,rows_cols.x)/rows_cols.x, floor(findex/rows_cols.x)/rows_cols.y) + (uv / rows_cols);
//vUv = vec2(mod(index,rows_cols.x)/rows_cols.x, floor(index/rows_cols.x)/rows_cols.y) + (uv / rows_cols);

gl_Position = projectionMatrix * v;
// gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position, 1.0);
}
`
const fragment_shader = (texture_count) => {
var fragShader = `
precision highp float;
uniform sampler2D textures[${texture_count}];
varying float vTexIndex;
varying vec2 vUv;
varying vec4 transformed_normal;

void main() {
vec4 finalColor;
`;
for (var i = 0; i < texture_count; i++) {
if (i == 0) {
fragShader += `if (vTexIndex < ${i}.5) {
finalColor = texture2D(textures[${i}], vUv);
}
`
} else {
fragShader += `else if (vTexIndex < ${i}.5) {
finalColor = texture2D(textures[${i}], vUv);
}
`
}
}
//fragShader += `gl_FragColor = finalColor * transformed_normal; }`;
fragShader += `gl_FragColor = finalColor; }`;
// fragShader += `gl_FragColor = startColor * finalColor; }`;
// int index = int(v_TexIndex+0.5); //https://stackoverflow.com/questions/60896915/texture-slot-not-getting-picked-properly-in-shader-issue
//console.log('frag shader: ', fragShader)
return fragShader;
}

function reset_instance_positions() {
const dummy = new THREE.Object3D();
const offset = 500*4
for (var i = 0; i < max_instances; i++) {
dummy.position.set(offset-(Math.floor(i % 8)*500), offset-(Math.floor(i / 8)*500), 0);
dummy.updateMatrix();
mesh.setMatrixAt(i, dummy.matrix);
}
mesh.instanceMatrix.needsUpdate = true;
}

function setup_geometry() {
const geometry = new THREE.InstancedBufferGeometry().copy(new THREE.PlaneBufferGeometry(400, 400));
const index = new Float32Array(max_instances * 1); // index
for (let i = 0; i < max_instances; i++) {
index[i] = (i % max_instances) * 1.0 /* index[i] = 0.0 */
}
geometry.setAttribute("index", new THREE.InstancedBufferAttribute(index, 1));
const texture_index = new Float32Array(max_instances * 1); // texture_index
const max_maps = 1
for (let i = 0; i < max_instances; i++) {
texture_index[i] = (Math.floor(i / max_instances) % max_maps) * 1.0 /* index[i] = 0.0 */
}
geometry.setAttribute("texture_index", new THREE.InstancedBufferAttribute(texture_index, 1));
const textures = [texture]
const grid_xy = new THREE.Vector2(8, 8)
mesh = new THREE.InstancedMesh(geometry,
new THREE.RawShaderMaterial({
uniforms: {
textures: {
type: 'tv',
value: textures
},
rows_cols: {
value: new THREE.Vector2(grid_xy.x * 1.0, grid_xy.y * 1.0)
},
camera_location: {
value: camera.position
}
},
vertexShader: vertex_shader,
fragmentShader: fragment_shader(textures.length),
side: THREE.DoubleSide,
// transparent: true,
}), max_instances);
scene.add(mesh);
reset_instance_positions()
}

var camera, scene, mesh, renderer;
const max_instances = 64

function init() {

camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight,1, 10000 );
camera.position.z = 1024;

scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);

setup_geometry()
var canvas = document.createElement('canvas');
var context = canvas.getContext('webgl2');

renderer = new THREE.WebGLRenderer({
canvas: canvas,
context: context
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

window.addEventListener('resize', onWindowResize, false);

var controls = new THREE.OrbitControls(camera, renderer.domElement);
}

function onWindowResize() {

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

renderer.setSize(window.innerWidth, window.innerHeight);

}

function animate() {
requestAnimationFrame(animate);

renderer.render(scene, camera);
}
var dataurl = "/image/accaU.png"

var texture;
var imageElement = document.createElement('img');
imageElement.onload = function(e) {
texture = new THREE.Texture(this);
texture.needsUpdate = true;
init();
animate();
};
imageElement.src = dataurl;

JSFiddle of work so far

最佳答案

因此,您在 xy 平面 QUAD 上使用了 4x4 变换矩阵 M,并希望以类似“repaeat”的方式(跨越边界)将其 4 个角(p0、p1、p2、p3)映射到您的纹理从左/右/上/下将根据矩阵的 Z 轴方向返回右/左/下/上)。

你面临两个问题......

  1. M 旋转是 3 DOF,而您只需要 2 DOF(偏航、俯仰),因此如果存在滚动,结果可能有问题

  2. 如果纹理跨越边界,您需要在 GLSL 中处理它以避免看起来

    所以要么在几何着色器中执行此操作,并在需要时将四边形划分为更多,要么在需要重叠的地方使用放大的纹理 ...

现在,如果我没有遗漏某些东西,转换是这样的:

const float pi=3.1415926535897932384626433832795;
vec3 d = normalize(z axis from M);
vec2 dd = normalize(d.xy);
u = atan2(dd.y,dd.x);
v = acos(d.z);
u = (u+pi)/(2.0*pi);
v = v/pi

z 轴提取只是矩阵“M”中第 3 列/行(取决于您的符号)的简单副本或通过它转换 (1,0,0,0)。有关详细信息,请参阅:

如果纹理重叠,您还需要添加:

const float ov = 1.0/8.0; // overlap size
u = ov + (u/(ov+ov+1.0));
v = ov + (v/(ov+ov+1.0));

纹理看起来像:

overlap texture

如果您的四边形覆盖超过原始纹理的 1/8,您需要扩大重叠 ...

现在要处理 QUAD 的角而不仅仅是轴,您可以在网格局部坐标的 Z+ 方向上按距离 l 平移四边形,在它们上应用 M 并使用这 4 个点作为在顶点着色器中计算 u,v 的方向。 l 将影响有多少纹理区域用于四边形...这种方法甚至可以处理滚动但尚未测试任何这些...

实现后,我的担心是有根据的,因为任何 2 个欧拉角会相互影响,所以结果在大多数方向上都可以,但在边缘情况下,可能由于区域覆盖,东西会在一个或两个轴上镜像和/或跳跃3 DOF 和 2 DOF 之间的区别(除非我在我的代码中犯了一个错误,或者由于驱动程序中的错误而在我之前发生的顶点中的数学计算不正确)

如果你想要的方位角/仰角应该没问题,因为它的 2 DOF 也应该适用于上面的等式 +/- 如果需要,一些范围转换。

关于matrix - 在顶点着色器中将 GLSL mat4 分解为原始 RTS 值以计算 View UV 偏移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71597995/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com