Уроки, алгоритмы, программы, примеры

Вход на сайт

Материалы по разделам

Построения
на плоскости (2D)
Графика
в пространстве (3D)
Вычислительная
геометрия
Физическое
моделирование
Фрактальная
графика

Новые комментарии

Рекурсия присутствует?
И где эти прикрепленные файлы?
Я код на C++ набрал сам. Строил кривую Безье, но "прилипал" к нулю. То есть я задаю точки далеко от нуля, а он строил из нуля, а потом только обходил предложенные точки. Потом я нашёл Ваш сайт и эту статью. Оказалось, что я забыл возвести t в...
просто я не так понял, здесь мы вращаем точки куба что вращает сам куб. Мне нужно вращать просто 3д объект , данный способ не подходит
Задавайте объект в мировых координатах. Вращайте его относительно мировой системы координат. А при отрисовке преобразуйте в экранные координаты. Посмотрите пример преобразования в экранные координаты.

Счетчики и рейтинг

Рейтинг@Mail.ru Яндекс.Метрика
Скриншот к примеру
Среда программирования: 
Linux QT Creator
Статья по теме: 

Пример для шума перлина, кода довольно много, но он хорошо раскомментирован.
Весь шум перлина отделен в отдельный класс - можете использовать по своему усмотрению.

Запуск: выкидываете ехе-фаил в любое удобное место и кладете рядом SDL.dll, должно работать.

Интерфейс: Окно с сами шумом. Вводите 3 коэффициента через пробел и получаете отрисовку шума.

Управление: консоль

Код программы: 

Конструктор класса для шума

//PN.H BEGIN
#ifndef PN_H
#define PN_H
#include <vector>
class PN {
    // Вектор значений
    std::vector<int> p;
public:
    // Инициализируем значения вектора
    PN();
    // Генерирует новый вектор из зерна
    PN(unsigned int PSeed);
    // Получаем 2D шум, z может принимать любое значение
    double PNoise(double x, double y, double z);
private:
    double FadeOut(double t);
    double LinearInterpolation(double t, double a, double b);
    double Gradient(int hash, double x, double y, double z);
};
 
#endif 
// PN.H END

сам шум:

//PN.CPP BEGIN
#include "PN.h"
#include <algorithm>
#include <numeric>
#include <random>
 
PN::PN() {
 
    // Инициализируем вектор псевдослучайных чисел
    p = {
        151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,
        8,99,37,240,21,10,23,190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,
        35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,
        134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,
        55,46,245,40,244,102,143,54, 65,25,63,161,1,216,80,73,209,76,132,187,208, 89,
        18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,
        250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,
        189,28,42,223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167,
        43,172,9,129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,
        97,228,251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,
        107,49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
        138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 };
    p.insert(p.end(), p.begin(), p.end());
}
 
// Генерируем новый вектор из зерна (рандомное число = рандомный вектор)
PN::PN(unsigned int PSeed) {
    p.resize(256); //сжимаем вектор до 256 значений
 
    // Заполним р значениями от 0 до 255
    std::iota(p.begin(), p.end(), 0);
 
    // Инициализируем рандомные значения зерном
    std::default_random_engine engine(PSeed);
 
    // Перемешиваем значения вектора
    std::shuffle(p.begin(), p.end(), engine);
 
    // И вставим
    p.insert(p.end(), p.begin(), p.end());
}
 
double PN::PNoise(double x, double y, double z) {
    // Находим куб содержащий данную точку
    int X = (int) floor(x) & 255;
    int Y = (int) floor(y) & 255;
    int Z = (int) floor(z) & 255;
 
    // Находим значение x, y, z после запятой
    x -= floor(x);
    y -= floor(y);
    z -= floor(z);
 
    // Вычисляем кривую по значения переменных
    double u = FadeOut(x);
    double v = FadeOut(y);
    double w = FadeOut(z);
 
    // Получаем 8 векторов из углов куба
    int A = p[X] + Y;
    int AA = p[A] + Z;
    int AB = p[A + 1] + Z;
    int B = p[X + 1] + Y;
    int BA = p[B] + Z;
    int BB = p[B + 1] + Z;
    double res = LinearInterpolation(w, LinearInterpolation(v, LinearInterpolation(u, Gradient(p[AA], x, y, z), Gradient(p[BA], x-1, y, z)), LinearInterpolation(u, Gradient(p[AB], x, y-1, z), Gradient(p[BB], x-1, y-1, z))),	LinearInterpolation(v, LinearInterpolation(u, Gradient(p[AA+1], x, y, z-1), Gradient(p[BA+1], x-1, y, z-1)), LinearInterpolation(u, Gradient(p[AB+1], x, y-1, z-1),	Gradient(p[BB+1], x-1, y-1, z-1))));
    return (res + 1.0)/2.0;
}
 
double PN::FadeOut(double t) {
    return t * t * t * (t * (t * 6 - 15) + 10);
}
 
double PN::LinearInterpolation(double t, double a, double b) {
    return a + t * (b - a);
}
 
double PN::Gradient(int hash, double x, double y, double z) {
    int h = hash & 15;
    // Конвертирует 4 нижних значения векторов в 12 градиентных
    double u = h < 8 ? x : y,
           v = h < 4 ? y : h == 12 || h == 14 ? x : z;
    return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
// PN.CPP END

Графическая обертка (SDL2):
//main.cpp BEGIN
#include "PN.h"
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <random>
#include <SDL.h>
#undef main
 
#define TEST 400
 
using namespace std;
 
void SetPixel(SDL_Surface* surface, int x, int y, Uint32 pixel) //функция установки пикселя на поверхность, принимает название поверхности, координаты х и у, и цвет в формате uint32
{
    Uint32 *p = (Uint32 *) surface->pixels + y*surface->w+x;
    *p = pixel;
}
 
int main()
{
    unsigned int width=TEST, height=TEST; //размеры нашего окна
 
    SDL_Window *window= NULL; //пустое окно
    SDL_Renderer *renderer = NULL; //пустой рендерер
    SDL_Surface *image = NULL; //пустая поверхность
    SDL_Texture *imageTexture = NULL; //пустая текстура
 
    if(SDL_Init(SDL_INIT_VIDEO)<0)
	{ 
		//инициализируем видеодрайвер или выкидываем ошибку
        cout<<"Ошибка инициализации видео"<<endl;
        return 1;
    }
 
    window = SDL_CreateWindow("Perlin", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, 0); //создаем окно с ранее заданными размерами по центру или кидаем ошибку
    if(!window) 
	{
        cout<<"SDL не создало окно"<<endl;
        return 2;
    }
 
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); //создаем рендерер для нашего окна или кидаем ошибку
    if(!renderer) 
	{
        cout<<"SDL не получила доступа к рендереру"<<endl;
        return 3;
    }
 
    Uint32 rmask, gmask, bmask, amask; //создаем пиксель с цветами в формате RGBA
    #if SDL_BYTEORDER == SDL_BIG_ENDIAN //здесь описывается маска пикселей для разных архитектур
        rmask = 0xff000000;
        gmask = 0x00ff0000;
        bmask = 0x0000ff00;
        amask = 0x000000ff;
    #else
        rmask = 0x000000ff;
        gmask = 0x0000ff00;
        bmask = 0x00ff0000;
        amask = 0xff000000;
    #endif
 
    image = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, rmask, gmask, bmask,amask); //создаем поверхность под наши пиксели
    if(!image) 
	{
        cout << "Все плохо с поверхностью :(" <<endl;
        return 4;
    }
    unsigned int PSeed=0; //зернышко для рандома
 
    Uint8 colourByte; //упрощаем пиксель до uint (у нас же ЧБ изображение)
    bool quit = false; //бул для выхода
    SDL_Event event; //событие для обработки нажатий
 
    PN pn(PSeed); //создаем объект шума Перлина по зерну
    int ax=0, ay=0, e=0; //начальные значения для формулы шума
	while (!quit)
	{ //пока не ESC или не закрыли окно
 
		for (unsigned int i = 0; i < height; ++i) //циклом высчитываем шум и заполняем поверхность
			for (unsigned int j = 0; j < width; ++j)
			{
				double x = (double)j / ((double)width);
				double y = (double)i / ((double)height);
				double n = pn.PNoise(ax*x, ay*y, e);
				colourByte = Uint8(n * 0xff);
				SetPixel(image, j, i, SDL_MapRGB(image->format, colourByte, colourByte, colourByte));
			}
		SDL_RenderClear(renderer); //очищаем буфер рендерера и пихаем в него новую текстуру
		imageTexture = SDL_CreateTextureFromSurface(renderer, image); //создаем изображение (которое пойдет на экран)
		SDL_RenderCopy(renderer, imageTexture, NULL, NULL);
		SDL_RenderPresent(renderer); //проверяем все ли хорошо
 
		if (!imageTexture)
		{
			cout << "Не создалась поверхность из текстуры" << endl;
			return 5;
		}
 
		cout << " ax: " << ax << " ay: " << ay << " e: " << e << endl; //выводим в консоль текущие коэффициенты
		cout << "New ax, ay, e (spaced): ";
		cin >> ax >> ay >> e;
 
		//этот участок кода скорее всего не понадобится,
		//поскольку выход можно выполнить просто закрыв консоль
		//да и окно отвечать не будет, но пусть
		while (SDL_PollEvent(&event)) { //ждем дальнейших указаний:
			switch (event.type)
			{
			case SDL_QUIT: //закрыли окно -> выход
				quit = true;
				break;
			}
		}
	}
	//выход:
    SDL_FreeSurface(image); //очищаем поверхность
    SDL_DestroyTexture(imageTexture); //уничтожаем текстуру
    SDL_DestroyRenderer(renderer); //и рендерер
    SDL_DestroyWindow(window); // и окно
    SDL_Quit(); //выключаем библиотеку SDL
    return 0; //выход из программы
}
//main.cpp END

Прикрепленный файлРазмер
Perlin_noise.zip692.48 кб