How to draw a textured cube in WGPU using indices? - rust

I'm trying to draw a Minecraft-like textured cube in WGPU. I have a vertex buffer and an index buffer. I'm using Repeat for adress_mode on the texture sampler. I use texture coordinates greater or smaller than 0 to repeat the dirt texture. The front, right and left faces render properly. However, the texture coordinates of the back and top faces are messed up. I didn't add the bottom face yet as I wanted to get these working first. The back texture gets drawn twice and inside out and the top one is completely messed up.
Here's the code:
#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Vertex {
pub position: [f32; 3],
pub tex_coords: [f32; 2]
}
/// We arrange the vertices in counter-clockwise order: top, bottom left, bottom right.
pub const VERTICES: &[Vertex] = &[
// FRONT
Vertex {position: [-1.0, -1.0, 0.0], tex_coords: [0.0, 1.0]}, // 0
Vertex {position: [1.0, -1.0, 0.0], tex_coords: [1.0, 1.0]}, // 1
Vertex {position: [1.0, 1.0, 0.0], tex_coords: [1.0, 0.0]}, // 2
Vertex {position: [-1.0, 1.0, 0.0], tex_coords: [0.0, 0.0]}, // 3
// RIGHT
Vertex {position: [1.0, -1.0, -2.0], tex_coords: [2.0, 1.0]}, // 4
Vertex {position: [1.0, 1.0, -2.0], tex_coords: [2.0, 0.0]}, // 5
// LEFT
Vertex {position: [-1.0, -1.0, -2.0], tex_coords: [-1.0, 1.0]},
Vertex {position: [-1.0, 1.0, -2.0], tex_coords: [-1.0, 0.0]},
];
pub const INDICES: &[u16] = &[
// FRONT
0, 1, 2,
2, 3, 0,
// RIGHT
1, 4, 5,
5, 2, 1,
// LEFT
6, 0, 3,
3, 7, 6,
// BACK
6, 4, 5,
5, 7, 6,
// TOP
3, 2, 5,
5, 7, 3
];
My texture sampler:
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::Repeat,
address_mode_w: wgpu::AddressMode::Repeat,
mag_filter: wgpu::FilterMode::Nearest,
min_filter: wgpu::FilterMode::Nearest,
mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
});

Look at the first triangle of your BACK face: it uses vertices 6, 4, and 5. In that order, those vertices are:
Vertex {position: [-1.0, -1.0, -2.0], tex_coords: [-1.0, 1.0]}, // 6
Vertex {position: [1.0, -1.0, -2.0], tex_coords: [2.0, 1.0]}, // 4
Vertex {position: [1.0, 1.0, -2.0], tex_coords: [2.0, 0.0]}, // 5
The u texture coordinates span a range from -1 to 2 horizontally. So, they span 3 copies of the repeating texture, and 3 copies will be drawn in the space of your cube face.
It seems that you're trying to share vertices between different cube faces, and wrap the texture around them continuously. But the problem is that, in texture space, there is always going to be a “seam” at one of the edges of your block where instead of repeating again you start over from a low number (-1 in your code) — it's the same kind of problem as texture mapping a sphere. So, at least one edge must have non-shared vertices.
However, in the long run, you will probably want to stop sharing any vertices between different cube faces. This is because in order to do lighting, vertices must (usually) include normal vectors, and normals are different for each face. As a general rule in computer graphics, vertices can be shared between triangles when they are representing a smoothly curved (or flat) surface, but at any sharp edge, like the edges and corners of a cube, you must make separate vertices for each face.
You can still share vertices between the two triangles that make up one cube face.

Related

How to light all faces of rotating cube using glium

I made rotating cube using glium, but only one face is colored.
I am using Gouraud shading(from glium tutorial) for lighting.
The cube is made by defined 24 vertices and 6 normals.
Rotation is made by two matrices:
let m = [
[1.0, 0.0, 0.0, 0.0],
[0.0, t.cos(), -t.sin(), 0.0],
[0.0, t.sin(), t.cos(), 0.0],
[0.0, 0.0, 0.0, 1.0f32]
];
let n = [
[t.cos(), 0.0, t.sin(), 0.0],
[0.0, 1.0, 0.0, 0.0],
[-t.sin(), 0.0, t.cos(), 0.0],
[0.0, 0.0, 0.0, 1.0f32]
];
Fragment shader(glsl):
#version 150
in vec3 v_normal;
out vec4 color;
uniform vec3 u_light;
void main() {
float brightness = dot(normalize(v_normal), normalize(u_light));
vec3 dark_color = vec3(0.6, 0.0, 0.0);
vec3 regular_color = vec3(1.0, 0.0, 0.0);
color = vec4(mix(dark_color, regular_color, brightness), 1.0);
}
light:
let light = [-1.0, 0.4, 0.9f32];
The light should hit another face of cube in some point of rotation.
I try changing direction of light, that don't change anything.
Have anybody some idea?
for more info about the cube see this: my previous q. (some info like rotation is not actual here)
Images of the cube:
I think you have your normal direction in eye space and light direction in world space. So you have to convert light direction into camera (eye) space before passing into the shader, something like that (pseudo code):
normalize(VIEW_MATRIX * light)
Also, for the brightness I think you don't want to have negative value, so it have to be in a form
max(dot(N, L), 0.0)
I would recommend to read an introduction article about lighting, for example on learnOpenGL - https://learnopengl.com/Lighting/Basic-Lighting where you can see a description on what direction are for and how to prepare them.
or some GLSL tutorials about having light direction in camera space - https://www.lighthouse3d.com/tutorials/glsl-tutorial/directional-lights/

Is it possible to redraw a single Mesh in WebGl?

I'm having code as follows:
let arr = new Float32Array([-0.4, 0.3, -0.4, 0, 0.3, -0.2,
-0.5, -0.25,
0.7, 0.25,
0.9, -0.7
]);
let position_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, position_buffer);
gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW)
gl.vertexAttribPointer(position_location, 2, gl.FLOAT, false, 0 , 0);
gl.enableVertexAttribArray(position_location);
gl.drawArrays(gl.TRIANGLES, 0, 6)
If i want to change the second triangle (initial vertex -0.5, -0.25 in the arr), is there a way, to reach a gpu buffer, and tell him to redraw the vertices with an offset 3, and length of 3 ? So my first triangle wouldn't be redrawn?
It's called instanced drawing in webgl. Maybe for somebody would be helpful.

removing nested list elements with all zero entries

In a nested list (list of lists), how can I remove the elements that have all the entries as zero.
For instance: values =
[[1.1, 3.0], [2.5, 5.2], [4.7, 8.2], [69.2, 36.6], [0.7, 0.0], [0.0, 0.0], [0.4, 17.9], [14.7, 29.1], [6.8, 0.0], [0.0, 0.0]]
should change to
[[1.1, 3.0], [2.5, 5.2], [4.7, 8.2], [69.2, 36.6], [0.7, 0.0], [0.4, 17.9], [14.7, 29.1], [6.8, 0.0]]
Note: nested list could have n number of elements, not just 2.
Trying to do this to crop two other lists. something like:
for label, color, value in zip(labels, colors, values):
if any(value) in values: #this check needs update
new_labels.append(label)
new_colors.append(color)
Take advantage of the fact that 0.0 is falsey and filter using any().
result = [sublist for sublist in arr if any(sublist)]

How do you change the viewport size of the sublimetext in Python?

I'm trying to create my first plugin for Sublime Text 3.
How do I set the viewport size? I usually divide the layout into two, what I want to do is change the viewport size for the focused layout, so that I can read more content in the focused layout.
I was able to get the size of the viewport with the viewport_extent() method of the view, but I don't know how to set it to a new size.
Plugins do not have the ability to resize ST panels, or directly resize a viewport, but you can size the layout split when more than one row or column group is displayed.
You will want to use window.get_layout() to get the current layout together with window.set_layout to set the new layout, passing in the necessary arguments to give the active/focused group a larger size ratio.
A single pane layout looks like this in get_layout:
{'cells': [[0, 0, 1, 1]], 'rows': [0.0, 1.0], 'cols': [0.0, 1.0]}
An evenly split 2 column layout looks like this:
{'cells': [[0, 0, 1, 1], [1, 0, 2, 1]], 'rows': [0.0, 1.0], 'cols': [0.0, 0.5, 1.0]}
A wider left column might look like this:
{'cells': [[0, 0, 1, 1], [1, 0, 2, 1]], 'rows': [0.0, 1.0], 'cols': [0.0, 0.75, 1.0]}
you can determine which group is active using window.active_group(), and decide how to set the ratio based on that.
Note: some API functions don't appear in the official documentation. For exploration purposes, it can be useful to execute dir(window) or dir(view) in the ST console, to see what properties and methods are available.

vtkLookupTable specifing colors with opacities

I am trying to use a vtkLookupTable in order to set the colors for my mesh. I started with vtkColorTransferFunction which worked fined except that it does not enable me to set opacities for various colors.
vtkLookupTable offers this opportunity, but I am having problems to get it working.
My vtkPolyData have scalars value set that determine the color they shall get. Overall 7 values, set with the scalars 0 to 6.
My vtkLookupTable looks like this:
vtkLookupTable lut = new vtkLookupTable();
lut.SetNumberOfColors(7);
double opacity = 0.3;
lut.SetTableValue(0, 0, 0, 1, opacity);
lut.SetTableValue(1, 0, 1.0, 0, opacity);
lut.SetTableValue(2, 0.6, 1.0, 0.0, opacity);
lut.SetTableValue(3, 1.0, 1.0, 0.0, 0.7);
lut.SetTableValue(4, 1.0, 0.8, 0.0, opacity);
lut.SetTableValue(5, 1.0, 0.4, 0.0, opacity);
lut.SetTableValue(6, 1.0, 0.0, 0.0, 1);
If I use a vtkColorTransferFunction with the same values (just no opacity) it works. Anyone any idea why this is not working? I should be same?
Thanks for help.
From your pseudocode, two lines may be missing.
lut.SetTableRange(0.0,6.0)
lut.Build()
Do you call these functions?
If it is not this problem then it may be because of the polydatamapper you are using. Can you submit a whole pipeline for your problem?
As a guide the following code will need to be called to allow your scalar values to be
added to the mapper and visualised correctly.
mapper.SetLookupTable(lut)
mapper.SetScalarVisibility(1)
mapper.SetScalarRange(0.0,6.0)

Resources